From b1bfc3ab1476c46888719d0b0a2642955b2aa0e1 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sat, 27 Jun 2026 10:53:33 +0300 Subject: [PATCH 001/120] PMM-14109 Fix the read_more URLs --- managed/data/checks/mongodb_authmech_scramsha256.yml | 2 +- managed/data/checks/mongodb_balancer.yml | 2 +- managed/data/checks/mongodb_bindip.yml | 2 +- managed/data/checks/mongodb_collection_fragmented.yml | 2 +- managed/data/checks/mongodb_connection_sudden_spike.yml | 2 +- managed/data/checks/mongodb_connections.yml | 2 +- managed/data/checks/mongodb_dbpath_mount.yml | 2 +- managed/data/checks/mongodb_fcv_check.yml | 2 +- managed/data/checks/mongodb_journal.yml | 2 +- managed/data/checks/mongodb_localhost_auth_bypass.yml | 2 +- managed/data/checks/mongodb_loglevel.yml | 2 +- managed/data/checks/mongodb_maxsessions.yml | 2 +- managed/data/checks/mongodb_multiple_services.yml | 2 +- managed/data/checks/mongodb_oplog_size_recommendation.yml | 2 +- managed/data/checks/mongodb_psa_architecture_check.yml | 2 +- managed/data/checks/mongodb_read_tickets.yml | 2 +- managed/data/checks/mongodb_replicaset_topology.yml | 2 +- managed/data/checks/mongodb_replication_lag.yml | 2 +- .../checks/mongodb_shard_collection_inconsistent_indexes.yml | 2 +- managed/data/checks/mongodb_swap_allocation.yml | 2 +- managed/data/checks/mongodb_taskexecutor.yml | 2 +- managed/data/checks/mongodb_unused_index.yml | 2 +- managed/data/checks/mongodb_version.yml | 2 +- managed/data/checks/mongodb_write_tickets.yml | 2 +- managed/data/checks/mongodb_xfs_ftype.yml | 2 +- managed/data/checks/mysql_32binary_on_64system.yml | 2 +- .../checks/mysql_ahi_efficiency_performance_basic_check.yml | 2 +- managed/data/checks/mysql_automatic_sp_privileges_enabled.yml | 2 +- managed/data/checks/mysql_config_binlog_retention_period.yml | 2 +- managed/data/checks/mysql_config_binlog_row_image.yml | 2 +- managed/data/checks/mysql_config_binlogs_checksummed.yml | 2 +- managed/data/checks/mysql_config_general_log.yml | 2 +- managed/data/checks/mysql_config_innodb_redolog_disabled.yml | 2 +- managed/data/checks/mysql_config_local_infile.yml | 2 +- managed/data/checks/mysql_config_log_bin.yml | 2 +- managed/data/checks/mysql_config_relay_log_purge.yml | 2 +- managed/data/checks/mysql_config_replication_bp1.yml | 2 +- managed/data/checks/mysql_config_slave_parallel_workers.yml | 2 +- managed/data/checks/mysql_config_sql_mode.yml | 2 +- managed/data/checks/mysql_config_sync_binlog.yml | 2 +- managed/data/checks/mysql_config_tmp_table_size_limit.yml | 2 +- managed/data/checks/mysql_configuration_innodb_file_format.yml | 2 +- .../data/checks/mysql_configuration_innodb_file_maxlimit.yml | 2 +- .../mysql_configuration_innodb_file_per_table_not_enabled.yml | 2 +- managed/data/checks/mysql_configuration_innodb_flush_method.yml | 2 +- managed/data/checks/mysql_configuration_innodb_strict_mode.yml | 2 +- managed/data/checks/mysql_configuration_log_verbosity.yml | 2 +- .../data/checks/mysql_configuration_max_connections_usage.yml | 2 +- .../data/checks/mysql_configuration_secure_file_priv_empty.yml | 2 +- .../data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml | 2 +- managed/data/checks/mysql_log_replica_updates.yml | 2 +- managed/data/checks/mysql_password_expiry.yml | 2 +- .../data/checks/mysql_performance_temp_ondisk_table_high.yml | 2 +- ...mysql_replica_running_skipping_errors_or_idempotent_mode.yml | 2 +- managed/data/checks/mysql_replication_grants.yml | 2 +- managed/data/checks/mysql_require_secure_transport.yml | 2 +- managed/data/checks/mysql_security_anonymous_user.yml | 2 +- managed/data/checks/mysql_security_open_to_world_host.yml | 2 +- managed/data/checks/mysql_security_password_lifetime.yml | 2 +- managed/data/checks/mysql_security_password_policy.yml | 2 +- managed/data/checks/mysql_security_replication_grants_mixed.yml | 2 +- managed/data/checks/mysql_security_root_not_local.yml | 2 +- managed/data/checks/mysql_security_user_ssl.yml | 2 +- managed/data/checks/mysql_security_user_super_not_local.yml | 2 +- managed/data/checks/mysql_security_user_without_password.yml | 2 +- managed/data/checks/mysql_tables_without_pk.yml | 2 +- managed/data/checks/mysql_timezone.yml | 2 +- managed/data/checks/mysql_unsupported_version_check.yml | 2 +- managed/data/checks/mysql_version_eol_57.yml | 2 +- managed/data/checks/postgresql_archiver_failing.yml | 2 +- managed/data/checks/postgresql_cache_hit_ratio.yml | 2 +- managed/data/checks/postgresql_config_changes_need_restart.yml | 2 +- managed/data/checks/postgresql_cve_check.yml | 2 +- managed/data/checks/postgresql_eol_check.yml | 2 +- managed/data/checks/postgresql_expiring_passwd_check.yml | 2 +- managed/data/checks/postgresql_extension_check.yml | 2 +- managed/data/checks/postgresql_fsync.yml | 2 +- managed/data/checks/postgresql_log_autovacuum_min_duration.yml | 2 +- managed/data/checks/postgresql_log_checkpoints.yml | 2 +- .../data/checks/postgresql_logging_recommendation_checks.yml | 2 +- managed/data/checks/postgresql_max_connections.yml | 2 +- managed/data/checks/postgresql_number_of_index_check.yml | 2 +- managed/data/checks/postgresql_sequential_scan_check.yml | 2 +- managed/data/checks/postgresql_stale_replication_slot.yml | 2 +- managed/data/checks/postgresql_table_autovac_settings.yml | 2 +- managed/data/checks/postgresql_table_bloat_bytes.yml | 2 +- managed/data/checks/postgresql_table_bloat_in_percentage.yml | 2 +- managed/data/checks/postgresql_tmpfiles_check.yml | 2 +- managed/data/checks/postgresql_txid_wraparound_approaching.yml | 2 +- managed/data/checks/postgresql_unsupported_check.yml | 2 +- managed/data/checks/postgresql_unused_index_check.yml | 2 +- managed/data/checks/postgresql_vacuum_sanity_check.yml | 2 +- managed/data/checks/postgresql_version_check.yml | 2 +- managed/data/checks/postgresql_wal_retention_check.yml | 2 +- 94 files changed, 94 insertions(+), 94 deletions(-) diff --git a/managed/data/checks/mongodb_authmech_scramsha256.yml b/managed/data/checks/mongodb_authmech_scramsha256.yml index 5f17f8af54e..d0e48bbec97 100644 --- a/managed/data/checks/mongodb_authmech_scramsha256.yml +++ b/managed/data/checks/mongodb_authmech_scramsha256.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETPARAMETER script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_balancer.yml b/managed/data/checks/mongodb_balancer.yml index 95a540374d4..33de3a10a04 100644 --- a/managed/data/checks/mongodb_balancer.yml +++ b/managed/data/checks/mongodb_balancer.yml @@ -12,7 +12,7 @@ checks: - type: METRICS_INSTANT query: avg by(cluster) (mongodb_mongos_sharding_chunks_is_balancer_running{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_bindip.yml b/managed/data/checks/mongodb_bindip.yml index 28516650549..c86a0ac61f4 100644 --- a/managed/data/checks/mongodb_bindip.yml +++ b/managed/data/checks/mongodb_bindip.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_collection_fragmented.yml b/managed/data/checks/mongodb_collection_fragmented.yml index 2e9a82a62f5..030c86fc61b 100644 --- a/managed/data/checks/mongodb_collection_fragmented.yml +++ b/managed/data/checks/mongodb_collection_fragmented.yml @@ -19,7 +19,7 @@ checks: - type: METRICS_INSTANT query: avg by(collection,database) (mongodb_collstats_storageStats_size{database!="admin", database!="config", database!="local", collection!="system.profile", node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_connection_sudden_spike.yml b/managed/data/checks/mongodb_connection_sudden_spike.yml index 029330b4ae6..42814700dc5 100644 --- a/managed/data/checks/mongodb_connection_sudden_spike.yml +++ b/managed/data/checks/mongodb_connection_sudden_spike.yml @@ -15,7 +15,7 @@ checks: range: 24h step: 15m script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): #Gathering initial connection count. diff --git a/managed/data/checks/mongodb_connections.yml b/managed/data/checks/mongodb_connections.yml index b25e850e2c8..514c5d3c3b2 100644 --- a/managed/data/checks/mongodb_connections.yml +++ b/managed/data/checks/mongodb_connections.yml @@ -13,7 +13,7 @@ checks: queries: - type: MONGODB_GETDIAGNOSTICDATA script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_dbpath_mount.yml b/managed/data/checks/mongodb_dbpath_mount.yml index 1cf048549ad..0b9443031db 100644 --- a/managed/data/checks/mongodb_dbpath_mount.yml +++ b/managed/data/checks/mongodb_dbpath_mount.yml @@ -13,7 +13,7 @@ checks: - type: METRICS_INSTANT query: avg by (fstype,mountpoint,node_name) (node_filesystem_files{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_fcv_check.yml b/managed/data/checks/mongodb_fcv_check.yml index e5cc0878024..1e3da3cee46 100644 --- a/managed/data/checks/mongodb_fcv_check.yml +++ b/managed/data/checks/mongodb_fcv_check.yml @@ -13,7 +13,7 @@ checks: - type: MONGODB_BUILDINFO - type: MONGODB_GETPARAMETER script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_journal.yml b/managed/data/checks/mongodb_journal.yml index 8455389ac56..8023befdca5 100644 --- a/managed/data/checks/mongodb_journal.yml +++ b/managed/data/checks/mongodb_journal.yml @@ -12,7 +12,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_localhost_auth_bypass.yml b/managed/data/checks/mongodb_localhost_auth_bypass.yml index c23a22a9b8c..c1841a7c4b0 100644 --- a/managed/data/checks/mongodb_localhost_auth_bypass.yml +++ b/managed/data/checks/mongodb_localhost_auth_bypass.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_loglevel.yml b/managed/data/checks/mongodb_loglevel.yml index 440f0cb119f..d3005e5ff4e 100644 --- a/managed/data/checks/mongodb_loglevel.yml +++ b/managed/data/checks/mongodb_loglevel.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_maxsessions.yml b/managed/data/checks/mongodb_maxsessions.yml index 4f884534831..4d9a7f1a701 100644 --- a/managed/data/checks/mongodb_maxsessions.yml +++ b/managed/data/checks/mongodb_maxsessions.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_multiple_services.yml b/managed/data/checks/mongodb_multiple_services.yml index 716c4b81626..950579b1a72 100644 --- a/managed/data/checks/mongodb_multiple_services.yml +++ b/managed/data/checks/mongodb_multiple_services.yml @@ -12,7 +12,7 @@ checks: - type: METRICS_INSTANT query: avg by(node_name,rs_nm,cluster) (mongodb_ss_pid{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_oplog_size_recommendation.yml b/managed/data/checks/mongodb_oplog_size_recommendation.yml index 0f9ef75f3f6..af6669ff730 100644 --- a/managed/data/checks/mongodb_oplog_size_recommendation.yml +++ b/managed/data/checks/mongodb_oplog_size_recommendation.yml @@ -16,7 +16,7 @@ checks: range: 24h step: 15m script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_psa_architecture_check.yml b/managed/data/checks/mongodb_psa_architecture_check.yml index 2b29c8375c3..1dab6793bf4 100644 --- a/managed/data/checks/mongodb_psa_architecture_check.yml +++ b/managed/data/checks/mongodb_psa_architecture_check.yml @@ -14,7 +14,7 @@ checks: - type: METRICS_INSTANT query: avg by(cluster,node_name,set) (mongodb_mongod_replset_my_state{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_read_tickets.yml b/managed/data/checks/mongodb_read_tickets.yml index 2122108d721..07d2b72e126 100644 --- a/managed/data/checks/mongodb_read_tickets.yml +++ b/managed/data/checks/mongodb_read_tickets.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_replicaset_topology.yml b/managed/data/checks/mongodb_replicaset_topology.yml index 79ddb786a63..2447cdfc975 100644 --- a/managed/data/checks/mongodb_replicaset_topology.yml +++ b/managed/data/checks/mongodb_replicaset_topology.yml @@ -12,7 +12,7 @@ checks: queries: - type: MONGODB_REPLSETGETSTATUS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_replication_lag.yml b/managed/data/checks/mongodb_replication_lag.yml index 641ad0cbd90..95880572c24 100644 --- a/managed/data/checks/mongodb_replication_lag.yml +++ b/managed/data/checks/mongodb_replication_lag.yml @@ -12,7 +12,7 @@ checks: queries: - type: MONGODB_REPLSETGETSTATUS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml b/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml index f7b183c236e..d7959f6f4d4 100644 --- a/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml +++ b/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml @@ -12,7 +12,7 @@ checks: - type: METRICS_INSTANT query: avg by(cl_role,cluster,node_name,rs_state) (mongodb_ss_shardedIndexConsistency_numShardedCollectionsWithInconsistentIndexes{rs_state="1", node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_swap_allocation.yml b/managed/data/checks/mongodb_swap_allocation.yml index fd14436a05b..2d4df98eba4 100644 --- a/managed/data/checks/mongodb_swap_allocation.yml +++ b/managed/data/checks/mongodb_swap_allocation.yml @@ -16,7 +16,7 @@ checks: - type: METRICS_INSTANT query: avg by(cluster,node_name,set) (mongodb_mongod_replset_my_state{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_taskexecutor.yml b/managed/data/checks/mongodb_taskexecutor.yml index 4812b01c0ac..9b1ca226ff8 100644 --- a/managed/data/checks/mongodb_taskexecutor.yml +++ b/managed/data/checks/mongodb_taskexecutor.yml @@ -13,7 +13,7 @@ checks: - type: METRICS_INSTANT query: mongodb_sys_cpu_num_cpus{node_name="{{.NodeName}}"} script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_unused_index.yml b/managed/data/checks/mongodb_unused_index.yml index f1607d7f541..56b875651e6 100644 --- a/managed/data/checks/mongodb_unused_index.yml +++ b/managed/data/checks/mongodb_unused_index.yml @@ -14,7 +14,7 @@ checks: - type: METRICS_INSTANT query: avg by (cluster,collection,database,key_name) (mongodb_indexstats_accesses_ops{node_name=~"{{.NodeName}}"}) == 0 script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): threshold = 30 diff --git a/managed/data/checks/mongodb_version.yml b/managed/data/checks/mongodb_version.yml index b46decde185..0b8cd356d4c 100644 --- a/managed/data/checks/mongodb_version.yml +++ b/managed/data/checks/mongodb_version.yml @@ -20,7 +20,7 @@ checks: "7.0": 70032, # https://www.percona.com/downloads/percona-server-mongodb-7.0/ "8.0": 80021, # https://www.percona.com/downloads/percona-server-mongodb-8.0/ }, - "read_url": "https://docs.percona.com/percona-platform/advisors/checks/{}.html", + "read_url": "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html", } def check_context(docs, context): diff --git a/managed/data/checks/mongodb_write_tickets.yml b/managed/data/checks/mongodb_write_tickets.yml index 1e5232721e8..51dbaf91465 100644 --- a/managed/data/checks/mongodb_write_tickets.yml +++ b/managed/data/checks/mongodb_write_tickets.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_xfs_ftype.yml b/managed/data/checks/mongodb_xfs_ftype.yml index b68f877335b..ca78bcf7956 100644 --- a/managed/data/checks/mongodb_xfs_ftype.yml +++ b/managed/data/checks/mongodb_xfs_ftype.yml @@ -14,7 +14,7 @@ checks: - type: METRICS_INSTANT query: avg by (fstype,mountpoint,node_name) (node_filesystem_files{fstype="xfs", node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mysql_32binary_on_64system.yml b/managed/data/checks/mysql_32binary_on_64system.yml index 92a2d49afa0..173ac33d97a 100644 --- a/managed/data/checks/mysql_32binary_on_64system.yml +++ b/managed/data/checks/mysql_32binary_on_64system.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version_compile_machine as version_compile_machine" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml b/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml index 639c5630a5f..30c889b5fb1 100644 --- a/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml +++ b/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml @@ -45,7 +45,7 @@ checks: results = [] ahi_parts = 0 - read_more = "https://docs.percona.com/percona-platform/advisors/checks/mysql-ahi-efficiency-performance-basic-check.html" + read_more = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/mysql-ahi-efficiency-performance-basic-check.html" # Check if AHI is enabled and partitioned for row in docs[0]: diff --git a/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml b/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml index 48a11aa0580..0b946f245fe 100644 --- a/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml +++ b/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service, @@automatic_sp_privileges as automatic_sp_privileges" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs,context): results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_config_binlog_retention_period.yml b/managed/data/checks/mysql_config_binlog_retention_period.yml index a793a792ca2..5db27ef9bb2 100644 --- a/managed/data/checks/mysql_config_binlog_retention_period.yml +++ b/managed/data/checks/mysql_config_binlog_retention_period.yml @@ -46,7 +46,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] in_result = check_binlog_retention_period(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_binlog_row_image.yml b/managed/data/checks/mysql_config_binlog_row_image.yml index 4df2e1f2723..ec2c536e22e 100644 --- a/managed/data/checks/mysql_config_binlog_row_image.yml +++ b/managed/data/checks/mysql_config_binlog_row_image.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] in_result = check_binlog_row_image(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_binlogs_checksummed.yml b/managed/data/checks/mysql_config_binlogs_checksummed.yml index 93e9d3c0b7d..897f8ab5ac9 100644 --- a/managed/data/checks/mysql_config_binlogs_checksummed.yml +++ b/managed/data/checks/mysql_config_binlogs_checksummed.yml @@ -31,7 +31,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] in_result = check_binlog_checksum(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_general_log.yml b/managed/data/checks/mysql_config_general_log.yml index 45b33017ed3..b5f23fc8f3a 100644 --- a/managed/data/checks/mysql_config_general_log.yml +++ b/managed/data/checks/mysql_config_general_log.yml @@ -32,7 +32,7 @@ checks: } def check_context(docs, context): - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] in_result = check_general_log(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_innodb_redolog_disabled.yml b/managed/data/checks/mysql_config_innodb_redolog_disabled.yml index b61acf5e7c3..99783f2365b 100644 --- a/managed/data/checks/mysql_config_innodb_redolog_disabled.yml +++ b/managed/data/checks/mysql_config_innodb_redolog_disabled.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = innodb_redolog_disabled(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_local_infile.yml b/managed/data/checks/mysql_config_local_infile.yml index dc9f545df4c..fb4d89623b1 100644 --- a/managed/data/checks/mysql_config_local_infile.yml +++ b/managed/data/checks/mysql_config_local_infile.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_local_infile(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_log_bin.yml b/managed/data/checks/mysql_config_log_bin.yml index 069fdcbed69..1841e1927c2 100644 --- a/managed/data/checks/mysql_config_log_bin.yml +++ b/managed/data/checks/mysql_config_log_bin.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] in_result = check_log_bin(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_relay_log_purge.yml b/managed/data/checks/mysql_config_relay_log_purge.yml index e60c51e5e36..7baddb726b6 100644 --- a/managed/data/checks/mysql_config_relay_log_purge.yml +++ b/managed/data/checks/mysql_config_relay_log_purge.yml @@ -34,7 +34,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_relay_log_purge(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_replication_bp1.yml b/managed/data/checks/mysql_config_replication_bp1.yml index a1de0c7bde3..4ca00d14847 100644 --- a/managed/data/checks/mysql_config_replication_bp1.yml +++ b/managed/data/checks/mysql_config_replication_bp1.yml @@ -49,7 +49,7 @@ checks: } } def check_context(docs, context): - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_replication_bp1_RO(docs[0],read_url) if result1: diff --git a/managed/data/checks/mysql_config_slave_parallel_workers.yml b/managed/data/checks/mysql_config_slave_parallel_workers.yml index c746c1f7c02..c3b889a9625 100644 --- a/managed/data/checks/mysql_config_slave_parallel_workers.yml +++ b/managed/data/checks/mysql_config_slave_parallel_workers.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_slave_parallel_workers(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_sql_mode.yml b/managed/data/checks/mysql_config_sql_mode.yml index 3d99abc725a..fd2ccb95dbe 100644 --- a/managed/data/checks/mysql_config_sql_mode.yml +++ b/managed/data/checks/mysql_config_sql_mode.yml @@ -37,7 +37,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] in_result = check_sql_mode(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_sync_binlog.yml b/managed/data/checks/mysql_config_sync_binlog.yml index 76ed961ab29..abd44846340 100644 --- a/managed/data/checks/mysql_config_sync_binlog.yml +++ b/managed/data/checks/mysql_config_sync_binlog.yml @@ -27,7 +27,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_config_tmp_table_size_limit.yml b/managed/data/checks/mysql_config_tmp_table_size_limit.yml index 6866e195427..ccc9179dc8a 100644 --- a/managed/data/checks/mysql_config_tmp_table_size_limit.yml +++ b/managed/data/checks/mysql_config_tmp_table_size_limit.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] in_result = check_tmp_table_size(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_file_format.yml b/managed/data/checks/mysql_configuration_innodb_file_format.yml index 2950accc40e..d2a8b688d9d 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_format.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_format.yml @@ -45,7 +45,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_innodb_conf(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml b/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml index a87b2fc5a9f..48903921e76 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_innodb_conf(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml index 3b1db1c88bc..f055fcd04c6 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml @@ -14,7 +14,7 @@ checks: - type: MYSQL_SELECT query: "@@global.innodb_file_per_table as innodb_file_per_table, @@global.version as version, @@global.hostname as service" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_configuration_innodb_flush_method.yml b/managed/data/checks/mysql_configuration_innodb_flush_method.yml index 767f33529a1..384dd6624d6 100644 --- a/managed/data/checks/mysql_configuration_innodb_flush_method.yml +++ b/managed/data/checks/mysql_configuration_innodb_flush_method.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_innodb_conf(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_strict_mode.yml b/managed/data/checks/mysql_configuration_innodb_strict_mode.yml index 9d8ac9a9590..e903066d4c6 100644 --- a/managed/data/checks/mysql_configuration_innodb_strict_mode.yml +++ b/managed/data/checks/mysql_configuration_innodb_strict_mode.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_innodb_strict_mode(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_log_verbosity.yml b/managed/data/checks/mysql_configuration_log_verbosity.yml index d00ef20476c..9bd92017bb2 100644 --- a/managed/data/checks/mysql_configuration_log_verbosity.yml +++ b/managed/data/checks/mysql_configuration_log_verbosity.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SHOW query: VARIABLES script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_log_error_verbosity(log_error_verbosity): if log_error_verbosity < 2: diff --git a/managed/data/checks/mysql_configuration_max_connections_usage.yml b/managed/data/checks/mysql_configuration_max_connections_usage.yml index e8af9dd13a9..7ac40326fae 100644 --- a/managed/data/checks/mysql_configuration_max_connections_usage.yml +++ b/managed/data/checks/mysql_configuration_max_connections_usage.yml @@ -19,7 +19,7 @@ checks: query: mysql_global_status_max_used_connections_time{service_name=~"{{.ServiceName}}"} script: | def check_context(docs, context): - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] max_conn = "" max_used_conn = "" diff --git a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml index 13eae93ebe8..af21b536160 100644 --- a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml +++ b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml @@ -14,7 +14,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service, @@global.secure_file_priv as secure_file_priv" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs, context): results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml index 4fd12b98a8a..04090c4880d 100644 --- a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml +++ b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml @@ -28,7 +28,7 @@ checks: range: 168h step: 5m script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def redo_log_check(docs): for row in docs[0]: version = row["version"] diff --git a/managed/data/checks/mysql_log_replica_updates.yml b/managed/data/checks/mysql_log_replica_updates.yml index b0805f592ec..92aeeee1316 100644 --- a/managed/data/checks/mysql_log_replica_updates.yml +++ b/managed/data/checks/mysql_log_replica_updates.yml @@ -27,7 +27,7 @@ checks: # (Starlark does not support Python exceptions); # it is recommended to use global function `fail` for that instead. results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" for row in docs[0]: name, value = row["Variable_name"], row["Value"] diff --git a/managed/data/checks/mysql_password_expiry.yml b/managed/data/checks/mysql_password_expiry.yml index 5a9e033663a..7fecf470552 100644 --- a/managed/data/checks/mysql_password_expiry.yml +++ b/managed/data/checks/mysql_password_expiry.yml @@ -15,7 +15,7 @@ checks: query: " user,host,password_expired,password_last_changed,password_lifetime,password_expire_days,CASE WHEN (password_expired='Y' OR password_expire_days <= 10) THEN 'ERROR' WHEN (password_expire_days > 10 AND password_expire_days<=30) THEN 'WARNING' ELSE 'OK' END AS pwdresult FROM ( SELECT user, host, password_expired, password_last_changed, password_lifetime, @@default_password_lifetime, IFNULL(password_lifetime, CASE WHEN @@default_password_lifetime=0 THEN 99999 WHEN @@default_password_lifetime>0 THEN datediff(password_last_changed, NOW()) ELSE 99999 END ) password_expire_days FROM mysql.user) X" script: | def check_context(docs, context): - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] for row in docs[0]: version = row["version"] diff --git a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml index 127b4fca02e..ea2e0dacc1b 100644 --- a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml +++ b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml @@ -16,7 +16,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # This advisor check hints about creation of on-disk temp tables due to unoptimized query or low configuration value for tmp_table_size / max_heap_table_size. def check_tmp_table_ondisk(docs): diff --git a/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml b/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml index f6cb25f8ce5..2eced2e9ea0 100644 --- a/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml +++ b/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service /*!50700 , @@global.slave_exec_mode as slave_exec_mode */ /*!50700 , @@global.slave_skip_errors slave_skip_errors*/ /*!80026 , @@global.replica_exec_mode as replica_exec_mode */ /*!80026 , @@global.replica_skip_errors replica_skip_errors*/ " script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(docs,context): results = [] skip_errors = "" diff --git a/managed/data/checks/mysql_replication_grants.yml b/managed/data/checks/mysql_replication_grants.yml index fcae87d7fad..759ccc17db9 100644 --- a/managed/data/checks/mysql_replication_grants.yml +++ b/managed/data/checks/mysql_replication_grants.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_rep_grants(docs[0],read_url) diff --git a/managed/data/checks/mysql_require_secure_transport.yml b/managed/data/checks/mysql_require_secure_transport.yml index e7fbd73c8c4..da8911f74fd 100644 --- a/managed/data/checks/mysql_require_secure_transport.yml +++ b/managed/data/checks/mysql_require_secure_transport.yml @@ -14,7 +14,7 @@ checks: script: | def check_context(docs, context): results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" for row in docs[0]: name, value = row["Variable_name"], row["Value"] diff --git a/managed/data/checks/mysql_security_anonymous_user.yml b/managed/data/checks/mysql_security_anonymous_user.yml index a4ac8a3edc6..5e37733b1c8 100644 --- a/managed/data/checks/mysql_security_anonymous_user.yml +++ b/managed/data/checks/mysql_security_anonymous_user.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_anonym_user(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_open_to_world_host.yml b/managed/data/checks/mysql_security_open_to_world_host.yml index 9128a9da330..40813729460 100644 --- a/managed/data/checks/mysql_security_open_to_world_host.yml +++ b/managed/data/checks/mysql_security_open_to_world_host.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_open_host(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_password_lifetime.yml b/managed/data/checks/mysql_security_password_lifetime.yml index 13ff85e2fc2..4e07a9b16fd 100644 --- a/managed/data/checks/mysql_security_password_lifetime.yml +++ b/managed/data/checks/mysql_security_password_lifetime.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_slave_parallel_workers(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_password_policy.yml b/managed/data/checks/mysql_security_password_policy.yml index 8185ad484a3..34a7f2fee14 100644 --- a/managed/data/checks/mysql_security_password_policy.yml +++ b/managed/data/checks/mysql_security_password_policy.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_pw_policy(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_replication_grants_mixed.yml b/managed/data/checks/mysql_security_replication_grants_mixed.yml index e14c1a01498..697d37c429d 100644 --- a/managed/data/checks/mysql_security_replication_grants_mixed.yml +++ b/managed/data/checks/mysql_security_replication_grants_mixed.yml @@ -16,7 +16,7 @@ checks: script: | def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" whois = "This instance is a SOURCE" results = [] diff --git a/managed/data/checks/mysql_security_root_not_local.yml b/managed/data/checks/mysql_security_root_not_local.yml index b14845c3726..946494cbc65 100644 --- a/managed/data/checks/mysql_security_root_not_local.yml +++ b/managed/data/checks/mysql_security_root_not_local.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_root_user(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_user_ssl.yml b/managed/data/checks/mysql_security_user_ssl.yml index 0d53d77c1cc..75402dc155c 100644 --- a/managed/data/checks/mysql_security_user_ssl.yml +++ b/managed/data/checks/mysql_security_user_ssl.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_ssl(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_user_super_not_local.yml b/managed/data/checks/mysql_security_user_super_not_local.yml index 00a75012692..4bad54d3b17 100644 --- a/managed/data/checks/mysql_security_user_super_not_local.yml +++ b/managed/data/checks/mysql_security_user_super_not_local.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_super(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_user_without_password.yml b/managed/data/checks/mysql_security_user_without_password.yml index d2c77e2970c..c6c6d78cae7 100644 --- a/managed/data/checks/mysql_security_user_without_password.yml +++ b/managed/data/checks/mysql_security_user_without_password.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_user_without_password(docs[0],read_url) diff --git a/managed/data/checks/mysql_tables_without_pk.yml b/managed/data/checks/mysql_tables_without_pk.yml index c72bacf5e9a..9bef4bf1191 100644 --- a/managed/data/checks/mysql_tables_without_pk.yml +++ b/managed/data/checks/mysql_tables_without_pk.yml @@ -42,7 +42,7 @@ checks: # (Starlark does not support Python exceptions); # it is recommended to use global function `fail` for that instead. results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" for row in docs[0]: TABLE_SCHEMA, TABLE_NAME, TABLE_ROWS = row["TABLE_SCHEMA"], row["TABLE_NAME"], row["TABLE_ROWS"] results.append({ diff --git a/managed/data/checks/mysql_timezone.yml b/managed/data/checks/mysql_timezone.yml index ecf9f55282c..ed8238a2f31 100644 --- a/managed/data/checks/mysql_timezone.yml +++ b/managed/data/checks/mysql_timezone.yml @@ -27,7 +27,7 @@ checks: # (Starlark does not support Python exceptions); # it is recommended to use global function `fail` for that instead. results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" timezonecount = int(docs[0][0]["timezonecount"]) if timezonecount == 0: diff --git a/managed/data/checks/mysql_unsupported_version_check.yml b/managed/data/checks/mysql_unsupported_version_check.yml index 1dd26ab70af..88381c26a17 100644 --- a/managed/data/checks/mysql_unsupported_version_check.yml +++ b/managed/data/checks/mysql_unsupported_version_check.yml @@ -58,7 +58,7 @@ checks: } def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_unsupported_version(docs[0],read_url,context) if result1 : diff --git a/managed/data/checks/mysql_version_eol_57.yml b/managed/data/checks/mysql_version_eol_57.yml index a9413999f05..2813a056328 100644 --- a/managed/data/checks/mysql_version_eol_57.yml +++ b/managed/data/checks/mysql_version_eol_57.yml @@ -57,7 +57,7 @@ checks: } def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" results = [] result1 = check_eol(docs[0],read_url,context) if result1 : diff --git a/managed/data/checks/postgresql_archiver_failing.yml b/managed/data/checks/postgresql_archiver_failing.yml index 59d9c1e16d0..b7e48f2f61c 100644 --- a/managed/data/checks/postgresql_archiver_failing.yml +++ b/managed/data/checks/postgresql_archiver_failing.yml @@ -23,7 +23,7 @@ checks: trunc(extract(EPOCH FROM (now() - stats_reset))::numeric,0) AS sec_since_stats_reset FROM pg_stat_archiver script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor # threshold 24 hours = 86400 seconds diff --git a/managed/data/checks/postgresql_cache_hit_ratio.yml b/managed/data/checks/postgresql_cache_hit_ratio.yml index a8d3a941b74..0c72f1e4c12 100644 --- a/managed/data/checks/postgresql_cache_hit_ratio.yml +++ b/managed/data/checks/postgresql_cache_hit_ratio.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: round(100. * sd.blks_hit /(sd.blks_read + sd.blks_hit),0) AS dhitratio, d.datname, r.rolname AS rolname FROM pg_stat_database sd JOIN pg_database d ON (d.oid = sd.datid) AND d.datname != 'postgres' AND d.datname NOT LIKE 'template%' JOIN pg_roles r ON (r.oid = d.datdba) WHERE sd.blks_read + sd.blks_hit <> 0 ORDER BY 1 DESC script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_config_changes_need_restart.yml b/managed/data/checks/postgresql_config_changes_need_restart.yml index 70e9dae9eb1..1e1e7fa8a35 100644 --- a/managed/data/checks/postgresql_config_changes_need_restart.yml +++ b/managed/data/checks/postgresql_config_changes_need_restart.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting, short_desc, reset_val FROM pg_settings WHERE pending_restart IS true script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_cve_check.yml b/managed/data/checks/postgresql_cve_check.yml index 888704d7826..0b13c79ba19 100644 --- a/managed/data/checks/postgresql_cve_check.yml +++ b/managed/data/checks/postgresql_cve_check.yml @@ -177,7 +177,7 @@ checks: def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" description = "" for row in rows[0]: ver, major = int(row["setting"]), int(row["major"]) diff --git a/managed/data/checks/postgresql_eol_check.yml b/managed/data/checks/postgresql_eol_check.yml index d3b41a1a5ba..3ea35730167 100644 --- a/managed/data/checks/postgresql_eol_check.yml +++ b/managed/data/checks/postgresql_eol_check.yml @@ -30,7 +30,7 @@ checks: def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" description = "" iseol = False for row in rows[0]: diff --git a/managed/data/checks/postgresql_expiring_passwd_check.yml b/managed/data/checks/postgresql_expiring_passwd_check.yml index 41de4d13471..47c4165b59f 100644 --- a/managed/data/checks/postgresql_expiring_passwd_check.yml +++ b/managed/data/checks/postgresql_expiring_passwd_check.yml @@ -16,7 +16,7 @@ checks: script: | def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" description = "" sev="warning" for row in rows[0]: diff --git a/managed/data/checks/postgresql_extension_check.yml b/managed/data/checks/postgresql_extension_check.yml index e0a84c2a71d..d2f10ec8f96 100644 --- a/managed/data/checks/postgresql_extension_check.yml +++ b/managed/data/checks/postgresql_extension_check.yml @@ -13,7 +13,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_fsync.yml b/managed/data/checks/postgresql_fsync.yml index b7ab42f0c2c..f706bc5393c 100644 --- a/managed/data/checks/postgresql_fsync.yml +++ b/managed/data/checks/postgresql_fsync.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'fsync' script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_log_autovacuum_min_duration.yml b/managed/data/checks/postgresql_log_autovacuum_min_duration.yml index 52a33992afd..e644457b039 100644 --- a/managed/data/checks/postgresql_log_autovacuum_min_duration.yml +++ b/managed/data/checks/postgresql_log_autovacuum_min_duration.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'log_autovacuum_min_duration' script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_log_checkpoints.yml b/managed/data/checks/postgresql_log_checkpoints.yml index 7443a282eec..40ae11e2b34 100644 --- a/managed/data/checks/postgresql_log_checkpoints.yml +++ b/managed/data/checks/postgresql_log_checkpoints.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'log_checkpoints' script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_logging_recommendation_checks.yml b/managed/data/checks/postgresql_logging_recommendation_checks.yml index a1d5d0397ec..5ebec0771fb 100644 --- a/managed/data/checks/postgresql_logging_recommendation_checks.yml +++ b/managed/data/checks/postgresql_logging_recommendation_checks.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: " s1.setting AS logging_collector, s2.setting AS log_temp_files, s3.setting log_checkpoints, s4.setting log_min_duration_statement, s5.unit unit, s6.min_val AS minval, s7.setting AS log_autovacuum_min_duration FROM pg_settings s1 , pg_settings s2 , pg_settings s3 , pg_settings s4 , pg_settings s5 , pg_settings s6 , pg_settings s7 WHERE s1.name = 'logging_collector' and s2.name = 'log_temp_files' and s3.name = 'log_checkpoints' and s4.name = 'log_min_duration_statement' and s5.name = 'log_min_duration_statement' and s6.name = 'log_min_duration_statement' and s7.name = 'log_autovacuum_min_duration'" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(rows, context): results = [] diff --git a/managed/data/checks/postgresql_max_connections.yml b/managed/data/checks/postgresql_max_connections.yml index 76ccbcbbd42..8f36527908a 100644 --- a/managed/data/checks/postgresql_max_connections.yml +++ b/managed/data/checks/postgresql_max_connections.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'max_connections' script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_number_of_index_check.yml b/managed/data/checks/postgresql_number_of_index_check.yml index 396d7a93cdc..26d8f289093 100644 --- a/managed/data/checks/postgresql_number_of_index_check.yml +++ b/managed/data/checks/postgresql_number_of_index_check.yml @@ -13,7 +13,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_sequential_scan_check.yml b/managed/data/checks/postgresql_sequential_scan_check.yml index 1ad8f9acec5..8fbbe1528bb 100644 --- a/managed/data/checks/postgresql_sequential_scan_check.yml +++ b/managed/data/checks/postgresql_sequential_scan_check.yml @@ -13,7 +13,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_stale_replication_slot.yml b/managed/data/checks/postgresql_stale_replication_slot.yml index 1b0a77ae58b..3692a00ffa7 100644 --- a/managed/data/checks/postgresql_stale_replication_slot.yml +++ b/managed/data/checks/postgresql_stale_replication_slot.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: slot_name, pg_current_wal_insert_lsn()-restart_lsn stale_bytes, (SELECT setting FROM pg_settings WHERE name = 'max_wal_size') max_wal_size FROM pg_replication_slots WHERE active = FALSE AND temporary = FALSE AND restart_lsn IS NOT NULL script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_table_autovac_settings.yml b/managed/data/checks/postgresql_table_autovac_settings.yml index c74fd6e8c4a..43655d1abbc 100644 --- a/managed/data/checks/postgresql_table_autovac_settings.yml +++ b/managed/data/checks/postgresql_table_autovac_settings.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: " * FROM (SELECT c.relname, pg_catalog.array_to_string(c.reloptions || array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ') as opts FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid) ) AS tabopts WHERE opts like '%vacuum%'" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_table_bloat_bytes.yml b/managed/data/checks/postgresql_table_bloat_bytes.yml index 86a4deb0e87..41834d0ba76 100644 --- a/managed/data/checks/postgresql_table_bloat_bytes.yml +++ b/managed/data/checks/postgresql_table_bloat_bytes.yml @@ -13,7 +13,7 @@ checks: all_dbs: true query: " * FROM ( WITH a AS ( SELECT current_database(), schemaname, tblname, tblpages as pages,est_tblpages as est_pages ,est_tblpages_ff as est_pages_ff, bs*tblpages AS cur_size_byte, (tblpages-est_tblpages)*bs AS free_bytes, CASE WHEN tblpages - est_tblpages > 0 THEN 100 * (tblpages - est_tblpages)/tblpages::float ELSE 0 END AS extra_pages_pct, fillfactor, CASE WHEN tblpages - est_tblpages_ff > 0 THEN (tblpages-est_tblpages_ff)*bs ELSE 0 END AS bloatsize_byte, CASE WHEN tblpages - est_tblpages_ff > 0 THEN 100 * (tblpages - est_tblpages_ff)/tblpages::float ELSE 0 END AS bloat_pct, is_na AS stats_missing FROM ( SELECT ceil( reltuples / ( (bs-page_hdr)/tpl_size) ) + ceil( toasttuples / 4 ) AS est_tblpages, ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff, tblpages, fillfactor, bs, tblid, schemaname, tblname, heappages, toastpages, is_na FROM ( SELECT ( 4 + tpl_hdr_size + tpl_data_size + (2*ma) - CASE WHEN tpl_hdr_size%ma = 0 THEN ma ELSE tpl_hdr_size%ma END - CASE WHEN ceil(tpl_data_size)::int%ma = 0 THEN ma ELSE ceil(tpl_data_size)::int%ma END) AS tpl_size, bs - page_hdr AS size_per_block, (heappages + toastpages) AS tblpages, heappages, toastpages, reltuples, toasttuples, bs, page_hdr, tblid, schemaname, tblname, fillfactor, is_na FROM ( SELECT tbl.oid AS tblid, ns.nspname AS schemaname, tbl.relname AS tblname, tbl.reltuples, tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages, coalesce(toast.reltuples, 0) AS toasttuples, coalesce(substring( array_to_string(tbl.reloptions, ' ') FROM 'fillfactor=([0-9]+)')::smallint, 100) AS fillfactor, current_setting('block_size')::numeric AS bs, CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma, 24 AS page_hdr, 23 + CASE WHEN MAX(coalesce(s.null_frac,0)) > 0 THEN ( 7 + count(s.attname) ) / 8 ELSE 0::int END + CASE WHEN bool_or(att.attname = 'oid' and att.attnum < 0) THEN 4 ELSE 0 END AS tpl_hdr_size, sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 0) ) AS tpl_data_size, bool_or(att.atttypid = 'pg_catalog.name'::regtype) OR sum(CASE WHEN att.attnum > 0 THEN 1 ELSE 0 END) <> count(s.attname) AS is_na FROM pg_attribute AS att JOIN pg_class AS tbl ON att.attrelid = tbl.oid JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace AND ns.nspname NOT IN ('pg_catalog', 'information_schema') LEFT JOIN pg_stats AS s ON s.schemaname=ns.nspname AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid WHERE NOT att.attisdropped AND tbl.relkind in ('r','m') GROUP BY 1,2,3,4,5,6,7,8,9,10 ORDER BY 2,3) AS s) AS s2) AS s3 ORDER BY schemaname, tblname) SELECT current_database, schemaname, tblname, cur_size_byte real_size, pg_size_pretty(cur_size_byte::numeric) real_size_pretty, free_bytes, bloatsize_byte bloat_size_byte, pg_size_pretty(bloatsize_byte::numeric) bloat_size_byte_pretty FROM a WHERE schemaname != 'pg_catalog' AND bloatsize_byte > 250000000 ORDER BY cur_size_byte DESC) x" script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(tuples, context): results = [] diff --git a/managed/data/checks/postgresql_table_bloat_in_percentage.yml b/managed/data/checks/postgresql_table_bloat_in_percentage.yml index 4dc8ae08192..71661f2393a 100644 --- a/managed/data/checks/postgresql_table_bloat_in_percentage.yml +++ b/managed/data/checks/postgresql_table_bloat_in_percentage.yml @@ -83,7 +83,7 @@ checks: ORDER BY cur_size_byte DESC ) x script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor # threshold diff --git a/managed/data/checks/postgresql_tmpfiles_check.yml b/managed/data/checks/postgresql_tmpfiles_check.yml index 32c744af476..5f7ef851e93 100644 --- a/managed/data/checks/postgresql_tmpfiles_check.yml +++ b/managed/data/checks/postgresql_tmpfiles_check.yml @@ -15,7 +15,7 @@ checks: script: | def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" for row in rows[0]: db, tempfiles, tempbytes, age = row["datname"], row["temp_files"], row["temp_bytes"], row["age"] if tempfiles > 100: diff --git a/managed/data/checks/postgresql_txid_wraparound_approaching.yml b/managed/data/checks/postgresql_txid_wraparound_approaching.yml index e7f39633c3c..f3877020d88 100644 --- a/managed/data/checks/postgresql_txid_wraparound_approaching.yml +++ b/managed/data/checks/postgresql_txid_wraparound_approaching.yml @@ -16,7 +16,7 @@ checks: WHERE (age(datfrozenxid)::numeric/1000000000*100)::numeric(4,2) >= 20.0::numeric(4,2) ORDER BY 2 DESC script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_unsupported_check.yml b/managed/data/checks/postgresql_unsupported_check.yml index 126f37c5cc9..5917cf5e979 100644 --- a/managed/data/checks/postgresql_unsupported_check.yml +++ b/managed/data/checks/postgresql_unsupported_check.yml @@ -31,7 +31,7 @@ checks: def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" description = "" iseol = False for row in rows[0]: diff --git a/managed/data/checks/postgresql_unused_index_check.yml b/managed/data/checks/postgresql_unused_index_check.yml index f68fb28053c..95c9b7f9167 100644 --- a/managed/data/checks/postgresql_unused_index_check.yml +++ b/managed/data/checks/postgresql_unused_index_check.yml @@ -14,7 +14,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_vacuum_sanity_check.yml b/managed/data/checks/postgresql_vacuum_sanity_check.yml index 2cdea7b84db..08fc05401f6 100644 --- a/managed/data/checks/postgresql_vacuum_sanity_check.yml +++ b/managed/data/checks/postgresql_vacuum_sanity_check.yml @@ -11,7 +11,7 @@ checks: - type: POSTGRESQL_SELECT query: "current_setting('autovacuum') AS autovacuum, current_setting('autovacuum_max_workers') AS autovacuum_max_workers, current_setting('autovacuum_vacuum_scale_factor') AS autovacuum_vacuum_scale_factor, current_setting('vacuum_cost_page_hit') AS vacuum_cost_page_hit, current_setting('vacuum_cost_delay') AS vacuum_cost_delay, current_setting('vacuum_cost_page_dirty') AS vacuum_cost_page_dirty , current_setting('vacuum_cost_page_miss') AS vacuum_cost_page_miss " script: | - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" def check_context(rows, context): results = [] diff --git a/managed/data/checks/postgresql_version_check.yml b/managed/data/checks/postgresql_version_check.yml index a6f2d501869..8f8962dffab 100644 --- a/managed/data/checks/postgresql_version_check.yml +++ b/managed/data/checks/postgresql_version_check.yml @@ -84,7 +84,7 @@ checks: def check_context(rows, context): #fail(rows) results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" description = "" daysleft = "" minoroutdated = False diff --git a/managed/data/checks/postgresql_wal_retention_check.yml b/managed/data/checks/postgresql_wal_retention_check.yml index fc77d03813a..4147811bd64 100644 --- a/managed/data/checks/postgresql_wal_retention_check.yml +++ b/managed/data/checks/postgresql_wal_retention_check.yml @@ -14,7 +14,7 @@ checks: script: | def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" description = "" keeping = "" for row in rows[0]: From 61edeedfb01b266ea4f7b4f5509dfe2e61249d30 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sat, 27 Jun 2026 12:04:53 +0300 Subject: [PATCH 002/120] PMM-14109 Improve check target selection by skipping only internal PostgreSQL --- managed/services/checks/checks.go | 7 ++++--- managed/services/checks/checks_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index d620ffcd49c..658e420000e 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -1363,9 +1363,9 @@ func (s *Service) findTargets(serviceType models.ServiceType, minPMMAgentVersion } for _, service := range monitoredServices { - // skip pmm own services - if service.NodeID == models.PMMServerNodeID { - s.l.Debugf("Skip PMM service, name: %s, type: %s.", service.ServiceName, service.ServiceType) + // skip PMM Server's internal PostgreSQL database, but allow other services on the PMM Server node + if service.ServiceName == models.PMMServerPostgreSQLServiceName { + s.l.Debugf("Skip PMM Server's internal PostgreSQL service, name: %s, type: %s.", service.ServiceName, service.ServiceType) continue } @@ -1404,6 +1404,7 @@ func (s *Service) findTargets(serviceType models.ServiceType, minPMMAgentVersion ServiceID: service.ServiceID, ServiceName: service.ServiceName, ServiceType: service.ServiceType, + NodeID: node.NodeID, NodeName: node.NodeName, Labels: labels, DSN: DSN, diff --git a/managed/services/checks/checks_test.go b/managed/services/checks/checks_test.go index d51babe7929..dbcc2ddedea 100644 --- a/managed/services/checks/checks_test.go +++ b/managed/services/checks/checks_test.go @@ -540,6 +540,31 @@ func TestFindTargets(t *testing.T) { }) } +func TestFindTargetsSkipsOnlyInternalPostgreSQL(t *testing.T) { + t.Parallel() + sqlDB := testdb.Open(t, models.SetupFixtures, nil) + t.Cleanup(func() { + require.NoError(t, sqlDB.Close()) + }) + + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + + s := New(db, nil, vmClient, clickhouseDB) + + // A user service registered on the PMM Server node must still be a valid target. + setup(t, db, "mysql-on-pmm-node", models.PMMServerNodeID, "") + + mysqlTargets, err := s.findTargets(models.MySQLServiceType, nil) + require.NoError(t, err) + require.Len(t, mysqlTargets, 1) + assert.Equal(t, "mysql-on-pmm-node", mysqlTargets[0].ServiceName) + + // PMM Server's internal PostgreSQL must be skipped, leaving no PostgreSQL targets. + pgTargets, err := s.findTargets(models.PostgreSQLServiceType, nil) + require.NoError(t, err) + assert.Empty(t, pgTargets) +} + func TestFilterChecksByInterval(t *testing.T) { t.Parallel() s := New(nil, nil, vmClient, clickhouseDB) From 2734a0cd2f55f5978c2d791cab95947aa6c6b565 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sat, 27 Jun 2026 12:47:54 +0300 Subject: [PATCH 003/120] PMM-14109 Enhance advisor output and database schema for check results --- managed/Makefile | 10 + managed/data/checks/mysql_test_database.yml | 2 +- managed/models/check_result_model.go | 106 ++++++++++ managed/models/check_result_model_reform.go | 216 ++++++++++++++++++++ managed/models/database.go | 26 +++ managed/services/types.go | 2 + 6 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 managed/models/check_result_model.go create mode 100644 managed/models/check_result_model_reform.go diff --git a/managed/Makefile b/managed/Makefile index 8970e4a5e7e..61a153cbc1c 100644 --- a/managed/Makefile +++ b/managed/Makefile @@ -20,6 +20,7 @@ PMM_LD_FLAGS = -ldflags " \ -X 'github.com/percona/pmm/version.Timestamp=$(PMM_RELEASE_TIMESTAMP)' \ -X 'github.com/percona/pmm/version.FullCommit=$(PMM_RELEASE_FULLCOMMIT)' \ -X 'github.com/percona/pmm/version.Branch=$(PMM_RELEASE_BRANCH)' \ + -w \ " IS_ARM := $(filter arm64,$(shell uname -m)) @@ -41,6 +42,15 @@ pi-validate: ## Validate Percona Intelligence advisors and checks release: ## Build pmm-managed release binaries env CGO_ENABLED=0 go build -v $(PMM_LD_FLAGS) -o $(PMM_RELEASE_PATH)/ ./cmd/... +release2: ## Build pmm-managed release binaries + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v $(PMM_LD_FLAGS) -trimpath -o $(PMM_RELEASE_PATH)/ ./cmd/... + docker cp $(PMM_RELEASE_PATH)/pmm-managed pmm-server:/tmp/pmm-managed + docker exec -it -u root pmm-server chown 0:0 /tmp/pmm-managed + docker exec -it pmm-server /tmp/pmm-managed --version + docker exec -it pmm-server supervisorctl stop pmm-managed + docker exec -it -u root pmm-server mv /tmp/pmm-managed /usr/sbin/pmm-managed + docker exec -it pmm-server supervisorctl start pmm-managed + release-encryption-rotation: ## Build PMM encryption rotation tool env CGO_ENABLED=0 go build -v $(PMM_LD_FLAGS) -o $(PMM_RELEASE_PATH)/ ./cmd/pmm-encryption-rotation/... diff --git a/managed/data/checks/mysql_test_database.yml b/managed/data/checks/mysql_test_database.yml index 3ffb1e64e46..ba14d5fbc3c 100644 --- a/managed/data/checks/mysql_test_database.yml +++ b/managed/data/checks/mysql_test_database.yml @@ -29,7 +29,7 @@ checks: description = " is" return [{ "summary": "Test database{} detected: {}".format(description,dbs), - "description": "Please Improve MySQL Installation Security by running program mysql_secure_installation", + "description": "Improve MySQL Installation Security by running mysql_secure_installation", "severity": "notice" }] diff --git a/managed/models/check_result_model.go b/managed/models/check_result_model.go new file mode 100644 index 00000000000..12cd3ba911d --- /dev/null +++ b/managed/models/check_result_model.go @@ -0,0 +1,106 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models + +import ( + "time" + + "gopkg.in/reform.v1" +) + +//go:generate go tool reform + +// CheckResultStatus represents the outcome of an Advisor check run against a service. +type CheckResultStatus string + +// Available Advisor check result statuses. +const ( + // CheckResultOK means the check ran and found no issue. + CheckResultOK CheckResultStatus = "ok" + // CheckResultFailed means the check ran and detected an issue. + CheckResultFailed CheckResultStatus = "failed" + // CheckResultError means the check could not be executed. + CheckResultError CheckResultStatus = "error" +) + +// CheckResult represents a single Advisor check run against a target persisted to history. +// +//reform:check_results +type CheckResult struct { + ID string `reform:"id,pk"` + CheckName string `reform:"check_name"` + AdvisorName string `reform:"advisor_name"` + Category string `reform:"category"` + Interval Interval `reform:"interval"` + ServiceID string `reform:"service_id"` + ServiceName string `reform:"service_name"` + ServiceType ServiceType `reform:"service_type"` + NodeID string `reform:"node_id"` + NodeName string `reform:"node_name"` + Status CheckResultStatus `reform:"status"` + Summary string `reform:"summary"` + Description string `reform:"description"` + ReadMoreURL string `reform:"read_more_url"` + Severity int32 `reform:"severity"` + Labels []byte `reform:"labels"` + CheckedAt time.Time `reform:"checked_at"` + IsRead bool `reform:"is_read"` +} + +// BeforeInsert implements reform.BeforeInserter interface. +func (r *CheckResult) BeforeInsert() error { + if r.CheckedAt.IsZero() { + r.CheckedAt = Now() + } + if len(r.Labels) == 0 { + r.Labels = nil + } + return nil +} + +// BeforeUpdate implements reform.BeforeUpdater interface. +func (r *CheckResult) BeforeUpdate() error { + if len(r.Labels) == 0 { + r.Labels = nil + } + return nil +} + +// AfterFind implements reform.AfterFinder interface. +func (r *CheckResult) AfterFind() error { + r.CheckedAt = r.CheckedAt.UTC() + if len(r.Labels) == 0 { + r.Labels = nil + } + return nil +} + +// GetLabels decodes result labels. +func (r *CheckResult) GetLabels() (map[string]string, error) { + return getLabels(r.Labels) +} + +// SetLabels encodes result labels. +func (r *CheckResult) SetLabels(m map[string]string) error { + return setLabels(m, &r.Labels) +} + +// check interfaces. +var ( + _ reform.BeforeInserter = (*CheckResult)(nil) + _ reform.BeforeUpdater = (*CheckResult)(nil) + _ reform.AfterFinder = (*CheckResult)(nil) +) diff --git a/managed/models/check_result_model_reform.go b/managed/models/check_result_model_reform.go new file mode 100644 index 00000000000..0fa74731ce6 --- /dev/null +++ b/managed/models/check_result_model_reform.go @@ -0,0 +1,216 @@ +// Code generated by gopkg.in/reform.v1. DO NOT EDIT. + +package models + +import ( + "fmt" + "strings" + + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/parse" +) + +type checkResultTableType struct { + s parse.StructInfo + z []interface{} +} + +// Schema returns a schema name in SQL database (""). +func (v *checkResultTableType) Schema() string { + return v.s.SQLSchema +} + +// Name returns a view or table name in SQL database ("check_results"). +func (v *checkResultTableType) Name() string { + return v.s.SQLName +} + +// Columns returns a new slice of column names for that view or table in SQL database. +func (v *checkResultTableType) Columns() []string { + return []string{ + "id", + "check_name", + "advisor_name", + "category", + "interval", + "service_id", + "service_name", + "service_type", + "node_id", + "node_name", + "status", + "summary", + "description", + "read_more_url", + "severity", + "labels", + "checked_at", + "is_read", + } +} + +// NewStruct makes a new struct for that view or table. +func (v *checkResultTableType) NewStruct() reform.Struct { + return new(CheckResult) +} + +// NewRecord makes a new record for that table. +func (v *checkResultTableType) NewRecord() reform.Record { + return new(CheckResult) +} + +// PKColumnIndex returns an index of primary key column for that table in SQL database. +func (v *checkResultTableType) PKColumnIndex() uint { + return uint(v.s.PKFieldIndex) +} + +// CheckResultTable represents check_results view or table in SQL database. +var CheckResultTable = &checkResultTableType{ + s: parse.StructInfo{ + Type: "CheckResult", + SQLName: "check_results", + Fields: []parse.FieldInfo{ + {Name: "ID", Type: "string", Column: "id"}, + {Name: "CheckName", Type: "string", Column: "check_name"}, + {Name: "AdvisorName", Type: "string", Column: "advisor_name"}, + {Name: "Category", Type: "string", Column: "category"}, + {Name: "Interval", Type: "Interval", Column: "interval"}, + {Name: "ServiceID", Type: "string", Column: "service_id"}, + {Name: "ServiceName", Type: "string", Column: "service_name"}, + {Name: "ServiceType", Type: "ServiceType", Column: "service_type"}, + {Name: "NodeID", Type: "string", Column: "node_id"}, + {Name: "NodeName", Type: "string", Column: "node_name"}, + {Name: "Status", Type: "CheckResultStatus", Column: "status"}, + {Name: "Summary", Type: "string", Column: "summary"}, + {Name: "Description", Type: "string", Column: "description"}, + {Name: "ReadMoreURL", Type: "string", Column: "read_more_url"}, + {Name: "Severity", Type: "int32", Column: "severity"}, + {Name: "Labels", Type: "[]uint8", Column: "labels"}, + {Name: "CheckedAt", Type: "time.Time", Column: "checked_at"}, + {Name: "IsRead", Type: "bool", Column: "is_read"}, + }, + PKFieldIndex: 0, + }, + z: new(CheckResult).Values(), +} + +// String returns a string representation of this struct or record. +func (s CheckResult) String() string { + res := make([]string, 18) + res[0] = "ID: " + reform.Inspect(s.ID, true) + res[1] = "CheckName: " + reform.Inspect(s.CheckName, true) + res[2] = "AdvisorName: " + reform.Inspect(s.AdvisorName, true) + res[3] = "Category: " + reform.Inspect(s.Category, true) + res[4] = "Interval: " + reform.Inspect(s.Interval, true) + res[5] = "ServiceID: " + reform.Inspect(s.ServiceID, true) + res[6] = "ServiceName: " + reform.Inspect(s.ServiceName, true) + res[7] = "ServiceType: " + reform.Inspect(s.ServiceType, true) + res[8] = "NodeID: " + reform.Inspect(s.NodeID, true) + res[9] = "NodeName: " + reform.Inspect(s.NodeName, true) + res[10] = "Status: " + reform.Inspect(s.Status, true) + res[11] = "Summary: " + reform.Inspect(s.Summary, true) + res[12] = "Description: " + reform.Inspect(s.Description, true) + res[13] = "ReadMoreURL: " + reform.Inspect(s.ReadMoreURL, true) + res[14] = "Severity: " + reform.Inspect(s.Severity, true) + res[15] = "Labels: " + reform.Inspect(s.Labels, true) + res[16] = "CheckedAt: " + reform.Inspect(s.CheckedAt, true) + res[17] = "IsRead: " + reform.Inspect(s.IsRead, true) + return strings.Join(res, ", ") +} + +// Values returns a slice of struct or record field values. +// Returned interface{} values are never untyped nils. +func (s *CheckResult) Values() []interface{} { + return []interface{}{ + s.ID, + s.CheckName, + s.AdvisorName, + s.Category, + s.Interval, + s.ServiceID, + s.ServiceName, + s.ServiceType, + s.NodeID, + s.NodeName, + s.Status, + s.Summary, + s.Description, + s.ReadMoreURL, + s.Severity, + s.Labels, + s.CheckedAt, + s.IsRead, + } +} + +// Pointers returns a slice of pointers to struct or record fields. +// Returned interface{} values are never untyped nils. +func (s *CheckResult) Pointers() []interface{} { + return []interface{}{ + &s.ID, + &s.CheckName, + &s.AdvisorName, + &s.Category, + &s.Interval, + &s.ServiceID, + &s.ServiceName, + &s.ServiceType, + &s.NodeID, + &s.NodeName, + &s.Status, + &s.Summary, + &s.Description, + &s.ReadMoreURL, + &s.Severity, + &s.Labels, + &s.CheckedAt, + &s.IsRead, + } +} + +// View returns View object for that struct. +func (s *CheckResult) View() reform.View { + return CheckResultTable +} + +// Table returns Table object for that record. +func (s *CheckResult) Table() reform.Table { + return CheckResultTable +} + +// PKValue returns a value of primary key for that record. +// Returned interface{} value is never untyped nil. +func (s *CheckResult) PKValue() interface{} { + return s.ID +} + +// PKPointer returns a pointer to primary key field for that record. +// Returned interface{} value is never untyped nil. +func (s *CheckResult) PKPointer() interface{} { + return &s.ID +} + +// HasPK returns true if record has non-zero primary key set, false otherwise. +func (s *CheckResult) HasPK() bool { + return s.ID != CheckResultTable.z[CheckResultTable.s.PKFieldIndex] +} + +// SetPK sets record primary key, if possible. +// +// Deprecated: prefer direct field assignment where possible: s.ID = pk. +func (s *CheckResult) SetPK(pk interface{}) { + reform.SetPK(s, pk) +} + +// check interfaces +var ( + _ reform.View = CheckResultTable + _ reform.Struct = (*CheckResult)(nil) + _ reform.Table = CheckResultTable + _ reform.Record = (*CheckResult)(nil) + _ fmt.Stringer = (*CheckResult)(nil) +) + +func init() { + parse.AssertUpToDate(&CheckResultTable.s, new(CheckResult)) +} diff --git a/managed/models/database.go b/managed/models/database.go index 739e370fa8c..7a1368e0aaf 100644 --- a/managed/models/database.go +++ b/managed/models/database.go @@ -1185,6 +1185,32 @@ var databaseSchema = [][]string{ `ALTER TABLE dumps ADD COLUMN encrypted boolean NOT NULL DEFAULT false`, `UPDATE dumps SET encrypted = false`, }, + 119: { + `CREATE TABLE check_results ( + id VARCHAR NOT NULL, + check_name VARCHAR NOT NULL CHECK (check_name <> ''), + advisor_name VARCHAR NOT NULL, + category VARCHAR NOT NULL, + interval VARCHAR NOT NULL, + service_id VARCHAR NOT NULL, + service_name VARCHAR NOT NULL, + service_type VARCHAR NOT NULL, + node_id VARCHAR NOT NULL, + node_name VARCHAR NOT NULL, + status VARCHAR NOT NULL CHECK (status <> ''), + summary VARCHAR NOT NULL, + description TEXT NOT NULL, + read_more_url VARCHAR NOT NULL, + severity INTEGER NOT NULL, + labels TEXT, + checked_at TIMESTAMP NOT NULL, + is_read BOOLEAN NOT NULL, + + PRIMARY KEY (id) + )`, + `CREATE INDEX check_results_service_id_idx ON check_results (service_id)`, + `CREATE INDEX check_results_checked_at_idx ON check_results (checked_at)`, + }, } // ^^^ Avoid default values in schema definition. ^^^ diff --git a/managed/services/types.go b/managed/services/types.go index 1cf34920fab..55a0606406c 100644 --- a/managed/services/types.go +++ b/managed/services/types.go @@ -28,6 +28,7 @@ type Target struct { ServiceID string ServiceName string ServiceType models.ServiceType + NodeID string NodeName string Labels map[string]string DSN string @@ -49,6 +50,7 @@ func (t *Target) Copy() Target { ServiceID: t.ServiceID, ServiceName: t.ServiceName, ServiceType: t.ServiceType, + NodeID: t.NodeID, NodeName: t.NodeName, Labels: labels, DSN: t.DSN, From 1c28fa606328f14db8a1ecdef235e80fa9786a42 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sat, 27 Jun 2026 14:07:17 +0300 Subject: [PATCH 004/120] PMM-14109 Add advisor history retention settings and cleanup functionality --- .../deployment-options/docker/env_var.md | 1 + managed/cmd/pmm-managed/main.go | 8 +++ managed/models/check_result_helpers.go | 28 +++++++++ managed/models/settings.go | 6 ++ managed/models/settings_helpers.go | 20 ++++++ managed/utils/clean/check_results.go | 61 +++++++++++++++++++ managed/utils/envvars/parser.go | 7 +++ managed/utils/envvars/parser_test.go | 10 +-- 8 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 managed/models/check_result_helpers.go create mode 100644 managed/utils/clean/check_results.go diff --git a/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md b/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md index 4157168a730..4e39ccd9ee7 100644 --- a/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md +++ b/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md @@ -17,6 +17,7 @@ Fine-tune data retention and collection intervals to balance monitoring detail w | Variable | Default | Description | Example | |----------|---------|-------------|----------| | `PMM_DATA_RETENTION` | `30d` | Duration to retain metrics data (must be in multiples of 24h) | `720h` (30 days) | +| `PMM_ADVISOR_HISTORY_RETENTION` | `30d` | Duration to retain Advisor check results history (must be in multiples of 24h) | `720h` (30 days) | | `PMM_METRICS_RESOLUTION` | `1s` | Base metrics collection interval | `5s` | | `PMM_METRICS_RESOLUTION_HR` | `5s` | High-resolution metrics interval | `10s` | | `PMM_METRICS_RESOLUTION_MR` | `10s` | Medium-resolution metrics interval | `30s` | diff --git a/managed/cmd/pmm-managed/main.go b/managed/cmd/pmm-managed/main.go index 1e0b25cbdad..24f739152fd 100644 --- a/managed/cmd/pmm-managed/main.go +++ b/managed/cmd/pmm-managed/main.go @@ -129,6 +129,8 @@ const ( cleanInterval = 10 * time.Minute cleanOlderThan = 30 * time.Minute + advisorHistoryCleanInterval = time.Hour + defaultContextTimeout = 10 * time.Second pProfProfileDuration = 30 * time.Second pProfTraceDuration = 10 * time.Second @@ -897,6 +899,7 @@ func main() { //nolint:gocognit,maintidx,cyclop } cleaner := clean.New(db) + advisorHistoryCleaner := clean.NewCheckResults(db) externalRules := vmalert.NewExternalRules() vmdb, err := victoriametrics.NewVictoriaMetrics(*victoriaMetricsConfigF, db, vmParams, chParams, haService) if err != nil { @@ -1219,6 +1222,11 @@ func main() { //nolint:gocognit,maintidx,cyclop return nil })) + haService.AddLeaderService(ha.NewContextService("advisor-history-cleaner", func(ctx context.Context) error { + advisorHistoryCleaner.Run(ctx, advisorHistoryCleanInterval) + return nil + })) + wg.Go(func() { err := haService.Run(ctx) if err != nil { diff --git a/managed/models/check_result_helpers.go b/managed/models/check_result_helpers.go new file mode 100644 index 00000000000..864ffa780dc --- /dev/null +++ b/managed/models/check_result_helpers.go @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models + +import ( + "time" + + "gopkg.in/reform.v1" +) + +// CleanupOldCheckResults deletes Advisor check results older than a specified date. +func CleanupOldCheckResults(q *reform.Querier, olderThan time.Time) error { + _, err := q.DeleteFrom(CheckResultTable, " WHERE checked_at <= $1", olderThan) + return err +} diff --git a/managed/models/settings.go b/managed/models/settings.go index be03684d785..08ab7c453d9 100644 --- a/managed/models/settings.go +++ b/managed/models/settings.go @@ -77,6 +77,8 @@ type Settings struct { DataRetention time.Duration `json:"data_retention"` + AdvisorHistoryRetention time.Duration `json:"advisor_history_retention"` + AWSPartitions []string `json:"aws_partitions"` AWSInstanceChecked bool `json:"aws_instance_checked"` @@ -217,6 +219,10 @@ func (s *Settings) fillDefaults() { s.DataRetention = 30 * 24 * time.Hour //nolint:mnd } + if s.AdvisorHistoryRetention == 0 { + s.AdvisorHistoryRetention = 30 * 24 * time.Hour //nolint:mnd + } + if len(s.AWSPartitions) == 0 { s.AWSPartitions = []string{awsPartitionID} } diff --git a/managed/models/settings_helpers.go b/managed/models/settings_helpers.go index 58bac61635f..e6265ad3be6 100644 --- a/managed/models/settings_helpers.go +++ b/managed/models/settings_helpers.go @@ -60,6 +60,8 @@ type ChangeSettingsParams struct { DataRetention time.Duration + AdvisorHistoryRetention time.Duration + // List of AWS partitions to use. If empty - default partitions will be used. If nil - no changes will be made. AWSPartitions []string @@ -173,6 +175,10 @@ func UpdateSettings(q reform.DBTX, params *ChangeSettingsParams) (*Settings, err settings.DataRetention = params.DataRetention } + if params.AdvisorHistoryRetention != 0 { + settings.AdvisorHistoryRetention = params.AdvisorHistoryRetention + } + if params.AWSPartitions != nil { settings.AWSPartitions = deduplicateStrings(params.AWSPartitions) } @@ -326,6 +332,20 @@ func ValidateSettings(params *ChangeSettingsParams) error { } } + if params.AdvisorHistoryRetention != 0 { + _, err := validators.ValidateDataRetention(params.AdvisorHistoryRetention) + if err != nil { + switch err.(type) { //nolint:errorlint + case validators.DurationNotAllowedError: + return errors.New("advisor_history_retention: should be a natural number of days") + case validators.MinDurationError: + return errors.New("advisor_history_retention: minimal resolution is 24h") + default: + return fmt.Errorf("advisor_history_retention: %w", err) + } + } + } + err := validators.ValidateAWSPartitions(params.AWSPartitions) if err != nil { return err diff --git a/managed/utils/clean/check_results.go b/managed/utils/clean/check_results.go new file mode 100644 index 00000000000..e9e53da805c --- /dev/null +++ b/managed/utils/clean/check_results.go @@ -0,0 +1,61 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package clean + +import ( + "context" + "time" + + "github.com/sirupsen/logrus" + "gopkg.in/reform.v1" + + "github.com/percona/pmm/managed/models" +) + +// CheckResults cleans up Advisor check results history past the configured retention. +type CheckResults struct { + db *reform.DB +} + +// NewCheckResults returns a new CheckResults cleaner. +func NewCheckResults(db *reform.DB) *CheckResults { + return &CheckResults{db: db} +} + +// Run starts the Advisor check results history cleanup process. +func (c *CheckResults) Run(ctx context.Context, interval time.Duration) { + ticker := time.NewTicker(interval) + defer ticker.Stop() + l := logrus.WithField("component", "advisor-history-cleaner") + + for { + settings, err := models.GetSettings(c.db) + if err != nil { + l.Error(err) + } else { + olderThanTS := models.Now().Add(-1 * settings.AdvisorHistoryRetention) + if err := models.CleanupOldCheckResults(c.db.Querier, olderThanTS); err != nil { + l.Error(err) + } + } + + select { + case <-ctx.Done(): + return + case <-ticker.C: + } + } +} diff --git a/managed/utils/envvars/parser.go b/managed/utils/envvars/parser.go index b7e420012d5..3b3d8baddf4 100644 --- a/managed/utils/envvars/parser.go +++ b/managed/utils/envvars/parser.go @@ -63,6 +63,7 @@ func (e InvalidDurationError) Error() string { return string(e) } // - PMM_ENABLE_ALERTING disables Percona Alerting; // - PMM_METRICS_RESOLUTION, PMM_METRICS_RESOLUTION_MR, PMM_METRICS_RESOLUTION_HR, PMM_METRICS_RESOLUTION_LR are durations of metrics resolution; // - PMM_DATA_RETENTION is the duration of how long keep time-series data in ClickHouse; +// - PMM_ADVISOR_HISTORY_RETENTION is the duration of how long to keep Advisor check results history; // - PMM_ENABLE_AZURE_DISCOVER enables Azure Discover; // - PMM_ENABLE_ACCESS_CONTROL enables Access control; // - the environment variables prefixed with GF_ passed as related to Grafana. @@ -177,6 +178,12 @@ func ParseEnvVars(envs []string) (*models.ChangeSettingsParams, []error, []strin errs = append(errs, formatEnvVariableError(err, env, v)) continue } + case "PMM_ADVISOR_HISTORY_RETENTION": + envSettings.AdvisorHistoryRetention, err = parseStringDuration(v) + if err != nil { + errs = append(errs, formatEnvVariableError(err, env, v)) + continue + } case "PMM_ENABLE_VM_CACHE": b, err := strconv.ParseBool(v) if err != nil { diff --git a/managed/utils/envvars/parser_test.go b/managed/utils/envvars/parser_test.go index e4cf310b7d4..2ee86dd508e 100644 --- a/managed/utils/envvars/parser_test.go +++ b/managed/utils/envvars/parser_test.go @@ -38,13 +38,15 @@ func TestEnvVarValidator(t *testing.T) { "PMM_METRICS_RESOLUTION_MR=5s", "PMM_METRICS_RESOLUTION_LR=1h", "PMM_DATA_RETENTION=72h", + "PMM_ADVISOR_HISTORY_RETENTION=48h", "PMM_UPDATE_SNOOZE_DURATION=1h", } expectedEnvVars := &models.ChangeSettingsParams{ - DataRetention: 72 * time.Hour, - EnableTelemetry: new(true), - EnableUpdates: new(false), - EnableAdvisors: nil, + DataRetention: 72 * time.Hour, + AdvisorHistoryRetention: 48 * time.Hour, + EnableTelemetry: new(true), + EnableUpdates: new(false), + EnableAdvisors: nil, MetricsResolutions: models.MetricsResolutions{ HR: 5 * time.Minute, MR: 5 * time.Second, From d1d7b8b640a1fbae032daf9e1b19672f638a96a5 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sat, 27 Jun 2026 19:45:06 +0300 Subject: [PATCH 005/120] PMM-12345 Refactor check result handling and add history retrieval --- api/accesscontrol/v1beta1/accesscontrol.pb.go | 1 - .../v1beta1/accesscontrol.swagger.json | 410 ++ api/actions/v1/actions.pb.go | 1 - api/actions/v1/actions.swagger.json | 737 +++ api/advisors/v1/advisors.pb.go | 662 ++- api/advisors/v1/advisors.pb.gw.go | 98 +- api/advisors/v1/advisors.pb.validate.go | 518 ++ api/advisors/v1/advisors.proto | 96 + api/advisors/v1/advisors.swagger.json | 788 +++ api/advisors/v1/advisors_grpc.pb.go | 53 +- .../advisor_service/advisor_service_client.go | 46 + .../list_check_results_history_parameters.go | 551 ++ .../list_check_results_history_responses.go | 819 +++ api/advisors/v1/json/v1.json | 291 ++ api/agent/pb/agent.swagger.json | 55 + api/agent/v1/agent.pb.go | 1 - api/agent/v1/agent.swagger.json | 55 + api/agent/v1/collector.pb.go | 1 - api/agent/v1/collector.swagger.json | 50 + api/agentlocal/v1/agentlocal.pb.go | 1 - api/agentlocal/v1/agentlocal.swagger.json | 295 ++ api/alerting/v1/alerting.pb.go | 1 - api/alerting/v1/alerting.swagger.json | 581 +++ api/alerting/v1/params.pb.go | 1 - api/alerting/v1/params.swagger.json | 44 + api/backup/v1/artifacts.pb.go | 1 - api/backup/v1/artifacts.swagger.json | 44 + api/backup/v1/backup.pb.go | 1 - api/backup/v1/backup.swagger.json | 1003 ++++ api/backup/v1/common.pb.go | 1 - api/backup/v1/common.swagger.json | 44 + api/backup/v1/errors.pb.go | 1 - api/backup/v1/errors.swagger.json | 44 + api/backup/v1/locations.pb.go | 1 - api/backup/v1/locations.swagger.json | 353 ++ api/backup/v1/restores.pb.go | 1 - api/backup/v1/restores.swagger.json | 303 ++ api/common/common.pb.go | 1 - api/common/common.swagger.json | 44 + api/common/metrics_resolutions.pb.go | 1 - api/common/metrics_resolutions.swagger.json | 44 + api/descriptor.bin | Bin 817461 -> 823750 bytes api/dump/v1beta1/dump.pb.go | 1 - api/dump/v1beta1/dump.swagger.json | 395 ++ api/extensions/v1/redact.pb.go | 1 - api/extensions/v1/redact.swagger.json | 44 + api/ha/v1beta1/ha.pb.go | 1 - api/ha/v1beta1/ha.swagger.json | 148 + api/inventory/v1/agent_status.pb.go | 1 - api/inventory/v1/agent_status.swagger.json | 44 + api/inventory/v1/agents.pb.go | 1 - api/inventory/v1/agents.swagger.json | 4490 ++++++++++++++++ api/inventory/v1/log_level.pb.go | 1 - api/inventory/v1/log_level.swagger.json | 44 + api/inventory/v1/nodes.pb.go | 1 - api/inventory/v1/nodes.swagger.json | 708 +++ api/inventory/v1/services.pb.go | 1 - api/inventory/v1/services.swagger.json | 1189 +++++ api/management/v1/agent.pb.go | 1 - api/management/v1/agent.swagger.json | 44 + api/management/v1/annotation.pb.go | 1 - api/management/v1/annotation.swagger.json | 44 + api/management/v1/azure.pb.go | 1 - api/management/v1/azure.swagger.json | 44 + api/management/v1/external.pb.go | 1 - api/management/v1/external.swagger.json | 44 + api/management/v1/haproxy.pb.go | 1 - api/management/v1/haproxy.swagger.json | 44 + api/management/v1/metrics.pb.go | 1 - api/management/v1/metrics.swagger.json | 44 + api/management/v1/mongodb.pb.go | 1 - api/management/v1/mongodb.swagger.json | 44 + api/management/v1/mysql.pb.go | 1 - api/management/v1/mysql.swagger.json | 44 + api/management/v1/node.pb.go | 1 - api/management/v1/node.swagger.json | 44 + api/management/v1/postgresql.pb.go | 1 - api/management/v1/postgresql.swagger.json | 44 + api/management/v1/proxysql.pb.go | 1 - api/management/v1/proxysql.swagger.json | 44 + api/management/v1/rds.pb.go | 1 - api/management/v1/rds.swagger.json | 44 + api/management/v1/service.pb.go | 1 - api/management/v1/service.swagger.json | 4547 +++++++++++++++++ api/management/v1/severity.pb.go | 1 - api/management/v1/severity.swagger.json | 44 + api/management/v1/valkey.pb.go | 1 - api/management/v1/valkey.swagger.json | 44 + api/qan/v1/collector.pb.go | 1 - api/qan/v1/collector.swagger.json | 44 + api/qan/v1/filters.pb.go | 1 - api/qan/v1/filters.swagger.json | 44 + api/qan/v1/object_details.pb.go | 1 - api/qan/v1/object_details.swagger.json | 44 + api/qan/v1/profile.pb.go | 1 - api/qan/v1/profile.swagger.json | 44 + api/qan/v1/qan.pb.go | 1 - api/qan/v1/qan.swagger.json | 44 + api/qan/v1/service.pb.go | 1 - api/qan/v1/service.swagger.json | 1568 ++++++ api/realtimeanalytics/v1/collector.pb.go | 1 - .../v1/collector.swagger.json | 44 + api/realtimeanalytics/v1/query.pb.go | 1 - api/realtimeanalytics/v1/query.swagger.json | 44 + .../v1/realtimeanalytics.pb.go | 1 - .../v1/realtimeanalytics.swagger.json | 516 ++ api/server/v1/httperror.pb.go | 1 - api/server/v1/httperror.swagger.json | 46 + api/server/v1/server.pb.go | 1 - api/server/v1/server.swagger.json | 798 +++ api/swagger/swagger-dev.json | 291 ++ api/swagger/swagger.json | 291 ++ api/user/v1/user.pb.go | 1 - api/user/v1/user.swagger.json | 243 + managed/models/check_result_helpers.go | 115 + managed/models/check_result_model.go | 2 +- managed/models/check_result_model_reform.go | 2 +- managed/models/settings_helpers.go | 6 +- managed/services/checks/checks.go | 98 + managed/services/management/checks.go | 133 + managed/services/management/checks_test.go | 86 + managed/services/management/deps.go | 1 + .../management/mock_checks_service_test.go | 38 + 123 files changed, 24712 insertions(+), 133 deletions(-) create mode 100644 api/accesscontrol/v1beta1/accesscontrol.swagger.json create mode 100644 api/actions/v1/actions.swagger.json create mode 100644 api/advisors/v1/advisors.swagger.json create mode 100644 api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go create mode 100644 api/agent/pb/agent.swagger.json create mode 100644 api/agent/v1/agent.swagger.json create mode 100644 api/agent/v1/collector.swagger.json create mode 100644 api/agentlocal/v1/agentlocal.swagger.json create mode 100644 api/alerting/v1/alerting.swagger.json create mode 100644 api/alerting/v1/params.swagger.json create mode 100644 api/backup/v1/artifacts.swagger.json create mode 100644 api/backup/v1/backup.swagger.json create mode 100644 api/backup/v1/common.swagger.json create mode 100644 api/backup/v1/errors.swagger.json create mode 100644 api/backup/v1/locations.swagger.json create mode 100644 api/backup/v1/restores.swagger.json create mode 100644 api/common/common.swagger.json create mode 100644 api/common/metrics_resolutions.swagger.json create mode 100644 api/dump/v1beta1/dump.swagger.json create mode 100644 api/extensions/v1/redact.swagger.json create mode 100644 api/ha/v1beta1/ha.swagger.json create mode 100644 api/inventory/v1/agent_status.swagger.json create mode 100644 api/inventory/v1/agents.swagger.json create mode 100644 api/inventory/v1/log_level.swagger.json create mode 100644 api/inventory/v1/nodes.swagger.json create mode 100644 api/inventory/v1/services.swagger.json create mode 100644 api/management/v1/agent.swagger.json create mode 100644 api/management/v1/annotation.swagger.json create mode 100644 api/management/v1/azure.swagger.json create mode 100644 api/management/v1/external.swagger.json create mode 100644 api/management/v1/haproxy.swagger.json create mode 100644 api/management/v1/metrics.swagger.json create mode 100644 api/management/v1/mongodb.swagger.json create mode 100644 api/management/v1/mysql.swagger.json create mode 100644 api/management/v1/node.swagger.json create mode 100644 api/management/v1/postgresql.swagger.json create mode 100644 api/management/v1/proxysql.swagger.json create mode 100644 api/management/v1/rds.swagger.json create mode 100644 api/management/v1/service.swagger.json create mode 100644 api/management/v1/severity.swagger.json create mode 100644 api/management/v1/valkey.swagger.json create mode 100644 api/qan/v1/collector.swagger.json create mode 100644 api/qan/v1/filters.swagger.json create mode 100644 api/qan/v1/object_details.swagger.json create mode 100644 api/qan/v1/profile.swagger.json create mode 100644 api/qan/v1/qan.swagger.json create mode 100644 api/qan/v1/service.swagger.json create mode 100644 api/realtimeanalytics/v1/collector.swagger.json create mode 100644 api/realtimeanalytics/v1/query.swagger.json create mode 100644 api/realtimeanalytics/v1/realtimeanalytics.swagger.json create mode 100644 api/server/v1/httperror.swagger.json create mode 100644 api/server/v1/server.swagger.json create mode 100644 api/user/v1/user.swagger.json diff --git a/api/accesscontrol/v1beta1/accesscontrol.pb.go b/api/accesscontrol/v1beta1/accesscontrol.pb.go index f5e8ea4b004..ebec3bf05b7 100644 --- a/api/accesscontrol/v1beta1/accesscontrol.pb.go +++ b/api/accesscontrol/v1beta1/accesscontrol.pb.go @@ -844,7 +844,6 @@ var ( (*ListRolesResponse_RoleData)(nil), // 14: accesscontrol.v1beta1.ListRolesResponse.RoleData } ) - var file_accesscontrol_v1beta1_accesscontrol_proto_depIdxs = []int32{ 14, // 0: accesscontrol.v1beta1.ListRolesResponse.roles:type_name -> accesscontrol.v1beta1.ListRolesResponse.RoleData 0, // 1: accesscontrol.v1beta1.AccessControlService.CreateRole:input_type -> accesscontrol.v1beta1.CreateRoleRequest diff --git a/api/accesscontrol/v1beta1/accesscontrol.swagger.json b/api/accesscontrol/v1beta1/accesscontrol.swagger.json new file mode 100644 index 00000000000..d9435ab700b --- /dev/null +++ b/api/accesscontrol/v1beta1/accesscontrol.swagger.json @@ -0,0 +1,410 @@ +{ + "swagger": "2.0", + "info": { + "title": "accesscontrol/v1beta1/accesscontrol.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "AccessControlService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/accesscontrol/roles": { + "get": { + "summary": "List Roles", + "description": "Lists all roles.", + "operationId": "ListRoles", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1ListRolesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "AccessControlService" + ] + }, + "post": { + "summary": "Create a Role", + "description": "Creates a new role.", + "operationId": "CreateRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1CreateRoleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1beta1CreateRoleRequest" + } + } + ], + "tags": [ + "AccessControlService" + ] + } + }, + "/v1/accesscontrol/roles/{role_id}": { + "get": { + "summary": "Get a Role", + "description": "Retrieves a role by ID.", + "operationId": "GetRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1GetRoleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "type": "integer", + "format": "int64" + } + ], + "tags": [ + "AccessControlService" + ] + }, + "delete": { + "summary": "Delete a Role", + "description": "Deletes a role.", + "operationId": "DeleteRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1DeleteRoleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "type": "integer", + "format": "int64" + }, + { + "name": "replacement_role_id", + "description": "Role ID to be used as a replacement for the role. Additional logic applies.", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + } + ], + "tags": [ + "AccessControlService" + ] + }, + "put": { + "summary": "Update a Role", + "description": "Updates an existing role.", + "operationId": "UpdateRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1UpdateRoleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "type": "integer", + "format": "int64" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AccessControlServiceUpdateRoleBody" + } + } + ], + "tags": [ + "AccessControlService" + ] + } + }, + "/v1/accesscontrol/roles:assign": { + "post": { + "summary": "Assign Roles to a User", + "description": "Replaces all existing roles for a user.", + "operationId": "AssignRoles", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1AssignRolesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1beta1AssignRolesRequest" + } + } + ], + "tags": [ + "AccessControlService" + ] + } + }, + "/v1/accesscontrol/roles:setDefault": { + "post": { + "summary": "Set a Default Role", + "description": "Configures a default role assigned to users.", + "operationId": "SetDefaultRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1SetDefaultRoleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1beta1SetDefaultRoleRequest" + } + } + ], + "tags": [ + "AccessControlService" + ] + } + } + }, + "definitions": { + "AccessControlServiceUpdateRoleBody": { + "type": "object", + "properties": { + "title": { + "type": "string", + "x-nullable": true + }, + "filter": { + "type": "string", + "x-nullable": true + }, + "description": { + "type": "string", + "x-nullable": true + } + } + }, + "ListRolesResponseRoleData": { + "type": "object", + "properties": { + "role_id": { + "type": "integer", + "format": "int64" + }, + "title": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1beta1AssignRolesRequest": { + "type": "object", + "properties": { + "role_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + } + }, + "user_id": { + "type": "integer", + "format": "int64" + } + } + }, + "v1beta1AssignRolesResponse": { + "type": "object" + }, + "v1beta1CreateRoleRequest": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "v1beta1CreateRoleResponse": { + "type": "object", + "properties": { + "role_id": { + "type": "integer", + "format": "int64" + } + } + }, + "v1beta1DeleteRoleResponse": { + "type": "object" + }, + "v1beta1GetRoleResponse": { + "type": "object", + "properties": { + "role_id": { + "type": "integer", + "format": "int64" + }, + "title": { + "type": "string" + }, + "filter": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "v1beta1ListRolesResponse": { + "type": "object", + "properties": { + "roles": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/ListRolesResponseRoleData" + } + } + } + }, + "v1beta1SetDefaultRoleRequest": { + "type": "object", + "properties": { + "role_id": { + "type": "integer", + "format": "int64" + } + } + }, + "v1beta1SetDefaultRoleResponse": { + "type": "object" + }, + "v1beta1UpdateRoleResponse": { + "type": "object" + } + } +} diff --git a/api/actions/v1/actions.pb.go b/api/actions/v1/actions.pb.go index f1cfdec8cfa..35461ae3739 100644 --- a/api/actions/v1/actions.pb.go +++ b/api/actions/v1/actions.pb.go @@ -2649,7 +2649,6 @@ var ( (*StartServiceActionResponse)(nil), // 32: actions.v1.StartServiceActionResponse } ) - var file_actions_v1_actions_proto_depIdxs = []int32{ 3, // 0: actions.v1.StartServiceActionRequest.mysql_explain:type_name -> actions.v1.StartMySQLExplainActionParams 5, // 1: actions.v1.StartServiceActionRequest.mysql_explain_json:type_name -> actions.v1.StartMySQLExplainJSONActionParams diff --git a/api/actions/v1/actions.swagger.json b/api/actions/v1/actions.swagger.json new file mode 100644 index 00000000000..04404da66a7 --- /dev/null +++ b/api/actions/v1/actions.swagger.json @@ -0,0 +1,737 @@ +{ + "swagger": "2.0", + "info": { + "title": "actions/v1/actions.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "ActionsService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/actions/{action_id}": { + "get": { + "summary": "Get Action", + "description": "Gets the result of a given Action.", + "operationId": "GetAction", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetActionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "action_id", + "description": "Unique Action ID.", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ActionsService" + ] + } + }, + "/v1/actions:cancelAction": { + "post": { + "summary": "Cancel an Action", + "description": "Stops an Action.", + "operationId": "CancelAction", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CancelActionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1CancelActionRequest" + } + } + ], + "tags": [ + "ActionsService" + ] + } + }, + "/v1/actions:startNodeAction": { + "post": { + "summary": "Start 'PT Summary' Action", + "description": "Starts 'Percona Toolkit Summary' Action.", + "operationId": "StartPTSummaryAction", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartPTSummaryActionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StartPTSummaryActionRequest" + } + } + ], + "tags": [ + "ActionsService" + ] + } + }, + "/v1/actions:startServiceAction": { + "post": { + "summary": "Start a Service Action", + "description": "Starts a Service Action.", + "operationId": "StartServiceAction", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartServiceActionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StartServiceActionRequest" + } + } + ], + "tags": [ + "ActionsService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1CancelActionRequest": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID. Required." + } + } + }, + "v1CancelActionResponse": { + "type": "object" + }, + "v1GetActionResponse": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where this Action is running / was run." + }, + "output": { + "type": "string", + "description": "Current Action output; may be partial if Action is still running." + }, + "done": { + "type": "boolean", + "description": "True if Action is finished." + }, + "error": { + "type": "string", + "description": "Error message if Action failed." + } + } + }, + "v1StartMongoDBExplainActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "query": { + "type": "string", + "description": "Query. Required." + } + } + }, + "v1StartMongoDBExplainActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartMySQLExplainActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "query_id": { + "type": "string", + "description": "Query ID of query." + }, + "placeholders": { + "type": "array", + "items": { + "type": "string" + }, + "title": "Array of placeholder values" + }, + "database": { + "type": "string", + "description": "Database name. Required if it can't be deduced from the query ID." + } + } + }, + "v1StartMySQLExplainActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartMySQLExplainJSONActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "query_id": { + "type": "string", + "description": "Query ID of query." + }, + "placeholders": { + "type": "array", + "items": { + "type": "string" + }, + "title": "Array of placeholder values" + }, + "database": { + "type": "string", + "description": "Database name. Required if it can't be deduced from the query ID." + } + } + }, + "v1StartMySQLExplainJSONActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartMySQLExplainTraditionalJSONActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "query_id": { + "type": "string", + "description": "Query ID of query." + }, + "placeholders": { + "type": "array", + "items": { + "type": "string" + }, + "title": "Array of placeholder values" + }, + "database": { + "type": "string", + "description": "Database name. Required if it can't be deduced from the query ID." + } + } + }, + "v1StartMySQLExplainTraditionalJSONActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartMySQLShowCreateTableActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "table_name": { + "type": "string", + "description": "Table name. Required. May additionally contain a database name." + }, + "database": { + "type": "string", + "description": "Database name. Required if not given in the table_name field." + } + } + }, + "v1StartMySQLShowCreateTableActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartMySQLShowIndexActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "table_name": { + "type": "string", + "description": "Table name. Required. May additionally contain a database name." + }, + "database": { + "type": "string", + "description": "Database name. Required if not given in the table_name field." + } + } + }, + "v1StartMySQLShowIndexActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartMySQLShowTableStatusActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "table_name": { + "type": "string", + "description": "Table name. Required. May additionally contain a database name." + }, + "database": { + "type": "string", + "description": "Database name. Required if not given in the table_name field." + } + } + }, + "v1StartMySQLShowTableStatusActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartPTMongoDBSummaryActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action." + } + }, + "title": "Message to prepare pt-mongodb-summary data" + }, + "v1StartPTMongoDBSummaryActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + }, + "title": "Message to retrieve the prepared pt-mongodb-summary data" + }, + "v1StartPTMySQLSummaryActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action." + } + }, + "title": "Message to prepare pt-mysql-summary data" + }, + "v1StartPTMySQLSummaryActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + }, + "title": "Message to retrieve the prepared pt-mysql-summary data" + }, + "v1StartPTPgSummaryActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action." + } + }, + "title": "Message to prepare pt-pg-summary data" + }, + "v1StartPTPgSummaryActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + }, + "title": "Message to retrieve the prepared pt-pg-summary data" + }, + "v1StartPTSummaryActionRequest": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "node_id": { + "type": "string", + "description": "Node ID for this Action." + } + } + }, + "v1StartPTSummaryActionResponse": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartPostgreSQLShowCreateTableActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "table_name": { + "type": "string", + "description": "Table name. Required. May additionally contain a database name." + }, + "database": { + "type": "string", + "description": "Database name. Required if not given in the table_name field." + } + } + }, + "v1StartPostgreSQLShowCreateTableActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartPostgreSQLShowIndexActionParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to run this Action." + }, + "service_id": { + "type": "string", + "description": "Service ID for this Action. Required." + }, + "table_name": { + "type": "string", + "description": "Table name. Required. May additionally contain a database name." + }, + "database": { + "type": "string", + "description": "Database name. Required if not given in the table_name field." + } + } + }, + "v1StartPostgreSQLShowIndexActionResult": { + "type": "object", + "properties": { + "action_id": { + "type": "string", + "description": "Unique Action ID." + }, + "pmm_agent_id": { + "type": "string", + "description": "pmm-agent ID where to this Action was started." + } + } + }, + "v1StartServiceActionRequest": { + "type": "object", + "properties": { + "mysql_explain": { + "$ref": "#/definitions/v1StartMySQLExplainActionParams" + }, + "mysql_explain_json": { + "$ref": "#/definitions/v1StartMySQLExplainJSONActionParams" + }, + "mysql_explain_traditional_json": { + "$ref": "#/definitions/v1StartMySQLExplainTraditionalJSONActionParams" + }, + "mysql_show_index": { + "$ref": "#/definitions/v1StartMySQLShowIndexActionParams" + }, + "mysql_show_create_table": { + "$ref": "#/definitions/v1StartMySQLShowCreateTableActionParams" + }, + "mysql_show_table_status": { + "$ref": "#/definitions/v1StartMySQLShowTableStatusActionParams" + }, + "postgres_show_create_table": { + "$ref": "#/definitions/v1StartPostgreSQLShowCreateTableActionParams" + }, + "postgres_show_index": { + "$ref": "#/definitions/v1StartPostgreSQLShowIndexActionParams" + }, + "mongodb_explain": { + "$ref": "#/definitions/v1StartMongoDBExplainActionParams" + }, + "pt_mongodb_summary": { + "$ref": "#/definitions/v1StartPTMongoDBSummaryActionParams" + }, + "pt_mysql_summary": { + "$ref": "#/definitions/v1StartPTMySQLSummaryActionParams" + }, + "pt_postgres_summary": { + "$ref": "#/definitions/v1StartPTPgSummaryActionParams" + } + } + }, + "v1StartServiceActionResponse": { + "type": "object", + "properties": { + "mysql_explain": { + "$ref": "#/definitions/v1StartMySQLExplainActionResult" + }, + "mysql_explain_json": { + "$ref": "#/definitions/v1StartMySQLExplainJSONActionResult" + }, + "mysql_explain_traditional_json": { + "$ref": "#/definitions/v1StartMySQLExplainTraditionalJSONActionResult" + }, + "mysql_show_index": { + "$ref": "#/definitions/v1StartMySQLShowIndexActionResult" + }, + "mysql_show_create_table": { + "$ref": "#/definitions/v1StartMySQLShowCreateTableActionResult" + }, + "mysql_show_table_status": { + "$ref": "#/definitions/v1StartMySQLShowTableStatusActionResult" + }, + "postgresql_show_create_table": { + "$ref": "#/definitions/v1StartPostgreSQLShowCreateTableActionResult" + }, + "postgresql_show_index": { + "$ref": "#/definitions/v1StartPostgreSQLShowIndexActionResult" + }, + "mongodb_explain": { + "$ref": "#/definitions/v1StartMongoDBExplainActionResult" + }, + "pt_mongodb_summary": { + "$ref": "#/definitions/v1StartPTMongoDBSummaryActionResult" + }, + "pt_mysql_summary": { + "$ref": "#/definitions/v1StartPTMySQLSummaryActionResult" + }, + "pt_postgres_summary": { + "$ref": "#/definitions/v1StartPTPgSummaryActionResult" + } + } + } + } +} diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index 3e4995415ad..48949e35583 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -16,6 +16,7 @@ import ( _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" v1 "github.com/percona/pmm/api/management/v1" ) @@ -132,6 +133,62 @@ func (AdvisorCheckFamily) EnumDescriptor() ([]byte, []int) { return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{1} } +// AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service. +type AdvisorCheckResultStatus int32 + +const ( + AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED AdvisorCheckResultStatus = 0 + // The check ran and found no issue. + AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_OK AdvisorCheckResultStatus = 1 + // The check ran and detected an issue. + AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_FAILED AdvisorCheckResultStatus = 2 + // The check could not be executed. + AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_ERROR AdvisorCheckResultStatus = 3 +) + +// Enum value maps for AdvisorCheckResultStatus. +var ( + AdvisorCheckResultStatus_name = map[int32]string{ + 0: "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + 1: "ADVISOR_CHECK_RESULT_STATUS_OK", + 2: "ADVISOR_CHECK_RESULT_STATUS_FAILED", + 3: "ADVISOR_CHECK_RESULT_STATUS_ERROR", + } + AdvisorCheckResultStatus_value = map[string]int32{ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED": 0, + "ADVISOR_CHECK_RESULT_STATUS_OK": 1, + "ADVISOR_CHECK_RESULT_STATUS_FAILED": 2, + "ADVISOR_CHECK_RESULT_STATUS_ERROR": 3, + } +) + +func (x AdvisorCheckResultStatus) Enum() *AdvisorCheckResultStatus { + p := new(AdvisorCheckResultStatus) + *p = x + return p +} + +func (x AdvisorCheckResultStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AdvisorCheckResultStatus) Descriptor() protoreflect.EnumDescriptor { + return file_advisors_v1_advisors_proto_enumTypes[2].Descriptor() +} + +func (AdvisorCheckResultStatus) Type() protoreflect.EnumType { + return &file_advisors_v1_advisors_proto_enumTypes[2] +} + +func (x AdvisorCheckResultStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AdvisorCheckResultStatus.Descriptor instead. +func (AdvisorCheckResultStatus) EnumDescriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{2} +} + // AdvisorCheckResult represents the check result returned from pmm-managed after running the check. type AdvisorCheckResult struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1229,11 +1286,417 @@ func (x *GetFailedChecksResponse) GetResults() []*CheckResult { return nil } +// CheckResultHistoryItem represents a single persisted Advisor check run against a service. +type CheckResultHistoryItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Unique identifier of the history record. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Name of the check that ran. + CheckName string `protobuf:"bytes,2,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` + // Name of the advisor the check belongs to. + AdvisorName string `protobuf:"bytes,3,opt,name=advisor_name,json=advisorName,proto3" json:"advisor_name,omitempty"` + // Category of the advisor the check belongs to. + Category string `protobuf:"bytes,4,opt,name=category,proto3" json:"category,omitempty"` + // Check execution interval. + Interval AdvisorCheckInterval `protobuf:"varint,5,opt,name=interval,proto3,enum=advisors.v1.AdvisorCheckInterval" json:"interval,omitempty"` + // ID of the monitored service on which the check ran. + ServiceId string `protobuf:"bytes,6,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // Name of the monitored service on which the check ran. + ServiceName string `protobuf:"bytes,7,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + // Type of the monitored service on which the check ran. + ServiceType string `protobuf:"bytes,8,opt,name=service_type,json=serviceType,proto3" json:"service_type,omitempty"` + // ID of the node the service runs on. + NodeId string `protobuf:"bytes,9,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // Name of the node the service runs on. + NodeName string `protobuf:"bytes,10,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + // Outcome of the check run. + Status AdvisorCheckResultStatus `protobuf:"varint,11,opt,name=status,proto3,enum=advisors.v1.AdvisorCheckResultStatus" json:"status,omitempty"` + // Short human-readable summary of the result. + Summary string `protobuf:"bytes,12,opt,name=summary,proto3" json:"summary,omitempty"` + // Long human-readable description of the result. + Description string `protobuf:"bytes,13,opt,name=description,proto3" json:"description,omitempty"` + // URL containing information on how to resolve a detected issue. + ReadMoreUrl string `protobuf:"bytes,14,opt,name=read_more_url,json=readMoreUrl,proto3" json:"read_more_url,omitempty"` + // Severity of the result. + Severity v1.Severity `protobuf:"varint,15,opt,name=severity,proto3,enum=management.v1.Severity" json:"severity,omitempty"` + // Result labels. + Labels map[string]string `protobuf:"bytes,16,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Time when the check ran. + CheckedAt *timestamppb.Timestamp `protobuf:"bytes,17,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"` + // Whether the result has been marked as read. + IsRead bool `protobuf:"varint,18,opt,name=is_read,json=isRead,proto3" json:"is_read,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CheckResultHistoryItem) Reset() { + *x = CheckResultHistoryItem{} + mi := &file_advisors_v1_advisors_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CheckResultHistoryItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckResultHistoryItem) ProtoMessage() {} + +func (x *CheckResultHistoryItem) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckResultHistoryItem.ProtoReflect.Descriptor instead. +func (*CheckResultHistoryItem) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{18} +} + +func (x *CheckResultHistoryItem) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *CheckResultHistoryItem) GetCheckName() string { + if x != nil { + return x.CheckName + } + return "" +} + +func (x *CheckResultHistoryItem) GetAdvisorName() string { + if x != nil { + return x.AdvisorName + } + return "" +} + +func (x *CheckResultHistoryItem) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *CheckResultHistoryItem) GetInterval() AdvisorCheckInterval { + if x != nil { + return x.Interval + } + return AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_UNSPECIFIED +} + +func (x *CheckResultHistoryItem) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *CheckResultHistoryItem) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *CheckResultHistoryItem) GetServiceType() string { + if x != nil { + return x.ServiceType + } + return "" +} + +func (x *CheckResultHistoryItem) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *CheckResultHistoryItem) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *CheckResultHistoryItem) GetStatus() AdvisorCheckResultStatus { + if x != nil { + return x.Status + } + return AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED +} + +func (x *CheckResultHistoryItem) GetSummary() string { + if x != nil { + return x.Summary + } + return "" +} + +func (x *CheckResultHistoryItem) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *CheckResultHistoryItem) GetReadMoreUrl() string { + if x != nil { + return x.ReadMoreUrl + } + return "" +} + +func (x *CheckResultHistoryItem) GetSeverity() v1.Severity { + if x != nil { + return x.Severity + } + return v1.Severity(0) +} + +func (x *CheckResultHistoryItem) GetLabels() map[string]string { + if x != nil { + return x.Labels + } + return nil +} + +func (x *CheckResultHistoryItem) GetCheckedAt() *timestamppb.Timestamp { + if x != nil { + return x.CheckedAt + } + return nil +} + +func (x *CheckResultHistoryItem) GetIsRead() bool { + if x != nil { + return x.IsRead + } + return false +} + +type ListCheckResultsHistoryRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Maximum number of results per page. + PageSize *int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3,oneof" json:"page_size,omitempty"` + // Index of the requested page, starts from 0. + PageIndex *int32 `protobuf:"varint,2,opt,name=page_index,json=pageIndex,proto3,oneof" json:"page_index,omitempty"` + // Filter by service ID. + ServiceId string `protobuf:"bytes,3,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + // Filter by outcome. + Status *AdvisorCheckResultStatus `protobuf:"varint,4,opt,name=status,proto3,enum=advisors.v1.AdvisorCheckResultStatus,oneof" json:"status,omitempty"` + // Filter by read state. + IsRead *bool `protobuf:"varint,5,opt,name=is_read,json=isRead,proto3,oneof" json:"is_read,omitempty"` + // Return only results recorded at or after this time. + From *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=from,proto3" json:"from,omitempty"` + // Return only results recorded at or before this time. + To *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=to,proto3" json:"to,omitempty"` + // Filter by service name (partial, case-insensitive match). + ServiceName string `protobuf:"bytes,8,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + // Filter by node name (partial, case-insensitive match). + NodeName string `protobuf:"bytes,9,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + // Filter by advisor category. + Category string `protobuf:"bytes,10,opt,name=category,proto3" json:"category,omitempty"` + // Filter by check name. + CheckName string `protobuf:"bytes,11,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` + // Filter by severity. + Severity *v1.Severity `protobuf:"varint,12,opt,name=severity,proto3,enum=management.v1.Severity,oneof" json:"severity,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListCheckResultsHistoryRequest) Reset() { + *x = ListCheckResultsHistoryRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListCheckResultsHistoryRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListCheckResultsHistoryRequest) ProtoMessage() {} + +func (x *ListCheckResultsHistoryRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListCheckResultsHistoryRequest.ProtoReflect.Descriptor instead. +func (*ListCheckResultsHistoryRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{19} +} + +func (x *ListCheckResultsHistoryRequest) GetPageSize() int32 { + if x != nil && x.PageSize != nil { + return *x.PageSize + } + return 0 +} + +func (x *ListCheckResultsHistoryRequest) GetPageIndex() int32 { + if x != nil && x.PageIndex != nil { + return *x.PageIndex + } + return 0 +} + +func (x *ListCheckResultsHistoryRequest) GetServiceId() string { + if x != nil { + return x.ServiceId + } + return "" +} + +func (x *ListCheckResultsHistoryRequest) GetStatus() AdvisorCheckResultStatus { + if x != nil && x.Status != nil { + return *x.Status + } + return AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED +} + +func (x *ListCheckResultsHistoryRequest) GetIsRead() bool { + if x != nil && x.IsRead != nil { + return *x.IsRead + } + return false +} + +func (x *ListCheckResultsHistoryRequest) GetFrom() *timestamppb.Timestamp { + if x != nil { + return x.From + } + return nil +} + +func (x *ListCheckResultsHistoryRequest) GetTo() *timestamppb.Timestamp { + if x != nil { + return x.To + } + return nil +} + +func (x *ListCheckResultsHistoryRequest) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *ListCheckResultsHistoryRequest) GetNodeName() string { + if x != nil { + return x.NodeName + } + return "" +} + +func (x *ListCheckResultsHistoryRequest) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *ListCheckResultsHistoryRequest) GetCheckName() string { + if x != nil { + return x.CheckName + } + return "" +} + +func (x *ListCheckResultsHistoryRequest) GetSeverity() v1.Severity { + if x != nil && x.Severity != nil { + return *x.Severity + } + return v1.Severity(0) +} + +type ListCheckResultsHistoryResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Total number of results. + TotalItems int32 `protobuf:"varint,1,opt,name=total_items,json=totalItems,proto3" json:"total_items,omitempty"` + // Total number of pages. + TotalPages int32 `protobuf:"varint,2,opt,name=total_pages,json=totalPages,proto3" json:"total_pages,omitempty"` + // History records. + Results []*CheckResultHistoryItem `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListCheckResultsHistoryResponse) Reset() { + *x = ListCheckResultsHistoryResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListCheckResultsHistoryResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListCheckResultsHistoryResponse) ProtoMessage() {} + +func (x *ListCheckResultsHistoryResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListCheckResultsHistoryResponse.ProtoReflect.Descriptor instead. +func (*ListCheckResultsHistoryResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{20} +} + +func (x *ListCheckResultsHistoryResponse) GetTotalItems() int32 { + if x != nil { + return x.TotalItems + } + return 0 +} + +func (x *ListCheckResultsHistoryResponse) GetTotalPages() int32 { + if x != nil { + return x.TotalPages + } + return 0 +} + +func (x *ListCheckResultsHistoryResponse) GetResults() []*CheckResultHistoryItem { + if x != nil { + return x.Results + } + return nil +} + var File_advisors_v1_advisors_proto protoreflect.FileDescriptor const file_advisors_v1_advisors_proto_rawDesc = "" + "\n" + - "\x1aadvisors/v1/advisors.proto\x12\vadvisors.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1cmanagement/v1/severity.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\x1a\x17validate/validate.proto\"\xcc\x02\n" + + "\x1aadvisors/v1/advisors.proto\x12\vadvisors.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1cmanagement/v1/severity.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\x1a\x17validate/validate.proto\"\xcc\x02\n" + "\x12AdvisorCheckResult\x12\x18\n" + "\asummary\x18\x01 \x01(\tR\asummary\x12 \n" + "\vdescription\x18\x02 \x01(\tR\vdescription\x123\n" + @@ -1325,7 +1788,63 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "totalItems\x12\x1f\n" + "\vtotal_pages\x18\x02 \x01(\x05R\n" + "totalPages\x122\n" + - "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults*\xa9\x01\n" + + "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\x8c\x06\n" + + "\x16CheckResultHistoryItem\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" + + "\n" + + "check_name\x18\x02 \x01(\tR\tcheckName\x12!\n" + + "\fadvisor_name\x18\x03 \x01(\tR\vadvisorName\x12\x1a\n" + + "\bcategory\x18\x04 \x01(\tR\bcategory\x12=\n" + + "\binterval\x18\x05 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\binterval\x12\x1d\n" + + "\n" + + "service_id\x18\x06 \x01(\tR\tserviceId\x12!\n" + + "\fservice_name\x18\a \x01(\tR\vserviceName\x12!\n" + + "\fservice_type\x18\b \x01(\tR\vserviceType\x12\x17\n" + + "\anode_id\x18\t \x01(\tR\x06nodeId\x12\x1b\n" + + "\tnode_name\x18\n" + + " \x01(\tR\bnodeName\x12=\n" + + "\x06status\x18\v \x01(\x0e2%.advisors.v1.AdvisorCheckResultStatusR\x06status\x12\x18\n" + + "\asummary\x18\f \x01(\tR\asummary\x12 \n" + + "\vdescription\x18\r \x01(\tR\vdescription\x12\"\n" + + "\rread_more_url\x18\x0e \x01(\tR\vreadMoreUrl\x123\n" + + "\bseverity\x18\x0f \x01(\x0e2\x17.management.v1.SeverityR\bseverity\x12G\n" + + "\x06labels\x18\x10 \x03(\v2/.advisors.v1.CheckResultHistoryItem.LabelsEntryR\x06labels\x129\n" + + "\n" + + "checked_at\x18\x11 \x01(\v2\x1a.google.protobuf.TimestampR\tcheckedAt\x12\x17\n" + + "\ais_read\x18\x12 \x01(\bR\x06isRead\x1a9\n" + + "\vLabelsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xcb\x04\n" + + "\x1eListCheckResultsHistoryRequest\x12)\n" + + "\tpage_size\x18\x01 \x01(\x05B\a\xfaB\x04\x1a\x02(\x01H\x00R\bpageSize\x88\x01\x01\x12+\n" + + "\n" + + "page_index\x18\x02 \x01(\x05B\a\xfaB\x04\x1a\x02(\x00H\x01R\tpageIndex\x88\x01\x01\x12\x1d\n" + + "\n" + + "service_id\x18\x03 \x01(\tR\tserviceId\x12B\n" + + "\x06status\x18\x04 \x01(\x0e2%.advisors.v1.AdvisorCheckResultStatusH\x02R\x06status\x88\x01\x01\x12\x1c\n" + + "\ais_read\x18\x05 \x01(\bH\x03R\x06isRead\x88\x01\x01\x12.\n" + + "\x04from\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\x04from\x12*\n" + + "\x02to\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\x02to\x12!\n" + + "\fservice_name\x18\b \x01(\tR\vserviceName\x12\x1b\n" + + "\tnode_name\x18\t \x01(\tR\bnodeName\x12\x1a\n" + + "\bcategory\x18\n" + + " \x01(\tR\bcategory\x12\x1d\n" + + "\n" + + "check_name\x18\v \x01(\tR\tcheckName\x128\n" + + "\bseverity\x18\f \x01(\x0e2\x17.management.v1.SeverityH\x04R\bseverity\x88\x01\x01B\f\n" + + "\n" + + "_page_sizeB\r\n" + + "\v_page_indexB\t\n" + + "\a_statusB\n" + + "\n" + + "\b_is_readB\v\n" + + "\t_severity\"\xa2\x01\n" + + "\x1fListCheckResultsHistoryResponse\x12\x1f\n" + + "\vtotal_items\x18\x01 \x01(\x05R\n" + + "totalItems\x12\x1f\n" + + "\vtotal_pages\x18\x02 \x01(\x05R\n" + + "totalPages\x12=\n" + + "\aresults\x18\x03 \x03(\v2#.advisors.v1.CheckResultHistoryItemR\aresults*\xa9\x01\n" + "\x14AdvisorCheckInterval\x12&\n" + "\"ADVISOR_CHECK_INTERVAL_UNSPECIFIED\x10\x00\x12#\n" + "\x1fADVISOR_CHECK_INTERVAL_STANDARD\x10\x01\x12#\n" + @@ -1335,11 +1854,16 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + " ADVISOR_CHECK_FAMILY_UNSPECIFIED\x10\x00\x12\x1e\n" + "\x1aADVISOR_CHECK_FAMILY_MYSQL\x10\x01\x12#\n" + "\x1fADVISOR_CHECK_FAMILY_POSTGRESQL\x10\x02\x12 \n" + - "\x1cADVISOR_CHECK_FAMILY_MONGODB\x10\x032\xee\n" + - "\n" + + "\x1cADVISOR_CHECK_FAMILY_MONGODB\x10\x03*\xba\x01\n" + + "\x18AdvisorCheckResultStatus\x12+\n" + + "'ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED\x10\x00\x12\"\n" + + "\x1eADVISOR_CHECK_RESULT_STATUS_OK\x10\x01\x12&\n" + + "\"ADVISOR_CHECK_RESULT_STATUS_FAILED\x10\x02\x12%\n" + + "!ADVISOR_CHECK_RESULT_STATUS_ERROR\x10\x032\xf8\f\n" + "\x0eAdvisorService\x12\xf3\x01\n" + "\x12ListFailedServices\x12&.advisors.v1.ListFailedServicesRequest\x1a'.advisors.v1.ListFailedServicesResponse\"\x8b\x01\x92Ae\x12\x14List Failed Services\x1aMReturns a list of services with failed checks and a summary of check results.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/failedServices\x12\xd5\x01\n" + - "\x0fGetFailedChecks\x12#.advisors.v1.GetFailedChecksRequest\x1a$.advisors.v1.GetFailedChecksResponse\"w\x92AR\x12\x19Get Failed Advisor Checks\x1a5Returns the latest check results for a given service.\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/advisors/checks/failed\x12\xb0\x02\n" + + "\x0fGetFailedChecks\x12#.advisors.v1.GetFailedChecksRequest\x1a$.advisors.v1.GetFailedChecksResponse\"w\x92AR\x12\x19Get Failed Advisor Checks\x1a5Returns the latest check results for a given service.\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/advisors/checks/failed\x12\x87\x02\n" + + "\x17ListCheckResultsHistory\x12+.advisors.v1.ListCheckResultsHistoryRequest\x1a,.advisors.v1.ListCheckResultsHistoryResponse\"\x90\x01\x92Aj\x12\"List Advisor Check Results History\x1aDReturns the history of Advisor check runs, including their outcomes.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/checks/history\x12\xb0\x02\n" + "\x12StartAdvisorChecks\x12&.advisors.v1.StartAdvisorChecksRequest\x1a'.advisors.v1.StartAdvisorChecksResponse\"\xc8\x01\x92A\xa0\x01\x12\x14Start Advisor Checks\x1a\x87\x01Executes Advisor checks and returns when all checks are executed. All available checks will be started if check names aren't specified.\x82\xd3\xe4\x93\x02\x1e:\x01*\"\x19/v1/advisors/checks:start\x12\xc3\x01\n" + "\x11ListAdvisorChecks\x12%.advisors.v1.ListAdvisorChecksRequest\x1a&.advisors.v1.ListAdvisorChecksResponse\"_\x92AA\x12\x13List Advisor Checks\x1a*List advisor checks available to the user.\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/advisors/checks\x12\xa1\x01\n" + "\fListAdvisors\x12 .advisors.v1.ListAdvisorsRequest\x1a!.advisors.v1.ListAdvisorsResponse\"L\x92A5\x12\rList Advisors\x1a$List advisors available to the user.\x82\xd3\xe4\x93\x02\x0e\x12\f/v1/advisors\x12\xf0\x01\n" + @@ -1359,66 +1883,83 @@ func file_advisors_v1_advisors_proto_rawDescGZIP() []byte { } var ( - file_advisors_v1_advisors_proto_enumTypes = make([]protoimpl.EnumInfo, 2) - file_advisors_v1_advisors_proto_msgTypes = make([]protoimpl.MessageInfo, 20) + file_advisors_v1_advisors_proto_enumTypes = make([]protoimpl.EnumInfo, 3) + file_advisors_v1_advisors_proto_msgTypes = make([]protoimpl.MessageInfo, 24) file_advisors_v1_advisors_proto_goTypes = []any{ - AdvisorCheckInterval(0), // 0: advisors.v1.AdvisorCheckInterval - AdvisorCheckFamily(0), // 1: advisors.v1.AdvisorCheckFamily - (*AdvisorCheckResult)(nil), // 2: advisors.v1.AdvisorCheckResult - (*CheckResultSummary)(nil), // 3: advisors.v1.CheckResultSummary - (*CheckResult)(nil), // 4: advisors.v1.CheckResult - (*AdvisorCheck)(nil), // 5: advisors.v1.AdvisorCheck - (*Advisor)(nil), // 6: advisors.v1.Advisor - (*ChangeAdvisorCheckParams)(nil), // 7: advisors.v1.ChangeAdvisorCheckParams - (*StartAdvisorChecksRequest)(nil), // 8: advisors.v1.StartAdvisorChecksRequest - (*StartAdvisorChecksResponse)(nil), // 9: advisors.v1.StartAdvisorChecksResponse - (*ListAdvisorChecksRequest)(nil), // 10: advisors.v1.ListAdvisorChecksRequest - (*ListAdvisorChecksResponse)(nil), // 11: advisors.v1.ListAdvisorChecksResponse - (*ListAdvisorsRequest)(nil), // 12: advisors.v1.ListAdvisorsRequest - (*ListAdvisorsResponse)(nil), // 13: advisors.v1.ListAdvisorsResponse - (*ChangeAdvisorChecksRequest)(nil), // 14: advisors.v1.ChangeAdvisorChecksRequest - (*ChangeAdvisorChecksResponse)(nil), // 15: advisors.v1.ChangeAdvisorChecksResponse - (*ListFailedServicesRequest)(nil), // 16: advisors.v1.ListFailedServicesRequest - (*ListFailedServicesResponse)(nil), // 17: advisors.v1.ListFailedServicesResponse - (*GetFailedChecksRequest)(nil), // 18: advisors.v1.GetFailedChecksRequest - (*GetFailedChecksResponse)(nil), // 19: advisors.v1.GetFailedChecksResponse - nil, // 20: advisors.v1.AdvisorCheckResult.LabelsEntry - nil, // 21: advisors.v1.CheckResult.LabelsEntry - v1.Severity(0), // 22: management.v1.Severity + AdvisorCheckInterval(0), // 0: advisors.v1.AdvisorCheckInterval + AdvisorCheckFamily(0), // 1: advisors.v1.AdvisorCheckFamily + AdvisorCheckResultStatus(0), // 2: advisors.v1.AdvisorCheckResultStatus + (*AdvisorCheckResult)(nil), // 3: advisors.v1.AdvisorCheckResult + (*CheckResultSummary)(nil), // 4: advisors.v1.CheckResultSummary + (*CheckResult)(nil), // 5: advisors.v1.CheckResult + (*AdvisorCheck)(nil), // 6: advisors.v1.AdvisorCheck + (*Advisor)(nil), // 7: advisors.v1.Advisor + (*ChangeAdvisorCheckParams)(nil), // 8: advisors.v1.ChangeAdvisorCheckParams + (*StartAdvisorChecksRequest)(nil), // 9: advisors.v1.StartAdvisorChecksRequest + (*StartAdvisorChecksResponse)(nil), // 10: advisors.v1.StartAdvisorChecksResponse + (*ListAdvisorChecksRequest)(nil), // 11: advisors.v1.ListAdvisorChecksRequest + (*ListAdvisorChecksResponse)(nil), // 12: advisors.v1.ListAdvisorChecksResponse + (*ListAdvisorsRequest)(nil), // 13: advisors.v1.ListAdvisorsRequest + (*ListAdvisorsResponse)(nil), // 14: advisors.v1.ListAdvisorsResponse + (*ChangeAdvisorChecksRequest)(nil), // 15: advisors.v1.ChangeAdvisorChecksRequest + (*ChangeAdvisorChecksResponse)(nil), // 16: advisors.v1.ChangeAdvisorChecksResponse + (*ListFailedServicesRequest)(nil), // 17: advisors.v1.ListFailedServicesRequest + (*ListFailedServicesResponse)(nil), // 18: advisors.v1.ListFailedServicesResponse + (*GetFailedChecksRequest)(nil), // 19: advisors.v1.GetFailedChecksRequest + (*GetFailedChecksResponse)(nil), // 20: advisors.v1.GetFailedChecksResponse + (*CheckResultHistoryItem)(nil), // 21: advisors.v1.CheckResultHistoryItem + (*ListCheckResultsHistoryRequest)(nil), // 22: advisors.v1.ListCheckResultsHistoryRequest + (*ListCheckResultsHistoryResponse)(nil), // 23: advisors.v1.ListCheckResultsHistoryResponse + nil, // 24: advisors.v1.AdvisorCheckResult.LabelsEntry + nil, // 25: advisors.v1.CheckResult.LabelsEntry + nil, // 26: advisors.v1.CheckResultHistoryItem.LabelsEntry + v1.Severity(0), // 27: management.v1.Severity + (*timestamppb.Timestamp)(nil), // 28: google.protobuf.Timestamp } ) - var file_advisors_v1_advisors_proto_depIdxs = []int32{ - 22, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity - 20, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry - 22, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity - 21, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry + 27, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity + 24, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry + 27, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity + 25, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry 0, // 4: advisors.v1.AdvisorCheck.interval:type_name -> advisors.v1.AdvisorCheckInterval 1, // 5: advisors.v1.AdvisorCheck.family:type_name -> advisors.v1.AdvisorCheckFamily - 5, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck + 6, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck 0, // 7: advisors.v1.ChangeAdvisorCheckParams.interval:type_name -> advisors.v1.AdvisorCheckInterval - 5, // 8: advisors.v1.ListAdvisorChecksResponse.checks:type_name -> advisors.v1.AdvisorCheck - 6, // 9: advisors.v1.ListAdvisorsResponse.advisors:type_name -> advisors.v1.Advisor - 7, // 10: advisors.v1.ChangeAdvisorChecksRequest.params:type_name -> advisors.v1.ChangeAdvisorCheckParams - 3, // 11: advisors.v1.ListFailedServicesResponse.result:type_name -> advisors.v1.CheckResultSummary - 4, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult - 16, // 13: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest - 18, // 14: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest - 8, // 15: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest - 10, // 16: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest - 12, // 17: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest - 14, // 18: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest - 17, // 19: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse - 19, // 20: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse - 9, // 21: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse - 11, // 22: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse - 13, // 23: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse - 15, // 24: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse - 19, // [19:25] is the sub-list for method output_type - 13, // [13:19] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 6, // 8: advisors.v1.ListAdvisorChecksResponse.checks:type_name -> advisors.v1.AdvisorCheck + 7, // 9: advisors.v1.ListAdvisorsResponse.advisors:type_name -> advisors.v1.Advisor + 8, // 10: advisors.v1.ChangeAdvisorChecksRequest.params:type_name -> advisors.v1.ChangeAdvisorCheckParams + 4, // 11: advisors.v1.ListFailedServicesResponse.result:type_name -> advisors.v1.CheckResultSummary + 5, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult + 0, // 13: advisors.v1.CheckResultHistoryItem.interval:type_name -> advisors.v1.AdvisorCheckInterval + 2, // 14: advisors.v1.CheckResultHistoryItem.status:type_name -> advisors.v1.AdvisorCheckResultStatus + 27, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity + 26, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry + 28, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp + 2, // 18: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus + 28, // 19: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp + 28, // 20: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp + 27, // 21: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity + 21, // 22: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem + 17, // 23: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest + 19, // 24: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest + 22, // 25: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest + 9, // 26: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest + 11, // 27: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest + 13, // 28: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest + 15, // 29: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest + 18, // 30: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse + 20, // 31: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse + 23, // 32: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse + 10, // 33: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse + 12, // 34: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse + 14, // 35: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse + 16, // 36: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse + 30, // [30:37] is the sub-list for method output_type + 23, // [23:30] is the sub-list for method input_type + 23, // [23:23] is the sub-list for extension type_name + 23, // [23:23] is the sub-list for extension extendee + 0, // [0:23] is the sub-list for field type_name } func init() { file_advisors_v1_advisors_proto_init() } @@ -1428,13 +1969,14 @@ func file_advisors_v1_advisors_proto_init() { } file_advisors_v1_advisors_proto_msgTypes[5].OneofWrappers = []any{} file_advisors_v1_advisors_proto_msgTypes[16].OneofWrappers = []any{} + file_advisors_v1_advisors_proto_msgTypes[19].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_advisors_v1_advisors_proto_rawDesc), len(file_advisors_v1_advisors_proto_rawDesc)), - NumEnums: 2, - NumMessages: 20, + NumEnums: 3, + NumMessages: 24, NumExtensions: 0, NumServices: 1, }, diff --git a/api/advisors/v1/advisors.pb.gw.go b/api/advisors/v1/advisors.pb.gw.go index 3897f4315fd..367941ad5e4 100644 --- a/api/advisors/v1/advisors.pb.gw.go +++ b/api/advisors/v1/advisors.pb.gw.go @@ -91,6 +91,41 @@ func local_request_AdvisorService_GetFailedChecks_0(ctx context.Context, marshal return msg, metadata, err } +var filter_AdvisorService_ListCheckResultsHistory_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + +func request_AdvisorService_ListCheckResultsHistory_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListCheckResultsHistoryRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AdvisorService_ListCheckResultsHistory_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.ListCheckResultsHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_ListCheckResultsHistory_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListCheckResultsHistoryRequest + metadata runtime.ServerMetadata + ) + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AdvisorService_ListCheckResultsHistory_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.ListCheckResultsHistory(ctx, &protoReq) + return msg, metadata, err +} + func request_AdvisorService_StartAdvisorChecks_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq StartAdvisorChecksRequest @@ -233,6 +268,26 @@ func RegisterAdvisorServiceHandlerServer(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_GetFailedChecks_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_ListCheckResultsHistory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/ListCheckResultsHistory", runtime.WithHTTPPathPattern("/v1/advisors/checks/history")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_ListCheckResultsHistory_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_ListCheckResultsHistory_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_AdvisorService_StartAdvisorChecks_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -387,6 +442,23 @@ func RegisterAdvisorServiceHandlerClient(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_GetFailedChecks_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_ListCheckResultsHistory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/ListCheckResultsHistory", runtime.WithHTTPPathPattern("/v1/advisors/checks/history")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_ListCheckResultsHistory_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_ListCheckResultsHistory_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_AdvisorService_StartAdvisorChecks_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -459,19 +531,21 @@ func RegisterAdvisorServiceHandlerClient(ctx context.Context, mux *runtime.Serve } var ( - pattern_AdvisorService_ListFailedServices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "failedServices"}, "")) - pattern_AdvisorService_GetFailedChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "failed"}, "")) - pattern_AdvisorService_StartAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "start")) - pattern_AdvisorService_ListAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "")) - pattern_AdvisorService_ListAdvisors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "advisors"}, "")) - pattern_AdvisorService_ChangeAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "batchChange")) + pattern_AdvisorService_ListFailedServices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "failedServices"}, "")) + pattern_AdvisorService_GetFailedChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "failed"}, "")) + pattern_AdvisorService_ListCheckResultsHistory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "")) + pattern_AdvisorService_StartAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "start")) + pattern_AdvisorService_ListAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "")) + pattern_AdvisorService_ListAdvisors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "advisors"}, "")) + pattern_AdvisorService_ChangeAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "batchChange")) ) var ( - forward_AdvisorService_ListFailedServices_0 = runtime.ForwardResponseMessage - forward_AdvisorService_GetFailedChecks_0 = runtime.ForwardResponseMessage - forward_AdvisorService_StartAdvisorChecks_0 = runtime.ForwardResponseMessage - forward_AdvisorService_ListAdvisorChecks_0 = runtime.ForwardResponseMessage - forward_AdvisorService_ListAdvisors_0 = runtime.ForwardResponseMessage - forward_AdvisorService_ChangeAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListFailedServices_0 = runtime.ForwardResponseMessage + forward_AdvisorService_GetFailedChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListCheckResultsHistory_0 = runtime.ForwardResponseMessage + forward_AdvisorService_StartAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListAdvisors_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ChangeAdvisorChecks_0 = runtime.ForwardResponseMessage ) diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 74c3d47a85b..388f67cd9d1 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -2199,3 +2199,521 @@ var _ interface { Cause() error ErrorName() string } = GetFailedChecksResponseValidationError{} + +// Validate checks the field values on CheckResultHistoryItem with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *CheckResultHistoryItem) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on CheckResultHistoryItem with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// CheckResultHistoryItemMultiError, or nil if none found. +func (m *CheckResultHistoryItem) ValidateAll() error { + return m.validate(true) +} + +func (m *CheckResultHistoryItem) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Id + + // no validation rules for CheckName + + // no validation rules for AdvisorName + + // no validation rules for Category + + // no validation rules for Interval + + // no validation rules for ServiceId + + // no validation rules for ServiceName + + // no validation rules for ServiceType + + // no validation rules for NodeId + + // no validation rules for NodeName + + // no validation rules for Status + + // no validation rules for Summary + + // no validation rules for Description + + // no validation rules for ReadMoreUrl + + // no validation rules for Severity + + // no validation rules for Labels + + if all { + switch v := interface{}(m.GetCheckedAt()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CheckResultHistoryItemValidationError{ + field: "CheckedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CheckResultHistoryItemValidationError{ + field: "CheckedAt", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCheckedAt()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CheckResultHistoryItemValidationError{ + field: "CheckedAt", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for IsRead + + if len(errors) > 0 { + return CheckResultHistoryItemMultiError(errors) + } + + return nil +} + +// CheckResultHistoryItemMultiError is an error wrapping multiple validation +// errors returned by CheckResultHistoryItem.ValidateAll() if the designated +// constraints aren't met. +type CheckResultHistoryItemMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m CheckResultHistoryItemMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m CheckResultHistoryItemMultiError) AllErrors() []error { return m } + +// CheckResultHistoryItemValidationError is the validation error returned by +// CheckResultHistoryItem.Validate if the designated constraints aren't met. +type CheckResultHistoryItemValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e CheckResultHistoryItemValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e CheckResultHistoryItemValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e CheckResultHistoryItemValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e CheckResultHistoryItemValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e CheckResultHistoryItemValidationError) ErrorName() string { + return "CheckResultHistoryItemValidationError" +} + +// Error satisfies the builtin error interface +func (e CheckResultHistoryItemValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sCheckResultHistoryItem.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = CheckResultHistoryItemValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = CheckResultHistoryItemValidationError{} + +// Validate checks the field values on ListCheckResultsHistoryRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListCheckResultsHistoryRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListCheckResultsHistoryRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// ListCheckResultsHistoryRequestMultiError, or nil if none found. +func (m *ListCheckResultsHistoryRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ListCheckResultsHistoryRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for ServiceId + + if all { + switch v := interface{}(m.GetFrom()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListCheckResultsHistoryRequestValidationError{ + field: "From", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListCheckResultsHistoryRequestValidationError{ + field: "From", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetFrom()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListCheckResultsHistoryRequestValidationError{ + field: "From", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if all { + switch v := interface{}(m.GetTo()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListCheckResultsHistoryRequestValidationError{ + field: "To", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListCheckResultsHistoryRequestValidationError{ + field: "To", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetTo()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListCheckResultsHistoryRequestValidationError{ + field: "To", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for ServiceName + + // no validation rules for NodeName + + // no validation rules for Category + + // no validation rules for CheckName + + if m.PageSize != nil { + if m.GetPageSize() < 1 { + err := ListCheckResultsHistoryRequestValidationError{ + field: "PageSize", + reason: "value must be greater than or equal to 1", + } + if !all { + return err + } + errors = append(errors, err) + } + } + + if m.PageIndex != nil { + if m.GetPageIndex() < 0 { + err := ListCheckResultsHistoryRequestValidationError{ + field: "PageIndex", + reason: "value must be greater than or equal to 0", + } + if !all { + return err + } + errors = append(errors, err) + } + } + + if m.Status != nil { + // no validation rules for Status + } + + if m.IsRead != nil { + // no validation rules for IsRead + } + + if m.Severity != nil { + // no validation rules for Severity + } + + if len(errors) > 0 { + return ListCheckResultsHistoryRequestMultiError(errors) + } + + return nil +} + +// ListCheckResultsHistoryRequestMultiError is an error wrapping multiple +// validation errors returned by ListCheckResultsHistoryRequest.ValidateAll() +// if the designated constraints aren't met. +type ListCheckResultsHistoryRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListCheckResultsHistoryRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListCheckResultsHistoryRequestMultiError) AllErrors() []error { return m } + +// ListCheckResultsHistoryRequestValidationError is the validation error +// returned by ListCheckResultsHistoryRequest.Validate if the designated +// constraints aren't met. +type ListCheckResultsHistoryRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListCheckResultsHistoryRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListCheckResultsHistoryRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListCheckResultsHistoryRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListCheckResultsHistoryRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListCheckResultsHistoryRequestValidationError) ErrorName() string { + return "ListCheckResultsHistoryRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ListCheckResultsHistoryRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListCheckResultsHistoryRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListCheckResultsHistoryRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListCheckResultsHistoryRequestValidationError{} + +// Validate checks the field values on ListCheckResultsHistoryResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *ListCheckResultsHistoryResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListCheckResultsHistoryResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// ListCheckResultsHistoryResponseMultiError, or nil if none found. +func (m *ListCheckResultsHistoryResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *ListCheckResultsHistoryResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for TotalItems + + // no validation rules for TotalPages + + for idx, item := range m.GetResults() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ListCheckResultsHistoryResponseValidationError{ + field: fmt.Sprintf("Results[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ListCheckResultsHistoryResponseValidationError{ + field: fmt.Sprintf("Results[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ListCheckResultsHistoryResponseValidationError{ + field: fmt.Sprintf("Results[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + if len(errors) > 0 { + return ListCheckResultsHistoryResponseMultiError(errors) + } + + return nil +} + +// ListCheckResultsHistoryResponseMultiError is an error wrapping multiple +// validation errors returned by ListCheckResultsHistoryResponse.ValidateAll() +// if the designated constraints aren't met. +type ListCheckResultsHistoryResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListCheckResultsHistoryResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListCheckResultsHistoryResponseMultiError) AllErrors() []error { return m } + +// ListCheckResultsHistoryResponseValidationError is the validation error +// returned by ListCheckResultsHistoryResponse.Validate if the designated +// constraints aren't met. +type ListCheckResultsHistoryResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListCheckResultsHistoryResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListCheckResultsHistoryResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListCheckResultsHistoryResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListCheckResultsHistoryResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListCheckResultsHistoryResponseValidationError) ErrorName() string { + return "ListCheckResultsHistoryResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e ListCheckResultsHistoryResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListCheckResultsHistoryResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListCheckResultsHistoryResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListCheckResultsHistoryResponseValidationError{} diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index 4475eafb59e..e1bae401213 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package advisors.v1; import "google/api/annotations.proto"; +import "google/protobuf/timestamp.proto"; import "management/v1/severity.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; import "validate/validate.proto"; @@ -22,6 +23,17 @@ enum AdvisorCheckFamily { ADVISOR_CHECK_FAMILY_MONGODB = 3; } +// AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service. +enum AdvisorCheckResultStatus { + ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED = 0; + // The check ran and found no issue. + ADVISOR_CHECK_RESULT_STATUS_OK = 1; + // The check ran and detected an issue. + ADVISOR_CHECK_RESULT_STATUS_FAILED = 2; + // The check could not be executed. + ADVISOR_CHECK_RESULT_STATUS_ERROR = 3; +} + // AdvisorCheckResult represents the check result returned from pmm-managed after running the check. message AdvisorCheckResult { string summary = 1; @@ -163,6 +175,82 @@ message GetFailedChecksResponse { repeated CheckResult results = 3; } +// CheckResultHistoryItem represents a single persisted Advisor check run against a service. +message CheckResultHistoryItem { + // Unique identifier of the history record. + string id = 1; + // Name of the check that ran. + string check_name = 2; + // Name of the advisor the check belongs to. + string advisor_name = 3; + // Category of the advisor the check belongs to. + string category = 4; + // Check execution interval. + AdvisorCheckInterval interval = 5; + // ID of the monitored service on which the check ran. + string service_id = 6; + // Name of the monitored service on which the check ran. + string service_name = 7; + // Type of the monitored service on which the check ran. + string service_type = 8; + // ID of the node the service runs on. + string node_id = 9; + // Name of the node the service runs on. + string node_name = 10; + // Outcome of the check run. + AdvisorCheckResultStatus status = 11; + // Short human-readable summary of the result. + string summary = 12; + // Long human-readable description of the result. + string description = 13; + // URL containing information on how to resolve a detected issue. + string read_more_url = 14; + // Severity of the result. + management.v1.Severity severity = 15; + // Result labels. + map labels = 16; + // Time when the check ran. + google.protobuf.Timestamp checked_at = 17; + // Whether the result has been marked as read. + bool is_read = 18; +} + +message ListCheckResultsHistoryRequest { + // Maximum number of results per page. + optional int32 page_size = 1 [(validate.rules).int32.gte = 1]; + // Index of the requested page, starts from 0. + optional int32 page_index = 2 [(validate.rules).int32.gte = 0]; + // Filter by service ID. + string service_id = 3; + // Filter by outcome. + optional AdvisorCheckResultStatus status = 4; + // Filter by read state. + optional bool is_read = 5; + // Return only results recorded at or after this time. + google.protobuf.Timestamp from = 6; + // Return only results recorded at or before this time. + google.protobuf.Timestamp to = 7; + // Filter by service name (partial, case-insensitive match). + string service_name = 8; + // Filter by node name (partial, case-insensitive match). + string node_name = 9; + // Filter by advisor category. + string category = 10; + // Filter by check name. + string check_name = 11; + // Filter by severity. + optional management.v1.Severity severity = 12; +} + +message ListCheckResultsHistoryResponse { + // Total number of results. + int32 total_items = 1; + // Total number of pages. + int32 total_pages = 2; + // History records. + repeated CheckResultHistoryItem results = 3; +} + // AdvisorService service provides public Management API methods for Advisor Service. service AdvisorService { // ListFailedServices returns a list of services with failed checks. @@ -181,6 +269,14 @@ service AdvisorService { description: "Returns the latest check results for a given service." }; } + // ListCheckResultsHistory returns the history of Advisor check runs. + rpc ListCheckResultsHistory(ListCheckResultsHistoryRequest) returns (ListCheckResultsHistoryResponse) { + option (google.api.http) = {get: "/v1/advisors/checks/history"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List Advisor Check Results History" + description: "Returns the history of Advisor check runs, including their outcomes." + }; + } // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. rpc StartAdvisorChecks(StartAdvisorChecksRequest) returns (StartAdvisorChecksResponse) { option (google.api.http) = { diff --git a/api/advisors/v1/advisors.swagger.json b/api/advisors/v1/advisors.swagger.json new file mode 100644 index 00000000000..2a24c0513a7 --- /dev/null +++ b/api/advisors/v1/advisors.swagger.json @@ -0,0 +1,788 @@ +{ + "swagger": "2.0", + "info": { + "title": "advisors/v1/advisors.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "AdvisorService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/advisors": { + "get": { + "summary": "List Advisors", + "description": "List advisors available to the user.", + "operationId": "ListAdvisors", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListAdvisorsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "AdvisorService" + ] + } + }, + "/v1/advisors/checks": { + "get": { + "summary": "List Advisor Checks", + "description": "List advisor checks available to the user.", + "operationId": "ListAdvisorChecks", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListAdvisorChecksResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "AdvisorService" + ] + } + }, + "/v1/advisors/checks/failed": { + "get": { + "summary": "Get Failed Advisor Checks", + "description": "Returns the latest check results for a given service.", + "operationId": "GetFailedChecks", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetFailedChecksResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "page_size", + "description": "Maximum number of results per page.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "page_index", + "description": "Index of the requested page, starts from 0.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "service_id", + "description": "Service ID.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "AdvisorService" + ] + } + }, + "/v1/advisors/checks/history": { + "get": { + "summary": "List Advisor Check Results History", + "description": "Returns the history of Advisor check runs, including their outcomes.", + "operationId": "ListCheckResultsHistory", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListCheckResultsHistoryResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "page_size", + "description": "Maximum number of results per page.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "page_index", + "description": "Index of the requested page, starts from 0.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "service_id", + "description": "Filter by service ID.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "status", + "description": "Filter by outcome.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED" + }, + { + "name": "is_read", + "description": "Filter by read state.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "from", + "description": "Return only results recorded at or after this time.", + "in": "query", + "required": false, + "type": "string", + "format": "date-time" + }, + { + "name": "to", + "description": "Return only results recorded at or before this time.", + "in": "query", + "required": false, + "type": "string", + "format": "date-time" + }, + { + "name": "service_name", + "description": "Filter by service name (partial, case-insensitive match).", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "node_name", + "description": "Filter by node name (partial, case-insensitive match).", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "category", + "description": "Filter by advisor category.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "check_name", + "description": "Filter by check name.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "severity", + "description": "Filter by severity.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "default": "SEVERITY_UNSPECIFIED" + } + ], + "tags": [ + "AdvisorService" + ] + } + }, + "/v1/advisors/checks:batchChange": { + "post": { + "summary": "Change Advisor Checks", + "description": "Enables/disables advisor checks or changes their exec interval.", + "operationId": "ChangeAdvisorChecks", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ChangeAdvisorChecksResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ChangeAdvisorChecksRequest" + } + } + ], + "tags": [ + "AdvisorService" + ] + } + }, + "/v1/advisors/checks:start": { + "post": { + "summary": "Start Advisor Checks", + "description": "Executes Advisor checks and returns when all checks are executed. All available checks will be started if check names aren't specified.", + "operationId": "StartAdvisorChecks", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartAdvisorChecksResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StartAdvisorChecksRequest" + } + } + ], + "tags": [ + "AdvisorService" + ] + } + }, + "/v1/advisors/failedServices": { + "get": { + "summary": "List Failed Services", + "description": "Returns a list of services with failed checks and a summary of check results.", + "operationId": "ListFailedServices", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListFailedServicesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "AdvisorService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1Advisor": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Machine-readable name (ID) that is used in expression." + }, + "description": { + "type": "string", + "description": "Long human-readable description." + }, + "summary": { + "type": "string", + "description": "Short human-readable summary." + }, + "comment": { + "type": "string", + "description": "Comment." + }, + "category": { + "type": "string", + "description": "Category." + }, + "checks": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1AdvisorCheck" + }, + "description": "Advisor checks." + } + } + }, + "v1AdvisorCheck": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Machine-readable name (ID) that is used in expression." + }, + "enabled": { + "type": "boolean", + "description": "True if that check is enabled." + }, + "description": { + "type": "string", + "description": "Long human-readable description." + }, + "summary": { + "type": "string", + "description": "Short human-readable summary." + }, + "interval": { + "$ref": "#/definitions/v1AdvisorCheckInterval", + "description": "Check execution interval." + }, + "family": { + "$ref": "#/definitions/v1AdvisorCheckFamily", + "description": "DB family." + } + }, + "description": "AdvisorCheck contains check name and status." + }, + "v1AdvisorCheckFamily": { + "type": "string", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + }, + "v1AdvisorCheckInterval": { + "type": "string", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "description": "AdvisorCheckInterval represents possible execution interval values for checks." + }, + "v1AdvisorCheckResultStatus": { + "type": "string", + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed." + }, + "v1ChangeAdvisorCheckParams": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the check to change." + }, + "enable": { + "type": "boolean", + "x-nullable": true + }, + "interval": { + "$ref": "#/definitions/v1AdvisorCheckInterval", + "description": "check execution interval." + } + }, + "description": "ChangeAdvisorCheckParams specifies a single check parameters." + }, + "v1ChangeAdvisorChecksRequest": { + "type": "object", + "properties": { + "params": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ChangeAdvisorCheckParams" + } + } + } + }, + "v1ChangeAdvisorChecksResponse": { + "type": "object" + }, + "v1CheckResult": { + "type": "object", + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "severity": { + "$ref": "#/definitions/v1Severity" + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "read_more_url": { + "type": "string", + "description": "URL containing information on how to resolve an issue detected by an Advisor check." + }, + "service_name": { + "type": "string", + "description": "Name of the monitored service on which the check ran." + }, + "service_id": { + "type": "string", + "description": "ID of the monitored service on which the check ran." + }, + "check_name": { + "type": "string", + "title": "Name of the check that failed" + }, + "silenced": { + "type": "boolean", + "title": "Silence status of the check result" + } + }, + "description": "CheckResult represents the check results for a given service." + }, + "v1CheckResultHistoryItem": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of the history record." + }, + "check_name": { + "type": "string", + "description": "Name of the check that ran." + }, + "advisor_name": { + "type": "string", + "description": "Name of the advisor the check belongs to." + }, + "category": { + "type": "string", + "description": "Category of the advisor the check belongs to." + }, + "interval": { + "$ref": "#/definitions/v1AdvisorCheckInterval", + "description": "Check execution interval." + }, + "service_id": { + "type": "string", + "description": "ID of the monitored service on which the check ran." + }, + "service_name": { + "type": "string", + "description": "Name of the monitored service on which the check ran." + }, + "service_type": { + "type": "string", + "description": "Type of the monitored service on which the check ran." + }, + "node_id": { + "type": "string", + "description": "ID of the node the service runs on." + }, + "node_name": { + "type": "string", + "description": "Name of the node the service runs on." + }, + "status": { + "$ref": "#/definitions/v1AdvisorCheckResultStatus", + "description": "Outcome of the check run." + }, + "summary": { + "type": "string", + "description": "Short human-readable summary of the result." + }, + "description": { + "type": "string", + "description": "Long human-readable description of the result." + }, + "read_more_url": { + "type": "string", + "description": "URL containing information on how to resolve a detected issue." + }, + "severity": { + "$ref": "#/definitions/v1Severity", + "description": "Severity of the result." + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Result labels." + }, + "checked_at": { + "type": "string", + "format": "date-time", + "description": "Time when the check ran." + }, + "is_read": { + "type": "boolean", + "description": "Whether the result has been marked as read." + } + }, + "description": "CheckResultHistoryItem represents a single persisted Advisor check run against a service." + }, + "v1CheckResultSummary": { + "type": "object", + "properties": { + "service_name": { + "type": "string" + }, + "service_id": { + "type": "string" + }, + "emergency_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"EMERGENCY\"." + }, + "alert_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"ALERT\"." + }, + "critical_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"CRITICAL\"." + }, + "error_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"ERROR\"." + }, + "warning_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"WARNING\"." + }, + "notice_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"NOTICE\"." + }, + "info_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"INFO\"." + }, + "debug_count": { + "type": "integer", + "format": "int64", + "description": "Number of failed checks for this service with severity level \"DEBUG\"." + } + }, + "description": "CheckResultSummary is a summary of check results." + }, + "v1GetFailedChecksResponse": { + "type": "object", + "properties": { + "total_items": { + "type": "integer", + "format": "int32", + "description": "Total number of results." + }, + "total_pages": { + "type": "integer", + "format": "int32", + "description": "Total number of pages." + }, + "results": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1CheckResult" + }, + "title": "Check results" + } + } + }, + "v1ListAdvisorChecksResponse": { + "type": "object", + "properties": { + "checks": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1AdvisorCheck" + } + } + } + }, + "v1ListAdvisorsResponse": { + "type": "object", + "properties": { + "advisors": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Advisor" + } + } + } + }, + "v1ListCheckResultsHistoryResponse": { + "type": "object", + "properties": { + "total_items": { + "type": "integer", + "format": "int32", + "description": "Total number of results." + }, + "total_pages": { + "type": "integer", + "format": "int32", + "description": "Total number of pages." + }, + "results": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1CheckResultHistoryItem" + }, + "description": "History records." + } + } + }, + "v1ListFailedServicesResponse": { + "type": "object", + "properties": { + "result": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1CheckResultSummary" + } + } + } + }, + "v1Severity": { + "type": "string", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "default": "SEVERITY_UNSPECIFIED", + "description": "Severity represents severity level of the check result or alert." + }, + "v1StartAdvisorChecksRequest": { + "type": "object", + "properties": { + "names": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Names of the checks that should be started." + } + } + }, + "v1StartAdvisorChecksResponse": { + "type": "object" + } + } +} diff --git a/api/advisors/v1/advisors_grpc.pb.go b/api/advisors/v1/advisors_grpc.pb.go index 968dd072fc8..73e451ce1d5 100644 --- a/api/advisors/v1/advisors_grpc.pb.go +++ b/api/advisors/v1/advisors_grpc.pb.go @@ -20,12 +20,13 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - AdvisorService_ListFailedServices_FullMethodName = "/advisors.v1.AdvisorService/ListFailedServices" - AdvisorService_GetFailedChecks_FullMethodName = "/advisors.v1.AdvisorService/GetFailedChecks" - AdvisorService_StartAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/StartAdvisorChecks" - AdvisorService_ListAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisorChecks" - AdvisorService_ListAdvisors_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisors" - AdvisorService_ChangeAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ChangeAdvisorChecks" + AdvisorService_ListFailedServices_FullMethodName = "/advisors.v1.AdvisorService/ListFailedServices" + AdvisorService_GetFailedChecks_FullMethodName = "/advisors.v1.AdvisorService/GetFailedChecks" + AdvisorService_ListCheckResultsHistory_FullMethodName = "/advisors.v1.AdvisorService/ListCheckResultsHistory" + AdvisorService_StartAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/StartAdvisorChecks" + AdvisorService_ListAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisorChecks" + AdvisorService_ListAdvisors_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisors" + AdvisorService_ChangeAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ChangeAdvisorChecks" ) // AdvisorServiceClient is the client API for AdvisorService service. @@ -38,6 +39,8 @@ type AdvisorServiceClient interface { ListFailedServices(ctx context.Context, in *ListFailedServicesRequest, opts ...grpc.CallOption) (*ListFailedServicesResponse, error) // GetFailedChecks returns the checks result for a given service. GetFailedChecks(ctx context.Context, in *GetFailedChecksRequest, opts ...grpc.CallOption) (*GetFailedChecksResponse, error) + // ListCheckResultsHistory returns the history of Advisor check runs. + ListCheckResultsHistory(ctx context.Context, in *ListCheckResultsHistoryRequest, opts ...grpc.CallOption) (*ListCheckResultsHistoryResponse, error) // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. StartAdvisorChecks(ctx context.Context, in *StartAdvisorChecksRequest, opts ...grpc.CallOption) (*StartAdvisorChecksResponse, error) // ListAdvisorChecks returns a list of advisor checks available to the user.. @@ -76,6 +79,16 @@ func (c *advisorServiceClient) GetFailedChecks(ctx context.Context, in *GetFaile return out, nil } +func (c *advisorServiceClient) ListCheckResultsHistory(ctx context.Context, in *ListCheckResultsHistoryRequest, opts ...grpc.CallOption) (*ListCheckResultsHistoryResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListCheckResultsHistoryResponse) + err := c.cc.Invoke(ctx, AdvisorService_ListCheckResultsHistory_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *advisorServiceClient) StartAdvisorChecks(ctx context.Context, in *StartAdvisorChecksRequest, opts ...grpc.CallOption) (*StartAdvisorChecksResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(StartAdvisorChecksResponse) @@ -126,6 +139,8 @@ type AdvisorServiceServer interface { ListFailedServices(context.Context, *ListFailedServicesRequest) (*ListFailedServicesResponse, error) // GetFailedChecks returns the checks result for a given service. GetFailedChecks(context.Context, *GetFailedChecksRequest) (*GetFailedChecksResponse, error) + // ListCheckResultsHistory returns the history of Advisor check runs. + ListCheckResultsHistory(context.Context, *ListCheckResultsHistoryRequest) (*ListCheckResultsHistoryResponse, error) // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. StartAdvisorChecks(context.Context, *StartAdvisorChecksRequest) (*StartAdvisorChecksResponse, error) // ListAdvisorChecks returns a list of advisor checks available to the user.. @@ -152,6 +167,10 @@ func (UnimplementedAdvisorServiceServer) GetFailedChecks(context.Context, *GetFa return nil, status.Error(codes.Unimplemented, "method GetFailedChecks not implemented") } +func (UnimplementedAdvisorServiceServer) ListCheckResultsHistory(context.Context, *ListCheckResultsHistoryRequest) (*ListCheckResultsHistoryResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListCheckResultsHistory not implemented") +} + func (UnimplementedAdvisorServiceServer) StartAdvisorChecks(context.Context, *StartAdvisorChecksRequest) (*StartAdvisorChecksResponse, error) { return nil, status.Error(codes.Unimplemented, "method StartAdvisorChecks not implemented") } @@ -224,6 +243,24 @@ func _AdvisorService_GetFailedChecks_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } +func _AdvisorService_ListCheckResultsHistory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListCheckResultsHistoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).ListCheckResultsHistory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_ListCheckResultsHistory_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).ListCheckResultsHistory(ctx, req.(*ListCheckResultsHistoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AdvisorService_StartAdvisorChecks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(StartAdvisorChecksRequest) if err := dec(in); err != nil { @@ -311,6 +348,10 @@ var AdvisorService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetFailedChecks", Handler: _AdvisorService_GetFailedChecks_Handler, }, + { + MethodName: "ListCheckResultsHistory", + Handler: _AdvisorService_ListCheckResultsHistory_Handler, + }, { MethodName: "StartAdvisorChecks", Handler: _AdvisorService_StartAdvisorChecks_Handler, diff --git a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go index 6f48af3f1e6..3a2b067da37 100644 --- a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go +++ b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go @@ -59,6 +59,8 @@ type ClientService interface { ListAdvisors(params *ListAdvisorsParams, opts ...ClientOption) (*ListAdvisorsOK, error) + ListCheckResultsHistory(params *ListCheckResultsHistoryParams, opts ...ClientOption) (*ListCheckResultsHistoryOK, error) + ListFailedServices(params *ListFailedServicesParams, opts ...ClientOption) (*ListFailedServicesOK, error) StartAdvisorChecks(params *StartAdvisorChecksParams, opts ...ClientOption) (*StartAdvisorChecksOK, error) @@ -242,6 +244,50 @@ func (a *Client) ListAdvisors(params *ListAdvisorsParams, opts ...ClientOption) return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +ListCheckResultsHistory lists advisor check results history + +Returns the history of Advisor check runs, including their outcomes. +*/ +func (a *Client) ListCheckResultsHistory(params *ListCheckResultsHistoryParams, opts ...ClientOption) (*ListCheckResultsHistoryOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListCheckResultsHistoryParams() + } + op := &runtime.ClientOperation{ + ID: "ListCheckResultsHistory", + Method: "GET", + PathPattern: "/v1/advisors/checks/history", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListCheckResultsHistoryReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*ListCheckResultsHistoryOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListCheckResultsHistoryDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* ListFailedServices lists failed services diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go new file mode 100644 index 00000000000..1313a1ca74f --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go @@ -0,0 +1,551 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// NewListCheckResultsHistoryParams creates a new ListCheckResultsHistoryParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewListCheckResultsHistoryParams() *ListCheckResultsHistoryParams { + return &ListCheckResultsHistoryParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListCheckResultsHistoryParamsWithTimeout creates a new ListCheckResultsHistoryParams object +// with the ability to set a timeout on a request. +func NewListCheckResultsHistoryParamsWithTimeout(timeout time.Duration) *ListCheckResultsHistoryParams { + return &ListCheckResultsHistoryParams{ + timeout: timeout, + } +} + +// NewListCheckResultsHistoryParamsWithContext creates a new ListCheckResultsHistoryParams object +// with the ability to set a context for a request. +func NewListCheckResultsHistoryParamsWithContext(ctx context.Context) *ListCheckResultsHistoryParams { + return &ListCheckResultsHistoryParams{ + Context: ctx, + } +} + +// NewListCheckResultsHistoryParamsWithHTTPClient creates a new ListCheckResultsHistoryParams object +// with the ability to set a custom HTTPClient for a request. +func NewListCheckResultsHistoryParamsWithHTTPClient(client *http.Client) *ListCheckResultsHistoryParams { + return &ListCheckResultsHistoryParams{ + HTTPClient: client, + } +} + +/* +ListCheckResultsHistoryParams contains all the parameters to send to the API endpoint + + for the list check results history operation. + + Typically these are written to a http.Request. +*/ +type ListCheckResultsHistoryParams struct { + /* Category. + + Filter by advisor category. + */ + Category *string + + /* CheckName. + + Filter by check name. + */ + CheckName *string + + /* From. + + Return only results recorded at or after this time. + + Format: date-time + */ + From *strfmt.DateTime + + /* IsRead. + + Filter by read state. + */ + IsRead *bool + + /* NodeName. + + Filter by node name (partial, case-insensitive match). + */ + NodeName *string + + /* PageIndex. + + Index of the requested page, starts from 0. + + Format: int32 + */ + PageIndex *int32 + + /* PageSize. + + Maximum number of results per page. + + Format: int32 + */ + PageSize *int32 + + /* ServiceID. + + Filter by service ID. + */ + ServiceID *string + + /* ServiceName. + + Filter by service name (partial, case-insensitive match). + */ + ServiceName *string + + /* Severity. + + Filter by severity. + + Default: "SEVERITY_UNSPECIFIED" + */ + Severity *string + + /* Status. + + Filter by outcome. + + - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue. + - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue. + - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed. + + Default: "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED" + */ + Status *string + + /* To. + + Return only results recorded at or before this time. + + Format: date-time + */ + To *strfmt.DateTime + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list check results history params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListCheckResultsHistoryParams) WithDefaults() *ListCheckResultsHistoryParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list check results history params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListCheckResultsHistoryParams) SetDefaults() { + var ( + severityDefault = string("SEVERITY_UNSPECIFIED") + + statusDefault = string("ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED") + ) + + val := ListCheckResultsHistoryParams{ + Severity: &severityDefault, + Status: &statusDefault, + } + + val.timeout = o.timeout + val.Context = o.Context + val.HTTPClient = o.HTTPClient + *o = val +} + +// WithTimeout adds the timeout to the list check results history params +func (o *ListCheckResultsHistoryParams) WithTimeout(timeout time.Duration) *ListCheckResultsHistoryParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list check results history params +func (o *ListCheckResultsHistoryParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list check results history params +func (o *ListCheckResultsHistoryParams) WithContext(ctx context.Context) *ListCheckResultsHistoryParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list check results history params +func (o *ListCheckResultsHistoryParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list check results history params +func (o *ListCheckResultsHistoryParams) WithHTTPClient(client *http.Client) *ListCheckResultsHistoryParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list check results history params +func (o *ListCheckResultsHistoryParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithCategory adds the category to the list check results history params +func (o *ListCheckResultsHistoryParams) WithCategory(category *string) *ListCheckResultsHistoryParams { + o.SetCategory(category) + return o +} + +// SetCategory adds the category to the list check results history params +func (o *ListCheckResultsHistoryParams) SetCategory(category *string) { + o.Category = category +} + +// WithCheckName adds the checkName to the list check results history params +func (o *ListCheckResultsHistoryParams) WithCheckName(checkName *string) *ListCheckResultsHistoryParams { + o.SetCheckName(checkName) + return o +} + +// SetCheckName adds the checkName to the list check results history params +func (o *ListCheckResultsHistoryParams) SetCheckName(checkName *string) { + o.CheckName = checkName +} + +// WithFrom adds the from to the list check results history params +func (o *ListCheckResultsHistoryParams) WithFrom(from *strfmt.DateTime) *ListCheckResultsHistoryParams { + o.SetFrom(from) + return o +} + +// SetFrom adds the from to the list check results history params +func (o *ListCheckResultsHistoryParams) SetFrom(from *strfmt.DateTime) { + o.From = from +} + +// WithIsRead adds the isRead to the list check results history params +func (o *ListCheckResultsHistoryParams) WithIsRead(isRead *bool) *ListCheckResultsHistoryParams { + o.SetIsRead(isRead) + return o +} + +// SetIsRead adds the isRead to the list check results history params +func (o *ListCheckResultsHistoryParams) SetIsRead(isRead *bool) { + o.IsRead = isRead +} + +// WithNodeName adds the nodeName to the list check results history params +func (o *ListCheckResultsHistoryParams) WithNodeName(nodeName *string) *ListCheckResultsHistoryParams { + o.SetNodeName(nodeName) + return o +} + +// SetNodeName adds the nodeName to the list check results history params +func (o *ListCheckResultsHistoryParams) SetNodeName(nodeName *string) { + o.NodeName = nodeName +} + +// WithPageIndex adds the pageIndex to the list check results history params +func (o *ListCheckResultsHistoryParams) WithPageIndex(pageIndex *int32) *ListCheckResultsHistoryParams { + o.SetPageIndex(pageIndex) + return o +} + +// SetPageIndex adds the pageIndex to the list check results history params +func (o *ListCheckResultsHistoryParams) SetPageIndex(pageIndex *int32) { + o.PageIndex = pageIndex +} + +// WithPageSize adds the pageSize to the list check results history params +func (o *ListCheckResultsHistoryParams) WithPageSize(pageSize *int32) *ListCheckResultsHistoryParams { + o.SetPageSize(pageSize) + return o +} + +// SetPageSize adds the pageSize to the list check results history params +func (o *ListCheckResultsHistoryParams) SetPageSize(pageSize *int32) { + o.PageSize = pageSize +} + +// WithServiceID adds the serviceID to the list check results history params +func (o *ListCheckResultsHistoryParams) WithServiceID(serviceID *string) *ListCheckResultsHistoryParams { + o.SetServiceID(serviceID) + return o +} + +// SetServiceID adds the serviceId to the list check results history params +func (o *ListCheckResultsHistoryParams) SetServiceID(serviceID *string) { + o.ServiceID = serviceID +} + +// WithServiceName adds the serviceName to the list check results history params +func (o *ListCheckResultsHistoryParams) WithServiceName(serviceName *string) *ListCheckResultsHistoryParams { + o.SetServiceName(serviceName) + return o +} + +// SetServiceName adds the serviceName to the list check results history params +func (o *ListCheckResultsHistoryParams) SetServiceName(serviceName *string) { + o.ServiceName = serviceName +} + +// WithSeverity adds the severity to the list check results history params +func (o *ListCheckResultsHistoryParams) WithSeverity(severity *string) *ListCheckResultsHistoryParams { + o.SetSeverity(severity) + return o +} + +// SetSeverity adds the severity to the list check results history params +func (o *ListCheckResultsHistoryParams) SetSeverity(severity *string) { + o.Severity = severity +} + +// WithStatus adds the status to the list check results history params +func (o *ListCheckResultsHistoryParams) WithStatus(status *string) *ListCheckResultsHistoryParams { + o.SetStatus(status) + return o +} + +// SetStatus adds the status to the list check results history params +func (o *ListCheckResultsHistoryParams) SetStatus(status *string) { + o.Status = status +} + +// WithTo adds the to to the list check results history params +func (o *ListCheckResultsHistoryParams) WithTo(to *strfmt.DateTime) *ListCheckResultsHistoryParams { + o.SetTo(to) + return o +} + +// SetTo adds the to to the list check results history params +func (o *ListCheckResultsHistoryParams) SetTo(to *strfmt.DateTime) { + o.To = to +} + +// WriteToRequest writes these params to a swagger request +func (o *ListCheckResultsHistoryParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Category != nil { + + // query param category + var qrCategory string + + if o.Category != nil { + qrCategory = *o.Category + } + qCategory := qrCategory + if qCategory != "" { + if err := r.SetQueryParam("category", qCategory); err != nil { + return err + } + } + } + + if o.CheckName != nil { + + // query param check_name + var qrCheckName string + + if o.CheckName != nil { + qrCheckName = *o.CheckName + } + qCheckName := qrCheckName + if qCheckName != "" { + if err := r.SetQueryParam("check_name", qCheckName); err != nil { + return err + } + } + } + + if o.From != nil { + + // query param from + var qrFrom strfmt.DateTime + + if o.From != nil { + qrFrom = *o.From + } + qFrom := qrFrom.String() + if qFrom != "" { + if err := r.SetQueryParam("from", qFrom); err != nil { + return err + } + } + } + + if o.IsRead != nil { + + // query param is_read + var qrIsRead bool + + if o.IsRead != nil { + qrIsRead = *o.IsRead + } + qIsRead := swag.FormatBool(qrIsRead) + if qIsRead != "" { + if err := r.SetQueryParam("is_read", qIsRead); err != nil { + return err + } + } + } + + if o.NodeName != nil { + + // query param node_name + var qrNodeName string + + if o.NodeName != nil { + qrNodeName = *o.NodeName + } + qNodeName := qrNodeName + if qNodeName != "" { + if err := r.SetQueryParam("node_name", qNodeName); err != nil { + return err + } + } + } + + if o.PageIndex != nil { + + // query param page_index + var qrPageIndex int32 + + if o.PageIndex != nil { + qrPageIndex = *o.PageIndex + } + qPageIndex := swag.FormatInt32(qrPageIndex) + if qPageIndex != "" { + if err := r.SetQueryParam("page_index", qPageIndex); err != nil { + return err + } + } + } + + if o.PageSize != nil { + + // query param page_size + var qrPageSize int32 + + if o.PageSize != nil { + qrPageSize = *o.PageSize + } + qPageSize := swag.FormatInt32(qrPageSize) + if qPageSize != "" { + if err := r.SetQueryParam("page_size", qPageSize); err != nil { + return err + } + } + } + + if o.ServiceID != nil { + + // query param service_id + var qrServiceID string + + if o.ServiceID != nil { + qrServiceID = *o.ServiceID + } + qServiceID := qrServiceID + if qServiceID != "" { + if err := r.SetQueryParam("service_id", qServiceID); err != nil { + return err + } + } + } + + if o.ServiceName != nil { + + // query param service_name + var qrServiceName string + + if o.ServiceName != nil { + qrServiceName = *o.ServiceName + } + qServiceName := qrServiceName + if qServiceName != "" { + if err := r.SetQueryParam("service_name", qServiceName); err != nil { + return err + } + } + } + + if o.Severity != nil { + + // query param severity + var qrSeverity string + + if o.Severity != nil { + qrSeverity = *o.Severity + } + qSeverity := qrSeverity + if qSeverity != "" { + if err := r.SetQueryParam("severity", qSeverity); err != nil { + return err + } + } + } + + if o.Status != nil { + + // query param status + var qrStatus string + + if o.Status != nil { + qrStatus = *o.Status + } + qStatus := qrStatus + if qStatus != "" { + if err := r.SetQueryParam("status", qStatus); err != nil { + return err + } + } + } + + if o.To != nil { + + // query param to + var qrTo strfmt.DateTime + + if o.To != nil { + qrTo = *o.To + } + qTo := qrTo.String() + if qTo != "" { + if err := r.SetQueryParam("to", qTo); err != nil { + return err + } + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go new file mode 100644 index 00000000000..af4221cfe55 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go @@ -0,0 +1,819 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// ListCheckResultsHistoryReader is a Reader for the ListCheckResultsHistory structure. +type ListCheckResultsHistoryReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListCheckResultsHistoryReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListCheckResultsHistoryOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListCheckResultsHistoryDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListCheckResultsHistoryOK creates a ListCheckResultsHistoryOK with default headers values +func NewListCheckResultsHistoryOK() *ListCheckResultsHistoryOK { + return &ListCheckResultsHistoryOK{} +} + +/* +ListCheckResultsHistoryOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListCheckResultsHistoryOK struct { + Payload *ListCheckResultsHistoryOKBody +} + +// IsSuccess returns true when this list check results history Ok response has a 2xx status code +func (o *ListCheckResultsHistoryOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list check results history Ok response has a 3xx status code +func (o *ListCheckResultsHistoryOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list check results history Ok response has a 4xx status code +func (o *ListCheckResultsHistoryOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list check results history Ok response has a 5xx status code +func (o *ListCheckResultsHistoryOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list check results history Ok response a status code equal to that given +func (o *ListCheckResultsHistoryOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list check results history Ok response +func (o *ListCheckResultsHistoryOK) Code() int { + return 200 +} + +func (o *ListCheckResultsHistoryOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history][%d] listCheckResultsHistoryOk %s", 200, payload) +} + +func (o *ListCheckResultsHistoryOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history][%d] listCheckResultsHistoryOk %s", 200, payload) +} + +func (o *ListCheckResultsHistoryOK) GetPayload() *ListCheckResultsHistoryOKBody { + return o.Payload +} + +func (o *ListCheckResultsHistoryOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListCheckResultsHistoryOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListCheckResultsHistoryDefault creates a ListCheckResultsHistoryDefault with default headers values +func NewListCheckResultsHistoryDefault(code int) *ListCheckResultsHistoryDefault { + return &ListCheckResultsHistoryDefault{ + _statusCode: code, + } +} + +/* +ListCheckResultsHistoryDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListCheckResultsHistoryDefault struct { + _statusCode int + + Payload *ListCheckResultsHistoryDefaultBody +} + +// IsSuccess returns true when this list check results history default response has a 2xx status code +func (o *ListCheckResultsHistoryDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list check results history default response has a 3xx status code +func (o *ListCheckResultsHistoryDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list check results history default response has a 4xx status code +func (o *ListCheckResultsHistoryDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list check results history default response has a 5xx status code +func (o *ListCheckResultsHistoryDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list check results history default response a status code equal to that given +func (o *ListCheckResultsHistoryDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list check results history default response +func (o *ListCheckResultsHistoryDefault) Code() int { + return o._statusCode +} + +func (o *ListCheckResultsHistoryDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history][%d] ListCheckResultsHistory default %s", o._statusCode, payload) +} + +func (o *ListCheckResultsHistoryDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history][%d] ListCheckResultsHistory default %s", o._statusCode, payload) +} + +func (o *ListCheckResultsHistoryDefault) GetPayload() *ListCheckResultsHistoryDefaultBody { + return o.Payload +} + +func (o *ListCheckResultsHistoryDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListCheckResultsHistoryDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +ListCheckResultsHistoryDefaultBody list check results history default body +swagger:model ListCheckResultsHistoryDefaultBody +*/ +type ListCheckResultsHistoryDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListCheckResultsHistoryDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list check results history default body +func (o *ListCheckResultsHistoryDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListCheckResultsHistoryDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListCheckResultsHistory default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListCheckResultsHistory default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list check results history default body based on the context it is used +func (o *ListCheckResultsHistoryDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListCheckResultsHistoryDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListCheckResultsHistory default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListCheckResultsHistory default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListCheckResultsHistoryDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListCheckResultsHistoryDefaultBody) UnmarshalBinary(b []byte) error { + var res ListCheckResultsHistoryDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListCheckResultsHistoryDefaultBodyDetailsItems0 list check results history default body details items0 +swagger:model ListCheckResultsHistoryDefaultBodyDetailsItems0 +*/ +type ListCheckResultsHistoryDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // list check results history default body details items0 + ListCheckResultsHistoryDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *ListCheckResultsHistoryDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv ListCheckResultsHistoryDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.ListCheckResultsHistoryDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o ListCheckResultsHistoryDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.ListCheckResultsHistoryDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.ListCheckResultsHistoryDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this list check results history default body details items0 +func (o *ListCheckResultsHistoryDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list check results history default body details items0 based on context it is used +func (o *ListCheckResultsHistoryDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListCheckResultsHistoryDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListCheckResultsHistoryDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListCheckResultsHistoryDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListCheckResultsHistoryOKBody list check results history OK body +swagger:model ListCheckResultsHistoryOKBody +*/ +type ListCheckResultsHistoryOKBody struct { + // Total number of results. + TotalItems int32 `json:"total_items,omitempty"` + + // Total number of pages. + TotalPages int32 `json:"total_pages,omitempty"` + + // History records. + Results []*ListCheckResultsHistoryOKBodyResultsItems0 `json:"results"` +} + +// Validate validates this list check results history OK body +func (o *ListCheckResultsHistoryOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateResults(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListCheckResultsHistoryOKBody) validateResults(formats strfmt.Registry) error { + if swag.IsZero(o.Results) { // not required + return nil + } + + for i := 0; i < len(o.Results); i++ { + if swag.IsZero(o.Results[i]) { // not required + continue + } + + if o.Results[i] != nil { + if err := o.Results[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listCheckResultsHistoryOk" + "." + "results" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listCheckResultsHistoryOk" + "." + "results" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list check results history OK body based on the context it is used +func (o *ListCheckResultsHistoryOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateResults(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListCheckResultsHistoryOKBody) contextValidateResults(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Results); i++ { + if o.Results[i] != nil { + + if swag.IsZero(o.Results[i]) { // not required + return nil + } + + if err := o.Results[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("listCheckResultsHistoryOk" + "." + "results" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("listCheckResultsHistoryOk" + "." + "results" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListCheckResultsHistoryOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListCheckResultsHistoryOKBody) UnmarshalBinary(b []byte) error { + var res ListCheckResultsHistoryOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListCheckResultsHistoryOKBodyResultsItems0 CheckResultHistoryItem represents a single persisted Advisor check run against a service. +swagger:model ListCheckResultsHistoryOKBodyResultsItems0 +*/ +type ListCheckResultsHistoryOKBodyResultsItems0 struct { + // Unique identifier of the history record. + ID string `json:"id,omitempty"` + + // Name of the check that ran. + CheckName string `json:"check_name,omitempty"` + + // Name of the advisor the check belongs to. + AdvisorName string `json:"advisor_name,omitempty"` + + // Category of the advisor the check belongs to. + Category string `json:"category,omitempty"` + + // AdvisorCheckInterval represents possible execution interval values for checks. + // Enum: ["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"] + Interval *string `json:"interval,omitempty"` + + // ID of the monitored service on which the check ran. + ServiceID string `json:"service_id,omitempty"` + + // Name of the monitored service on which the check ran. + ServiceName string `json:"service_name,omitempty"` + + // Type of the monitored service on which the check ran. + ServiceType string `json:"service_type,omitempty"` + + // ID of the node the service runs on. + NodeID string `json:"node_id,omitempty"` + + // Name of the node the service runs on. + NodeName string `json:"node_name,omitempty"` + + // AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service. + // + // - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue. + // - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue. + // - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed. + // Enum: ["ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED","ADVISOR_CHECK_RESULT_STATUS_OK","ADVISOR_CHECK_RESULT_STATUS_FAILED","ADVISOR_CHECK_RESULT_STATUS_ERROR"] + Status *string `json:"status,omitempty"` + + // Short human-readable summary of the result. + Summary string `json:"summary,omitempty"` + + // Long human-readable description of the result. + Description string `json:"description,omitempty"` + + // URL containing information on how to resolve a detected issue. + ReadMoreURL string `json:"read_more_url,omitempty"` + + // Severity represents severity level of the check result or alert. + // Enum: ["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"] + Severity *string `json:"severity,omitempty"` + + // Result labels. + Labels map[string]string `json:"labels,omitempty"` + + // Time when the check ran. + // Format: date-time + CheckedAt strfmt.DateTime `json:"checked_at,omitempty"` + + // Whether the result has been marked as read. + IsRead bool `json:"is_read,omitempty"` +} + +// Validate validates this list check results history OK body results items0 +func (o *ListCheckResultsHistoryOKBodyResultsItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateInterval(formats); err != nil { + res = append(res, err) + } + + if err := o.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := o.validateSeverity(formats); err != nil { + res = append(res, err) + } + + if err := o.validateCheckedAt(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var listCheckResultsHistoryOkBodyResultsItems0TypeIntervalPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + listCheckResultsHistoryOkBodyResultsItems0TypeIntervalPropEnum = append(listCheckResultsHistoryOkBodyResultsItems0TypeIntervalPropEnum, v) + } +} + +const ( + + // ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALUNSPECIFIED captures enum value "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALUNSPECIFIED string = "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + + // ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALSTANDARD captures enum value "ADVISOR_CHECK_INTERVAL_STANDARD" + ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALSTANDARD string = "ADVISOR_CHECK_INTERVAL_STANDARD" + + // ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALFREQUENT captures enum value "ADVISOR_CHECK_INTERVAL_FREQUENT" + ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALFREQUENT string = "ADVISOR_CHECK_INTERVAL_FREQUENT" + + // ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALRARE captures enum value "ADVISOR_CHECK_INTERVAL_RARE" + ListCheckResultsHistoryOKBodyResultsItems0IntervalADVISORCHECKINTERVALRARE string = "ADVISOR_CHECK_INTERVAL_RARE" +) + +// prop value enum +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateIntervalEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, listCheckResultsHistoryOkBodyResultsItems0TypeIntervalPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateInterval(formats strfmt.Registry) error { + if swag.IsZero(o.Interval) { // not required + return nil + } + + // value enum + if err := o.validateIntervalEnum("interval", "body", *o.Interval); err != nil { + return err + } + + return nil +} + +var listCheckResultsHistoryOkBodyResultsItems0TypeStatusPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED","ADVISOR_CHECK_RESULT_STATUS_OK","ADVISOR_CHECK_RESULT_STATUS_FAILED","ADVISOR_CHECK_RESULT_STATUS_ERROR"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + listCheckResultsHistoryOkBodyResultsItems0TypeStatusPropEnum = append(listCheckResultsHistoryOkBodyResultsItems0TypeStatusPropEnum, v) + } +} + +const ( + + // ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSUNSPECIFIED captures enum value "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED" + ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSUNSPECIFIED string = "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED" + + // ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSOK captures enum value "ADVISOR_CHECK_RESULT_STATUS_OK" + ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSOK string = "ADVISOR_CHECK_RESULT_STATUS_OK" + + // ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSFAILED captures enum value "ADVISOR_CHECK_RESULT_STATUS_FAILED" + ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSFAILED string = "ADVISOR_CHECK_RESULT_STATUS_FAILED" + + // ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSERROR captures enum value "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ListCheckResultsHistoryOKBodyResultsItems0StatusADVISORCHECKRESULTSTATUSERROR string = "ADVISOR_CHECK_RESULT_STATUS_ERROR" +) + +// prop value enum +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateStatusEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, listCheckResultsHistoryOkBodyResultsItems0TypeStatusPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(o.Status) { // not required + return nil + } + + // value enum + if err := o.validateStatusEnum("status", "body", *o.Status); err != nil { + return err + } + + return nil +} + +var listCheckResultsHistoryOkBodyResultsItems0TypeSeverityPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + listCheckResultsHistoryOkBodyResultsItems0TypeSeverityPropEnum = append(listCheckResultsHistoryOkBodyResultsItems0TypeSeverityPropEnum, v) + } +} + +const ( + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYUNSPECIFIED captures enum value "SEVERITY_UNSPECIFIED" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYUNSPECIFIED string = "SEVERITY_UNSPECIFIED" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYEMERGENCY captures enum value "SEVERITY_EMERGENCY" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYEMERGENCY string = "SEVERITY_EMERGENCY" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYALERT captures enum value "SEVERITY_ALERT" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYALERT string = "SEVERITY_ALERT" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYCRITICAL captures enum value "SEVERITY_CRITICAL" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYCRITICAL string = "SEVERITY_CRITICAL" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYERROR captures enum value "SEVERITY_ERROR" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYERROR string = "SEVERITY_ERROR" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYWARNING captures enum value "SEVERITY_WARNING" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYWARNING string = "SEVERITY_WARNING" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYNOTICE captures enum value "SEVERITY_NOTICE" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYNOTICE string = "SEVERITY_NOTICE" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYINFO captures enum value "SEVERITY_INFO" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYINFO string = "SEVERITY_INFO" + + // ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYDEBUG captures enum value "SEVERITY_DEBUG" + ListCheckResultsHistoryOKBodyResultsItems0SeveritySEVERITYDEBUG string = "SEVERITY_DEBUG" +) + +// prop value enum +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateSeverityEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, listCheckResultsHistoryOkBodyResultsItems0TypeSeverityPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateSeverity(formats strfmt.Registry) error { + if swag.IsZero(o.Severity) { // not required + return nil + } + + // value enum + if err := o.validateSeverityEnum("severity", "body", *o.Severity); err != nil { + return err + } + + return nil +} + +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateCheckedAt(formats strfmt.Registry) error { + if swag.IsZero(o.CheckedAt) { // not required + return nil + } + + if err := validate.FormatOf("checked_at", "body", "date-time", o.CheckedAt.String(), formats); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this list check results history OK body results items0 based on context it is used +func (o *ListCheckResultsHistoryOKBodyResultsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListCheckResultsHistoryOKBodyResultsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListCheckResultsHistoryOKBodyResultsItems0) UnmarshalBinary(b []byte) error { + var res ListCheckResultsHistoryOKBodyResultsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index c14828b864b..d6b7d30d4c3 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -411,6 +411,297 @@ } } }, + "/v1/advisors/checks/history": { + "get": { + "description": "Returns the history of Advisor check runs, including their outcomes.", + "tags": [ + "AdvisorService" + ], + "summary": "List Advisor Check Results History", + "operationId": "ListCheckResultsHistory", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "Maximum number of results per page.", + "name": "page_size", + "in": "query" + }, + { + "type": "integer", + "format": "int32", + "description": "Index of the requested page, starts from 0.", + "name": "page_index", + "in": "query" + }, + { + "type": "string", + "description": "Filter by service ID.", + "name": "service_id", + "in": "query" + }, + { + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "type": "string", + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "description": "Filter by outcome.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", + "name": "status", + "in": "query" + }, + { + "type": "boolean", + "description": "Filter by read state.", + "name": "is_read", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Return only results recorded at or after this time.", + "name": "from", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Return only results recorded at or before this time.", + "name": "to", + "in": "query" + }, + { + "type": "string", + "description": "Filter by service name (partial, case-insensitive match).", + "name": "service_name", + "in": "query" + }, + { + "type": "string", + "description": "Filter by node name (partial, case-insensitive match).", + "name": "node_name", + "in": "query" + }, + { + "type": "string", + "description": "Filter by advisor category.", + "name": "category", + "in": "query" + }, + { + "type": "string", + "description": "Filter by check name.", + "name": "check_name", + "in": "query" + }, + { + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "description": "Filter by severity.", + "name": "severity", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "total_items": { + "description": "Total number of results.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "total_pages": { + "description": "Total number of pages.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "results": { + "description": "History records.", + "type": "array", + "items": { + "description": "CheckResultHistoryItem represents a single persisted Advisor check run against a service.", + "type": "object", + "properties": { + "id": { + "description": "Unique identifier of the history record.", + "type": "string", + "x-order": 0 + }, + "check_name": { + "description": "Name of the check that ran.", + "type": "string", + "x-order": 1 + }, + "advisor_name": { + "description": "Name of the advisor the check belongs to.", + "type": "string", + "x-order": 2 + }, + "category": { + "description": "Category of the advisor the check belongs to.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "service_id": { + "description": "ID of the monitored service on which the check ran.", + "type": "string", + "x-order": 5 + }, + "service_name": { + "description": "Name of the monitored service on which the check ran.", + "type": "string", + "x-order": 6 + }, + "service_type": { + "description": "Type of the monitored service on which the check ran.", + "type": "string", + "x-order": 7 + }, + "node_id": { + "description": "ID of the node the service runs on.", + "type": "string", + "x-order": 8 + }, + "node_name": { + "description": "Name of the node the service runs on.", + "type": "string", + "x-order": 9 + }, + "status": { + "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", + "type": "string", + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "x-order": 10 + }, + "summary": { + "description": "Short human-readable summary of the result.", + "type": "string", + "x-order": 11 + }, + "description": { + "description": "Long human-readable description of the result.", + "type": "string", + "x-order": 12 + }, + "read_more_url": { + "description": "URL containing information on how to resolve a detected issue.", + "type": "string", + "x-order": 13 + }, + "severity": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 14 + }, + "labels": { + "description": "Result labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 15 + }, + "checked_at": { + "description": "Time when the check ran.", + "type": "string", + "format": "date-time", + "x-order": 16 + }, + "is_read": { + "description": "Whether the result has been marked as read.", + "type": "boolean", + "x-order": 17 + } + } + }, + "x-order": 2 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks:batchChange": { "post": { "description": "Enables/disables advisor checks or changes their exec interval.", diff --git a/api/agent/pb/agent.swagger.json b/api/agent/pb/agent.swagger.json new file mode 100644 index 00000000000..5c75bc6dbe5 --- /dev/null +++ b/api/agent/pb/agent.swagger.json @@ -0,0 +1,55 @@ +{ + "swagger": "2.0", + "info": { + "title": "agent/pb/agent.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "Agent" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + } + }, + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]." + }, + "message": { + "type": "string", + "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client." + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + }, + "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." + } + }, + "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." + } + } +} diff --git a/api/agent/v1/agent.pb.go b/api/agent/v1/agent.pb.go index c2f2a8b6a9e..7f5d935624b 100644 --- a/api/agent/v1/agent.pb.go +++ b/api/agent/v1/agent.pb.go @@ -7221,7 +7221,6 @@ var ( (*v11.Metadata)(nil), // 104: backup.v1.Metadata } ) - var file_agent_v1_agent_proto_depIdxs = []int32{ 44, // 0: agent.v1.TextFiles.files:type_name -> agent.v1.TextFiles.FilesEntry 94, // 1: agent.v1.Pong.current_time:type_name -> google.protobuf.Timestamp diff --git a/api/agent/v1/agent.swagger.json b/api/agent/v1/agent.swagger.json new file mode 100644 index 00000000000..9be2eb39da2 --- /dev/null +++ b/api/agent/v1/agent.swagger.json @@ -0,0 +1,55 @@ +{ + "swagger": "2.0", + "info": { + "title": "agent/v1/agent.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "AgentService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + } + }, + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]." + }, + "message": { + "type": "string", + "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client." + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + }, + "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." + } + }, + "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." + } + } +} diff --git a/api/agent/v1/collector.pb.go b/api/agent/v1/collector.pb.go index 65633c05d17..da17db39c64 100644 --- a/api/agent/v1/collector.pb.go +++ b/api/agent/v1/collector.pb.go @@ -2827,7 +2827,6 @@ var ( v1.AgentType(0), // 9: inventory.v1.AgentType } ) - var file_agent_v1_collector_proto_depIdxs = []int32{ 3, // 0: agent.v1.MetricsBucket.common:type_name -> agent.v1.MetricsBucket.Common 4, // 1: agent.v1.MetricsBucket.mysql:type_name -> agent.v1.MetricsBucket.MySQL diff --git a/api/agent/v1/collector.swagger.json b/api/agent/v1/collector.swagger.json new file mode 100644 index 00000000000..461533c2478 --- /dev/null +++ b/api/agent/v1/collector.swagger.json @@ -0,0 +1,50 @@ +{ + "swagger": "2.0", + "info": { + "title": "agent/v1/collector.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + } + }, + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]." + }, + "message": { + "type": "string", + "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client." + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + }, + "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." + } + }, + "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." + } + } +} diff --git a/api/agentlocal/v1/agentlocal.pb.go b/api/agentlocal/v1/agentlocal.pb.go index 7bb13a7cb58..12053d57921 100644 --- a/api/agentlocal/v1/agentlocal.pb.go +++ b/api/agentlocal/v1/agentlocal.pb.go @@ -485,7 +485,6 @@ var ( v1.AgentStatus(0), // 8: inventory.v1.AgentStatus } ) - var file_agentlocal_v1_agentlocal_proto_depIdxs = []int32{ 6, // 0: agentlocal.v1.ServerInfo.latency:type_name -> google.protobuf.Duration 6, // 1: agentlocal.v1.ServerInfo.clock_drift:type_name -> google.protobuf.Duration diff --git a/api/agentlocal/v1/agentlocal.swagger.json b/api/agentlocal/v1/agentlocal.swagger.json new file mode 100644 index 00000000000..4f22ad35a7c --- /dev/null +++ b/api/agentlocal/v1/agentlocal.swagger.json @@ -0,0 +1,295 @@ +{ + "swagger": "2.0", + "info": { + "title": "agentlocal/v1/agentlocal.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "AgentLocalService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/local/Reload": { + "post": { + "summary": "Reload reloads pmm-agent configuration.", + "operationId": "Reload", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ReloadResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ReloadRequest" + } + } + ], + "tags": [ + "AgentLocalService" + ] + } + }, + "/local/Status": { + "get": { + "summary": "Status returns current pmm-agent status.", + "operationId": "Status2", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StatusResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "get_network_info", + "description": "Returns network info (latency and clock_drift) if true.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "AgentLocalService" + ] + }, + "post": { + "summary": "Status returns current pmm-agent status.", + "operationId": "Status", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StatusResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StatusRequest" + } + } + ], + "tags": [ + "AgentLocalService" + ] + } + } + }, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "v1AgentInfo": { + "type": "object", + "properties": { + "agent_id": { + "type": "string" + }, + "agent_type": { + "$ref": "#/definitions/v1AgentType" + }, + "status": { + "$ref": "#/definitions/v1AgentStatus" + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "The current listen port of this Agent (exporter or vmagent).\nZero for other Agent types, or if unknown or not yet supported." + }, + "process_exec_path": { + "type": "string" + } + }, + "description": "AgentInfo contains information about Agent managed by pmm-agent." + }, + "v1AgentStatus": { + "type": "string", + "enum": [ + "AGENT_STATUS_UNSPECIFIED", + "AGENT_STATUS_STARTING", + "AGENT_STATUS_INITIALIZATION_ERROR", + "AGENT_STATUS_RUNNING", + "AGENT_STATUS_WAITING", + "AGENT_STATUS_STOPPING", + "AGENT_STATUS_DONE", + "AGENT_STATUS_UNKNOWN" + ], + "default": "AGENT_STATUS_UNSPECIFIED", + "description": "AgentStatus represents actual Agent status.\n\n - AGENT_STATUS_STARTING: Agent is starting.\n - AGENT_STATUS_INITIALIZATION_ERROR: Agent encountered error when starting.\n - AGENT_STATUS_RUNNING: Agent is running.\n - AGENT_STATUS_WAITING: Agent encountered error and will be restarted automatically soon.\n - AGENT_STATUS_STOPPING: Agent is stopping.\n - AGENT_STATUS_DONE: Agent has been stopped or disabled.\n - AGENT_STATUS_UNKNOWN: Agent is not connected, we don't know anything about it's state." + }, + "v1AgentType": { + "type": "string", + "enum": [ + "AGENT_TYPE_UNSPECIFIED", + "AGENT_TYPE_PMM_AGENT", + "AGENT_TYPE_VM_AGENT", + "AGENT_TYPE_NODE_EXPORTER", + "AGENT_TYPE_MYSQLD_EXPORTER", + "AGENT_TYPE_MONGODB_EXPORTER", + "AGENT_TYPE_POSTGRES_EXPORTER", + "AGENT_TYPE_PROXYSQL_EXPORTER", + "AGENT_TYPE_VALKEY_EXPORTER", + "AGENT_TYPE_QAN_MYSQL_PERFSCHEMA_AGENT", + "AGENT_TYPE_QAN_MYSQL_SLOWLOG_AGENT", + "AGENT_TYPE_QAN_MONGODB_PROFILER_AGENT", + "AGENT_TYPE_QAN_MONGODB_MONGOLOG_AGENT", + "AGENT_TYPE_QAN_POSTGRESQL_PGSTATEMENTS_AGENT", + "AGENT_TYPE_QAN_POSTGRESQL_PGSTATMONITOR_AGENT", + "AGENT_TYPE_EXTERNAL_EXPORTER", + "AGENT_TYPE_RDS_EXPORTER", + "AGENT_TYPE_AZURE_DATABASE_EXPORTER", + "AGENT_TYPE_NOMAD_AGENT", + "AGENT_TYPE_RTA_MONGODB_AGENT" + ], + "default": "AGENT_TYPE_UNSPECIFIED", + "description": "AgentType describes supported Agent types." + }, + "v1ReloadRequest": { + "type": "object" + }, + "v1ReloadResponse": { + "type": "object", + "description": "ReloadRequest may not be received by the client due to pmm-agent restart." + }, + "v1ServerInfo": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "PMM Server URL in a form https://HOST:PORT/." + }, + "insecure_tls": { + "type": "boolean", + "description": "PMM Server's TLS certificate validation should be skipped if true." + }, + "connected": { + "type": "boolean", + "description": "True if pmm-agent is currently connected to the server." + }, + "version": { + "type": "string", + "description": "PMM Server version (if agent is connected)." + }, + "latency": { + "type": "string", + "description": "Ping time from pmm-agent to pmm-managed (if agent is connected)." + }, + "clock_drift": { + "type": "string", + "description": "Clock drift from PMM Server (if agent is connected)." + } + }, + "description": "ServerInfo contains information about the PMM Server." + }, + "v1StatusRequest": { + "type": "object", + "properties": { + "get_network_info": { + "type": "boolean", + "description": "Returns network info (latency and clock_drift) if true." + } + } + }, + "v1StatusResponse": { + "type": "object", + "properties": { + "agent_id": { + "type": "string" + }, + "runs_on_node_id": { + "type": "string", + "title": "TODO: rename to node_id" + }, + "node_name": { + "type": "string" + }, + "server_info": { + "$ref": "#/definitions/v1ServerInfo" + }, + "agents_info": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1AgentInfo" + } + }, + "config_filepath": { + "type": "string", + "description": "Config file path if pmm-agent was started with one." + }, + "agent_version": { + "type": "string", + "description": "PMM Agent version." + }, + "connection_uptime": { + "type": "number", + "format": "float", + "title": "Shows connection uptime in percentage between agent and server" + } + } + } + } +} diff --git a/api/alerting/v1/alerting.pb.go b/api/alerting/v1/alerting.pb.go index 3b2c47d73ec..bccb6659d24 100644 --- a/api/alerting/v1/alerting.pb.go +++ b/api/alerting/v1/alerting.pb.go @@ -1459,7 +1459,6 @@ var ( (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp } ) - var file_alerting_v1_alerting_proto_depIdxs = []int32{ 22, // 0: alerting.v1.ParamDefinition.unit:type_name -> alerting.v1.ParamUnit 23, // 1: alerting.v1.ParamDefinition.type:type_name -> alerting.v1.ParamType diff --git a/api/alerting/v1/alerting.swagger.json b/api/alerting/v1/alerting.swagger.json new file mode 100644 index 00000000000..726625709d5 --- /dev/null +++ b/api/alerting/v1/alerting.swagger.json @@ -0,0 +1,581 @@ +{ + "swagger": "2.0", + "info": { + "title": "alerting/v1/alerting.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "AlertingService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/alerting/rules": { + "post": { + "summary": "CreateRule creates alerting rule from the given template.", + "operationId": "CreateRule", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CreateRuleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1CreateRuleRequest" + } + } + ], + "tags": [ + "AlertingService" + ] + } + }, + "/v1/alerting/templates": { + "get": { + "summary": "ListTemplates returns a list of all collected alert rule templates.", + "operationId": "ListTemplates", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListTemplatesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "page_size", + "description": "Maximum number of results per page.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "page_index", + "description": "Index of the requested page, starts from 0.", + "in": "query", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "reload", + "description": "If true, template files will be re-read from disk.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "AlertingService" + ] + }, + "post": { + "summary": "CreateTemplate creates a new template.", + "operationId": "CreateTemplate", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CreateTemplateResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1CreateTemplateRequest" + } + } + ], + "tags": [ + "AlertingService" + ] + } + }, + "/v1/alerting/templates/{name}": { + "delete": { + "summary": "DeleteTemplate deletes existing, previously created via API.", + "operationId": "DeleteTemplate", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1DeleteTemplateResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "AlertingService" + ] + }, + "put": { + "summary": "UpdateTemplate updates existing template, previously created via API.", + "operationId": "UpdateTemplate", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UpdateTemplateResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "name", + "description": "Machine-readable name (ID).", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AlertingServiceUpdateTemplateBody" + } + } + ], + "tags": [ + "AlertingService" + ] + } + } + }, + "definitions": { + "AlertingServiceUpdateTemplateBody": { + "type": "object", + "properties": { + "yaml": { + "type": "string", + "description": "YAML template file content." + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1BoolParamDefinition": { + "type": "object", + "properties": { + "default": { + "type": "boolean", + "x-nullable": true + } + }, + "description": "BoolParamDefinition represents boolean parameter's default value." + }, + "v1CreateRuleRequest": { + "type": "object", + "properties": { + "template_name": { + "type": "string", + "description": "Template name." + }, + "name": { + "type": "string", + "description": "Rule name." + }, + "group": { + "type": "string", + "description": "Rule group name." + }, + "folder_uid": { + "type": "string", + "description": "Folder UID." + }, + "params": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ParamValue" + }, + "description": "Rule parameters. All template parameters should be set." + }, + "for": { + "type": "string", + "description": "Rule duration. Should be set." + }, + "severity": { + "$ref": "#/definitions/v1Severity", + "description": "Rule severity. Should be set." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "All custom labels to add or remove (with empty values) to default labels from template." + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Filter" + }, + "description": "Filters." + }, + "interval": { + "type": "string", + "title": "Evaluation Interval" + } + } + }, + "v1CreateRuleResponse": { + "type": "object" + }, + "v1CreateTemplateRequest": { + "type": "object", + "properties": { + "yaml": { + "type": "string", + "description": "YAML template file content." + } + } + }, + "v1CreateTemplateResponse": { + "type": "object" + }, + "v1DeleteTemplateResponse": { + "type": "object" + }, + "v1Filter": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/v1FilterType" + }, + "label": { + "type": "string" + }, + "regexp": { + "type": "string" + } + }, + "description": "Filter represents a single filter condition." + }, + "v1FilterType": { + "type": "string", + "enum": [ + "FILTER_TYPE_UNSPECIFIED", + "FILTER_TYPE_MATCH", + "FILTER_TYPE_MISMATCH" + ], + "default": "FILTER_TYPE_UNSPECIFIED", + "description": "FilterType represents filter matching type." + }, + "v1FloatParamDefinition": { + "type": "object", + "properties": { + "default": { + "type": "number", + "format": "double", + "x-nullable": true, + "description": "Default value." + }, + "min": { + "type": "number", + "format": "double", + "x-nullable": true, + "description": "Minimum valid value (inclusive)." + }, + "max": { + "type": "number", + "format": "double", + "x-nullable": true, + "description": "Maximum valid value (inclusive)." + } + }, + "description": "FloatParamDefinition represents float parameter's default value and valid range." + }, + "v1ListTemplatesResponse": { + "type": "object", + "properties": { + "total_items": { + "type": "integer", + "format": "int32", + "description": "Total number of results." + }, + "total_pages": { + "type": "integer", + "format": "int32", + "description": "Total number of pages." + }, + "templates": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Template" + }, + "description": "Alerting templates." + } + } + }, + "v1ParamDefinition": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Machine-readable name (ID) that is used in expression." + }, + "summary": { + "type": "string", + "description": "Short human-readable parameter summary." + }, + "unit": { + "$ref": "#/definitions/v1ParamUnit", + "description": "Parameter unit. TODO: remove this parameter." + }, + "type": { + "$ref": "#/definitions/v1ParamType", + "description": "Parameter type." + }, + "bool": { + "$ref": "#/definitions/v1BoolParamDefinition", + "description": "Bool value." + }, + "float": { + "$ref": "#/definitions/v1FloatParamDefinition", + "description": "Float value." + }, + "string": { + "$ref": "#/definitions/v1StringParamDefinition", + "description": "String value." + } + }, + "description": "ParamDefinition represents a single query parameter." + }, + "v1ParamType": { + "type": "string", + "enum": [ + "PARAM_TYPE_UNSPECIFIED", + "PARAM_TYPE_BOOL", + "PARAM_TYPE_FLOAT", + "PARAM_TYPE_STRING" + ], + "default": "PARAM_TYPE_UNSPECIFIED", + "description": "ParamType represents template parameter type." + }, + "v1ParamUnit": { + "type": "string", + "enum": [ + "PARAM_UNIT_UNSPECIFIED", + "PARAM_UNIT_PERCENTAGE", + "PARAM_UNIT_SECONDS" + ], + "default": "PARAM_UNIT_UNSPECIFIED", + "description": "ParamUnit represents template parameter unit.\n\n - PARAM_UNIT_UNSPECIFIED: Invalid, unknown or absent.\n - PARAM_UNIT_PERCENTAGE: %\n - PARAM_UNIT_SECONDS: s" + }, + "v1ParamValue": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Machine-readable name (ID) that is used in expression." + }, + "type": { + "$ref": "#/definitions/v1ParamType", + "description": "Parameter type." + }, + "bool": { + "type": "boolean", + "description": "Bool value." + }, + "float": { + "type": "number", + "format": "double", + "description": "Float value." + }, + "string": { + "type": "string", + "description": "String value." + } + }, + "description": "ParamValue represents a single rule parameter value." + }, + "v1Severity": { + "type": "string", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "default": "SEVERITY_UNSPECIFIED", + "description": "Severity represents severity level of the check result or alert." + }, + "v1StringParamDefinition": { + "type": "object", + "properties": { + "default": { + "type": "string", + "x-nullable": true, + "description": "Default value." + } + }, + "description": "StringParamDefinition represents string parameter's default value." + }, + "v1Template": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Machine-readable name (ID)." + }, + "summary": { + "type": "string", + "description": "Short human-readable summary." + }, + "expr": { + "type": "string", + "description": "PromQL query expression with templating parameters." + }, + "params": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ParamDefinition" + }, + "description": "Query parameters definitions." + }, + "for": { + "type": "string", + "description": "Default duration value." + }, + "severity": { + "$ref": "#/definitions/v1Severity", + "description": "Severity." + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Labels." + }, + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Annotations." + }, + "source": { + "$ref": "#/definitions/v1TemplateSource", + "description": "Template source. Only templates created via API can be updated or deleted via API." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "Template creation time. Empty for built-in and SaaS templates." + }, + "yaml": { + "type": "string", + "description": "YAML template file content. Empty for built-in and SaaS templates." + } + }, + "description": "Template represents Alert Template that is used to create Alert Rule." + }, + "v1TemplateSource": { + "type": "string", + "enum": [ + "TEMPLATE_SOURCE_UNSPECIFIED", + "TEMPLATE_SOURCE_BUILT_IN", + "TEMPLATE_SOURCE_SAAS", + "TEMPLATE_SOURCE_USER_FILE", + "TEMPLATE_SOURCE_USER_API" + ], + "default": "TEMPLATE_SOURCE_UNSPECIFIED", + "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API." + }, + "v1UpdateTemplateResponse": { + "type": "object" + } + } +} diff --git a/api/alerting/v1/params.pb.go b/api/alerting/v1/params.pb.go index 69d88497102..eb001a606db 100644 --- a/api/alerting/v1/params.pb.go +++ b/api/alerting/v1/params.pb.go @@ -163,7 +163,6 @@ var ( ParamType(0), // 1: alerting.v1.ParamType } ) - var file_alerting_v1_params_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/alerting/v1/params.swagger.json b/api/alerting/v1/params.swagger.json new file mode 100644 index 00000000000..d56f9a7c05a --- /dev/null +++ b/api/alerting/v1/params.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "alerting/v1/params.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/backup/v1/artifacts.pb.go b/api/backup/v1/artifacts.pb.go index dde03ceefef..e2352f61cd1 100644 --- a/api/backup/v1/artifacts.pb.go +++ b/api/backup/v1/artifacts.pb.go @@ -656,7 +656,6 @@ var ( (*Metadata)(nil), // 12: backup.v1.Metadata } ) - var file_backup_v1_artifacts_proto_depIdxs = []int32{ 9, // 0: backup.v1.Artifact.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.Artifact.status:type_name -> backup.v1.BackupStatus diff --git a/api/backup/v1/artifacts.swagger.json b/api/backup/v1/artifacts.swagger.json new file mode 100644 index 00000000000..c160f10d3e5 --- /dev/null +++ b/api/backup/v1/artifacts.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "backup/v1/artifacts.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/backup/v1/backup.pb.go b/api/backup/v1/backup.pb.go index 4d587217600..19241fc6afd 100644 --- a/api/backup/v1/backup.pb.go +++ b/api/backup/v1/backup.pb.go @@ -1276,7 +1276,6 @@ var ( (*ListPitrTimerangesResponse)(nil), // 27: backup.v1.ListPitrTimerangesResponse } ) - var file_backup_v1_backup_proto_depIdxs = []int32{ 15, // 0: backup.v1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration 16, // 1: backup.v1.StartBackupRequest.data_model:type_name -> backup.v1.DataModel diff --git a/api/backup/v1/backup.swagger.json b/api/backup/v1/backup.swagger.json new file mode 100644 index 00000000000..084b996bce7 --- /dev/null +++ b/api/backup/v1/backup.swagger.json @@ -0,0 +1,1003 @@ +{ + "swagger": "2.0", + "info": { + "title": "backup/v1/backup.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "BackupService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/backups/artifacts": { + "get": { + "summary": "List artifacts", + "description": "Return a list of backup artifacts.", + "operationId": "ListArtifacts", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListArtifactsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups/artifacts/{artifact_id}": { + "delete": { + "summary": "Delete Artifact", + "description": "Deletes an artifact.", + "operationId": "DeleteArtifact", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1DeleteArtifactResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "artifact_id", + "description": "Machine-readable artifact ID.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "remove_files", + "description": "Removes all the backup files associated with artifact if flag is set.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups/artifacts/{artifact_id}/pitr-timeranges": { + "get": { + "summary": "List PITR Timeranges", + "description": "Return a list of available MongoDB point-in-time-recovery timeranges.", + "operationId": "ListPitrTimeranges", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListPitrTimerangesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "artifact_id", + "description": "Artifact ID represents artifact whose location has PITR timeranges to be retrieved.", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups/scheduled": { + "get": { + "summary": "List Scheduled Backups", + "description": "List all scheduled backups.", + "operationId": "ListScheduledBackups", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListScheduledBackupsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups/{artifact_id}/compatible-services": { + "get": { + "summary": "List Compatible Services", + "description": "List services that are compatible with the backup artifact.", + "operationId": "ListArtifactCompatibleServices", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListArtifactCompatibleServicesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "artifact_id", + "description": "Artifact id used to determine restore compatibility.", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups/{artifact_id}/logs": { + "get": { + "summary": "Get Logs", + "description": "Get logs from the underlying tools for a backup/restore job.", + "operationId": "GetLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetLogsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "artifact_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "offset", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + }, + { + "name": "limit", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + } + ], + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups/{scheduled_backup_id}": { + "delete": { + "summary": "Remove a Scheduled Backup", + "description": "Remove a scheduled backup.", + "operationId": "RemoveScheduledBackup", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RemoveScheduledBackupResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "scheduled_backup_id", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups:changeScheduled": { + "put": { + "summary": "Change a Scheduled Backup", + "description": "Change a scheduled backup.", + "operationId": "ChangeScheduledBackup", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ChangeScheduledBackupResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ChangeScheduledBackupRequest" + } + } + ], + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups:schedule": { + "post": { + "summary": "Schedule a Backup", + "description": "Schedule a backup to run at a specified time.", + "operationId": "ScheduleBackup", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ScheduleBackupResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ScheduleBackupRequest" + } + } + ], + "tags": [ + "BackupService" + ] + } + }, + "/v1/backups:start": { + "post": { + "summary": "Start a Backup", + "description": "Could return the Error message in the details containing specific ErrorCode indicating failure reason:\nERROR_CODE_XTRABACKUP_NOT_INSTALLED - xtrabackup is not installed on the service\nERROR_CODE_INVALID_XTRABACKUP - different versions of xtrabackup and xbcloud\nERROR_CODE_INCOMPATIBLE_XTRABACKUP - xtrabackup is not compatible with MySQL for taking a backup", + "operationId": "StartBackup", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartBackupResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StartBackupRequest" + } + } + ], + "tags": [ + "BackupService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1Artifact": { + "type": "object", + "properties": { + "artifact_id": { + "type": "string", + "description": "Machine-readable artifact ID." + }, + "name": { + "type": "string", + "title": "Artifact name" + }, + "vendor": { + "type": "string", + "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL." + }, + "location_id": { + "type": "string", + "description": "Machine-readable location ID." + }, + "location_name": { + "type": "string", + "description": "Location name." + }, + "service_id": { + "type": "string", + "description": "Machine-readable service ID." + }, + "service_name": { + "type": "string", + "description": "Service name." + }, + "data_model": { + "$ref": "#/definitions/v1DataModel", + "description": "Backup data model." + }, + "status": { + "$ref": "#/definitions/v1BackupStatus", + "description": "Backup status." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "Artifact creation time." + }, + "mode": { + "$ref": "#/definitions/v1BackupMode", + "description": "Backup mode." + }, + "is_sharded_cluster": { + "type": "boolean", + "description": "Source database setup type." + }, + "folder": { + "type": "string", + "description": "Folder to store artifact on a storage." + }, + "metadata_list": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Metadata" + }, + "description": "List of artifact metadata." + } + }, + "description": "Artifact represents single backup artifact." + }, + "v1BackupMode": { + "type": "string", + "enum": [ + "BACKUP_MODE_UNSPECIFIED", + "BACKUP_MODE_SNAPSHOT", + "BACKUP_MODE_INCREMENTAL", + "BACKUP_MODE_PITR" + ], + "default": "BACKUP_MODE_UNSPECIFIED", + "description": "BackupMode specifies backup mode." + }, + "v1BackupStatus": { + "type": "string", + "enum": [ + "BACKUP_STATUS_UNSPECIFIED", + "BACKUP_STATUS_PENDING", + "BACKUP_STATUS_IN_PROGRESS", + "BACKUP_STATUS_PAUSED", + "BACKUP_STATUS_SUCCESS", + "BACKUP_STATUS_ERROR", + "BACKUP_STATUS_DELETING", + "BACKUP_STATUS_FAILED_TO_DELETE", + "BACKUP_STATUS_CLEANUP_IN_PROGRESS" + ], + "default": "BACKUP_STATUS_UNSPECIFIED", + "description": "BackupStatus shows the current status of execution of backup." + }, + "v1ChangeScheduledBackupRequest": { + "type": "object", + "properties": { + "scheduled_backup_id": { + "type": "string" + }, + "enabled": { + "type": "boolean", + "x-nullable": true + }, + "cron_expression": { + "type": "string", + "x-nullable": true, + "description": "How often backup should be run in cron format." + }, + "start_time": { + "type": "string", + "format": "date-time", + "description": "First backup wouldn't happen before this time." + }, + "name": { + "type": "string", + "x-nullable": true, + "description": "Name of backup." + }, + "description": { + "type": "string", + "x-nullable": true, + "description": "Human-readable description." + }, + "retries": { + "type": "integer", + "format": "int64", + "x-nullable": true, + "description": "How many times to retry a failed backup before giving up." + }, + "retry_interval": { + "type": "string", + "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h." + }, + "retention": { + "type": "integer", + "format": "int64", + "x-nullable": true, + "description": "How many artifacts keep. 0 - unlimited." + } + } + }, + "v1ChangeScheduledBackupResponse": { + "type": "object" + }, + "v1DataModel": { + "type": "string", + "enum": [ + "DATA_MODEL_UNSPECIFIED", + "DATA_MODEL_PHYSICAL", + "DATA_MODEL_LOGICAL" + ], + "default": "DATA_MODEL_UNSPECIFIED", + "description": "DataModel is a model used for performing a backup." + }, + "v1DeleteArtifactResponse": { + "type": "object" + }, + "v1File": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "is_directory": { + "type": "boolean" + } + }, + "description": "File represents file or folder on a storage." + }, + "v1GetLogsResponse": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1LogChunk" + } + }, + "end": { + "type": "boolean" + } + } + }, + "v1ListArtifactCompatibleServicesResponse": { + "type": "object", + "properties": { + "mysql": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MySQLService" + } + }, + "mongodb": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MongoDBService" + } + } + } + }, + "v1ListArtifactsResponse": { + "type": "object", + "properties": { + "artifacts": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Artifact" + } + } + } + }, + "v1ListPitrTimerangesResponse": { + "type": "object", + "properties": { + "timeranges": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1PitrTimerange" + } + } + } + }, + "v1ListScheduledBackupsResponse": { + "type": "object", + "properties": { + "scheduled_backups": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ScheduledBackup" + } + } + } + }, + "v1LogChunk": { + "type": "object", + "properties": { + "chunk_id": { + "type": "integer", + "format": "int64" + }, + "data": { + "type": "string" + } + }, + "description": "LogChunk represent one chunk of logs." + }, + "v1Metadata": { + "type": "object", + "properties": { + "file_list": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1File" + }, + "description": "List of files backup consists of." + }, + "restore_to": { + "type": "string", + "format": "date-time", + "description": "Exact time DB can be restored to." + }, + "pbm_metadata": { + "$ref": "#/definitions/v1PbmMetadata" + } + }, + "description": "Metadata contains extra artifact data like files it consists of, tool specific data, etc." + }, + "v1MongoDBService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "MongoDB version." + } + }, + "description": "MongoDBService represents a generic MongoDB instance." + }, + "v1MySQLService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "MySQL version." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra parameters to be added to the DSN." + } + }, + "description": "MySQLService represents a generic MySQL instance." + }, + "v1PbmMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of backup in backup tool representation." + } + }, + "description": "PbmMetadata contains additional data for pbm cli tools." + }, + "v1PitrTimerange": { + "type": "object", + "properties": { + "start_timestamp": { + "type": "string", + "format": "date-time", + "description": "start_timestamp is the time of the first event in the PITR chunk." + }, + "end_timestamp": { + "type": "string", + "format": "date-time", + "description": "end_timestamp is the time of the last event in the PITR chunk." + } + } + }, + "v1RemoveScheduledBackupResponse": { + "type": "object" + }, + "v1ScheduleBackupRequest": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Service identifier where backup should be performed." + }, + "location_id": { + "type": "string", + "description": "Machine-readable location ID." + }, + "folder": { + "type": "string", + "description": "How often backup should be run in cron format.\nFolder on storage for artifact." + }, + "cron_expression": { + "type": "string" + }, + "start_time": { + "type": "string", + "format": "date-time", + "description": "First backup wouldn't happen before this time." + }, + "name": { + "type": "string", + "description": "Name of backup." + }, + "description": { + "type": "string", + "description": "Human-readable description." + }, + "enabled": { + "type": "boolean", + "description": "If scheduling is enabled." + }, + "retries": { + "type": "integer", + "format": "int64", + "description": "How many times to retry a failed backup before giving up." + }, + "retry_interval": { + "type": "string", + "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h." + }, + "mode": { + "$ref": "#/definitions/v1BackupMode", + "description": "Backup mode." + }, + "data_model": { + "$ref": "#/definitions/v1DataModel", + "description": "Backup data model (physical or logical)." + }, + "retention": { + "type": "integer", + "format": "int64", + "description": "How many artifacts keep. 0 - unlimited." + } + } + }, + "v1ScheduleBackupResponse": { + "type": "object", + "properties": { + "scheduled_backup_id": { + "type": "string" + } + } + }, + "v1ScheduledBackup": { + "type": "object", + "properties": { + "scheduled_backup_id": { + "type": "string", + "description": "Machine-readable ID." + }, + "service_id": { + "type": "string", + "description": "Machine-readable service ID." + }, + "service_name": { + "type": "string", + "description": "Service name." + }, + "location_id": { + "type": "string", + "description": "Machine-readable location ID." + }, + "location_name": { + "type": "string", + "description": "Location name." + }, + "folder": { + "type": "string", + "description": "Folder on storage for artifact." + }, + "cron_expression": { + "type": "string", + "description": "How often backup will be run in cron format." + }, + "start_time": { + "type": "string", + "format": "date-time", + "description": "First backup wouldn't happen before this time." + }, + "name": { + "type": "string", + "description": "Artifact name." + }, + "description": { + "type": "string", + "description": "Description." + }, + "enabled": { + "type": "boolean", + "description": "If scheduling is enabled." + }, + "retries": { + "type": "integer", + "format": "int64", + "description": "How many times to retry a failed backup before giving up." + }, + "retry_interval": { + "type": "string", + "description": "Delay between each retry. Should have a suffix in JSON: 2s, 1m, 1h." + }, + "data_model": { + "$ref": "#/definitions/v1DataModel", + "description": "Backup data model (physical or logical)." + }, + "mode": { + "$ref": "#/definitions/v1BackupMode", + "description": "Backup mode." + }, + "vendor": { + "type": "string", + "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL." + }, + "last_run": { + "type": "string", + "format": "date-time", + "description": "Last run." + }, + "next_run": { + "type": "string", + "format": "date-time", + "description": "Next run." + }, + "retention": { + "type": "integer", + "format": "int64", + "description": "How many artifacts keep. 0 - unlimited." + } + }, + "description": "ScheduledBackup represents scheduled task for backup." + }, + "v1StartBackupRequest": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "location_id": { + "type": "string", + "description": "Machine-readable location ID." + }, + "name": { + "type": "string", + "description": "If empty then name is auto-generated." + }, + "description": { + "type": "string", + "description": "Human-readable description." + }, + "retry_interval": { + "type": "string", + "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h." + }, + "retries": { + "type": "integer", + "format": "int64", + "description": "How many times to retry a failed backup before giving up." + }, + "data_model": { + "$ref": "#/definitions/v1DataModel", + "description": "DataModel represents the data model used for the backup." + }, + "folder": { + "type": "string", + "description": "Folder on storage for artifact." + } + } + }, + "v1StartBackupResponse": { + "type": "object", + "properties": { + "artifact_id": { + "type": "string", + "description": "Unique identifier." + } + } + } + } +} diff --git a/api/backup/v1/common.pb.go b/api/backup/v1/common.pb.go index c8274024e38..f84ca11de32 100644 --- a/api/backup/v1/common.pb.go +++ b/api/backup/v1/common.pb.go @@ -423,7 +423,6 @@ var ( (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp } ) - var file_backup_v1_common_proto_depIdxs = []int32{ 2, // 0: backup.v1.Metadata.file_list:type_name -> backup.v1.File 6, // 1: backup.v1.Metadata.restore_to:type_name -> google.protobuf.Timestamp diff --git a/api/backup/v1/common.swagger.json b/api/backup/v1/common.swagger.json new file mode 100644 index 00000000000..4e41fc07567 --- /dev/null +++ b/api/backup/v1/common.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "backup/v1/common.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/backup/v1/errors.pb.go b/api/backup/v1/errors.pb.go index 902adc277c1..5709e5ac243 100644 --- a/api/backup/v1/errors.pb.go +++ b/api/backup/v1/errors.pb.go @@ -169,7 +169,6 @@ var ( (*Error)(nil), // 1: backup.v1.Error } ) - var file_backup_v1_errors_proto_depIdxs = []int32{ 0, // 0: backup.v1.Error.code:type_name -> backup.v1.ErrorCode 1, // [1:1] is the sub-list for method output_type diff --git a/api/backup/v1/errors.swagger.json b/api/backup/v1/errors.swagger.json new file mode 100644 index 00000000000..59e7b363676 --- /dev/null +++ b/api/backup/v1/errors.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "backup/v1/errors.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/backup/v1/locations.pb.go b/api/backup/v1/locations.pb.go index 396b552ee80..72c13dece43 100644 --- a/api/backup/v1/locations.pb.go +++ b/api/backup/v1/locations.pb.go @@ -833,7 +833,6 @@ var ( (*TestLocationConfigResponse)(nil), // 12: backup.v1.TestLocationConfigResponse } ) - var file_backup_v1_locations_proto_depIdxs = []int32{ 0, // 0: backup.v1.Location.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig 1, // 1: backup.v1.Location.s3_config:type_name -> backup.v1.S3LocationConfig diff --git a/api/backup/v1/locations.swagger.json b/api/backup/v1/locations.swagger.json new file mode 100644 index 00000000000..26f36fcb836 --- /dev/null +++ b/api/backup/v1/locations.swagger.json @@ -0,0 +1,353 @@ +{ + "swagger": "2.0", + "info": { + "title": "backup/v1/locations.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "LocationsService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/backups/locations": { + "get": { + "summary": "List Backup Locations", + "description": "List backup locations.", + "operationId": "ListLocations", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListLocationsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "LocationsService" + ] + }, + "post": { + "summary": "Add a Backup Location", + "description": "Add a backup location.", + "operationId": "AddLocation", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AddLocationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1AddLocationRequest" + } + } + ], + "tags": [ + "LocationsService" + ] + } + }, + "/v1/backups/locations/{location_id}": { + "delete": { + "summary": "Remove a Scheduled Backup", + "description": "Remove a backup location.", + "operationId": "RemoveLocation", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RemoveLocationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "location_id", + "description": "Machine-readable ID.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "force", + "description": "Force mode", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "LocationsService" + ] + }, + "put": { + "summary": "Change a Backup Location", + "description": "Change a backup location.", + "operationId": "ChangeLocation", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ChangeLocationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "location_id", + "description": "Machine-readable ID.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/LocationsServiceChangeLocationBody" + } + } + ], + "tags": [ + "LocationsService" + ] + } + }, + "/v1/backups/locations:testConfig": { + "post": { + "summary": "Test a Backup Location and Credentials", + "description": "Test a backup location and credentials.", + "operationId": "TestLocationConfig", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1TestLocationConfigResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1TestLocationConfigRequest" + } + } + ], + "tags": [ + "LocationsService" + ] + } + } + }, + "definitions": { + "LocationsServiceChangeLocationBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Location name" + }, + "description": { + "type": "string" + }, + "filesystem_config": { + "$ref": "#/definitions/v1FilesystemLocationConfig", + "description": "Filesystem location configuration. Exactly one config should be set." + }, + "s3_config": { + "$ref": "#/definitions/v1S3LocationConfig", + "description": "S3 Bucket configuration. Exactly one config should be set." + } + } + }, + "backupV1Location": { + "type": "object", + "properties": { + "location_id": { + "type": "string", + "description": "Machine-readable ID." + }, + "name": { + "type": "string", + "title": "Location name" + }, + "description": { + "type": "string", + "title": "Short description" + }, + "filesystem_config": { + "$ref": "#/definitions/v1FilesystemLocationConfig" + }, + "s3_config": { + "$ref": "#/definitions/v1S3LocationConfig" + } + }, + "description": "Location represents single Backup Location." + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1AddLocationRequest": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Location name" + }, + "description": { + "type": "string" + }, + "filesystem_config": { + "$ref": "#/definitions/v1FilesystemLocationConfig", + "description": "Filesystem location configuration. Exactly one config should be set." + }, + "s3_config": { + "$ref": "#/definitions/v1S3LocationConfig", + "description": "S3 Bucket configuration. Exactly one config should be set." + } + } + }, + "v1AddLocationResponse": { + "type": "object", + "properties": { + "location_id": { + "type": "string", + "description": "Machine-readable ID." + } + } + }, + "v1ChangeLocationResponse": { + "type": "object" + }, + "v1FilesystemLocationConfig": { + "type": "object", + "properties": { + "path": { + "type": "string" + } + }, + "description": "FilesystemLocationConfig represents file system location config." + }, + "v1ListLocationsResponse": { + "type": "object", + "properties": { + "locations": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/backupV1Location" + } + } + } + }, + "v1RemoveLocationResponse": { + "type": "object" + }, + "v1S3LocationConfig": { + "type": "object", + "properties": { + "endpoint": { + "type": "string" + }, + "access_key": { + "type": "string" + }, + "secret_key": { + "type": "string" + }, + "bucket_name": { + "type": "string" + } + }, + "description": "S3LocationConfig represents S3 bucket configuration." + }, + "v1TestLocationConfigRequest": { + "type": "object", + "properties": { + "filesystem_config": { + "$ref": "#/definitions/v1FilesystemLocationConfig", + "description": "Filesystem location configuration. Exactly one config should be set." + }, + "s3_config": { + "$ref": "#/definitions/v1S3LocationConfig", + "description": "S3 Bucket configuration. Exactly one config should be set." + } + } + }, + "v1TestLocationConfigResponse": { + "type": "object" + } + } +} diff --git a/api/backup/v1/restores.pb.go b/api/backup/v1/restores.pb.go index ee12d6b9285..580c158b119 100644 --- a/api/backup/v1/restores.pb.go +++ b/api/backup/v1/restores.pb.go @@ -625,7 +625,6 @@ var ( (*LogChunk)(nil), // 10: backup.v1.LogChunk } ) - var file_backup_v1_restores_proto_depIdxs = []int32{ 8, // 0: backup.v1.RestoreHistoryItem.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.RestoreHistoryItem.status:type_name -> backup.v1.RestoreStatus diff --git a/api/backup/v1/restores.swagger.json b/api/backup/v1/restores.swagger.json new file mode 100644 index 00000000000..e7089206289 --- /dev/null +++ b/api/backup/v1/restores.swagger.json @@ -0,0 +1,303 @@ +{ + "swagger": "2.0", + "info": { + "title": "backup/v1/restores.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "RestoreService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/backups/restores": { + "get": { + "summary": "List Restore History", + "description": "List all backup restore history items", + "operationId": "ListRestores", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListRestoresResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "RestoreService" + ] + } + }, + "/v1/backups/restores/{restore_id}/logs": { + "get": { + "summary": "Get Logs", + "description": "Get logs from the underlying tools for a restore job", + "operationId": "GetLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RestoreServiceGetLogsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "restore_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "offset", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + }, + { + "name": "limit", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + } + ], + "tags": [ + "RestoreService" + ] + } + }, + "/v1/backups/restores:start": { + "post": { + "summary": "Restore from a Backup", + "description": "Could return the Error message in the details containing specific ErrorCode indicating failure reason:\nERROR_CODE_XTRABACKUP_NOT_INSTALLED - xtrabackup is not installed on the service\nERROR_CODE_INVALID_XTRABACKUP - different versions of xtrabackup and xbcloud\nERROR_CODE_INCOMPATIBLE_XTRABACKUP - xtrabackup is not compatible with MySQL for taking a backup\nERROR_CODE_INCOMPATIBLE_TARGET_MYSQL - target MySQL version is not compatible with the artifact for performing a restore of the backup", + "operationId": "RestoreBackup", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RestoreBackupResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1RestoreBackupRequest" + } + } + ], + "tags": [ + "RestoreService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1DataModel": { + "type": "string", + "enum": [ + "DATA_MODEL_UNSPECIFIED", + "DATA_MODEL_PHYSICAL", + "DATA_MODEL_LOGICAL" + ], + "default": "DATA_MODEL_UNSPECIFIED", + "description": "DataModel is a model used for performing a backup." + }, + "v1ListRestoresResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1RestoreHistoryItem" + } + } + } + }, + "v1LogChunk": { + "type": "object", + "properties": { + "chunk_id": { + "type": "integer", + "format": "int64" + }, + "data": { + "type": "string" + } + }, + "description": "LogChunk represent one chunk of logs." + }, + "v1RestoreBackupRequest": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Service identifier where backup should be restored." + }, + "artifact_id": { + "type": "string", + "description": "Artifact id to restore." + }, + "pitr_timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp of PITR to restore to" + } + } + }, + "v1RestoreBackupResponse": { + "type": "object", + "properties": { + "restore_id": { + "type": "string", + "description": "Unique restore identifier." + } + } + }, + "v1RestoreHistoryItem": { + "type": "object", + "properties": { + "restore_id": { + "type": "string", + "description": "Machine-readable restore id." + }, + "artifact_id": { + "type": "string", + "description": "ID of the artifact used for restore." + }, + "name": { + "type": "string", + "description": "Artifact name used for restore." + }, + "vendor": { + "type": "string", + "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL." + }, + "location_id": { + "type": "string", + "description": "Machine-readable location ID." + }, + "location_name": { + "type": "string", + "description": "Location name." + }, + "service_id": { + "type": "string", + "description": "Machine-readable service ID." + }, + "service_name": { + "type": "string", + "description": "Service name." + }, + "data_model": { + "$ref": "#/definitions/v1DataModel", + "description": "Backup data model." + }, + "status": { + "$ref": "#/definitions/v1RestoreStatus", + "description": "Restore status." + }, + "started_at": { + "type": "string", + "format": "date-time", + "description": "Restore start time." + }, + "finished_at": { + "type": "string", + "format": "date-time", + "description": "Restore finish time." + }, + "pitr_timestamp": { + "type": "string", + "format": "date-time", + "description": "PITR timestamp is filled for PITR restores, empty otherwise." + } + }, + "description": "RestoreHistoryItem represents single backup restore item." + }, + "v1RestoreServiceGetLogsResponse": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1LogChunk" + } + }, + "end": { + "type": "boolean" + } + } + }, + "v1RestoreStatus": { + "type": "string", + "enum": [ + "RESTORE_STATUS_UNSPECIFIED", + "RESTORE_STATUS_IN_PROGRESS", + "RESTORE_STATUS_SUCCESS", + "RESTORE_STATUS_ERROR" + ], + "default": "RESTORE_STATUS_UNSPECIFIED", + "description": "RestoreStatus shows the current status of execution of restore." + } + } +} diff --git a/api/common/common.pb.go b/api/common/common.pb.go index 0d05883daa1..2303ccd29ab 100644 --- a/api/common/common.pb.go +++ b/api/common/common.pb.go @@ -147,7 +147,6 @@ var ( nil, // 2: common.StringMap.ValuesEntry } ) - var file_common_common_proto_depIdxs = []int32{ 2, // 0: common.StringMap.values:type_name -> common.StringMap.ValuesEntry 1, // [1:1] is the sub-list for method output_type diff --git a/api/common/common.swagger.json b/api/common/common.swagger.json new file mode 100644 index 00000000000..613dea17f41 --- /dev/null +++ b/api/common/common.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "common/common.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/common/metrics_resolutions.pb.go b/api/common/metrics_resolutions.pb.go index 75e587ba9a5..389e4572992 100644 --- a/api/common/metrics_resolutions.pb.go +++ b/api/common/metrics_resolutions.pb.go @@ -118,7 +118,6 @@ var ( (*durationpb.Duration)(nil), // 1: google.protobuf.Duration } ) - var file_common_metrics_resolutions_proto_depIdxs = []int32{ 1, // 0: common.MetricsResolutions.hr:type_name -> google.protobuf.Duration 1, // 1: common.MetricsResolutions.mr:type_name -> google.protobuf.Duration diff --git a/api/common/metrics_resolutions.swagger.json b/api/common/metrics_resolutions.swagger.json new file mode 100644 index 00000000000..995cc971e4a --- /dev/null +++ b/api/common/metrics_resolutions.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "common/metrics_resolutions.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/descriptor.bin b/api/descriptor.bin index 517f7c82c89a4c3250b8841faee43505120846e6..4e17e1f01dc4a132ec9ea22974b6bd2613802e6f 100644 GIT binary patch delta 10292 zcmb7JdvF}Zncwanjb>+LJ!WNTHInR+Y)iImNq(L&#<3;K;0MN7vU!AuSW9ChBTLHe z%Gj8&#sO^ew0UIUFh_ib90%rcfnbhs6iKBhisLAb5bih^;V6!xD2k%sQWQn5a`*eX zduHV%$K*O6E*b zdaW3x$@!oo80E(wWE({>**huQ&Y0xwGV*rg$XcT}jsR@zF0<|a@ywM$e{T4ipnHn# zC^S4e80_v&+NJ#}L%MC->emkLcI;$-6vgJhW%l%M@@&^UYlFMOF3m~@=F&n2c*Y+E z_~h?~#Kmk$+w;s$cd6|$DNrgE-MMyaSI-6O`Zo3UuU@-m^@jf5HGNyp-4Y&q$Eqnb z+tdEkWPjh5t}R>p`ZsN;WNwSy{O4%S?pk;5nx0DT&a#{S9Nn7U-c7xgV&PY1cDXjT z?__3&_%$mW;CAgd_`;prp*MN1W7mR?Z=mW8zBdu%^4`2}N1PiU8_fmHhuNK7JKW}T z3rKKZo8(Ie`s%>S`8wCVp57ooksZzX`JuocQsc8&djc$GCt_7XZqB_Cp3|y7#)Iv`#84*W>ef{Njsaujr z{1Xqm>h0?AvBj1Xel{kYvN?9r=7PJzOtgd>U$$z?FSU6|!Zn;kCG*brLpCU?!^PvG zr{I*-*=2S~NrESsE6Vsx+p!Ho1m;9j5LMPXTO;f~F@-m2LJ3-;DG*MXIZGpsx$>A0 zQ{_A&Ps?47Eu2Oy-E$v7Eb!>4JH zFusP*&@#yQnxUl>rRe*u@^V&5e=QMKPo-ZjS znB~pzw;-RjQkan$9rU-4P2m6Nm_MA$O$5+N4&>5-jWcFyL{>~kLM@WgplCXu2Kith9}LnePnSrZo~|>GOHVh!xt&rXJl(`+d(D$14vbBVkX?CyTi^$~gMkT1 zjm@KIG_|zaV>UOi8D=FqSoqQR#Asob<&n(>(!RtME!-ks5h5@(n!<8gl9dsH_Lfw& zMhtANF&hY5x!hKeK|XCw#)M#Ntxan-Zn|PNPZzX0m^WMH82HG0v+HDP5(3|Bm2p4< zd~;x!vJz8sR1VV=*yhwUXa$1iR7PXYfR%G$F}5^h!47r|t? zb(io)Z$o%wmsl09pAa?kmLwxNy|&bu86! z1R>4oI5O$jWnjBdvca*-c!Rf|^sNjx?t;E$$;dYH?J}=k+fBY*9_y1p>w9CDNVP4G z^^uF0$NEfAt^nHwQXi6GML6YZaZ%d}9YV%U(67)TWV{sgD?z_i(w72+cU&zlY+D)o zy%h8-W4~LV?*e_Fq_+UV%H3jXTUYFG3-n#F!;_$29WNsZ5Z79ouLfQf#u&vV`!~qVct&et|JkQtbod*EE^?K(4fp5Luc>v(spm&~}+MstH0N6I@ zod*QA4SMHsnIIcsCG9*QS8Ocqyo=^z1iTw{@PNR(Q3nsnj1_JIFYP~>+M8(qty+rT z;M$}^2n4Q8I)qpsxHf~UTXMnb%{=Wb@z?c)r>+spI!v%`*3kqpSU2lva+xiCV4Wvf zku81UQ+q{6TVG61+0qx&Q?_j7roBMYBU`qH*0o|$!`9LYndY2Rwrq8)?K2U5;Tjhw zwucv9E6!}V*iz@BkkP*cI@dr3kSi_;AHP9Ls0 z!fD?Zoo$zumPZtzzpTpDh>nDQ$VcUXd>pj>;kgAdcRqfDxnE}q5V-nvmI!$qWV9!M zT#*THUSZ7!7X>?`Qxb@#bV>?tz}o}7#-1&8A=m?9+jXL?ZJ>6#wuS;c&@7t-SW^P} zfLGgfk{*Tz;dR%E`tD$=Iwn8?`e530>VXWyHHH!svIoN9=87Slb97o7(uX^=4}n~< zgM8REAHPAjLwgbk(spQ18gc`TXwLw-VuU=iplw9^1Y@8d(LPZbII4XDxM5SZsPyedCx;i;bq!+oNnE$^ta87vT&PfyeC zB&X-myU~$V;u^aX*M)EF6B`#e%{$+SM3?jBB*3(UrlZ zy)cQ6IN77^3o0&MqJVGrfAnUk_Bnn&16~`OiPk!Kr^IfAd?`1NrnJ|_hyD@Y6!b-W(X(Q zWxK|0EI}Q+Fl^A>#w-d1HyqczgC&k=^$w=)U{-?^;qU@^=5VCmA@xAMo+b5%nd3$f zyoXt;K7vqxm|+W(mNM78izV*STFO9q7deIuEt6}!J5mDZ8bF;iS)f^Hxtlp^&4A#& zo6T&Cc%kKP)=swoZcK5FkR@8=BBy{ZWY!EhQSKV|u>@W8gi(%(`^dv&SA}cd&k_%4 zyDBhse`Hq$>?*j%(a11hiRMVnK(Om5a~dNE-lJ^V%m~7+qfEB(+^BTT2U+6BS_|F| zj0c&e!c-|&e~gsi(qI6(2GA;RmcKExJKWu6H4l-OFo7gI#+*v201#4+u_`Zu(07bA z#zK*9$Jq3hc9oqZUh7EOyfAIrJS$C#xahESKTO96pj~lU{ivoN<|bj z&~cn1stjV#ah&<9v<{|q9A`}{H3dqL@i4=2Q7?6%3j#`eQ~W;l*ofMUz$s~D!NV+> z>WMIvJ|~s^}B~#5Np8zPYaX6PEZl#=J|^lgb}G0f(6{tf`lb2iY8+Q*b|= ze0pC+Pbq)$3QURZLhnzaymF;mo+0O-0aF281E|t#3;*@Mom2t$>&b66*v7 z4~QY^8J2V+h$TG3$}2P^?>$SB=Ss<-1xkC3K0O1|&7CBx+jD*>llQZk(O5F2)UzyE zP=Rq}PCXm>*QI99c#cFblcM2YAkUk7nrQtd9^N;*nAAnLM$C_csukZ#YBx{yLI zFh&iMzfu!`{RM`)r6Jf~U?^M)q8m0|BvV&Qc7=+a?V>X@8HBuu4HR)f$cshCqB%BR zA|cdnx~Ql?)Ks6fN^w&~e5vRzw8wz4yKtK_eo^E`kpuF)r9M6lg#U4kSS$;r%cen6lcIb~4^M^|3FBzIBWj5Mu zz*KcXV_eIOmr2DEsUj&++G{;6fBs)3RD@qboy!P<+6;|WM zNUD1Mjzv<%ezoWj2O?i(sVMczAo4X5`5h^;Od`*lAD&+jet6;&X07=Hc~qNUW9WpH zgUcZAHHK@ff>R*xb&_|Ul!t-~)ZncOH|IoW!H-|Hq9-lQ1(~liT=q1C%-30+Dl0B8 zhd3y;%XVZz8{BJM8ibiJHAi z{fOr+wdK~S|Gr=r#)MVA8O-Kg~d z1ftesX#u~X>D{6xsuu4?4G3nT>D{OS0feS^qXvYa()4cBfTUzOd5_X{7QzPT8bE2U z)<1iABoFUy+Y>z_Q!7$XsIVD{feza z0~Vyu`%w=I2>I_vJuILU(GL9-xRku`en1M8)ldi2aGKQ=c%Qzd(Mz=Eg6lqDxKL>b z9Urhtb!b5*bbLUU6g7(rxbY$7Gu4z7Rb8OMEIgN}FFH7KNA@7S==(IK8FdGga(RC& z>u0u;@ACLGFBm z{P_W^TGkjaLd!?2LA6(a(DD(rS4s<2s*fq+>!cP`Dj?5WJ}Ed+X`#=f{_OEgHb0yh zndc8=azQ)3Ed-;v;r#Hf0NX4-Ff=D#U1I4W)_PQ~pLQhc^ljMN0G z_0E{2Sk|4tP%G8DPgE%?P;OAc`-DwZM`?;vz5A53QY!{1Q7u}rVuD8vO!SpEUJzBe zPot&!8XN0P9Z6LRH{sMX^w-aGw>o4pq3%SWQ|-$3ZTCPMJMJ znu`htG~b&#$=v8ma4gY5rhLwvCc9Tfmkv4l&c2i zZ<*C9DXZlv_GNTW0CbHn>7FoiF@A&c%c$uGgv>9a4PPw}rLUsf0-$SrRlF@21&qic zec1p6`&UJFx-)!Di}tbTYC42~Iy^V}imJC)POlggSn=1iVp=dDq<_tt)x8rC(!XZ- zfVIu$X2LZ~e$VK8XmCJWk@`KeYUl~uqz^gfKF)9A;lCdcn+yB6DPuqrFkm0ATS(Fg zLfk&S;=%~R*z38`Lzg<5HJ*C)g=QLZR@<&^$3qZuJ@>oq3MIsF&HdcC5rwSEE|o-g zS~TR`$V==>d%mT|!1e=f&caYM0`)g=bDMp>w3@l*LC$Z7)d$6Sg@fFbjSQIaq0%_W zYvyS)$;Aix((@t+s}FHwwYHjRs}FIfTU)J$AmkADyR_A)L*~ugxGlDt8D#a%+__C! zT_7823~aY>vrSt~BT#=UH`miw6VPziJk0qIx$t`YZ}=3CAb-m*5 z2*ZrSeA-!h&6Ed+`8nGo2p1eF299eN94Q7)4ME6}V&IUQ=AGQQCw2jsF1V9B_wbTM zdciaXw!64Fc?9b3=H|urcIg7)n)h;kjEBEIB(5k>fxEYua`*}f7^fW7yL&0+RPvyn zn)h+zC~Qc{q!Y?^3_3><2$gnf5R3e4ZnmB_hBN+tZdOc^w($XO{3u?MkV|@iJ3o?9 zrJ&LfZ2B8Y#VVPKG=h)o4|4M;voDoPf?3Bo|9c*?Tf_wg`pkEno3frl0)5gs&eQX? z_o=)d=gYT55OzMqjk9z<8afycac8+UT@69VL)<@8n~u)Xe3%=L#FiV<@`t(e2wzOw zh)kz3u>F{uGbfEe{oiqOrM+2NUgDaMasCfHv~R@+Co0R2;Y`uC(O3D$cuMwukVjSe zF}`3;Gz-g5aAS$KyhK}mf;)?~k|~$;9Cv;erx6Xo rrhnvSi(V0pz^v!_fu`F9{tWz;;LpTgDgG?{CGlsUY`Wd4{^b7vTcKHw delta 5124 zcmY*dZE#h^89wjs-jj3B2}$lI^ZSN?o6KD z_j%uEpM7`FIeGW##V`M>_rMfQiI?Q2G4a{$=38U(2J_yru-X&`f@%|dqq4_b_lnG4 zSa7@iPxivRNqGy&#s3U1T)SI-MHkxl%4r#1=?^P(#`FG4=5LFFI`he0vfc#m1dUZ& zLXq*b3cYH|-%>Q6-XZHu>27&_Im|SLm0>3136Hdl#GEh+6(a`olPLkzHP0bJV5Mkx zffjToQwXe_GuI)3xmjr-re=vGP%uJZIj$`cStVLrO39$ZC6S1%Dz=9qRzO#RF-nMOQL~1bS{mMY9W}GNX1ENr}sL>zsOGy>(7K z03)|d5-fhUXmu$eezv&E%2(&^vl~bTr{> z*(@5%t{lWR$7=+Sm*3oEtziUSbG%|830@0?#VRq?5_`x~ptaODy8@EuVn;Ejpt21r z$L-=2gF=3!IAT8kksK?vW$PVFfz{TOSdsy&9jxmui-Gy-xa{wY4MR`J_H5!&2F&)x zrf>j$qgm#9*P1u(lLO_s&S10#5_CGJY@>9FxKP|foh}s+QgtE~mqFWr)|JvwvrEJ# z#vRp_txW#DbH37PJdczz*v4owB- z0u;Q}5;3*FR2`5*=H{}jEiG{Si7=jV`$^W|ZjeST2?lqYqh-0d)SXQPv9;a#f)mTu z_M}A^aFLCro-{uj+LPw@5z>qJjW$1;px6BPfZSB-bz4WmM|`i_IuaF#??e2EjjsSO zH3#KrsV{Z80`YyR%K_q-Abx|54*<-g2jxgG-c@S@yunp0V9Nf!5TK2mW2Y`LL0lX#ZDn%e>^-v5oj3sSR=N`h1l~$_;sC%Ka3{`A4Y(5r z0NQ{%aX_FAxDzLALkvPCpEw{b2WL*)rbQS5chGGf5V(VG^U%6j;Sjid?rb9u*>h)( zP06q{U>YD+|` ztTDZZ5mtThiEl6}o=i3^~@< zJ*DA_sw4vO!#V8`pZ*QV-(%x(yKXQaACU_dNxRh>T#EpKwZXNBv?qVWIRT{Qh$(Cg z=7GgKJ>vQih^JgXN}=HOsHhL;*;?4?QS@c#k<2kcyW(uxdm4mUyRCnIOaSA(sGPF99)FI z5jWhn=?=-YdDd}ngcJqts( zVqX8wY}^ydo|&C>@$*NC3}_P~3|nmuB%Bae<#R>%z%Op&Cw}9@vbr=8#Wyl2NH@{g z>XNhR6L?|Z`zoW=o!%ZZ{IFctd}m-^OH{@hzROt$q~$Ji@nP9p-sP;u7;@}#R%Zl3 z(j+AD{RYG!-eCX;oQ&d~1md}x_!$g@B$Mtg$k=OZx9ct-Eq9AK`GQ@~cZ)mj-m&e6 z=GDWp?gq>u%Wl_mK*+KiJ;y!dYqi(AEAAn_3HAo@%Y`pINZbdB%ODX5zo|L;)j{(3l~Ae> zFCqsiVAF+)wEqBkhluP{gsBH8Xbxv#r4d(FQ-so$s2qth-WUOk$t(<epq^wBMUGH(6~i(IgL{PLl#*#w zIYQky3#c+ntE1#~+Lg>g+))bRovzaA5%Ty;LaHiEJVMr7p{liijJ!vku4+sjOLSFR zUDJs!Ks})V=iADF5H?LwO9H{2rq($Lgsy3_UnoM=X#Y5QKXFxR5P6(}RvTGktDN8} zeef7is}p4CwxBe@?qC3??gT|ONjTUiD3?zl>YSjKG+Dr~Z6M5rS>^`64DjBDq2fwM z!0A(l%PqI%kj*@POs*I+GbM2D5R!{GvW5>HAT~1ALnvXWc%3Uju7siX0T+R%j5I{3+ zVu=ub#ymGI+j`DWRPT~=x---e8=m9)1Q3U8JQTjC{jzDHGO&ivl+W+Oy=(#ZWSW^3Rb!9^PVAllIS( z_%&3YmN%ErlRw+(!e^;EPxV(P5VZ5O^yUOY^$VnioN98aU!Z7}QymW>$qQ5*bgI#p z{)?nuPF0g))h|-?@{DR81MOGjmz-)ILHU=+zcJitRSWH3B=I{kJI~-lmbdHTjNf=t z0H%KP?pXp^VrjJV;L`9>MinZ zw<80-=m8rSIrs4j0l56u1VZQAr25@vNVgepQ?%SkkB5-tZ7MEv(j|;|ht&J2a%q*n zL(%(m4fhaB=P}UUC4bJ>Mo|7e@(03Us~mYQk@$?v6FUf# zlgjVJm#BAj0-^jPQcIk2<&=L!(KSwaJcJ}4QL)b{$BUu=F{w{e<;p7mn4(W-l=B#9 zzbC)dDd!QC|AhQ+hC8hCjP@^+_zRhnKa;nY`5!%($!~JnGGJe({51&#^)e0I<}~1) z%m19z7ik-1TpN8((HChO#e-PnAIR@^D~iX^Mt_`XBhI$=OHx dump.v1beta1.DumpStatus 14, // 1: dump.v1beta1.Dump.start_time:type_name -> google.protobuf.Timestamp diff --git a/api/dump/v1beta1/dump.swagger.json b/api/dump/v1beta1/dump.swagger.json new file mode 100644 index 00000000000..25bbd5672a3 --- /dev/null +++ b/api/dump/v1beta1/dump.swagger.json @@ -0,0 +1,395 @@ +{ + "swagger": "2.0", + "info": { + "title": "dump/v1beta1/dump.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "DumpService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/dumps": { + "get": { + "summary": "List All Dumps", + "description": "List all dumps", + "operationId": "ListDumps", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1ListDumpsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "DumpService" + ] + } + }, + "/v1/dumps/{dump_id}/logs": { + "get": { + "summary": "Get Dump Logs", + "description": "Get logs of a selected dump.", + "operationId": "GetDumpLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1GetDumpLogsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "dump_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "offset", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + }, + { + "name": "limit", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + } + ], + "tags": [ + "DumpService" + ] + } + }, + "/v1/dumps:batchDelete": { + "post": { + "summary": "Delete Dumps", + "description": "Delete selected dumps.", + "operationId": "DeleteDump", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1DeleteDumpResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1beta1DeleteDumpRequest" + } + } + ], + "tags": [ + "DumpService" + ] + } + }, + "/v1/dumps:start": { + "post": { + "summary": "Start a New Dump", + "description": "Start a new dump.", + "operationId": "StartDump", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1StartDumpResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1beta1StartDumpRequest" + } + } + ], + "tags": [ + "DumpService" + ] + } + }, + "/v1/dumps:upload": { + "post": { + "summary": "Upload Dumps", + "description": "Upload selected dumps to a remote server.", + "operationId": "UploadDump", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1UploadDumpResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1beta1UploadDumpRequest" + } + } + ], + "tags": [ + "DumpService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1beta1DeleteDumpRequest": { + "type": "object", + "properties": { + "dump_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "v1beta1DeleteDumpResponse": { + "type": "object" + }, + "v1beta1Dump": { + "type": "object", + "properties": { + "dump_id": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/v1beta1DumpStatus" + }, + "service_names": { + "type": "array", + "items": { + "type": "string" + } + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "encrypted": { + "type": "boolean", + "description": "This field is set to true if the dump was created with encryption enabled, and false otherwise." + } + } + }, + "v1beta1DumpStatus": { + "type": "string", + "enum": [ + "DUMP_STATUS_UNSPECIFIED", + "DUMP_STATUS_IN_PROGRESS", + "DUMP_STATUS_SUCCESS", + "DUMP_STATUS_ERROR" + ], + "default": "DUMP_STATUS_UNSPECIFIED" + }, + "v1beta1GetDumpLogsResponse": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1beta1LogChunk" + } + }, + "end": { + "type": "boolean" + } + } + }, + "v1beta1ListDumpsResponse": { + "type": "object", + "properties": { + "dumps": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1beta1Dump" + } + } + } + }, + "v1beta1LogChunk": { + "type": "object", + "properties": { + "chunk_id": { + "type": "integer", + "format": "int64" + }, + "data": { + "type": "string" + } + }, + "description": "LogChunk represent one chunk of logs." + }, + "v1beta1SFTPParameters": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "user": { + "type": "string" + }, + "password": { + "type": "string" + }, + "directory": { + "type": "string" + } + } + }, + "v1beta1StartDumpRequest": { + "type": "object", + "properties": { + "service_names": { + "type": "array", + "items": { + "type": "string" + } + }, + "start_time": { + "type": "string", + "format": "date-time" + }, + "end_time": { + "type": "string", + "format": "date-time" + }, + "export_qan": { + "type": "boolean" + }, + "ignore_load": { + "type": "boolean" + }, + "enable_encryption": { + "type": "boolean", + "description": "If true, the dump will be encrypted. Note that enabling encryption may increase the time required to create the dump." + }, + "encryption_password": { + "type": "string", + "description": "The password used for encryption. It must be at least 8 characters long. This field is required if enable_encryption is true." + } + } + }, + "v1beta1StartDumpResponse": { + "type": "object", + "properties": { + "dump_id": { + "type": "string" + } + } + }, + "v1beta1UploadDumpRequest": { + "type": "object", + "properties": { + "dump_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "sftp_parameters": { + "$ref": "#/definitions/v1beta1SFTPParameters", + "description": "SFTP upload parameters." + } + } + }, + "v1beta1UploadDumpResponse": { + "type": "object" + } + } +} diff --git a/api/extensions/v1/redact.pb.go b/api/extensions/v1/redact.pb.go index 738ce213118..c850a90df3c 100644 --- a/api/extensions/v1/redact.pb.go +++ b/api/extensions/v1/redact.pb.go @@ -135,7 +135,6 @@ var ( (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions } ) - var file_extensions_v1_redact_proto_depIdxs = []int32{ 1, // 0: extensions.v1.sensitive:extendee -> google.protobuf.FieldOptions 0, // 1: extensions.v1.sensitive:type_name -> extensions.v1.RedactType diff --git a/api/extensions/v1/redact.swagger.json b/api/extensions/v1/redact.swagger.json new file mode 100644 index 00000000000..833d6404187 --- /dev/null +++ b/api/extensions/v1/redact.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "extensions/v1/redact.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index f798cccbcc0..655996ccdbc 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -351,7 +351,6 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) - var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/ha/v1beta1/ha.swagger.json b/api/ha/v1beta1/ha.swagger.json new file mode 100644 index 00000000000..eab5d5f5d2f --- /dev/null +++ b/api/ha/v1beta1/ha.swagger.json @@ -0,0 +1,148 @@ +{ + "swagger": "2.0", + "info": { + "title": "ha/v1beta1/ha.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "HAService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/ha/nodes": { + "get": { + "summary": "List HA Nodes", + "description": "Returns a list of all nodes in the High Availability cluster with their current status and roles.", + "operationId": "ListNodes", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1ListNodesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "tags": [ + "HAService" + ] + } + }, + "/v1/ha/status": { + "get": { + "summary": "HA Status", + "description": "Returns whether High Availability mode is enabled or disabled.", + "operationId": "Status", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1beta1StatusResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "tags": [ + "HAService" + ] + } + } + }, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "v1beta1HANode": { + "type": "object", + "properties": { + "node_name": { + "type": "string", + "description": "Human-readable name of the node." + }, + "role": { + "$ref": "#/definitions/v1beta1NodeRole", + "description": "Role of the node in the cluster." + }, + "status": { + "type": "string", + "description": "Current status of the node from MemberList." + } + }, + "description": "HANode represents a single node in the HA cluster." + }, + "v1beta1ListNodesResponse": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1beta1HANode" + }, + "description": "List of nodes in the HA cluster." + } + } + }, + "v1beta1NodeRole": { + "type": "string", + "enum": [ + "NODE_ROLE_UNSPECIFIED", + "NODE_ROLE_LEADER", + "NODE_ROLE_FOLLOWER" + ], + "default": "NODE_ROLE_UNSPECIFIED", + "description": "NodeRole represents the role of a node in the HA cluster." + }, + "v1beta1StatusResponse": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Status of HA mode: \"Enabled\" or \"Disabled\"." + } + } + } + } +} diff --git a/api/inventory/v1/agent_status.pb.go b/api/inventory/v1/agent_status.pb.go index 1e23074d2fc..ace1432a5e8 100644 --- a/api/inventory/v1/agent_status.pb.go +++ b/api/inventory/v1/agent_status.pb.go @@ -128,7 +128,6 @@ var ( AgentStatus(0), // 0: inventory.v1.AgentStatus } ) - var file_inventory_v1_agent_status_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/agent_status.swagger.json b/api/inventory/v1/agent_status.swagger.json new file mode 100644 index 00000000000..2e9902fb83f --- /dev/null +++ b/api/inventory/v1/agent_status.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "inventory/v1/agent_status.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/inventory/v1/agents.pb.go b/api/inventory/v1/agents.pb.go index 3784fc8b7fc..f5d83515360 100644 --- a/api/inventory/v1/agents.pb.go +++ b/api/inventory/v1/agents.pb.go @@ -12513,7 +12513,6 @@ var ( (*common.StringMap)(nil), // 112: common.StringMap } ) - var file_inventory_v1_agents_proto_depIdxs = []int32{ 68, // 0: inventory.v1.PMMAgent.custom_labels:type_name -> inventory.v1.PMMAgent.CustomLabelsEntry 108, // 1: inventory.v1.VMAgent.status:type_name -> inventory.v1.AgentStatus diff --git a/api/inventory/v1/agents.swagger.json b/api/inventory/v1/agents.swagger.json new file mode 100644 index 00000000000..971cac4cec1 --- /dev/null +++ b/api/inventory/v1/agents.swagger.json @@ -0,0 +1,4490 @@ +{ + "swagger": "2.0", + "info": { + "title": "inventory/v1/agents.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "AgentsService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/inventory/agents": { + "get": { + "summary": "List Agents", + "description": "Returns a list of all Agents.", + "operationId": "ListAgents", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListAgentsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "pmm_agent_id", + "description": "Return only Agents started by this pmm-agent.\nExactly one of these parameters should be present: pmm_agent_id, node_id, service_id.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "node_id", + "description": "Return only Agents that provide insights for that Node.\nExactly one of these parameters should be present: pmm_agent_id, node_id, service_id.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "service_id", + "description": "Return only Agents that provide insights for that Service.\nExactly one of these parameters should be present: pmm_agent_id, node_id, service_id.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "agent_type", + "description": "Return only agents of a particular type.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "AGENT_TYPE_UNSPECIFIED", + "AGENT_TYPE_PMM_AGENT", + "AGENT_TYPE_VM_AGENT", + "AGENT_TYPE_NODE_EXPORTER", + "AGENT_TYPE_MYSQLD_EXPORTER", + "AGENT_TYPE_MONGODB_EXPORTER", + "AGENT_TYPE_POSTGRES_EXPORTER", + "AGENT_TYPE_PROXYSQL_EXPORTER", + "AGENT_TYPE_VALKEY_EXPORTER", + "AGENT_TYPE_QAN_MYSQL_PERFSCHEMA_AGENT", + "AGENT_TYPE_QAN_MYSQL_SLOWLOG_AGENT", + "AGENT_TYPE_QAN_MONGODB_PROFILER_AGENT", + "AGENT_TYPE_QAN_MONGODB_MONGOLOG_AGENT", + "AGENT_TYPE_QAN_POSTGRESQL_PGSTATEMENTS_AGENT", + "AGENT_TYPE_QAN_POSTGRESQL_PGSTATMONITOR_AGENT", + "AGENT_TYPE_EXTERNAL_EXPORTER", + "AGENT_TYPE_RDS_EXPORTER", + "AGENT_TYPE_AZURE_DATABASE_EXPORTER", + "AGENT_TYPE_NOMAD_AGENT", + "AGENT_TYPE_RTA_MONGODB_AGENT" + ], + "default": "AGENT_TYPE_UNSPECIFIED" + } + ], + "tags": [ + "AgentsService" + ] + }, + "post": { + "summary": "Add an Agent to Inventory", + "description": "Adds an Agent to Inventory. Only one agent at a time can be passed.", + "operationId": "AddAgent", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AddAgentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1AddAgentRequest" + } + } + ], + "tags": [ + "AgentsService" + ] + } + }, + "/v1/inventory/agents/{agent_id}": { + "get": { + "summary": "Get Agent", + "description": "Returns a single Agent by ID.", + "operationId": "GetAgent", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetAgentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "agent_id", + "description": "Unique randomly generated instance identifier.", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "AgentsService" + ] + }, + "delete": { + "summary": "Remove an Agent from Inventory", + "description": "Removes an Agent from Inventory.", + "operationId": "RemoveAgent", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RemoveAgentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "agent_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "force", + "description": "Remove agent with all dependencies.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "AgentsService" + ] + }, + "put": { + "summary": "Update an Agent in Inventory", + "description": "Updates an Agent in Inventory. Only one agent at a time can be passed.", + "operationId": "ChangeAgent", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ChangeAgentResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "agent_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AgentsServiceChangeAgentBody" + } + } + ], + "tags": [ + "AgentsService" + ] + } + }, + "/v1/inventory/agents/{agent_id}/logs": { + "get": { + "summary": "Get Agent logs", + "description": "Returns Agent logs by ID.", + "operationId": "GetAgentLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetAgentLogsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "agent_id", + "description": "Unique randomly generated instance identifier.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "limit", + "description": "Limit the number of log lines to this value. Pass 0 for no limit.", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + } + ], + "tags": [ + "AgentsService" + ] + } + } + }, + "definitions": { + "AgentsServiceChangeAgentBody": { + "type": "object", + "properties": { + "node_exporter": { + "$ref": "#/definitions/v1ChangeNodeExporterParams" + }, + "mysqld_exporter": { + "$ref": "#/definitions/v1ChangeMySQLdExporterParams" + }, + "mongodb_exporter": { + "$ref": "#/definitions/v1ChangeMongoDBExporterParams" + }, + "postgres_exporter": { + "$ref": "#/definitions/v1ChangePostgresExporterParams" + }, + "proxysql_exporter": { + "$ref": "#/definitions/v1ChangeProxySQLExporterParams" + }, + "external_exporter": { + "$ref": "#/definitions/v1ChangeExternalExporterParams" + }, + "rds_exporter": { + "$ref": "#/definitions/v1ChangeRDSExporterParams" + }, + "azure_database_exporter": { + "$ref": "#/definitions/v1ChangeAzureDatabaseExporterParams" + }, + "qan_mysql_perfschema_agent": { + "$ref": "#/definitions/v1ChangeQANMySQLPerfSchemaAgentParams" + }, + "qan_mysql_slowlog_agent": { + "$ref": "#/definitions/v1ChangeQANMySQLSlowlogAgentParams" + }, + "qan_mongodb_profiler_agent": { + "$ref": "#/definitions/v1ChangeQANMongoDBProfilerAgentParams" + }, + "qan_mongodb_mongolog_agent": { + "$ref": "#/definitions/v1ChangeQANMongoDBMongologAgentParams" + }, + "qan_postgresql_pgstatements_agent": { + "$ref": "#/definitions/v1ChangeQANPostgreSQLPgStatementsAgentParams" + }, + "qan_postgresql_pgstatmonitor_agent": { + "$ref": "#/definitions/v1ChangeQANPostgreSQLPgStatMonitorAgentParams" + }, + "nomad_agent": { + "$ref": "#/definitions/v1ChangeNomadAgentParams" + }, + "valkey_exporter": { + "$ref": "#/definitions/v1ChangeValkeyExporterParams" + }, + "rta_mongodb_agent": { + "$ref": "#/definitions/v1ChangeRTAMongoDBAgentParams" + } + } + }, + "commonMetricsResolutions": { + "type": "object", + "properties": { + "hr": { + "type": "string", + "description": "High resolution. In JSON should be represented as a string with number of seconds with `s` suffix." + }, + "mr": { + "type": "string", + "description": "Medium resolution. In JSON should be represented as a string with number of seconds with `s` suffix." + }, + "lr": { + "type": "string", + "description": "Low resolution. In JSON should be represented as a string with number of seconds with `s` suffix." + } + }, + "description": "MetricsResolutions represents Prometheus exporters metrics resolutions." + }, + "commonStringMap": { + "type": "object", + "properties": { + "values": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "description": "A wrapper for map[string]string. This type allows to distinguish between an empty map and a null value." + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1AddAgentRequest": { + "type": "object", + "properties": { + "pmm_agent": { + "$ref": "#/definitions/v1AddPMMAgentParams" + }, + "node_exporter": { + "$ref": "#/definitions/v1AddNodeExporterParams" + }, + "mysqld_exporter": { + "$ref": "#/definitions/v1AddMySQLdExporterParams" + }, + "mongodb_exporter": { + "$ref": "#/definitions/v1AddMongoDBExporterParams" + }, + "postgres_exporter": { + "$ref": "#/definitions/v1AddPostgresExporterParams" + }, + "proxysql_exporter": { + "$ref": "#/definitions/v1AddProxySQLExporterParams" + }, + "external_exporter": { + "$ref": "#/definitions/v1AddExternalExporterParams" + }, + "rds_exporter": { + "$ref": "#/definitions/v1AddRDSExporterParams" + }, + "azure_database_exporter": { + "$ref": "#/definitions/v1AddAzureDatabaseExporterParams" + }, + "qan_mysql_perfschema_agent": { + "$ref": "#/definitions/v1AddQANMySQLPerfSchemaAgentParams" + }, + "qan_mysql_slowlog_agent": { + "$ref": "#/definitions/v1AddQANMySQLSlowlogAgentParams" + }, + "qan_mongodb_profiler_agent": { + "$ref": "#/definitions/v1AddQANMongoDBProfilerAgentParams" + }, + "qan_mongodb_mongolog_agent": { + "$ref": "#/definitions/v1AddQANMongoDBMongologAgentParams" + }, + "qan_postgresql_pgstatements_agent": { + "$ref": "#/definitions/v1AddQANPostgreSQLPgStatementsAgentParams" + }, + "qan_postgresql_pgstatmonitor_agent": { + "$ref": "#/definitions/v1AddQANPostgreSQLPgStatMonitorAgentParams" + }, + "valkey_exporter": { + "$ref": "#/definitions/v1AddValkeyExporterParams" + }, + "rta_mongodb_agent": { + "$ref": "#/definitions/v1AddRTAMongoDBAgentParams" + } + } + }, + "v1AddAgentResponse": { + "type": "object", + "properties": { + "pmm_agent": { + "$ref": "#/definitions/v1PMMAgent" + }, + "node_exporter": { + "$ref": "#/definitions/v1NodeExporter" + }, + "mysqld_exporter": { + "$ref": "#/definitions/v1MySQLdExporter" + }, + "mongodb_exporter": { + "$ref": "#/definitions/v1MongoDBExporter" + }, + "postgres_exporter": { + "$ref": "#/definitions/v1PostgresExporter" + }, + "proxysql_exporter": { + "$ref": "#/definitions/v1ProxySQLExporter" + }, + "external_exporter": { + "$ref": "#/definitions/v1ExternalExporter" + }, + "rds_exporter": { + "$ref": "#/definitions/v1RDSExporter" + }, + "azure_database_exporter": { + "$ref": "#/definitions/v1AzureDatabaseExporter" + }, + "qan_mysql_perfschema_agent": { + "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" + }, + "qan_mysql_slowlog_agent": { + "$ref": "#/definitions/v1QANMySQLSlowlogAgent" + }, + "qan_mongodb_profiler_agent": { + "$ref": "#/definitions/v1QANMongoDBProfilerAgent" + }, + "qan_mongodb_mongolog_agent": { + "$ref": "#/definitions/v1QANMongoDBMongologAgent" + }, + "qan_postgresql_pgstatements_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" + }, + "qan_postgresql_pgstatmonitor_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" + }, + "valkey_exporter": { + "$ref": "#/definitions/v1ValkeyExporter" + }, + "rta_mongodb_agent": { + "$ref": "#/definitions/v1RTAMongoDBAgent" + } + } + }, + "v1AddAzureDatabaseExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "node_id": { + "type": "string", + "description": "Node identifier." + }, + "azure_client_id": { + "type": "string", + "title": "Azure client ID" + }, + "azure_client_secret": { + "type": "string", + "title": "Azure client secret" + }, + "azure_tenant_id": { + "type": "string", + "title": "Azure tanant ID" + }, + "azure_subscription_id": { + "type": "string", + "title": "Azure subscription ID" + }, + "azure_resource_group": { + "type": "string", + "description": "Azure resource group." + }, + "azure_database_resource_type": { + "type": "string", + "title": "Azure resource type (mysql, maria, postgres)" + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + } + }, + "v1AddExternalExporterParams": { + "type": "object", + "properties": { + "runs_on_node_id": { + "type": "string", + "description": "The node identifier where this instance is run." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "HTTP basic auth username for collecting metrics." + }, + "password": { + "type": "string", + "description": "HTTP basic auth password for collecting metrics." + }, + "scheme": { + "type": "string", + "description": "Scheme to generate URI to exporter metrics endpoints(default: http)." + }, + "metrics_path": { + "type": "string", + "description": "Path under which metrics are exposed, used to generate URI(default: /metrics)." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname verification." + } + } + }, + "v1AddMongoDBExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for scraping metrics." + }, + "password": { + "type": "string", + "description": "MongoDB password for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "authentication_mechanism": { + "type": "string", + "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." + }, + "authentication_database": { + "type": "string", + "description": "Authentication database." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "stats_collections": { + "type": "array", + "items": { + "type": "string" + }, + "title": "List of colletions to get stats from. Can use *" + }, + "collections_limit": { + "type": "integer", + "format": "int32", + "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "environment_variable_names": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Environment variable names to pass to the exporter.\nValues will be resolved from pmm-agent's environment when starting the exporter." + }, + "enable_all_collectors": { + "type": "boolean", + "description": "Enable all collectors." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddMySQLdExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for scraping metrics." + }, + "password": { + "type": "string", + "description": "MySQL password for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "tablestats_group_table_limit": { + "type": "integer", + "format": "int32", + "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddNodeExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Expose the node_exporter process on all public interfaces" + } + } + }, + "v1AddPMMAgentParams": { + "type": "object", + "properties": { + "runs_on_node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddPostgresExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for scraping metrics." + }, + "password": { + "type": "string", + "description": "PostgreSQL password for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "tls_ca": { + "type": "string", + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "description": "TLS Certifcate." + }, + "tls_key": { + "type": "string", + "description": "TLS Certificate Key." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "max_exporter_connections": { + "type": "integer", + "format": "int32", + "description": "Maximum number of connections that exporter can open to the database instance." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddProxySQLExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "ProxySQL username for scraping metrics." + }, + "password": { + "type": "string", + "description": "ProxySQL password for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddQANMongoDBMongologAgentParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profile data." + }, + "password": { + "type": "string", + "description": "MongoDB password for getting profile data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "authentication_mechanism": { + "type": "string", + "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." + }, + "authentication_database": { + "type": "string", + "description": "Authentication database." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for agent." + } + } + }, + "v1AddQANMongoDBProfilerAgentParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profile data." + }, + "password": { + "type": "string", + "description": "MongoDB password for getting profile data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "authentication_mechanism": { + "type": "string", + "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." + }, + "authentication_database": { + "type": "string", + "description": "Authentication database." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for agent." + } + } + }, + "v1AddQANMySQLPerfSchemaAgentParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for getting performance data." + }, + "password": { + "type": "string", + "description": "MySQL password for getting performance data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "description": "Disable query examples." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + } + } + }, + "v1AddQANMySQLSlowlogAgentParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for getting slowlog data." + }, + "password": { + "type": "string", + "description": "MySQL password for getting slowlog data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "description": "Disable query examples." + }, + "max_slowlog_file_size": { + "type": "string", + "format": "int64", + "description": "Rotate slowlog file at this size if \u003e 0.\nUse zero or negative value to disable rotation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + } + } + }, + "v1AddQANPostgreSQLPgStatMonitorAgentParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for getting pg stat monitor data." + }, + "password": { + "type": "string", + "description": "PostgreSQL password for getting pg stat monitor data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "description": "Disable query examples." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "tls_ca": { + "type": "string", + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "description": "TLS Certifcate." + }, + "tls_key": { + "type": "string", + "description": "TLS Certificate Key." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + } + }, + "v1AddQANPostgreSQLPgStatementsAgentParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for getting pg stat statements data." + }, + "password": { + "type": "string", + "description": "PostgreSQL password for getting pg stat statements data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "tls_ca": { + "type": "string", + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "description": "TLS Certifcate." + }, + "tls_key": { + "type": "string", + "description": "TLS Certificate Key." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + } + }, + "v1AddRDSExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "node_id": { + "type": "string", + "description": "Node identifier." + }, + "aws_access_key": { + "type": "string", + "description": "AWS Access Key." + }, + "aws_secret_key": { + "type": "string", + "description": "AWS Secret Key." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "disable_basic_metrics": { + "type": "boolean", + "description": "Disable basic metrics." + }, + "disable_enhanced_metrics": { + "type": "boolean", + "description": "Disable enhanced metrics." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + } + }, + "v1AddRTAMongoDBAgentParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting queries data." + }, + "password": { + "type": "string", + "description": "MongoDB password for getting queries data." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for agent." + }, + "tls": { + "type": "boolean", + "description": "MongoDB specific options.\nUse TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "authentication_mechanism": { + "type": "string", + "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." + }, + "rta_options": { + "$ref": "#/definitions/v1RTAOptions", + "description": "Real-Time Analytics options." + } + } + }, + "v1AddValkeyExporterParams": { + "type": "object", + "properties": { + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "Valkey username for scraping metrics." + }, + "password": { + "type": "string", + "description": "Valkey password for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "push_metrics": { + "type": "boolean", + "description": "Enables push metrics mode for exporter." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "tls_ca": { + "type": "string", + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "description": "TLS Certifcate." + }, + "tls_key": { + "type": "string", + "description": "TLS Certificate Key." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AgentStatus": { + "type": "string", + "enum": [ + "AGENT_STATUS_UNSPECIFIED", + "AGENT_STATUS_STARTING", + "AGENT_STATUS_INITIALIZATION_ERROR", + "AGENT_STATUS_RUNNING", + "AGENT_STATUS_WAITING", + "AGENT_STATUS_STOPPING", + "AGENT_STATUS_DONE", + "AGENT_STATUS_UNKNOWN" + ], + "default": "AGENT_STATUS_UNSPECIFIED", + "description": "AgentStatus represents actual Agent status.\n\n - AGENT_STATUS_STARTING: Agent is starting.\n - AGENT_STATUS_INITIALIZATION_ERROR: Agent encountered error when starting.\n - AGENT_STATUS_RUNNING: Agent is running.\n - AGENT_STATUS_WAITING: Agent encountered error and will be restarted automatically soon.\n - AGENT_STATUS_STOPPING: Agent is stopping.\n - AGENT_STATUS_DONE: Agent has been stopped or disabled.\n - AGENT_STATUS_UNKNOWN: Agent is not connected, we don't know anything about it's state." + }, + "v1AgentType": { + "type": "string", + "enum": [ + "AGENT_TYPE_UNSPECIFIED", + "AGENT_TYPE_PMM_AGENT", + "AGENT_TYPE_VM_AGENT", + "AGENT_TYPE_NODE_EXPORTER", + "AGENT_TYPE_MYSQLD_EXPORTER", + "AGENT_TYPE_MONGODB_EXPORTER", + "AGENT_TYPE_POSTGRES_EXPORTER", + "AGENT_TYPE_PROXYSQL_EXPORTER", + "AGENT_TYPE_VALKEY_EXPORTER", + "AGENT_TYPE_QAN_MYSQL_PERFSCHEMA_AGENT", + "AGENT_TYPE_QAN_MYSQL_SLOWLOG_AGENT", + "AGENT_TYPE_QAN_MONGODB_PROFILER_AGENT", + "AGENT_TYPE_QAN_MONGODB_MONGOLOG_AGENT", + "AGENT_TYPE_QAN_POSTGRESQL_PGSTATEMENTS_AGENT", + "AGENT_TYPE_QAN_POSTGRESQL_PGSTATMONITOR_AGENT", + "AGENT_TYPE_EXTERNAL_EXPORTER", + "AGENT_TYPE_RDS_EXPORTER", + "AGENT_TYPE_AZURE_DATABASE_EXPORTER", + "AGENT_TYPE_NOMAD_AGENT", + "AGENT_TYPE_RTA_MONGODB_AGENT" + ], + "default": "AGENT_TYPE_UNSPECIFIED", + "description": "AgentType describes supported Agent types." + }, + "v1AzureDatabaseExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "node_id": { + "type": "string", + "description": "Node identifier." + }, + "azure_database_subscription_id": { + "type": "string", + "description": "Azure database subscription ID." + }, + "azure_database_resource_type": { + "type": "string", + "title": "Azure database resource type (mysql, maria, postgres)" + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status (the same for several configurations)." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics (the same for several configurations)." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if the exporter operates in push metrics mode." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + } + }, + "description": "AzureDatabaseExporter runs on Generic or Container Node and exposes RemoteAzure Node metrics." + }, + "v1ChangeAgentResponse": { + "type": "object", + "properties": { + "node_exporter": { + "$ref": "#/definitions/v1NodeExporter" + }, + "mysqld_exporter": { + "$ref": "#/definitions/v1MySQLdExporter" + }, + "mongodb_exporter": { + "$ref": "#/definitions/v1MongoDBExporter" + }, + "postgres_exporter": { + "$ref": "#/definitions/v1PostgresExporter" + }, + "proxysql_exporter": { + "$ref": "#/definitions/v1ProxySQLExporter" + }, + "external_exporter": { + "$ref": "#/definitions/v1ExternalExporter" + }, + "rds_exporter": { + "$ref": "#/definitions/v1RDSExporter" + }, + "azure_database_exporter": { + "$ref": "#/definitions/v1AzureDatabaseExporter" + }, + "qan_mysql_perfschema_agent": { + "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" + }, + "qan_mysql_slowlog_agent": { + "$ref": "#/definitions/v1QANMySQLSlowlogAgent" + }, + "qan_mongodb_profiler_agent": { + "$ref": "#/definitions/v1QANMongoDBProfilerAgent" + }, + "qan_mongodb_mongolog_agent": { + "$ref": "#/definitions/v1QANMongoDBMongologAgent" + }, + "qan_postgresql_pgstatements_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" + }, + "qan_postgresql_pgstatmonitor_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" + }, + "nomad_agent": { + "$ref": "#/definitions/v1NomadAgent" + }, + "valkey_exporter": { + "$ref": "#/definitions/v1ValkeyExporter" + }, + "rta_mongodb_agent": { + "$ref": "#/definitions/v1RTAMongoDBAgent" + } + } + }, + "v1ChangeAzureDatabaseExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "azure_client_id": { + "type": "string", + "x-nullable": true, + "title": "Azure client ID" + }, + "azure_client_secret": { + "type": "string", + "x-nullable": true, + "title": "Azure client secret" + }, + "azure_tenant_id": { + "type": "string", + "x-nullable": true, + "title": "Azure tenant ID" + }, + "azure_subscription_id": { + "type": "string", + "x-nullable": true, + "title": "Azure subscription ID" + }, + "azure_resource_group": { + "type": "string", + "x-nullable": true, + "description": "Azure resource group." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeExternalExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "HTTP basic auth username for collecting metrics." + }, + "scheme": { + "type": "string", + "x-nullable": true, + "description": "Scheme to generate URI to exporter metrics endpoints." + }, + "metrics_path": { + "type": "string", + "x-nullable": true, + "description": "Path under which metrics are exposed, used to generate URI." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "x-nullable": true, + "description": "Listen port for scraping metrics." + } + } + }, + "v1ChangeMongoDBExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "MongoDB username for scraping metrics." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "MongoDB password for scraping metrics." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "x-nullable": true, + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "x-nullable": true, + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "Certificate Authority certificate chain." + }, + "skip_connection_check": { + "type": "boolean", + "x-nullable": true, + "description": "Skip connection check." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "authentication_mechanism": { + "type": "string", + "x-nullable": true, + "description": "Authentication mechanism." + }, + "authentication_database": { + "type": "string", + "x-nullable": true, + "description": "Authentication database." + }, + "agent_password": { + "type": "string", + "x-nullable": true, + "description": "Custom password for exporter endpoint /metrics." + }, + "stats_collections": { + "type": "array", + "items": { + "type": "string" + }, + "title": "List of collections to get stats from. Can use *" + }, + "collections_limit": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server is less than this value. 0: no limit" + }, + "enable_all_collectors": { + "type": "boolean", + "x-nullable": true, + "description": "Enable all collectors." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "x-nullable": true, + "description": "Optionally expose the exporter process on all public interfaces." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1ChangeMySQLdExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "MySQL username for scraping metrics." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "MySQL password for scraping metrics." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "x-nullable": true, + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "x-nullable": true, + "description": "Password for decrypting tls_cert." + }, + "tablestats_group_table_limit": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Tablestats group collectors will be disabled if there are more than that number of tables." + }, + "skip_connection_check": { + "type": "boolean", + "x-nullable": true, + "description": "Skip connection check." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "agent_password": { + "type": "string", + "x-nullable": true, + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "x-nullable": true, + "description": "Optionally expose the exporter process on all public interfaces." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1ChangeNodeExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "x-nullable": true, + "description": "Expose the node_exporter process on all public interfaces." + } + } + }, + "v1ChangeNomadAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + } + } + }, + "v1ChangePostgresExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "PostgreSQL username for scraping metrics." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "PostgreSQL password for scraping metrics." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "skip_connection_check": { + "type": "boolean", + "x-nullable": true, + "description": "Skip connection check." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "x-nullable": true, + "description": "TLS Certificate." + }, + "tls_key": { + "type": "string", + "x-nullable": true, + "description": "TLS Certificate Key." + }, + "agent_password": { + "type": "string", + "x-nullable": true, + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Limit of databases for auto-discovery." + }, + "expose_exporter": { + "type": "boolean", + "x-nullable": true, + "description": "Optionally expose the exporter process on all public interfaces." + }, + "max_exporter_connections": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Maximum number of connections that exporter can open to the database instance." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1ChangeProxySQLExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "ProxySQL username for scraping metrics." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "ProxySQL password for scraping metrics." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "agent_password": { + "type": "string", + "x-nullable": true, + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "x-nullable": true, + "description": "Optionally expose the exporter process on all public interfaces." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1ChangeQANMongoDBMongologAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "MongoDB username for getting mongolog data." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "MongoDB password for getting mongolog data." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "x-nullable": true, + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "x-nullable": true, + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "Certificate Authority certificate chain." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "authentication_mechanism": { + "type": "string", + "x-nullable": true, + "description": "Authentication mechanism." + }, + "authentication_database": { + "type": "string", + "x-nullable": true, + "description": "Authentication database." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeQANMongoDBProfilerAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "MongoDB username for getting profile data." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "MongoDB password for getting profile data." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "x-nullable": true, + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "x-nullable": true, + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "Certificate Authority certificate chain." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "authentication_mechanism": { + "type": "string", + "x-nullable": true, + "description": "Authentication mechanism." + }, + "authentication_database": { + "type": "string", + "x-nullable": true, + "description": "Authentication database." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeQANMySQLPerfSchemaAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "MySQL username for getting performance data." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "MySQL password for getting performance data." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "x-nullable": true, + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "x-nullable": true, + "description": "Password for decrypting tls_cert." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "x-nullable": true, + "description": "Disable query examples." + }, + "skip_connection_check": { + "type": "boolean", + "x-nullable": true, + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "x-nullable": true, + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeQANMySQLSlowlogAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "MySQL username for getting slowlog data." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "MySQL password for getting slowlog data." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "x-nullable": true, + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "x-nullable": true, + "description": "Password for decrypting tls_cert." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "x-nullable": true, + "description": "Disable query examples." + }, + "max_slowlog_file_size": { + "type": "string", + "format": "int64", + "x-nullable": true, + "description": "Rotate slowlog file at this size if \u003e 0." + }, + "skip_connection_check": { + "type": "boolean", + "x-nullable": true, + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "x-nullable": true, + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeQANPostgreSQLPgStatMonitorAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "PostgreSQL username for getting pg stat monitor data." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "PostgreSQL password for getting pg stat monitor data." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "x-nullable": true, + "description": "Disable query examples." + }, + "disable_comments_parsing": { + "type": "boolean", + "x-nullable": true, + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "x-nullable": true, + "description": "TLS Certificate." + }, + "tls_key": { + "type": "string", + "x-nullable": true, + "description": "TLS Certificate Key." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeQANPostgreSQLPgStatementsAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "PostgreSQL username for getting pg stat statements data." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "PostgreSQL password for getting pg stat statements data." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "disable_comments_parsing": { + "type": "boolean", + "x-nullable": true, + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "x-nullable": true, + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "x-nullable": true, + "description": "TLS Certificate." + }, + "tls_key": { + "type": "string", + "x-nullable": true, + "description": "TLS Certificate Key." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeRDSExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "aws_access_key": { + "type": "string", + "x-nullable": true, + "description": "AWS Access Key." + }, + "aws_secret_key": { + "type": "string", + "x-nullable": true, + "description": "AWS Secret Key." + }, + "disable_basic_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Disable basic metrics." + }, + "disable_enhanced_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Disable enhanced metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + } + } + }, + "v1ChangeRTAMongoDBAgentParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "MongoDB username for getting profile data." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "MongoDB password for getting profile data." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "x-nullable": true, + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "x-nullable": true, + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "Certificate Authority certificate chain." + }, + "authentication_mechanism": { + "type": "string", + "x-nullable": true, + "description": "Authentication mechanism." + }, + "rta_options": { + "$ref": "#/definitions/v1RTAOptions", + "x-nullable": true, + "description": "Real-Time Analytics options." + } + } + }, + "v1ChangeValkeyExporterParams": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "x-nullable": true, + "description": "Enable this Agent. Agents are enabled by default when they get added." + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + }, + "enable_push_metrics": { + "type": "boolean", + "x-nullable": true, + "description": "Enables push metrics with vmagent." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "username": { + "type": "string", + "x-nullable": true, + "description": "Valkey username for scraping metrics." + }, + "password": { + "type": "string", + "x-nullable": true, + "description": "Valkey password for scraping metrics." + }, + "tls": { + "type": "boolean", + "x-nullable": true, + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "x-nullable": true, + "description": "Skip TLS certificate and hostname validation." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "tls_ca": { + "type": "string", + "x-nullable": true, + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "x-nullable": true, + "description": "TLS Certifcate." + }, + "tls_key": { + "type": "string", + "x-nullable": true, + "description": "TLS Certificate Key." + }, + "agent_password": { + "type": "string", + "x-nullable": true, + "description": "Custom password for exporter endpoint /metrics." + }, + "expose_exporter": { + "type": "boolean", + "x-nullable": true, + "title": "Optionally expose the exporter process on all public interfaces" + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "x-nullable": true, + "description": "Log level for exporter." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1ExternalExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "runs_on_node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "disabled": { + "type": "boolean", + "description": "If disabled, metrics from this exporter will not be collected." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "HTTP basic auth username for collecting metrics." + }, + "scheme": { + "type": "string", + "description": "Scheme to generate URI to exporter metrics endpoints." + }, + "metrics_path": { + "type": "string", + "description": "Path under which metrics are exposed, used to generate URI." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname verification." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + } + }, + "description": "ExternalExporter runs on any Node type, including Remote Node." + }, + "v1GetAgentLogsResponse": { + "type": "object", + "properties": { + "logs": { + "type": "array", + "items": { + "type": "string" + } + }, + "agent_config_log_lines_count": { + "type": "integer", + "format": "int64" + } + } + }, + "v1GetAgentResponse": { + "type": "object", + "properties": { + "pmm_agent": { + "$ref": "#/definitions/v1PMMAgent" + }, + "vmagent": { + "$ref": "#/definitions/v1VMAgent" + }, + "node_exporter": { + "$ref": "#/definitions/v1NodeExporter" + }, + "mysqld_exporter": { + "$ref": "#/definitions/v1MySQLdExporter" + }, + "mongodb_exporter": { + "$ref": "#/definitions/v1MongoDBExporter" + }, + "postgres_exporter": { + "$ref": "#/definitions/v1PostgresExporter" + }, + "proxysql_exporter": { + "$ref": "#/definitions/v1ProxySQLExporter" + }, + "qan_mysql_perfschema_agent": { + "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" + }, + "qan_mysql_slowlog_agent": { + "$ref": "#/definitions/v1QANMySQLSlowlogAgent" + }, + "qan_mongodb_profiler_agent": { + "$ref": "#/definitions/v1QANMongoDBProfilerAgent" + }, + "qan_mongodb_mongolog_agent": { + "$ref": "#/definitions/v1QANMongoDBMongologAgent" + }, + "qan_postgresql_pgstatements_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" + }, + "qan_postgresql_pgstatmonitor_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" + }, + "external_exporter": { + "$ref": "#/definitions/v1ExternalExporter" + }, + "rds_exporter": { + "$ref": "#/definitions/v1RDSExporter" + }, + "azure_database_exporter": { + "$ref": "#/definitions/v1AzureDatabaseExporter" + }, + "nomad_agent": { + "$ref": "#/definitions/v1NomadAgent" + }, + "valkey_exporter": { + "$ref": "#/definitions/v1ValkeyExporter" + }, + "rta_mongodb_agent": { + "$ref": "#/definitions/v1RTAMongoDBAgent" + } + } + }, + "v1ListAgentsResponse": { + "type": "object", + "properties": { + "pmm_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1PMMAgent" + } + }, + "vm_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1VMAgent" + } + }, + "node_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1NodeExporter" + } + }, + "mysqld_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MySQLdExporter" + } + }, + "mongodb_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MongoDBExporter" + } + }, + "postgres_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1PostgresExporter" + } + }, + "proxysql_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ProxySQLExporter" + } + }, + "qan_mysql_perfschema_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" + } + }, + "qan_mysql_slowlog_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QANMySQLSlowlogAgent" + } + }, + "qan_mongodb_profiler_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QANMongoDBProfilerAgent" + } + }, + "qan_mongodb_mongolog_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QANMongoDBMongologAgent" + } + }, + "qan_postgresql_pgstatements_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" + } + }, + "qan_postgresql_pgstatmonitor_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" + } + }, + "external_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ExternalExporter" + } + }, + "rds_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1RDSExporter" + } + }, + "azure_database_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1AzureDatabaseExporter" + } + }, + "nomad_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1NomadAgent" + } + }, + "valkey_exporter": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ValkeyExporter" + } + }, + "rta_mongodb_agent": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1RTAMongoDBAgent" + } + } + } + }, + "v1LogLevel": { + "type": "string", + "enum": [ + "LOG_LEVEL_UNSPECIFIED", + "LOG_LEVEL_FATAL", + "LOG_LEVEL_ERROR", + "LOG_LEVEL_WARN", + "LOG_LEVEL_INFO", + "LOG_LEVEL_DEBUG" + ], + "default": "LOG_LEVEL_UNSPECIFIED", + "description": "- LOG_LEVEL_UNSPECIFIED: Auto", + "title": "Log level for exporters" + }, + "v1MongoDBExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "stats_collections": { + "type": "array", + "items": { + "type": "string" + }, + "title": "List of colletions to get stats from. Can use *" + }, + "collections_limit": { + "type": "integer", + "format": "int32", + "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" + }, + "enable_all_collectors": { + "type": "boolean", + "description": "Enable all collectors." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "environment_variable_names": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Environment variable names passed to the exporter." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "MongoDBExporter runs on Generic or Container Node and exposes MongoDB Service metrics." + }, + "v1MySQLdExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "tablestats_group_table_limit": { + "type": "integer", + "format": "int32", + "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "table_count": { + "type": "integer", + "format": "int32", + "description": "Actual table count at the moment of adding." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "tablestats_group_disabled": { + "type": "boolean", + "description": "True if tablestats group collectors are currently disabled." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "MySQLdExporter runs on Generic or Container Node and exposes MySQL Service metrics." + }, + "v1NodeExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + } + }, + "description": "NodeExporter runs on Generic or Container Node and exposes its metrics." + }, + "v1NomadAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + } + } + }, + "v1PMMAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "runs_on_node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "connected": { + "type": "boolean", + "description": "True if Agent is running and connected to pmm-managed." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + } + }, + "description": "PMMAgent runs on Generic or Container Node." + }, + "v1PostgresExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "max_exporter_connections": { + "type": "integer", + "format": "int32", + "description": "Maximum number of connections that exporter can open to the database instance." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "PostgresExporter runs on Generic or Container Node and exposes PostgreSQL Service metrics." + }, + "v1ProxySQLExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "ProxySQL username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "ProxySQLExporter runs on Generic or Container Node and exposes ProxySQL Service metrics." + }, + "v1QANMongoDBMongologAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profiler data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANMongoDBMongologAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." + }, + "v1QANMongoDBProfilerAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profiler data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANMongoDBProfilerAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." + }, + "v1QANMySQLPerfSchemaAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for getting performance data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "query_examples_disabled": { + "type": "boolean", + "description": "True if query examples are disabled." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + } + }, + "description": "QANMySQLPerfSchemaAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." + }, + "v1QANMySQLSlowlogAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for getting performance data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "title": "Limit query length in QAN (default: server-defined; -1: no limit)" + }, + "query_examples_disabled": { + "type": "boolean", + "description": "True if query examples are disabled." + }, + "max_slowlog_file_size": { + "type": "string", + "format": "int64", + "description": "Slowlog file is rotated at this size if \u003e 0." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "title": "mod tidy" + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + } + }, + "description": "QANMySQLSlowlogAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." + }, + "v1QANPostgreSQLPgStatMonitorAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for getting pg stat monitor data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "query_examples_disabled": { + "type": "boolean", + "description": "True if query examples are disabled." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANPostgreSQLPgStatMonitorAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." + }, + "v1QANPostgreSQLPgStatementsAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for getting pg stat statements data." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANPostgreSQLPgStatementsAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." + }, + "v1RDSExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "node_id": { + "type": "string", + "description": "Node identifier." + }, + "aws_access_key": { + "type": "string", + "description": "AWS Access Key." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status (the same for several configurations)." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics (the same for several configurations)." + }, + "basic_metrics_disabled": { + "type": "boolean", + "description": "Basic metrics are disabled." + }, + "enhanced_metrics_disabled": { + "type": "boolean", + "description": "Enhanced metrics are disabled." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + } + }, + "description": "RDSExporter runs on Generic or Container Node and exposes RemoteRDS Node metrics." + }, + "v1RTAMongoDBAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique agent identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profiler data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "rta_options": { + "$ref": "#/definitions/v1RTAOptions", + "description": "Real-Time Analytics options." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "RTAMongoDBAgent runs within pmm-agent and sends MongoDB Real-Time Query Analytics data to the PMM Server." + }, + "v1RTAOptions": { + "type": "object", + "properties": { + "collect_interval": { + "type": "string", + "description": "Query collect interval (default 2s is set by server)." + } + }, + "description": "RTAOptions holds Real-Time Query Analytics agent options." + }, + "v1RemoveAgentResponse": { + "type": "object" + }, + "v1VMAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + } + }, + "description": "VMAgent runs on Generic or Container Node alongside pmm-agent.\nIt scrapes other exporter Agents that are configured with push_metrics_enabled\nand uses Prometheus remote write protocol to push metrics to PMM Server." + }, + "v1ValkeyExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "Valkey username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname verification." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "ValkeyExporter runs on Generic or Container Node and exposes Valkey Service metrics." + } + } +} diff --git a/api/inventory/v1/log_level.pb.go b/api/inventory/v1/log_level.pb.go index ff4d79ca3f2..47f0373d578 100644 --- a/api/inventory/v1/log_level.pb.go +++ b/api/inventory/v1/log_level.pb.go @@ -114,7 +114,6 @@ var ( LogLevel(0), // 0: inventory.v1.LogLevel } ) - var file_inventory_v1_log_level_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/log_level.swagger.json b/api/inventory/v1/log_level.swagger.json new file mode 100644 index 00000000000..0e16c21a9e1 --- /dev/null +++ b/api/inventory/v1/log_level.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "inventory/v1/log_level.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/inventory/v1/nodes.pb.go b/api/inventory/v1/nodes.pb.go index 447663477a9..e0186c91815 100644 --- a/api/inventory/v1/nodes.pb.go +++ b/api/inventory/v1/nodes.pb.go @@ -2043,7 +2043,6 @@ var ( nil, // 28: inventory.v1.AddRemoteAzureNodeParams.CustomLabelsEntry } ) - var file_inventory_v1_nodes_proto_depIdxs = []int32{ 19, // 0: inventory.v1.GenericNode.custom_labels:type_name -> inventory.v1.GenericNode.CustomLabelsEntry 20, // 1: inventory.v1.ContainerNode.custom_labels:type_name -> inventory.v1.ContainerNode.CustomLabelsEntry diff --git a/api/inventory/v1/nodes.swagger.json b/api/inventory/v1/nodes.swagger.json new file mode 100644 index 00000000000..32958ba155f --- /dev/null +++ b/api/inventory/v1/nodes.swagger.json @@ -0,0 +1,708 @@ +{ + "swagger": "2.0", + "info": { + "title": "inventory/v1/nodes.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "NodesService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/inventory/nodes": { + "get": { + "summary": "List Nodes", + "description": "Returns a list of all Nodes.", + "operationId": "ListNodes", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListNodesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_type", + "description": "Return only Nodes with matching Node type.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "NODE_TYPE_UNSPECIFIED", + "NODE_TYPE_GENERIC_NODE", + "NODE_TYPE_CONTAINER_NODE", + "NODE_TYPE_REMOTE_NODE", + "NODE_TYPE_REMOTE_RDS_NODE", + "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" + ], + "default": "NODE_TYPE_UNSPECIFIED" + } + ], + "tags": [ + "NodesService" + ] + }, + "post": { + "summary": "Add a Node", + "description": "Adds a Node.", + "operationId": "AddNode", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AddNodeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1AddNodeRequest" + } + } + ], + "tags": [ + "NodesService" + ] + } + }, + "/v1/inventory/nodes/{node_id}": { + "get": { + "summary": "Get a Node", + "description": "Returns a single Node by ID.", + "operationId": "GetNode", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetNodeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_id", + "description": "Unique randomly generated instance identifier.", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "NodesService" + ] + }, + "delete": { + "summary": "Remove a Node", + "description": "Removes a Node.", + "operationId": "RemoveNode", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RemoveNodeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_id", + "description": "Unique randomly generated instance identifier.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "force", + "description": "Remove node with all dependencies.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "NodesService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1AddContainerNodeParams": { + "type": "object", + "properties": { + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id of the Generic Node where this Container Node runs." + }, + "container_id": { + "type": "string", + "description": "Container identifier. If specified, must be a unique Docker container identifier." + }, + "container_name": { + "type": "string", + "description": "Container name." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddGenericNodeParams": { + "type": "object", + "properties": { + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id." + }, + "distro": { + "type": "string", + "description": "Linux distribution name and version." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddNodeRequest": { + "type": "object", + "properties": { + "generic": { + "$ref": "#/definitions/v1AddGenericNodeParams" + }, + "container": { + "$ref": "#/definitions/v1AddContainerNodeParams" + }, + "remote": { + "$ref": "#/definitions/v1AddRemoteNodeParams" + }, + "remote_rds": { + "$ref": "#/definitions/v1AddRemoteRDSNodeParams" + }, + "remote_azure": { + "$ref": "#/definitions/v1AddRemoteAzureNodeParams" + } + } + }, + "v1AddNodeResponse": { + "type": "object", + "properties": { + "generic": { + "$ref": "#/definitions/v1GenericNode" + }, + "container": { + "$ref": "#/definitions/v1ContainerNode" + }, + "remote": { + "$ref": "#/definitions/v1RemoteNode" + }, + "remote_rds": { + "$ref": "#/definitions/v1RemoteRDSNode" + }, + "remote_azure_database": { + "$ref": "#/definitions/v1RemoteAzureDatabaseNode" + } + } + }, + "v1AddRemoteAzureNodeParams": { + "type": "object", + "properties": { + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "DB instance identifier." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddRemoteNodeParams": { + "type": "object", + "properties": { + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddRemoteRDSNodeParams": { + "type": "object", + "properties": { + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "DB instance identifier." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1ContainerNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id of the Generic Node where this Container Node runs." + }, + "container_id": { + "type": "string", + "description": "Container identifier. If specified, must be a unique Docker container identifier." + }, + "container_name": { + "type": "string", + "description": "Container name." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "is_pmm_server_node": { + "type": "boolean", + "description": "True if this node is a PMM Server node (HA mode)." + } + }, + "description": "ContainerNode represents a Docker container." + }, + "v1GenericNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id." + }, + "distro": { + "type": "string", + "description": "Linux distribution name and version." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "is_pmm_server_node": { + "type": "boolean", + "description": "True if this node is a PMM Server node (HA mode)." + } + }, + "description": "GenericNode represents a bare metal server or virtual machine." + }, + "v1GetNodeResponse": { + "type": "object", + "properties": { + "generic": { + "$ref": "#/definitions/v1GenericNode" + }, + "container": { + "$ref": "#/definitions/v1ContainerNode" + }, + "remote": { + "$ref": "#/definitions/v1RemoteNode" + }, + "remote_rds": { + "$ref": "#/definitions/v1RemoteRDSNode" + }, + "remote_azure_database": { + "$ref": "#/definitions/v1RemoteAzureDatabaseNode" + } + } + }, + "v1ListNodesResponse": { + "type": "object", + "properties": { + "generic": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1GenericNode" + } + }, + "container": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ContainerNode" + } + }, + "remote": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1RemoteNode" + } + }, + "remote_rds": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1RemoteRDSNode" + } + }, + "remote_azure_database": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1RemoteAzureDatabaseNode" + } + } + } + }, + "v1NodeType": { + "type": "string", + "enum": [ + "NODE_TYPE_UNSPECIFIED", + "NODE_TYPE_GENERIC_NODE", + "NODE_TYPE_CONTAINER_NODE", + "NODE_TYPE_REMOTE_NODE", + "NODE_TYPE_REMOTE_RDS_NODE", + "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" + ], + "default": "NODE_TYPE_UNSPECIFIED", + "description": "NodeType describes supported Node types." + }, + "v1RemoteAzureDatabaseNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "DB instance identifier." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + }, + "description": "RemoteAzureDatabaseNode represents remote AzureDatabase Node. Agents can't run on Remote AzureDatabase Nodes." + }, + "v1RemoteNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + }, + "description": "RemoteNode represents generic remote Node. It's a node where we don't run pmm-agents. Only external exporters can run on Remote Nodes." + }, + "v1RemoteRDSNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "DB instance identifier." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "instance_id": { + "type": "string", + "description": "AWS instance ID." + } + }, + "description": "RemoteRDSNode represents remote RDS Node. Agents can't run on Remote RDS Nodes." + }, + "v1RemoveNodeResponse": { + "type": "object" + } + } +} diff --git a/api/inventory/v1/services.pb.go b/api/inventory/v1/services.pb.go index a8d1519b61f..23eeeb28b81 100644 --- a/api/inventory/v1/services.pb.go +++ b/api/inventory/v1/services.pb.go @@ -3334,7 +3334,6 @@ var ( (*common.StringMap)(nil), // 43: common.StringMap } ) - var file_inventory_v1_services_proto_depIdxs = []int32{ 27, // 0: inventory.v1.MySQLService.custom_labels:type_name -> inventory.v1.MySQLService.CustomLabelsEntry 28, // 1: inventory.v1.MySQLService.extra_dsn_params:type_name -> inventory.v1.MySQLService.ExtraDsnParamsEntry diff --git a/api/inventory/v1/services.swagger.json b/api/inventory/v1/services.swagger.json new file mode 100644 index 00000000000..ab118f837ff --- /dev/null +++ b/api/inventory/v1/services.swagger.json @@ -0,0 +1,1189 @@ +{ + "swagger": "2.0", + "info": { + "title": "inventory/v1/services.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "ServicesService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/inventory/services": { + "get": { + "summary": "List Services", + "description": "Returns a list of Services filtered by type.", + "operationId": "ListServices", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListServicesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_id", + "description": "Return only Services running on that Node.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "service_type", + "description": "Return only services filtered by service type.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "SERVICE_TYPE_UNSPECIFIED", + "SERVICE_TYPE_MYSQL_SERVICE", + "SERVICE_TYPE_MONGODB_SERVICE", + "SERVICE_TYPE_POSTGRESQL_SERVICE", + "SERVICE_TYPE_VALKEY_SERVICE", + "SERVICE_TYPE_PROXYSQL_SERVICE", + "SERVICE_TYPE_HAPROXY_SERVICE", + "SERVICE_TYPE_EXTERNAL_SERVICE" + ], + "default": "SERVICE_TYPE_UNSPECIFIED" + }, + { + "name": "external_group", + "description": "Return only services in this external group.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ServicesService" + ] + }, + "post": { + "summary": "Add a Service", + "description": "Adds a Service.", + "operationId": "AddService", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AddServiceResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1AddServiceRequest" + } + } + ], + "tags": [ + "ServicesService" + ] + } + }, + "/v1/inventory/services/{service_id}": { + "get": { + "summary": "Get a Service", + "description": "Returns a single Service by ID.", + "operationId": "GetService", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetServiceResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "service_id", + "description": "Unique randomly generated instance identifier.", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ServicesService" + ] + }, + "delete": { + "summary": "Remove Service", + "description": "Removes Service.", + "operationId": "RemoveService", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RemoveServiceResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "service_id", + "description": "Unique randomly generated instance identifier. Required.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "force", + "description": "Remove service with all dependencies.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "ServicesService" + ] + }, + "put": { + "summary": "Change service", + "description": "Changes service configuration. If a new cluster label is specified, it removes all backup/restore tasks scheduled for the related services. Fails if there are running backup/restore tasks.", + "operationId": "ChangeService", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ChangeServiceResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "service_id", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ServicesServiceChangeServiceBody" + } + } + ], + "tags": [ + "ServicesService" + ] + } + }, + "/v1/inventory/services:getTypes": { + "post": { + "summary": "List Active Service Types", + "description": "Returns a list of active Service types.", + "operationId": "ListActiveServiceTypes", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListActiveServiceTypesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ListActiveServiceTypesRequest" + } + } + ], + "tags": [ + "ServicesService" + ] + } + } + }, + "definitions": { + "ServicesServiceChangeServiceBody": { + "type": "object", + "properties": { + "environment": { + "type": "string", + "x-nullable": true + }, + "cluster": { + "type": "string", + "x-nullable": true + }, + "replication_set": { + "type": "string", + "x-nullable": true + }, + "external_group": { + "type": "string", + "x-nullable": true + }, + "custom_labels": { + "$ref": "#/definitions/commonStringMap", + "x-nullable": true, + "description": "Replace all custom user-assigned labels." + } + } + }, + "commonStringMap": { + "type": "object", + "properties": { + "values": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "description": "A wrapper for map[string]string. This type allows to distinguish between an empty map and a null value." + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1AddExternalServiceParams": { + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs. Required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "group": { + "type": "string", + "description": "Group name of external service." + } + } + }, + "v1AddHAProxyServiceParams": { + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs. Required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddMongoDBServiceParams": { + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs. Required." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddMySQLServiceParams": { + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs. Required." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra parameters to be added to the DSN." + } + } + }, + "v1AddPostgreSQLServiceParams": { + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs. Required." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + } + } + }, + "v1AddProxySQLServiceParams": { + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs. Required." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1AddServiceRequest": { + "type": "object", + "properties": { + "mysql": { + "$ref": "#/definitions/v1AddMySQLServiceParams" + }, + "mongodb": { + "$ref": "#/definitions/v1AddMongoDBServiceParams" + }, + "postgresql": { + "$ref": "#/definitions/v1AddPostgreSQLServiceParams" + }, + "proxysql": { + "$ref": "#/definitions/v1AddProxySQLServiceParams" + }, + "haproxy": { + "$ref": "#/definitions/v1AddHAProxyServiceParams" + }, + "external": { + "$ref": "#/definitions/v1AddExternalServiceParams" + }, + "valkey": { + "$ref": "#/definitions/v1AddValkeyServiceParams" + } + } + }, + "v1AddServiceResponse": { + "type": "object", + "properties": { + "mysql": { + "$ref": "#/definitions/v1MySQLService" + }, + "mongodb": { + "$ref": "#/definitions/v1MongoDBService" + }, + "postgresql": { + "$ref": "#/definitions/v1PostgreSQLService" + }, + "proxysql": { + "$ref": "#/definitions/v1ProxySQLService" + }, + "haproxy": { + "$ref": "#/definitions/v1HAProxyService" + }, + "external": { + "$ref": "#/definitions/v1ExternalService" + }, + "valkey": { + "$ref": "#/definitions/v1ValkeyService" + } + } + }, + "v1AddValkeyServiceParams": { + "type": "object", + "properties": { + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs. Required." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + } + }, + "v1ChangeServiceResponse": { + "type": "object", + "properties": { + "mysql": { + "$ref": "#/definitions/v1MySQLService" + }, + "mongodb": { + "$ref": "#/definitions/v1MongoDBService" + }, + "postgresql": { + "$ref": "#/definitions/v1PostgreSQLService" + }, + "proxysql": { + "$ref": "#/definitions/v1ProxySQLService" + }, + "haproxy": { + "$ref": "#/definitions/v1HAProxyService" + }, + "external": { + "$ref": "#/definitions/v1ExternalService" + }, + "valkey": { + "$ref": "#/definitions/v1ValkeyService" + } + } + }, + "v1ExternalService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this service instance runs." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "group": { + "type": "string", + "description": "Group name of external service." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP)." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port." + } + }, + "description": "ExternalService represents a generic External service instance." + }, + "v1GetServiceResponse": { + "type": "object", + "properties": { + "mysql": { + "$ref": "#/definitions/v1MySQLService" + }, + "mongodb": { + "$ref": "#/definitions/v1MongoDBService" + }, + "postgresql": { + "$ref": "#/definitions/v1PostgreSQLService" + }, + "proxysql": { + "$ref": "#/definitions/v1ProxySQLService" + }, + "haproxy": { + "$ref": "#/definitions/v1HAProxyService" + }, + "external": { + "$ref": "#/definitions/v1ExternalService" + }, + "valkey": { + "$ref": "#/definitions/v1ValkeyService" + } + } + }, + "v1HAProxyService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this service instance runs." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + }, + "description": "HAProxyService represents a generic HAProxy service instance." + }, + "v1ListActiveServiceTypesRequest": { + "type": "object" + }, + "v1ListActiveServiceTypesResponse": { + "type": "object", + "properties": { + "service_types": { + "type": "array", + "items": { + "$ref": "#/definitions/v1ServiceType" + } + } + } + }, + "v1ListServicesResponse": { + "type": "object", + "properties": { + "mysql": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MySQLService" + } + }, + "mongodb": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MongoDBService" + } + }, + "postgresql": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1PostgreSQLService" + } + }, + "proxysql": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ProxySQLService" + } + }, + "haproxy": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1HAProxyService" + } + }, + "external": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ExternalService" + } + }, + "valkey": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ValkeyService" + } + } + } + }, + "v1MongoDBService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "MongoDB version." + } + }, + "description": "MongoDBService represents a generic MongoDB instance." + }, + "v1MySQLService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "MySQL version." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra parameters to be added to the DSN." + } + }, + "description": "MySQLService represents a generic MySQL instance." + }, + "v1PostgreSQLService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "database_name": { + "type": "string", + "description": "Database name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "PostgreSQL version." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + } + }, + "description": "PostgreSQLService represents a generic PostgreSQL instance." + }, + "v1ProxySQLService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "ProxySQL version." + } + }, + "description": "ProxySQLService represents a generic ProxySQL instance." + }, + "v1RemoveServiceResponse": { + "type": "object" + }, + "v1ServiceType": { + "type": "string", + "enum": [ + "SERVICE_TYPE_UNSPECIFIED", + "SERVICE_TYPE_MYSQL_SERVICE", + "SERVICE_TYPE_MONGODB_SERVICE", + "SERVICE_TYPE_POSTGRESQL_SERVICE", + "SERVICE_TYPE_VALKEY_SERVICE", + "SERVICE_TYPE_PROXYSQL_SERVICE", + "SERVICE_TYPE_HAPROXY_SERVICE", + "SERVICE_TYPE_EXTERNAL_SERVICE" + ], + "default": "SERVICE_TYPE_UNSPECIFIED", + "description": "ServiceType describes supported Service types." + }, + "v1ValkeyService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "Valkey version." + } + }, + "description": "ValkeyService represents a generic Valkey instance." + } + } +} diff --git a/api/management/v1/agent.pb.go b/api/management/v1/agent.pb.go index c76c750f869..8a745a48910 100644 --- a/api/management/v1/agent.pb.go +++ b/api/management/v1/agent.pb.go @@ -1241,7 +1241,6 @@ var ( (*durationpb.Duration)(nil), // 17: google.protobuf.Duration } ) - var file_management_v1_agent_proto_depIdxs = []int32{ 8, // 0: management.v1.UniversalAgent.azure_options:type_name -> management.v1.UniversalAgent.AzureOptions 14, // 1: management.v1.UniversalAgent.created_at:type_name -> google.protobuf.Timestamp diff --git a/api/management/v1/agent.swagger.json b/api/management/v1/agent.swagger.json new file mode 100644 index 00000000000..66ea6d4a070 --- /dev/null +++ b/api/management/v1/agent.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/agent.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/annotation.pb.go b/api/management/v1/annotation.pb.go index ec781561e4c..53bbe233c1b 100644 --- a/api/management/v1/annotation.pb.go +++ b/api/management/v1/annotation.pb.go @@ -164,7 +164,6 @@ var ( (*AddAnnotationResponse)(nil), // 1: management.v1.AddAnnotationResponse } ) - var file_management_v1_annotation_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/annotation.swagger.json b/api/management/v1/annotation.swagger.json new file mode 100644 index 00000000000..3d5937159fb --- /dev/null +++ b/api/management/v1/annotation.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/annotation.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/azure.pb.go b/api/management/v1/azure.pb.go index 04a05c47ec1..863cff6d5ab 100644 --- a/api/management/v1/azure.pb.go +++ b/api/management/v1/azure.pb.go @@ -726,7 +726,6 @@ var ( (*durationpb.Duration)(nil), // 7: google.protobuf.Duration } ) - var file_management_v1_azure_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverAzureDatabaseInstance.type:type_name -> management.v1.DiscoverAzureDatabaseType 2, // 1: management.v1.DiscoverAzureDatabaseResponse.azure_database_instance:type_name -> management.v1.DiscoverAzureDatabaseInstance diff --git a/api/management/v1/azure.swagger.json b/api/management/v1/azure.swagger.json new file mode 100644 index 00000000000..83b5bc19d33 --- /dev/null +++ b/api/management/v1/azure.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/azure.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/external.pb.go b/api/management/v1/external.pb.go index 3632121e1c2..d990cb53abe 100644 --- a/api/management/v1/external.pb.go +++ b/api/management/v1/external.pb.go @@ -355,7 +355,6 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) - var file_management_v1_external_proto_depIdxs = []int32{ 3, // 0: management.v1.AddExternalServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddExternalServiceParams.custom_labels:type_name -> management.v1.AddExternalServiceParams.CustomLabelsEntry diff --git a/api/management/v1/external.swagger.json b/api/management/v1/external.swagger.json new file mode 100644 index 00000000000..ee98890ec3a --- /dev/null +++ b/api/management/v1/external.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/external.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/haproxy.pb.go b/api/management/v1/haproxy.pb.go index f3de5158762..95cad534323 100644 --- a/api/management/v1/haproxy.pb.go +++ b/api/management/v1/haproxy.pb.go @@ -333,7 +333,6 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) - var file_management_v1_haproxy_proto_depIdxs = []int32{ 3, // 0: management.v1.AddHAProxyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddHAProxyServiceParams.custom_labels:type_name -> management.v1.AddHAProxyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/haproxy.swagger.json b/api/management/v1/haproxy.swagger.json new file mode 100644 index 00000000000..456d36f1f16 --- /dev/null +++ b/api/management/v1/haproxy.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/haproxy.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/metrics.pb.go b/api/management/v1/metrics.pb.go index 748642db7cb..b552c7955fb 100644 --- a/api/management/v1/metrics.pb.go +++ b/api/management/v1/metrics.pb.go @@ -103,7 +103,6 @@ var ( MetricsMode(0), // 0: management.v1.MetricsMode } ) - var file_management_v1_metrics_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/metrics.swagger.json b/api/management/v1/metrics.swagger.json new file mode 100644 index 00000000000..48c8c4ec4ca --- /dev/null +++ b/api/management/v1/metrics.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/metrics.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/mongodb.pb.go b/api/management/v1/mongodb.pb.go index c25cc4f8282..aad151306df 100644 --- a/api/management/v1/mongodb.pb.go +++ b/api/management/v1/mongodb.pb.go @@ -559,7 +559,6 @@ var ( (*v1.RTAMongoDBAgent)(nil), // 11: inventory.v1.RTAMongoDBAgent } ) - var file_management_v1_mongodb_proto_depIdxs = []int32{ 3, // 0: management.v1.AddMongoDBServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMongoDBServiceParams.custom_labels:type_name -> management.v1.AddMongoDBServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mongodb.swagger.json b/api/management/v1/mongodb.swagger.json new file mode 100644 index 00000000000..2722b769cf7 --- /dev/null +++ b/api/management/v1/mongodb.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/mongodb.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/mysql.pb.go b/api/management/v1/mysql.pb.go index 18f64740d99..70660a14379 100644 --- a/api/management/v1/mysql.pb.go +++ b/api/management/v1/mysql.pb.go @@ -545,7 +545,6 @@ var ( (*v1.QANMySQLSlowlogAgent)(nil), // 11: inventory.v1.QANMySQLSlowlogAgent } ) - var file_management_v1_mysql_proto_depIdxs = []int32{ 4, // 0: management.v1.AddMySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMySQLServiceParams.custom_labels:type_name -> management.v1.AddMySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mysql.swagger.json b/api/management/v1/mysql.swagger.json new file mode 100644 index 00000000000..f0be3fa24f2 --- /dev/null +++ b/api/management/v1/mysql.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/mysql.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/node.pb.go b/api/management/v1/node.pb.go index 149fb30ad94..53bb2be68db 100644 --- a/api/management/v1/node.pb.go +++ b/api/management/v1/node.pb.go @@ -1255,7 +1255,6 @@ var ( (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp } ) - var file_management_v1_node_proto_depIdxs = []int32{ 16, // 0: management.v1.AddNodeParams.node_type:type_name -> inventory.v1.NodeType 11, // 1: management.v1.AddNodeParams.custom_labels:type_name -> management.v1.AddNodeParams.CustomLabelsEntry diff --git a/api/management/v1/node.swagger.json b/api/management/v1/node.swagger.json new file mode 100644 index 00000000000..87f7e2581d0 --- /dev/null +++ b/api/management/v1/node.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/node.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/postgresql.pb.go b/api/management/v1/postgresql.pb.go index 0271ba48788..0e6f54ad033 100644 --- a/api/management/v1/postgresql.pb.go +++ b/api/management/v1/postgresql.pb.go @@ -535,7 +535,6 @@ var ( (*v1.QANPostgreSQLPgStatMonitorAgent)(nil), // 10: inventory.v1.QANPostgreSQLPgStatMonitorAgent } ) - var file_management_v1_postgresql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddPostgreSQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddPostgreSQLServiceParams.custom_labels:type_name -> management.v1.AddPostgreSQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/postgresql.swagger.json b/api/management/v1/postgresql.swagger.json new file mode 100644 index 00000000000..a4694fd37f7 --- /dev/null +++ b/api/management/v1/postgresql.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/postgresql.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/proxysql.pb.go b/api/management/v1/proxysql.pb.go index e3142ed85df..7d9dbbcfc07 100644 --- a/api/management/v1/proxysql.pb.go +++ b/api/management/v1/proxysql.pb.go @@ -395,7 +395,6 @@ var ( (*v1.ProxySQLExporter)(nil), // 8: inventory.v1.ProxySQLExporter } ) - var file_management_v1_proxysql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddProxySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddProxySQLServiceParams.custom_labels:type_name -> management.v1.AddProxySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/proxysql.swagger.json b/api/management/v1/proxysql.swagger.json new file mode 100644 index 00000000000..64f40cbe45f --- /dev/null +++ b/api/management/v1/proxysql.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/proxysql.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/rds.pb.go b/api/management/v1/rds.pb.go index d338efd3738..fb882ea8de5 100644 --- a/api/management/v1/rds.pb.go +++ b/api/management/v1/rds.pb.go @@ -854,7 +854,6 @@ var ( (*v1.QANPostgreSQLPgStatementsAgent)(nil), // 16: inventory.v1.QANPostgreSQLPgStatementsAgent } ) - var file_management_v1_rds_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverRDSInstance.engine:type_name -> management.v1.DiscoverRDSEngine 1, // 1: management.v1.DiscoverRDSResponse.rds_instances:type_name -> management.v1.DiscoverRDSInstance diff --git a/api/management/v1/rds.swagger.json b/api/management/v1/rds.swagger.json new file mode 100644 index 00000000000..a03802476a3 --- /dev/null +++ b/api/management/v1/rds.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/rds.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index cbad04b7f53..6ea52fbc973 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -1005,7 +1005,6 @@ var ( (*AddAzureDatabaseResponse)(nil), // 47: management.v1.AddAzureDatabaseResponse } ) - var file_management_v1_service_proto_depIdxs = []int32{ 9, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams 10, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams diff --git a/api/management/v1/service.swagger.json b/api/management/v1/service.swagger.json new file mode 100644 index 00000000000..9ac693741d0 --- /dev/null +++ b/api/management/v1/service.swagger.json @@ -0,0 +1,4547 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/service.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "ManagementService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/management/agents": { + "get": { + "summary": "List Agents", + "description": "Lists Agents with filter.", + "operationId": "ListAgents", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListAgentsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "service_id", + "description": "Return only Agents that relate to a specific ServiceID.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "node_id", + "description": "Return only Agents that relate to a specific NodeID.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/agents/versions": { + "get": { + "summary": "List Agent Versions", + "description": "Lists Agent versions and their update severity.", + "operationId": "ListAgentVersions", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListAgentVersionsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/annotations": { + "post": { + "summary": "Add an Annotation", + "description": "Adds an annotation.", + "operationId": "AddAnnotation", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AddAnnotationResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "AddAnnotationRequest is a params to add new annotation.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1AddAnnotationRequest" + } + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/nodes": { + "get": { + "summary": "List Nodes", + "description": "Lists Nodes with filter.", + "operationId": "ListNodes", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListNodesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_type", + "description": "Node type to be filtered out.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "NODE_TYPE_UNSPECIFIED", + "NODE_TYPE_GENERIC_NODE", + "NODE_TYPE_CONTAINER_NODE", + "NODE_TYPE_REMOTE_NODE", + "NODE_TYPE_REMOTE_RDS_NODE", + "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" + ], + "default": "NODE_TYPE_UNSPECIFIED" + } + ], + "tags": [ + "ManagementService" + ] + }, + "post": { + "summary": "Register a Node", + "description": "Registers a new Node and a pmm-agent.", + "operationId": "RegisterNode", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RegisterNodeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1RegisterNodeRequest" + } + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/nodes/{node_id}": { + "get": { + "summary": "Get Node", + "description": "Gets a single Node by ID.", + "operationId": "GetNode", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetNodeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_id", + "description": "Unique Node identifier.", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "ManagementService" + ] + }, + "delete": { + "summary": "Unregister a Node", + "description": "Unregisters a Node and pmm-agent", + "operationId": "UnregisterNode", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UnregisterNodeResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_id", + "description": "Node_id to be unregistered.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "force", + "description": "Force delete node, related service account, even if it has more service tokens attached.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/services": { + "get": { + "summary": "List Services", + "description": "Returns a filtered list of Services.", + "operationId": "ListServices", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListServicesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "node_id", + "description": "Return only Services running on that Node.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "service_type", + "description": "Return only services filtered by service type.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "SERVICE_TYPE_UNSPECIFIED", + "SERVICE_TYPE_MYSQL_SERVICE", + "SERVICE_TYPE_MONGODB_SERVICE", + "SERVICE_TYPE_POSTGRESQL_SERVICE", + "SERVICE_TYPE_VALKEY_SERVICE", + "SERVICE_TYPE_PROXYSQL_SERVICE", + "SERVICE_TYPE_HAPROXY_SERVICE", + "SERVICE_TYPE_EXTERNAL_SERVICE" + ], + "default": "SERVICE_TYPE_UNSPECIFIED" + }, + { + "name": "external_group", + "description": "Return only services in this external group.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ManagementService" + ] + }, + "post": { + "summary": "Add a Service", + "description": "Adds a service and starts several agents.", + "operationId": "AddService", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AddServiceResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1AddServiceRequest" + } + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/services/azure": { + "post": { + "summary": "Add Azure Database", + "description": "Adds an Azure Database instance.", + "operationId": "AddAzureDatabase", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1AddAzureDatabaseResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1AddAzureDatabaseRequest" + } + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/services/{service_id}": { + "delete": { + "summary": "Remove a Service", + "description": "Removes a Service along with its Agents.", + "operationId": "RemoveService", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1RemoveServiceResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "service_id", + "description": "Either a Service ID or a Service Name.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "service_type", + "description": "Service type.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "SERVICE_TYPE_UNSPECIFIED", + "SERVICE_TYPE_MYSQL_SERVICE", + "SERVICE_TYPE_MONGODB_SERVICE", + "SERVICE_TYPE_POSTGRESQL_SERVICE", + "SERVICE_TYPE_VALKEY_SERVICE", + "SERVICE_TYPE_PROXYSQL_SERVICE", + "SERVICE_TYPE_HAPROXY_SERVICE", + "SERVICE_TYPE_EXTERNAL_SERVICE" + ], + "default": "SERVICE_TYPE_UNSPECIFIED" + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/services:discoverAzure": { + "post": { + "summary": "Discover Azure Database", + "description": "Discovers Azure Database for MySQL, MariaDB and PostgreSQL Server instances.", + "operationId": "DiscoverAzureDatabase", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1DiscoverAzureDatabaseResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "DiscoverAzureDatabaseRequest discover azure databases request.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1DiscoverAzureDatabaseRequest" + } + } + ], + "tags": [ + "ManagementService" + ] + } + }, + "/v1/management/services:discoverRDS": { + "post": { + "summary": "Discover RDS", + "description": "Discovers RDS instances.", + "operationId": "DiscoverRDS", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1DiscoverRDSResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googleRpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1DiscoverRDSRequest" + } + } + ], + "tags": [ + "ManagementService" + ] + } + } + }, + "definitions": { + "UniversalAgentAzureOptions": { + "type": "object", + "properties": { + "client_id": { + "type": "string", + "description": "Azure client ID." + }, + "is_client_secret_set": { + "type": "boolean", + "description": "True if Azure client secret is set." + }, + "resource_group": { + "type": "string", + "description": "Azure resource group." + }, + "subscription_id": { + "type": "string", + "description": "Azure subscription ID." + }, + "tenant_id": { + "type": "string", + "description": "Azure tenant ID." + } + } + }, + "UniversalAgentMongoDBOptions": { + "type": "object", + "properties": { + "is_tls_certificate_key_set": { + "type": "boolean", + "description": "True if TLS certificate is set." + }, + "is_tls_certificate_key_file_password_set": { + "type": "boolean", + "description": "True if TLS certificate file password is set." + }, + "authentication_mechanism": { + "type": "string", + "description": "MongoDB auth mechanism." + }, + "authentication_database": { + "type": "string", + "description": "MongoDB auth database." + }, + "stats_collections": { + "type": "array", + "items": { + "type": "string" + }, + "description": "MongoDB stats collections." + }, + "collections_limit": { + "type": "integer", + "format": "int32", + "description": "MongoDB collections limit." + }, + "enable_all_collectors": { + "type": "boolean", + "description": "True if all collectors are enabled." + } + } + }, + "UniversalAgentMySQLOptions": { + "type": "object", + "properties": { + "is_tls_key_set": { + "type": "boolean", + "description": "True if TLS key is set." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + } + } + }, + "UniversalAgentPostgreSQLOptions": { + "type": "object", + "properties": { + "is_ssl_key_set": { + "type": "boolean", + "description": "True if TLS key is set." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + }, + "max_exporter_connections": { + "type": "integer", + "format": "int32", + "description": "Maximum number of connections from exporter to PostgreSQL instance." + } + } + }, + "UniversalAgentValkeyOptions": { + "type": "object" + }, + "UniversalNodeAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique Agent identifier." + }, + "agent_type": { + "type": "string", + "description": "Agent type." + }, + "status": { + "type": "string", + "description": "Actual Agent status." + }, + "is_connected": { + "type": "boolean", + "description": "True if Agent is running and connected to pmm-managed." + } + } + }, + "UniversalNodeService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique Service identifier." + }, + "service_type": { + "type": "string", + "description": "Service type." + }, + "service_name": { + "type": "string", + "description": "Service name." + } + }, + "description": "Service represents a service running on a node." + }, + "commonMetricsResolutions": { + "type": "object", + "properties": { + "hr": { + "type": "string", + "description": "High resolution. In JSON should be represented as a string with number of seconds with `s` suffix." + }, + "mr": { + "type": "string", + "description": "Medium resolution. In JSON should be represented as a string with number of seconds with `s` suffix." + }, + "lr": { + "type": "string", + "description": "Low resolution. In JSON should be represented as a string with number of seconds with `s` suffix." + } + }, + "description": "MetricsResolutions represents Prometheus exporters metrics resolutions." + }, + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "v1AddAnnotationRequest": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "An annotation description. Required." + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags are used to filter annotations." + }, + "node_name": { + "type": "string", + "description": "Used for annotating a node." + }, + "service_names": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Used for annotating services." + } + }, + "description": "AddAnnotationRequest is a params to add new annotation." + }, + "v1AddAnnotationResponse": { + "type": "object" + }, + "v1AddAzureDatabaseRequest": { + "type": "object", + "properties": { + "region": { + "type": "string", + "description": "Azure database location." + }, + "az": { + "type": "string", + "description": "Azure database availability zone." + }, + "instance_id": { + "type": "string", + "description": "Azure database instance ID." + }, + "node_model": { + "type": "string", + "description": "Represents a purchasable Stock Keeping Unit (SKU) under a product.\nhttps://docs.microsoft.com/en-us/partner-center/develop/product-resources#sku." + }, + "address": { + "type": "string", + "description": "Address used to connect to it." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name. Defaults to Azure Database instance ID." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Defaults to Azure Database instance ID." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "username": { + "type": "string", + "description": "Username for scraping metrics." + }, + "password": { + "type": "string", + "description": "Password for scraping metrics." + }, + "azure_client_id": { + "type": "string", + "description": "Azure client ID." + }, + "azure_client_secret": { + "type": "string", + "description": "Azure client secret." + }, + "azure_tenant_id": { + "type": "string", + "description": "Azure tanant ID." + }, + "azure_subscription_id": { + "type": "string", + "description": "Azure subscription ID." + }, + "azure_resource_group": { + "type": "string", + "description": "Azure resource group." + }, + "azure_database_exporter": { + "type": "boolean", + "description": "If true, adds azure_database_exporter." + }, + "qan": { + "type": "boolean", + "description": "If true, adds qan-mysql-perfschema-agent or qan-postgresql-pgstatements-agent." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Node and Service." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "disable_query_examples": { + "type": "boolean", + "description": "Disable query examples." + }, + "tablestats_group_table_limit": { + "type": "integer", + "format": "int32", + "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\nIf zero, server's default value is used.\nUse negative value to disable them." + }, + "type": { + "$ref": "#/definitions/v1DiscoverAzureDatabaseType", + "title": "Azure database resource type (mysql, maria, postgres)" + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddAzureDatabaseResponse": { + "type": "object" + }, + "v1AddExternalServiceParams": { + "type": "object", + "properties": { + "runs_on_node_id": { + "type": "string", + "description": "Node identifier on which an external exporter is been running.\nruns_on_node_id should always be passed with node_id.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "node_name": { + "type": "string", + "description": "Node name on which a service and node is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "add_node": { + "$ref": "#/definitions/v1AddNodeParams", + "description": "Create a new Node with those parameters.\nadd_node should always be passed with address.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "address": { + "type": "string", + "description": "Node and Exporter access address (DNS name or IP).\naddress should always be passed with add_node." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "username": { + "type": "string", + "description": "HTTP basic auth username for collecting metrics." + }, + "password": { + "type": "string", + "description": "HTTP basic auth password for collecting metrics." + }, + "scheme": { + "type": "string", + "description": "Scheme to generate URI to exporter metrics endpoints." + }, + "metrics_path": { + "type": "string", + "description": "Path under which metrics are exposed, used to generate URI." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "node_id": { + "type": "string", + "description": "Node identifier on which an external service is been running.\nnode_id should always be passed with runs_on_node_id." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "group": { + "type": "string", + "description": "Group name of external service." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically.\nNode with registered pmm_agent_id must present at pmm-server\nin case of push metrics_mode." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + } + } + }, + "v1AddHAProxyServiceParams": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Node identifier on which an external exporter is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "node_name": { + "type": "string", + "description": "Node name on which a service and node is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "add_node": { + "$ref": "#/definitions/v1AddNodeParams", + "description": "Create a new Node with those parameters.\nadd_node always should be passed with address.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "address": { + "type": "string", + "description": "Node and Exporter access address (DNS name or IP).\naddress always should be passed with add_node." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "username": { + "type": "string", + "description": "HTTP basic auth username for collecting metrics." + }, + "password": { + "type": "string", + "description": "HTTP basic auth password for collecting metrics." + }, + "scheme": { + "type": "string", + "description": "Scheme to generate URI to exporter metrics endpoints." + }, + "metrics_path": { + "type": "string", + "description": "Path under which metrics are exposed, used to generate URI." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically.\nNode with registered pmm_agent_id must present at pmm-server\nin case of push metrics_mode." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + } + } + }, + "v1AddMongoDBServiceParams": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "node_name": { + "type": "string", + "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "add_node": { + "$ref": "#/definitions/v1AddNodeParams", + "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "address": { + "type": "string", + "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Service Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Service Access socket.\nAddress (and port) or socket is required." + }, + "pmm_agent_id": { + "type": "string", + "description": "The \"pmm-agent\" identifier which should run agents. Required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "username": { + "type": "string", + "description": "MongoDB username for exporter and QAN agent access." + }, + "password": { + "type": "string", + "description": "MongoDB password for exporter and QAN agent access." + }, + "qan_mongodb_profiler": { + "type": "boolean", + "description": "If true, adds qan-mongodb-profiler-agent for provided service." + }, + "qan_mongodb_mongolog": { + "type": "boolean", + "description": "If true, adds qan-mongodb-mongolog-agent for provided service." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_certificate_key": { + "type": "string", + "description": "Client certificate and key." + }, + "tls_certificate_key_file_password": { + "type": "string", + "description": "Password for decrypting tls_certificate_key." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "authentication_mechanism": { + "type": "string", + "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." + }, + "authentication_database": { + "type": "string", + "description": "Authentication database." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "stats_collections": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collections to get stats from. Can use * ." + }, + "collections_limit": { + "type": "integer", + "format": "int32", + "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" + }, + "enable_all_collectors": { + "type": "boolean", + "title": "Enable all collectors" + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "title": "Exporter log level" + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "environment_variable_names": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Environment variable names to pass to the exporter.\nValues will be resolved from pmm-agent's environment when starting the exporter." + }, + "rta_mongodb_agent": { + "type": "boolean", + "description": "If true, adds Real-Time Analytics agent for the provided service." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddMySQLServiceParams": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "node_name": { + "type": "string", + "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "add_node": { + "$ref": "#/definitions/v1AddNodeParams", + "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "address": { + "type": "string", + "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Service Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Service Access socket.\nAddress (and port) or socket is required." + }, + "pmm_agent_id": { + "type": "string", + "description": "The \"pmm-agent\" identifier which should run agents. Required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "username": { + "type": "string", + "description": "MySQL username for scraping metrics." + }, + "password": { + "type": "string", + "description": "MySQL password for scraping metrics." + }, + "qan_mysql_perfschema": { + "type": "boolean", + "description": "If true, adds qan-mysql-perfschema-agent for provided service." + }, + "qan_mysql_slowlog": { + "type": "boolean", + "description": "If true, adds qan-mysql-slowlog-agent for provided service." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "description": "Disable query examples." + }, + "max_slowlog_file_size": { + "type": "string", + "format": "int64", + "description": "If qan-mysql-slowlog-agent is added, slowlog file is rotated at this size if \u003e 0.\nIf zero, server's default value is used.\nUse negative value to disable rotation." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "tablestats_group_table_limit": { + "type": "integer", + "format": "int32", + "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\nIf zero, server's default value is used.\nUse negative value to disable them." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "title": "Exporter log level" + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "extra DSN parameters to be used for connecting to MySQL." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddNodeParams": { + "type": "object", + "properties": { + "node_type": { + "$ref": "#/definitions/v1NodeType", + "description": "Node type to be registered." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id." + }, + "distro": { + "type": "string", + "description": "Linux distribution name and version." + }, + "container_id": { + "type": "string", + "description": "Container identifier. If specified, must be a unique Docker container identifier." + }, + "container_name": { + "type": "string", + "description": "Container name." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Node." + } + }, + "description": "AddNodeParams holds node params and is used to add new node to inventory while adding new service." + }, + "v1AddPostgreSQLServiceParams": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "node_name": { + "type": "string", + "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "add_node": { + "$ref": "#/definitions/v1AddNodeParams", + "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "address": { + "type": "string", + "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Service Access port.\nPort is required when the address present." + }, + "database": { + "type": "string", + "description": "Database name." + }, + "socket": { + "type": "string", + "description": "Service Access socket.\nAddress (and port) or socket is required." + }, + "pmm_agent_id": { + "type": "string", + "description": "The \"pmm-agent\" identifier which should run agents. Required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for scraping metrics." + }, + "password": { + "type": "string", + "description": "PostgreSQL password for scraping metrics." + }, + "qan_postgresql_pgstatements_agent": { + "type": "boolean", + "description": "If true, adds qan-postgresql-pgstatements-agent for provided service." + }, + "qan_postgresql_pgstatmonitor_agent": { + "type": "boolean", + "description": "If true, adds qan-postgresql-pgstatmonitor-agent for provided service." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "disable_query_examples": { + "type": "boolean", + "description": "Disable query examples." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "tls_ca": { + "type": "string", + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "description": "TLS Certifcate." + }, + "tls_key": { + "type": "string", + "description": "TLS Certificate Key." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "title": "Exporter log level" + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit for auto discovery." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "max_exporter_connections": { + "type": "integer", + "format": "int32", + "description": "Maximum number of connections that exporter can open to the database instance." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddProxySQLServiceParams": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "node_name": { + "type": "string", + "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "add_node": { + "$ref": "#/definitions/v1AddNodeParams", + "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Required." + }, + "address": { + "type": "string", + "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Service Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Service Access socket.\nAddress (and port) or socket is required." + }, + "pmm_agent_id": { + "type": "string", + "description": "The \"pmm-agent\" identifier which should run agents. Required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "username": { + "type": "string", + "description": "ProxySQL username for scraping metrics." + }, + "password": { + "type": "string", + "description": "ProxySQL password for scraping metrics." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "title": "Exporter log level" + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddRDSServiceParams": { + "type": "object", + "properties": { + "region": { + "type": "string", + "description": "AWS region." + }, + "az": { + "type": "string", + "description": "AWS availability zone." + }, + "instance_id": { + "type": "string", + "description": "AWS instance ID." + }, + "node_model": { + "type": "string", + "description": "AWS instance class." + }, + "address": { + "type": "string", + "description": "Address used to connect to it." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port." + }, + "engine": { + "$ref": "#/definitions/v1DiscoverRDSEngine", + "description": "Instance engine." + }, + "pmm_agent_id": { + "type": "string", + "description": "PMM Agent ID." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name. Defaults to AWS instance ID." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name. Defaults to AWS instance ID." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "username": { + "type": "string", + "description": "Username for scraping metrics." + }, + "password": { + "type": "string", + "description": "Password for scraping metrics." + }, + "aws_access_key": { + "type": "string", + "description": "AWS Access key." + }, + "aws_secret_key": { + "type": "string", + "description": "AWS Secret key." + }, + "rds_exporter": { + "type": "boolean", + "description": "If true, adds rds_exporter." + }, + "qan_mysql_perfschema": { + "type": "boolean", + "description": "If true, adds qan-mysql-perfschema-agent." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Node and Service." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "disable_query_examples": { + "type": "boolean", + "description": "Disable query examples." + }, + "tablestats_group_table_limit": { + "type": "integer", + "format": "int32", + "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\nIf zero, server's default value is used.\nUse negative value to disable them." + }, + "disable_basic_metrics": { + "type": "boolean", + "description": "Disable basic metrics." + }, + "disable_enhanced_metrics": { + "type": "boolean", + "description": "Disable enhanced metrics." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for this exporter.\nPush metrics mode is not allowed." + }, + "qan_postgresql_pgstatements": { + "type": "boolean", + "title": "If true, add qan-pgstatements" + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "database": { + "type": "string", + "description": "Database name." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_postgresql_exporter_connections": { + "type": "integer", + "format": "int32", + "description": "Maximum number of exporter connections to PostgreSQL instance." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AddServiceRequest": { + "type": "object", + "properties": { + "mysql": { + "$ref": "#/definitions/v1AddMySQLServiceParams" + }, + "mongodb": { + "$ref": "#/definitions/v1AddMongoDBServiceParams" + }, + "postgresql": { + "$ref": "#/definitions/v1AddPostgreSQLServiceParams" + }, + "proxysql": { + "$ref": "#/definitions/v1AddProxySQLServiceParams" + }, + "haproxy": { + "$ref": "#/definitions/v1AddHAProxyServiceParams" + }, + "external": { + "$ref": "#/definitions/v1AddExternalServiceParams" + }, + "rds": { + "$ref": "#/definitions/v1AddRDSServiceParams" + }, + "valkey": { + "$ref": "#/definitions/v1AddValkeyServiceParams" + } + } + }, + "v1AddServiceResponse": { + "type": "object", + "properties": { + "mysql": { + "$ref": "#/definitions/v1MySQLServiceResult" + }, + "mongodb": { + "$ref": "#/definitions/v1MongoDBServiceResult" + }, + "postgresql": { + "$ref": "#/definitions/v1PostgreSQLServiceResult" + }, + "proxysql": { + "$ref": "#/definitions/v1ProxySQLServiceResult" + }, + "haproxy": { + "$ref": "#/definitions/v1HAProxyServiceResult" + }, + "external": { + "$ref": "#/definitions/v1ExternalServiceResult" + }, + "rds": { + "$ref": "#/definitions/v1RDSServiceResult" + }, + "valkey": { + "$ref": "#/definitions/v1ValkeyServiceResult" + } + } + }, + "v1AddValkeyServiceParams": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Node identifier on which the service is running.\nOnly one of these parameters should be present: node_id, node_name, add_node." + }, + "node_name": { + "type": "string", + "description": "Node name on which a service is running.\nOnly one of these parameters should be present: node_id, node_name, add_node." + }, + "add_node": { + "$ref": "#/definitions/v1AddNodeParams", + "description": "Create a new Node with those parameters.\nOnly one of these parameters should be present: node_id, node_name, add_node." + }, + "service_name": { + "type": "string", + "description": "User-defined name, it is required and should be unique across all services." + }, + "address": { + "type": "string", + "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Service access port.\nPort is required when the address is present." + }, + "socket": { + "type": "string", + "description": "Service access socket.\nAddress (and port) or socket is required." + }, + "pmm_agent_id": { + "type": "string", + "description": "The \"pmm-agent\" identifier which should run agents. Required." + }, + "username": { + "type": "string", + "description": "Valkey username for scraping metrics." + }, + "password": { + "type": "string", + "description": "Valkey password for scraping metrics." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "skip_connection_check": { + "type": "boolean", + "description": "Skip connection check." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for connection." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS verification." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for the Valkey exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "title": "Exporter log level" + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "tls_ca": { + "type": "string", + "description": "TLS CA certificate." + }, + "tls_cert": { + "type": "string", + "description": "TLS Certifcate." + }, + "tls_key": { + "type": "string", + "description": "TLS Certificate Key." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1AgentStatus": { + "type": "string", + "enum": [ + "AGENT_STATUS_UNSPECIFIED", + "AGENT_STATUS_STARTING", + "AGENT_STATUS_INITIALIZATION_ERROR", + "AGENT_STATUS_RUNNING", + "AGENT_STATUS_WAITING", + "AGENT_STATUS_STOPPING", + "AGENT_STATUS_DONE", + "AGENT_STATUS_UNKNOWN" + ], + "default": "AGENT_STATUS_UNSPECIFIED", + "description": "AgentStatus represents actual Agent status.\n\n - AGENT_STATUS_STARTING: Agent is starting.\n - AGENT_STATUS_INITIALIZATION_ERROR: Agent encountered error when starting.\n - AGENT_STATUS_RUNNING: Agent is running.\n - AGENT_STATUS_WAITING: Agent encountered error and will be restarted automatically soon.\n - AGENT_STATUS_STOPPING: Agent is stopping.\n - AGENT_STATUS_DONE: Agent has been stopped or disabled.\n - AGENT_STATUS_UNKNOWN: Agent is not connected, we don't know anything about it's state." + }, + "v1AgentVersions": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Agent ID." + }, + "version": { + "type": "string", + "description": "Agent version." + }, + "node_name": { + "type": "string", + "description": "Node name where the agent runs." + }, + "severity": { + "$ref": "#/definitions/v1UpdateSeverity", + "description": "Update severity." + } + } + }, + "v1ContainerNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id of the Generic Node where this Container Node runs." + }, + "container_id": { + "type": "string", + "description": "Container identifier. If specified, must be a unique Docker container identifier." + }, + "container_name": { + "type": "string", + "description": "Container name." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "is_pmm_server_node": { + "type": "boolean", + "description": "True if this node is a PMM Server node (HA mode)." + } + }, + "description": "ContainerNode represents a Docker container." + }, + "v1DiscoverAzureDatabaseInstance": { + "type": "object", + "properties": { + "instance_id": { + "type": "string", + "description": "Azure database instance ID." + }, + "region": { + "type": "string", + "description": "Azure database location." + }, + "service_name": { + "type": "string", + "description": "Azure database server name." + }, + "username": { + "type": "string", + "description": "Database username." + }, + "address": { + "type": "string", + "description": "Address used to connect to it." + }, + "azure_resource_group": { + "type": "string", + "description": "Azure Resource group." + }, + "environment": { + "type": "string", + "description": "Environment tag." + }, + "type": { + "$ref": "#/definitions/v1DiscoverAzureDatabaseType", + "description": "Database type." + }, + "az": { + "type": "string", + "description": "Azure database availability zone." + }, + "node_model": { + "type": "string", + "description": "Represents a purchasable Stock Keeping Unit (SKU) under a product.\nhttps://docs.microsoft.com/en-us/partner-center/develop/product-resources#sku." + } + }, + "description": "DiscoverAzureDatabaseInstance models an unique Azure Database instance for the list of instances returned by Discovery." + }, + "v1DiscoverAzureDatabaseRequest": { + "type": "object", + "properties": { + "azure_client_id": { + "type": "string", + "description": "Azure client ID." + }, + "azure_client_secret": { + "type": "string", + "description": "Azure client secret." + }, + "azure_tenant_id": { + "type": "string", + "description": "Azure tanant ID." + }, + "azure_subscription_id": { + "type": "string", + "description": "Azure subscription ID." + } + }, + "description": "DiscoverAzureDatabaseRequest discover azure databases request." + }, + "v1DiscoverAzureDatabaseResponse": { + "type": "object", + "properties": { + "azure_database_instance": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1DiscoverAzureDatabaseInstance" + } + } + }, + "description": "DiscoverAzureDatabaseResponse discover azure databases response." + }, + "v1DiscoverAzureDatabaseType": { + "type": "string", + "enum": [ + "DISCOVER_AZURE_DATABASE_TYPE_UNSPECIFIED", + "DISCOVER_AZURE_DATABASE_TYPE_MYSQL", + "DISCOVER_AZURE_DATABASE_TYPE_POSTGRESQL" + ], + "default": "DISCOVER_AZURE_DATABASE_TYPE_UNSPECIFIED", + "description": "DiscoverAzureDatabaseType describes supported Azure Database instance engines.\n\n - DISCOVER_AZURE_DATABASE_TYPE_MYSQL: MySQL type: microsoft.dbformysql or MariaDB type: microsoft.dbformariadb\n - DISCOVER_AZURE_DATABASE_TYPE_POSTGRESQL: PostgreSQL type: microsoft.dbformysql" + }, + "v1DiscoverRDSEngine": { + "type": "string", + "enum": [ + "DISCOVER_RDS_ENGINE_UNSPECIFIED", + "DISCOVER_RDS_ENGINE_MYSQL", + "DISCOVER_RDS_ENGINE_POSTGRESQL" + ], + "default": "DISCOVER_RDS_ENGINE_UNSPECIFIED", + "description": "DiscoverRDSEngine describes supported RDS instance engines." + }, + "v1DiscoverRDSInstance": { + "type": "object", + "properties": { + "region": { + "type": "string", + "description": "AWS region." + }, + "az": { + "type": "string", + "description": "AWS availability zone." + }, + "instance_id": { + "type": "string", + "description": "AWS instance ID." + }, + "node_model": { + "type": "string", + "description": "AWS instance class." + }, + "address": { + "type": "string", + "description": "Address used to connect to it." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port." + }, + "engine": { + "$ref": "#/definitions/v1DiscoverRDSEngine", + "description": "Instance engine." + }, + "engine_version": { + "type": "string", + "description": "Engine version." + } + }, + "description": "DiscoverRDSInstance models an unique RDS instance for the list of instances returned by Discovery." + }, + "v1DiscoverRDSRequest": { + "type": "object", + "properties": { + "aws_access_key": { + "type": "string", + "description": "AWS Access key. Optional." + }, + "aws_secret_key": { + "type": "string", + "description": "AWS Secret key. Optional." + } + } + }, + "v1DiscoverRDSResponse": { + "type": "object", + "properties": { + "rds_instances": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1DiscoverRDSInstance" + } + } + } + }, + "v1ExternalExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "runs_on_node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "disabled": { + "type": "boolean", + "description": "If disabled, metrics from this exporter will not be collected." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "HTTP basic auth username for collecting metrics." + }, + "scheme": { + "type": "string", + "description": "Scheme to generate URI to exporter metrics endpoints." + }, + "metrics_path": { + "type": "string", + "description": "Path under which metrics are exposed, used to generate URI." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname verification." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + } + }, + "description": "ExternalExporter runs on any Node type, including Remote Node." + }, + "v1ExternalService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this service instance runs." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "group": { + "type": "string", + "description": "Group name of external service." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP)." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port." + } + }, + "description": "ExternalService represents a generic External service instance." + }, + "v1ExternalServiceResult": { + "type": "object", + "properties": { + "service": { + "$ref": "#/definitions/v1ExternalService" + }, + "external_exporter": { + "$ref": "#/definitions/v1ExternalExporter" + } + } + }, + "v1GenericNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id." + }, + "distro": { + "type": "string", + "description": "Linux distribution name and version." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "is_pmm_server_node": { + "type": "boolean", + "description": "True if this node is a PMM Server node (HA mode)." + } + }, + "description": "GenericNode represents a bare metal server or virtual machine." + }, + "v1GetNodeResponse": { + "type": "object", + "properties": { + "node": { + "$ref": "#/definitions/v1UniversalNode" + } + } + }, + "v1HAProxyService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this service instance runs." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + } + }, + "description": "HAProxyService represents a generic HAProxy service instance." + }, + "v1HAProxyServiceResult": { + "type": "object", + "properties": { + "service": { + "$ref": "#/definitions/v1HAProxyService" + }, + "external_exporter": { + "$ref": "#/definitions/v1ExternalExporter" + } + } + }, + "v1ListAgentVersionsResponse": { + "type": "object", + "properties": { + "agent_versions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1AgentVersions" + }, + "description": "List of Agent versions." + } + } + }, + "v1ListAgentsResponse": { + "type": "object", + "properties": { + "agents": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1UniversalAgent" + }, + "description": "List of Agents." + } + } + }, + "v1ListNodesResponse": { + "type": "object", + "properties": { + "nodes": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1UniversalNode" + } + } + } + }, + "v1ListServicesResponse": { + "type": "object", + "properties": { + "services": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1UniversalService" + }, + "description": "List of Services." + } + } + }, + "v1LogLevel": { + "type": "string", + "enum": [ + "LOG_LEVEL_UNSPECIFIED", + "LOG_LEVEL_FATAL", + "LOG_LEVEL_ERROR", + "LOG_LEVEL_WARN", + "LOG_LEVEL_INFO", + "LOG_LEVEL_DEBUG" + ], + "default": "LOG_LEVEL_UNSPECIFIED", + "description": "- LOG_LEVEL_UNSPECIFIED: Auto", + "title": "Log level for exporters" + }, + "v1MetricsMode": { + "type": "string", + "enum": [ + "METRICS_MODE_UNSPECIFIED", + "METRICS_MODE_PULL", + "METRICS_MODE_PUSH" + ], + "default": "METRICS_MODE_UNSPECIFIED", + "description": "MetricsMode defines desired metrics mode for agent,\nit can be pull, push or auto mode chosen by server.\n\n - METRICS_MODE_UNSPECIFIED: Auto" + }, + "v1MongoDBExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "stats_collections": { + "type": "array", + "items": { + "type": "string" + }, + "title": "List of colletions to get stats from. Can use *" + }, + "collections_limit": { + "type": "integer", + "format": "int32", + "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" + }, + "enable_all_collectors": { + "type": "boolean", + "description": "Enable all collectors." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "environment_variable_names": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Environment variable names passed to the exporter." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "MongoDBExporter runs on Generic or Container Node and exposes MongoDB Service metrics." + }, + "v1MongoDBService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "MongoDB version." + } + }, + "description": "MongoDBService represents a generic MongoDB instance." + }, + "v1MongoDBServiceResult": { + "type": "object", + "properties": { + "service": { + "$ref": "#/definitions/v1MongoDBService" + }, + "mongodb_exporter": { + "$ref": "#/definitions/v1MongoDBExporter" + }, + "qan_mongodb_profiler": { + "$ref": "#/definitions/v1QANMongoDBProfilerAgent" + }, + "qan_mongodb_mongolog": { + "$ref": "#/definitions/v1QANMongoDBMongologAgent" + }, + "rta_mongodb_agent": { + "$ref": "#/definitions/v1RTAMongoDBAgent" + } + } + }, + "v1MySQLService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "MySQL version." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra parameters to be added to the DSN." + } + }, + "description": "MySQLService represents a generic MySQL instance." + }, + "v1MySQLServiceResult": { + "type": "object", + "properties": { + "service": { + "$ref": "#/definitions/v1MySQLService" + }, + "mysqld_exporter": { + "$ref": "#/definitions/v1MySQLdExporter" + }, + "qan_mysql_perfschema": { + "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" + }, + "qan_mysql_slowlog": { + "$ref": "#/definitions/v1QANMySQLSlowlogAgent" + }, + "table_count": { + "type": "integer", + "format": "int32", + "description": "Actual table count at the moment of adding." + } + } + }, + "v1MySQLdExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "tablestats_group_table_limit": { + "type": "integer", + "format": "int32", + "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "table_count": { + "type": "integer", + "format": "int32", + "description": "Actual table count at the moment of adding." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "tablestats_group_disabled": { + "type": "boolean", + "description": "True if tablestats group collectors are currently disabled." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "MySQLdExporter runs on Generic or Container Node and exposes MySQL Service metrics." + }, + "v1NodeType": { + "type": "string", + "enum": [ + "NODE_TYPE_UNSPECIFIED", + "NODE_TYPE_GENERIC_NODE", + "NODE_TYPE_CONTAINER_NODE", + "NODE_TYPE_REMOTE_NODE", + "NODE_TYPE_REMOTE_RDS_NODE", + "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" + ], + "default": "NODE_TYPE_UNSPECIFIED", + "description": "NodeType describes supported Node types." + }, + "v1PMMAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "runs_on_node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "connected": { + "type": "boolean", + "description": "True if Agent is running and connected to pmm-managed." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + } + }, + "description": "PMMAgent runs on Generic or Container Node." + }, + "v1PostgreSQLService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "database_name": { + "type": "string", + "description": "Database name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "PostgreSQL version." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + } + }, + "description": "PostgreSQLService represents a generic PostgreSQL instance." + }, + "v1PostgreSQLServiceResult": { + "type": "object", + "properties": { + "service": { + "$ref": "#/definitions/v1PostgreSQLService" + }, + "postgres_exporter": { + "$ref": "#/definitions/v1PostgresExporter" + }, + "qan_postgresql_pgstatements_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" + }, + "qan_postgresql_pgstatmonitor_agent": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" + }, + "warning": { + "type": "string", + "description": "Warning message." + } + } + }, + "v1PostgresExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "max_exporter_connections": { + "type": "integer", + "format": "int32", + "description": "Maximum number of connections that exporter can open to the database instance." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "PostgresExporter runs on Generic or Container Node and exposes PostgreSQL Service metrics." + }, + "v1ProxySQLExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "ProxySQL username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "ProxySQLExporter runs on Generic or Container Node and exposes ProxySQL Service metrics." + }, + "v1ProxySQLService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "ProxySQL version." + } + }, + "description": "ProxySQLService represents a generic ProxySQL instance." + }, + "v1ProxySQLServiceResult": { + "type": "object", + "properties": { + "service": { + "$ref": "#/definitions/v1ProxySQLService" + }, + "proxysql_exporter": { + "$ref": "#/definitions/v1ProxySQLExporter" + } + } + }, + "v1QANMongoDBMongologAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profiler data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANMongoDBMongologAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." + }, + "v1QANMongoDBProfilerAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profiler data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANMongoDBProfilerAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." + }, + "v1QANMySQLPerfSchemaAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for getting performance data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "query_examples_disabled": { + "type": "boolean", + "description": "True if query examples are disabled." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + } + }, + "description": "QANMySQLPerfSchemaAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." + }, + "v1QANMySQLSlowlogAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MySQL username for getting performance data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "tls_ca": { + "type": "string", + "description": "Certificate Authority certificate chain." + }, + "tls_cert": { + "type": "string", + "description": "Client certificate." + }, + "tls_key": { + "type": "string", + "description": "Password for decrypting tls_cert." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "title": "Limit query length in QAN (default: server-defined; -1: no limit)" + }, + "query_examples_disabled": { + "type": "boolean", + "description": "True if query examples are disabled." + }, + "max_slowlog_file_size": { + "type": "string", + "format": "int64", + "description": "Slowlog file is rotated at this size if \u003e 0." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "title": "mod tidy" + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "extra_dsn_params": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra DSN parameters for MySQL connection." + } + }, + "description": "QANMySQLSlowlogAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." + }, + "v1QANPostgreSQLPgStatMonitorAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for getting pg stat monitor data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "query_examples_disabled": { + "type": "boolean", + "description": "True if query examples are disabled." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANPostgreSQLPgStatMonitorAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." + }, + "v1QANPostgreSQLPgStatementsAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "PostgreSQL username for getting pg stat statements data." + }, + "disable_comments_parsing": { + "type": "boolean", + "description": "Disable parsing comments from queries and showing them in QAN." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN (default: server-defined; -1: no limit)." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "QANPostgreSQLPgStatementsAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." + }, + "v1RDSExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "node_id": { + "type": "string", + "description": "Node identifier." + }, + "aws_access_key": { + "type": "string", + "description": "AWS Access Key." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status (the same for several configurations)." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics (the same for several configurations)." + }, + "basic_metrics_disabled": { + "type": "boolean", + "description": "Basic metrics are disabled." + }, + "enhanced_metrics_disabled": { + "type": "boolean", + "description": "Enhanced metrics are disabled." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "auto_discovery_limit": { + "type": "integer", + "format": "int32", + "description": "Limit of databases for auto-discovery." + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + } + }, + "description": "RDSExporter runs on Generic or Container Node and exposes RemoteRDS Node metrics." + }, + "v1RDSServiceResult": { + "type": "object", + "properties": { + "node": { + "$ref": "#/definitions/v1RemoteRDSNode" + }, + "rds_exporter": { + "$ref": "#/definitions/v1RDSExporter" + }, + "mysql": { + "$ref": "#/definitions/v1MySQLService" + }, + "mysqld_exporter": { + "$ref": "#/definitions/v1MySQLdExporter" + }, + "qan_mysql_perfschema": { + "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" + }, + "postgresql": { + "$ref": "#/definitions/v1PostgreSQLService" + }, + "postgresql_exporter": { + "$ref": "#/definitions/v1PostgresExporter" + }, + "qan_postgresql_pgstatements": { + "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" + } + } + }, + "v1RTAMongoDBAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique agent identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "MongoDB username for getting profiler data." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "rta_options": { + "$ref": "#/definitions/v1RTAOptions", + "description": "Real-Time Analytics options." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + } + }, + "description": "RTAMongoDBAgent runs within pmm-agent and sends MongoDB Real-Time Query Analytics data to the PMM Server." + }, + "v1RTAOptions": { + "type": "object", + "properties": { + "collect_interval": { + "type": "string", + "description": "Query collect interval (default 2s is set by server)." + } + }, + "description": "RTAOptions holds Real-Time Query Analytics agent options." + }, + "v1RegisterNodeRequest": { + "type": "object", + "properties": { + "node_type": { + "$ref": "#/definitions/v1NodeType", + "description": "Node type to be registered." + }, + "node_name": { + "type": "string", + "description": "A user-defined name unique across all Nodes." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id." + }, + "distro": { + "type": "string", + "description": "Linux distribution name and version." + }, + "container_id": { + "type": "string", + "description": "Container identifier. If specified, must be a unique Docker container identifier." + }, + "container_name": { + "type": "string", + "description": "Container name." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Node." + }, + "reregister": { + "type": "boolean", + "description": "If true, and Node with that name already exist, it will be removed with all dependent Services and Agents." + }, + "metrics_mode": { + "$ref": "#/definitions/v1MetricsMode", + "description": "Defines metrics flow model for node_exporter being added by this request.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." + }, + "disable_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of collector names to disable in this exporter." + }, + "agent_password": { + "type": "string", + "description": "Custom password for exporter endpoint /metrics." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "instance_id": { + "type": "string", + "description": "AWS instance ID." + } + } + }, + "v1RegisterNodeResponse": { + "type": "object", + "properties": { + "generic_node": { + "$ref": "#/definitions/v1GenericNode" + }, + "container_node": { + "$ref": "#/definitions/v1ContainerNode" + }, + "pmm_agent": { + "$ref": "#/definitions/v1PMMAgent" + }, + "token": { + "type": "string", + "description": "Token represents token for vmagent auth config." + }, + "warning": { + "type": "string", + "description": "Warning message." + } + } + }, + "v1RemoteRDSNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "node_name": { + "type": "string", + "description": "Unique across all Nodes user-defined name." + }, + "address": { + "type": "string", + "description": "DB instance identifier." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "instance_id": { + "type": "string", + "description": "AWS instance ID." + } + }, + "description": "RemoteRDSNode represents remote RDS Node. Agents can't run on Remote RDS Nodes." + }, + "v1RemoveServiceResponse": { + "type": "object" + }, + "v1ServiceType": { + "type": "string", + "enum": [ + "SERVICE_TYPE_UNSPECIFIED", + "SERVICE_TYPE_MYSQL_SERVICE", + "SERVICE_TYPE_MONGODB_SERVICE", + "SERVICE_TYPE_POSTGRESQL_SERVICE", + "SERVICE_TYPE_VALKEY_SERVICE", + "SERVICE_TYPE_PROXYSQL_SERVICE", + "SERVICE_TYPE_HAPROXY_SERVICE", + "SERVICE_TYPE_EXTERNAL_SERVICE" + ], + "default": "SERVICE_TYPE_UNSPECIFIED", + "description": "ServiceType describes supported Service types." + }, + "v1UniversalAgent": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique agent identifier." + }, + "is_agent_password_set": { + "type": "boolean", + "description": "True if the agent password is set." + }, + "agent_type": { + "type": "string", + "description": "Agent type." + }, + "aws_access_key": { + "type": "string", + "description": "AWS Access Key." + }, + "is_aws_secret_key_set": { + "type": "boolean", + "description": "True if AWS Secret Key is set." + }, + "azure_options": { + "$ref": "#/definitions/UniversalAgentAzureOptions", + "description": "Options used for connecting to Azure." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "log_level": { + "$ref": "#/definitions/v1LogLevel", + "description": "Log level for exporter." + }, + "max_query_length": { + "type": "integer", + "format": "int32", + "description": "Limit query length in QAN." + }, + "max_query_log_size": { + "type": "string", + "format": "int64", + "description": "Limit query log size in QAN." + }, + "metrics_path": { + "type": "string", + "description": "Path under which metrics are exposed, used to generate URI." + }, + "metrics_scheme": { + "type": "string", + "description": "Scheme to generate URI to exporter metrics endpoints." + }, + "mongo_db_options": { + "$ref": "#/definitions/UniversalAgentMongoDBOptions", + "description": "TLS and other options for connecting to MongoDB." + }, + "mysql_options": { + "$ref": "#/definitions/UniversalAgentMySQLOptions", + "description": "TLS and other options for connecting to MySQL." + }, + "node_id": { + "type": "string", + "description": "A unique node identifier." + }, + "is_password_set": { + "type": "boolean", + "description": "True if password for connecting the agent to the database is set." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier." + }, + "postgresql_options": { + "$ref": "#/definitions/UniversalAgentPostgreSQLOptions", + "description": "TLS options for connecting to PostgreSQL." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "push_metrics": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "query_examples_disabled": { + "type": "boolean", + "description": "True if query examples are disabled." + }, + "comments_parsing_disabled": { + "type": "boolean", + "description": "True if query comments parsing is disabled." + }, + "rds_basic_metrics_disabled": { + "type": "boolean", + "description": "True if RDS basic metrics are disdabled." + }, + "rds_enhanced_metrics_disabled": { + "type": "boolean", + "description": "True if RDS enhanced metrics are disdabled." + }, + "runs_on_node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "status": { + "type": "string", + "description": "Actual Agent status." + }, + "table_count": { + "type": "integer", + "format": "int32", + "description": "Last known table count." + }, + "table_count_tablestats_group_limit": { + "type": "integer", + "format": "int32", + "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname validation." + }, + "username": { + "type": "string", + "description": "HTTP basic auth username for collecting metrics." + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp." + }, + "version": { + "type": "string", + "description": "Agent version." + }, + "is_connected": { + "type": "boolean", + "description": "True if Agent is running and connected to pmm-managed." + }, + "expose_exporter": { + "type": "boolean", + "description": "True if an exporter agent is exposed on all host addresses." + }, + "valkey_options": { + "$ref": "#/definitions/UniversalAgentValkeyOptions", + "description": "Options for connecting to Valkey." + }, + "rta_options": { + "$ref": "#/definitions/v1RTAOptions", + "description": "Real-Time Analytics options." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + } + }, + "v1UniversalNode": { + "type": "object", + "properties": { + "node_id": { + "type": "string", + "description": "Unique Node identifier." + }, + "node_type": { + "type": "string", + "description": "Node type." + }, + "node_name": { + "type": "string", + "description": "User-defined node name." + }, + "machine_id": { + "type": "string", + "description": "Linux machine-id." + }, + "distro": { + "type": "string", + "description": "Linux distribution name and version." + }, + "node_model": { + "type": "string", + "description": "Node model." + }, + "container_id": { + "type": "string", + "description": "A node's unique docker container identifier." + }, + "container_name": { + "type": "string", + "description": "Container name." + }, + "address": { + "type": "string", + "description": "Node address (DNS name or IP)." + }, + "region": { + "type": "string", + "description": "Node region." + }, + "az": { + "type": "string", + "description": "Node availability zone." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Node." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp." + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp." + }, + "status": { + "$ref": "#/definitions/v1UniversalNodeStatus", + "description": "The health status of the node." + }, + "agents": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/UniversalNodeAgent" + }, + "description": "List of agents related to this node." + }, + "services": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/UniversalNodeService" + }, + "description": "List of services running on this node." + }, + "instance_id": { + "type": "string", + "description": "Instance ID for cloud providers (e.g. AWS RDS)." + }, + "is_pmm_server_node": { + "type": "boolean", + "description": "True if this node is a PMM Server node (HA mode)." + } + } + }, + "v1UniversalNodeStatus": { + "type": "string", + "enum": [ + "STATUS_UNSPECIFIED", + "STATUS_UP", + "STATUS_DOWN", + "STATUS_UNKNOWN" + ], + "default": "STATUS_UNSPECIFIED", + "description": "Node status.\n\n - STATUS_UNSPECIFIED: Invalid status.\n - STATUS_UP: The node is up.\n - STATUS_DOWN: The node is down.\n - STATUS_UNKNOWN: The node's status cannot be known (e.g. there are no metrics yet)." + }, + "v1UniversalService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique service identifier." + }, + "service_type": { + "type": "string", + "description": "Service type." + }, + "service_name": { + "type": "string", + "description": "User-defined name unique across all Services." + }, + "database_name": { + "type": "string", + "description": "Database name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "node_name": { + "type": "string", + "description": "Node name where this instance runs." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels for Service." + }, + "external_group": { + "type": "string", + "description": "External group name." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp." + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp." + }, + "agents": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1UniversalAgent" + }, + "description": "List of agents related to this service." + }, + "status": { + "$ref": "#/definitions/v1UniversalServiceStatus", + "description": "The health status of the service." + }, + "version": { + "type": "string", + "description": "The service/database version." + } + } + }, + "v1UniversalServiceStatus": { + "type": "string", + "enum": [ + "STATUS_UNSPECIFIED", + "STATUS_UP", + "STATUS_DOWN", + "STATUS_UNKNOWN" + ], + "default": "STATUS_UNSPECIFIED", + "description": "Service status.\n\n - STATUS_UNSPECIFIED: In case we don't support the db vendor yet.\n - STATUS_UP: The service is up.\n - STATUS_DOWN: The service is down.\n - STATUS_UNKNOWN: The service's status cannot be known (e.g. there are no metrics yet)." + }, + "v1UnregisterNodeResponse": { + "type": "object", + "properties": { + "warning": { + "type": "string", + "description": "Warning message if there are more service tokens attached to service account." + } + } + }, + "v1UpdateSeverity": { + "type": "string", + "enum": [ + "UPDATE_SEVERITY_UNSPECIFIED", + "UPDATE_SEVERITY_UNSUPPORTED", + "UPDATE_SEVERITY_UP_TO_DATE", + "UPDATE_SEVERITY_REQUIRED", + "UPDATE_SEVERITY_CRITICAL" + ], + "default": "UPDATE_SEVERITY_UNSPECIFIED", + "description": " - UPDATE_SEVERITY_UNSUPPORTED: The client version is newer than the server version.\n - UPDATE_SEVERITY_UP_TO_DATE: The client version matches the server version.\n - UPDATE_SEVERITY_REQUIRED: The client's minor or patch version is older.\n - UPDATE_SEVERITY_CRITICAL: The client's major version is older." + }, + "v1ValkeyExporter": { + "type": "object", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "pmm_agent_id": { + "type": "string", + "description": "The pmm-agent identifier which runs this instance." + }, + "disabled": { + "type": "boolean", + "description": "Desired Agent status: enabled (false) or disabled (true)." + }, + "service_id": { + "type": "string", + "description": "Service identifier." + }, + "username": { + "type": "string", + "description": "Valkey username for scraping metrics." + }, + "tls": { + "type": "boolean", + "description": "Use TLS for database connections." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Skip TLS certificate and hostname verification." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "push_metrics_enabled": { + "type": "boolean", + "description": "True if exporter uses push metrics mode." + }, + "disabled_collectors": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of disabled collector names." + }, + "status": { + "$ref": "#/definitions/v1AgentStatus", + "description": "Actual Agent status." + }, + "listen_port": { + "type": "integer", + "format": "int64", + "description": "Listen port for scraping metrics." + }, + "process_exec_path": { + "type": "string", + "description": "Path to exec process." + }, + "expose_exporter": { + "type": "boolean", + "title": "Optionally expose the exporter process on all public interfaces" + }, + "metrics_resolutions": { + "$ref": "#/definitions/commonMetricsResolutions", + "description": "Metrics resolution for this agent." + }, + "connection_timeout": { + "type": "string", + "description": "Connection timeout for exporter (if set)." + } + }, + "description": "ValkeyExporter runs on Generic or Container Node and exposes Valkey Service metrics." + }, + "v1ValkeyService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "Valkey version." + } + }, + "description": "ValkeyService represents a generic Valkey instance." + }, + "v1ValkeyServiceResult": { + "type": "object", + "properties": { + "service": { + "$ref": "#/definitions/v1ValkeyService" + }, + "valkey_exporter": { + "$ref": "#/definitions/v1ValkeyExporter" + } + } + } + } +} diff --git a/api/management/v1/severity.pb.go b/api/management/v1/severity.pb.go index 6a14d366aa6..51c04a93a0e 100644 --- a/api/management/v1/severity.pb.go +++ b/api/management/v1/severity.pb.go @@ -125,7 +125,6 @@ var ( Severity(0), // 0: management.v1.Severity } ) - var file_management_v1_severity_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/severity.swagger.json b/api/management/v1/severity.swagger.json new file mode 100644 index 00000000000..251bda17116 --- /dev/null +++ b/api/management/v1/severity.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/severity.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/management/v1/valkey.pb.go b/api/management/v1/valkey.pb.go index a0fc2f73fe2..26cc4db7f99 100644 --- a/api/management/v1/valkey.pb.go +++ b/api/management/v1/valkey.pb.go @@ -417,7 +417,6 @@ var ( (*v1.ValkeyExporter)(nil), // 8: inventory.v1.ValkeyExporter } ) - var file_management_v1_valkey_proto_depIdxs = []int32{ 3, // 0: management.v1.AddValkeyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddValkeyServiceParams.custom_labels:type_name -> management.v1.AddValkeyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/valkey.swagger.json b/api/management/v1/valkey.swagger.json new file mode 100644 index 00000000000..a0170f19df2 --- /dev/null +++ b/api/management/v1/valkey.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "management/v1/valkey.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "googleRpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + } + } +} diff --git a/api/qan/v1/collector.pb.go b/api/qan/v1/collector.pb.go index b680bbd8f77..3716a3a24d1 100644 --- a/api/qan/v1/collector.pb.go +++ b/api/qan/v1/collector.pb.go @@ -2757,7 +2757,6 @@ var ( ExampleType(0), // 7: qan.v1.ExampleType } ) - var file_qan_v1_collector_proto_depIdxs = []int32{ 1, // 0: qan.v1.CollectRequest.metrics_bucket:type_name -> qan.v1.MetricsBucket 6, // 1: qan.v1.MetricsBucket.agent_type:type_name -> inventory.v1.AgentType diff --git a/api/qan/v1/collector.swagger.json b/api/qan/v1/collector.swagger.json new file mode 100644 index 00000000000..5313874d3b2 --- /dev/null +++ b/api/qan/v1/collector.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "qan/v1/collector.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/qan/v1/filters.pb.go b/api/qan/v1/filters.pb.go index fcbf5e7aead..390a687dbc4 100644 --- a/api/qan/v1/filters.pb.go +++ b/api/qan/v1/filters.pb.go @@ -293,7 +293,6 @@ var ( (*MapFieldEntry)(nil), // 6: qan.v1.MapFieldEntry } ) - var file_qan_v1_filters_proto_depIdxs = []int32{ 5, // 0: qan.v1.GetFilteredMetricsNamesRequest.period_start_from:type_name -> google.protobuf.Timestamp 5, // 1: qan.v1.GetFilteredMetricsNamesRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/filters.swagger.json b/api/qan/v1/filters.swagger.json new file mode 100644 index 00000000000..bd5c3eb7ba0 --- /dev/null +++ b/api/qan/v1/filters.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "qan/v1/filters.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/qan/v1/object_details.pb.go b/api/qan/v1/object_details.pb.go index f004bc0ec60..53e6c06150b 100644 --- a/api/qan/v1/object_details.pb.go +++ b/api/qan/v1/object_details.pb.go @@ -1645,7 +1645,6 @@ var ( ExampleType(0), // 29: qan.v1.ExampleType } ) - var file_qan_v1_object_details_proto_depIdxs = []int32{ 26, // 0: qan.v1.GetMetricsRequest.period_start_from:type_name -> google.protobuf.Timestamp 26, // 1: qan.v1.GetMetricsRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/object_details.swagger.json b/api/qan/v1/object_details.swagger.json new file mode 100644 index 00000000000..e5465adaa29 --- /dev/null +++ b/api/qan/v1/object_details.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "qan/v1/object_details.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/qan/v1/profile.pb.go b/api/qan/v1/profile.pb.go index 03ab97e871a..7700b76dcd3 100644 --- a/api/qan/v1/profile.pb.go +++ b/api/qan/v1/profile.pb.go @@ -598,7 +598,6 @@ var ( (*Point)(nil), // 8: qan.v1.Point } ) - var file_qan_v1_profile_proto_depIdxs = []int32{ 7, // 0: qan.v1.GetReportRequest.period_start_from:type_name -> google.protobuf.Timestamp 7, // 1: qan.v1.GetReportRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/profile.swagger.json b/api/qan/v1/profile.swagger.json new file mode 100644 index 00000000000..d893a4c50f0 --- /dev/null +++ b/api/qan/v1/profile.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "qan/v1/profile.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/qan/v1/qan.pb.go b/api/qan/v1/qan.pb.go index c1d3bc6bb2e..2d37431a7c0 100644 --- a/api/qan/v1/qan.pb.go +++ b/api/qan/v1/qan.pb.go @@ -1000,7 +1000,6 @@ var ( (*MapFieldEntry)(nil), // 2: qan.v1.MapFieldEntry } ) - var file_qan_v1_qan_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/qan/v1/qan.swagger.json b/api/qan/v1/qan.swagger.json new file mode 100644 index 00000000000..eef59052f3e --- /dev/null +++ b/api/qan/v1/qan.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "qan/v1/qan.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/qan/v1/service.pb.go b/api/qan/v1/service.pb.go index 0e52423aa51..c5c688d9000 100644 --- a/api/qan/v1/service.pb.go +++ b/api/qan/v1/service.pb.go @@ -258,7 +258,6 @@ var ( (*GetQueryExampleResponse)(nil), // 24: qan.v1.GetQueryExampleResponse } ) - var file_qan_v1_service_proto_depIdxs = []int32{ 4, // 0: qan.v1.GetMetricsNamesResponse.data:type_name -> qan.v1.GetMetricsNamesResponse.DataEntry 5, // 1: qan.v1.QANService.GetReport:input_type -> qan.v1.GetReportRequest diff --git a/api/qan/v1/service.swagger.json b/api/qan/v1/service.swagger.json new file mode 100644 index 00000000000..d3b007a1e21 --- /dev/null +++ b/api/qan/v1/service.swagger.json @@ -0,0 +1,1568 @@ +{ + "swagger": "2.0", + "info": { + "title": "qan/v1/service.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "QANService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/qan/health": { + "get": { + "summary": "Health Check", + "description": "Returns readiness of QAN API2 service.", + "operationId": "HealthCheck", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1HealthCheckResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "QANService" + ] + } + }, + "/v1/qan/metrics:getFilters": { + "post": { + "summary": "Get Filters", + "description": "Provides a filtered map of metrics names.", + "operationId": "GetFilteredMetricsNames", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetFilteredMetricsNamesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "GetFilteredMetricsNamesRequest contains period for which we need filters.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1GetFilteredMetricsNamesRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan/metrics:getNames": { + "post": { + "summary": "Get Metrics Names", + "description": "Provides a map of all metrics names.", + "operationId": "GetMetricsNames", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetMetricsNamesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "MetricsNamesRequest is empty.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1GetMetricsNamesRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan/metrics:getReport": { + "post": { + "summary": "Get Report", + "description": "Returns a list of metrics grouped by queryid or other dimensions.", + "operationId": "GetReport", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetReportResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "ReportRequest defines filtering of metrics report for db server or other dimentions.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1GetReportRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan/query/{queryid}/plan": { + "get": { + "summary": "Get Query Plan", + "description": "Provides a query plan and plan id for specific filtering.", + "operationId": "GetQueryPlan", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetQueryPlanResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "queryid", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan/query:exists": { + "post": { + "summary": "Check Query Existence", + "description": "Checks if query exists in clickhouse.", + "operationId": "QueryExists", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1QueryExistsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "QueryExistsRequest check if provided query exists or not.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1QueryExistsRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan/query:getExample": { + "post": { + "summary": "Get Query Example", + "description": "Provides a list of query examples.", + "operationId": "GetQueryExample", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetQueryExampleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "GetQueryExampleRequest defines filtering of query examples for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1GetQueryExampleRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan/query:getSchema": { + "post": { + "summary": "Get Schema", + "description": "Provides the schema for a given queryID and serviceID.", + "operationId": "SchemaByQueryID", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1SchemaByQueryIDResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "SchemaByQueryIDRequest returns schema for given query ID and service ID.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1SchemaByQueryIDRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan:explainFingerprint": { + "post": { + "summary": "Get Explain Fingerprint", + "description": "Provides an explain fingerprint for given query ID.", + "operationId": "ExplainFingerprintByQueryID", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ExplainFingerprintByQueryIDResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "ExplainFingerprintByQueryIDRequest get explain fingerprint for given query ID.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ExplainFingerprintByQueryIDRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan:getHistogram": { + "post": { + "summary": "Get Histogram", + "description": "Provides histogram items for specific filtering.", + "operationId": "GetHistogram", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetHistogramResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "GetHistogramRequest defines filtering by time range, labels and queryid.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1GetHistogramRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan:getLabels": { + "post": { + "summary": "Get Labels", + "description": "Provides a list of labels for object details.", + "operationId": "GetLabels", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetLabelsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "GetLabelsRequest defines filtering of object detail's labels for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1GetLabelsRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + }, + "/v1/qan:getMetrics": { + "post": { + "summary": "Get Metrics", + "description": "Provides a map of metrics for specific filtering.", + "operationId": "GetMetrics", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetMetricsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "GetMetricsRequest defines filtering of metrics for specific value of dimension (ex.: host=hostname1 or queryid=1D410B4BE5060972.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1GetMetricsRequest" + } + } + ], + "tags": [ + "QANService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1ExampleType": { + "type": "string", + "enum": [ + "EXAMPLE_TYPE_UNSPECIFIED", + "EXAMPLE_TYPE_RANDOM", + "EXAMPLE_TYPE_SLOWEST", + "EXAMPLE_TYPE_FASTEST", + "EXAMPLE_TYPE_WITH_ERROR" + ], + "default": "EXAMPLE_TYPE_UNSPECIFIED", + "description": "ExampleType is a type of query example selected for this query class in given period of time." + }, + "v1ExplainFingerprintByQueryIDRequest": { + "type": "object", + "properties": { + "serviceid": { + "type": "string" + }, + "query_id": { + "type": "string" + } + }, + "description": "ExplainFingerprintByQueryIDRequest get explain fingerprint for given query ID." + }, + "v1ExplainFingerprintByQueryIDResponse": { + "type": "object", + "properties": { + "explain_fingerprint": { + "type": "string" + }, + "placeholders_count": { + "type": "integer", + "format": "int64" + } + }, + "description": "ExplainFingerprintByQueryIDResponse is explain fingerprint and placeholders count for given query ID." + }, + "v1GetFilteredMetricsNamesRequest": { + "type": "object", + "properties": { + "period_start_from": { + "type": "string", + "format": "date-time" + }, + "period_start_to": { + "type": "string", + "format": "date-time" + }, + "main_metric_name": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MapFieldEntry" + } + } + }, + "description": "GetFilteredMetricsNamesRequest contains period for which we need filters." + }, + "v1GetFilteredMetricsNamesResponse": { + "type": "object", + "properties": { + "labels": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1ListLabels" + } + } + }, + "description": "GetFilteredMetricsNamesResponse is map of labels for given period by key.\nKey is label's name and value is label's value and how many times it occur." + }, + "v1GetHistogramRequest": { + "type": "object", + "properties": { + "period_start_from": { + "type": "string", + "format": "date-time" + }, + "period_start_to": { + "type": "string", + "format": "date-time" + }, + "labels": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MapFieldEntry" + } + }, + "queryid": { + "type": "string" + } + }, + "description": "GetHistogramRequest defines filtering by time range, labels and queryid." + }, + "v1GetHistogramResponse": { + "type": "object", + "properties": { + "histogram_items": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1HistogramItem" + } + } + }, + "description": "GetHistogramResponse is histogram items as a list." + }, + "v1GetLabelsRequest": { + "type": "object", + "properties": { + "period_start_from": { + "type": "string", + "format": "date-time" + }, + "period_start_to": { + "type": "string", + "format": "date-time" + }, + "filter_by": { + "type": "string", + "description": "dimension value: ex: queryid - 1D410B4BE5060972." + }, + "group_by": { + "type": "string", + "description": "one of dimension: queryid | host ..." + } + }, + "description": "GetLabelsRequest defines filtering of object detail's labels for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." + }, + "v1GetLabelsResponse": { + "type": "object", + "properties": { + "labels": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1ListLabelValues" + } + } + }, + "description": "GetLabelsResponse is a map of labels names as keys and labels values as a list." + }, + "v1GetMetricsNamesRequest": { + "type": "object", + "description": "MetricsNamesRequest is empty." + }, + "v1GetMetricsNamesResponse": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "description": "MetricsNamesReply is map of stored metrics:\nkey is root of metric name in db (Ex:. [m_]query_time[_sum]);\nvalue - Human readable name of metrics." + }, + "v1GetMetricsRequest": { + "type": "object", + "properties": { + "period_start_from": { + "type": "string", + "format": "date-time" + }, + "period_start_to": { + "type": "string", + "format": "date-time" + }, + "filter_by": { + "type": "string", + "description": "dimension value: ex: queryid - 1D410B4BE5060972." + }, + "group_by": { + "type": "string", + "description": "one of dimension: queryid | host ..." + }, + "labels": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MapFieldEntry" + } + }, + "include_only_fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "totals": { + "type": "boolean", + "title": "retrieve only values for totals, excluding N/A values" + } + }, + "description": "GetMetricsRequest defines filtering of metrics for specific value of dimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." + }, + "v1GetMetricsResponse": { + "type": "object", + "properties": { + "metrics": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1MetricValues" + } + }, + "text_metrics": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "sparkline": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Point" + } + }, + "totals": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1MetricValues" + } + }, + "fingerprint": { + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/v1GetSelectedQueryMetadataResponse" + } + }, + "description": "GetMetricsResponse defines metrics for specific value of dimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." + }, + "v1GetQueryExampleRequest": { + "type": "object", + "properties": { + "period_start_from": { + "type": "string", + "format": "date-time" + }, + "period_start_to": { + "type": "string", + "format": "date-time" + }, + "filter_by": { + "type": "string", + "description": "dimension value: ex: queryid - 1D410B4BE5060972." + }, + "group_by": { + "type": "string", + "description": "one of dimension: queryid | host ..." + }, + "labels": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MapFieldEntry" + } + }, + "limit": { + "type": "integer", + "format": "int64" + } + }, + "description": "GetQueryExampleRequest defines filtering of query examples for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." + }, + "v1GetQueryExampleResponse": { + "type": "object", + "properties": { + "query_examples": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QueryExample" + } + } + }, + "description": "GetQueryExampleResponse list of query examples." + }, + "v1GetQueryPlanResponse": { + "type": "object", + "properties": { + "planid": { + "type": "string" + }, + "query_plan": { + "type": "string" + } + }, + "description": "GetQueryPlanResponse contains planid and query_plan." + }, + "v1GetReportRequest": { + "type": "object", + "properties": { + "period_start_from": { + "type": "string", + "format": "date-time" + }, + "period_start_to": { + "type": "string", + "format": "date-time" + }, + "group_by": { + "type": "string" + }, + "labels": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ReportMapFieldEntry" + } + }, + "columns": { + "type": "array", + "items": { + "type": "string" + } + }, + "order_by": { + "type": "string" + }, + "offset": { + "type": "integer", + "format": "int64" + }, + "limit": { + "type": "integer", + "format": "int64" + }, + "main_metric": { + "type": "string" + }, + "search": { + "type": "string" + } + }, + "description": "ReportRequest defines filtering of metrics report for db server or other dimentions." + }, + "v1GetReportResponse": { + "type": "object", + "properties": { + "total_rows": { + "type": "integer", + "format": "int64" + }, + "offset": { + "type": "integer", + "format": "int64" + }, + "limit": { + "type": "integer", + "format": "int64" + }, + "rows": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Row" + } + } + }, + "description": "ReportReply is list of reports per quieryids, hosts etc." + }, + "v1GetSelectedQueryMetadataResponse": { + "type": "object", + "properties": { + "service_name": { + "type": "string" + }, + "database": { + "type": "string" + }, + "schema": { + "type": "string" + }, + "username": { + "type": "string" + }, + "replication_set": { + "type": "string" + }, + "cluster": { + "type": "string" + }, + "service_type": { + "type": "string" + }, + "service_id": { + "type": "string" + }, + "environment": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "node_name": { + "type": "string" + }, + "node_type": { + "type": "string" + } + }, + "description": "GetSlecetedQueryMetadataResponse consists selected query metadata to show in details for given query ID." + }, + "v1HealthCheckResponse": { + "type": "object", + "description": "HealthCheckResponse is empty, based on returned error qan-api2 is ready or not." + }, + "v1HistogramItem": { + "type": "object", + "properties": { + "range": { + "type": "string" + }, + "frequency": { + "type": "integer", + "format": "int64" + } + }, + "description": "HistogramItem represents one item in histogram." + }, + "v1ListLabelValues": { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "ListLabelValues is list of label's values." + }, + "v1ListLabels": { + "type": "object", + "properties": { + "name": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Values" + } + } + }, + "description": "ListLabels is list of label's values: duplicates are impossible." + }, + "v1MapFieldEntry": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "MapFieldEntry allows to pass labels/dimensions in form like {\"server\": [\"db1\", \"db2\"...]}." + }, + "v1Metric": { + "type": "object", + "properties": { + "stats": { + "$ref": "#/definitions/v1Stat" + } + }, + "description": "Metric cell." + }, + "v1MetricValues": { + "type": "object", + "properties": { + "rate": { + "type": "number", + "format": "float" + }, + "cnt": { + "type": "number", + "format": "float" + }, + "sum": { + "type": "number", + "format": "float" + }, + "min": { + "type": "number", + "format": "float" + }, + "max": { + "type": "number", + "format": "float" + }, + "avg": { + "type": "number", + "format": "float" + }, + "p99": { + "type": "number", + "format": "float" + }, + "percent_of_total": { + "type": "number", + "format": "float" + } + }, + "description": "MetricValues is statistics of specific metric." + }, + "v1Point": { + "type": "object", + "properties": { + "point": { + "type": "integer", + "format": "int64", + "description": "The serial number of the chart point from the largest time in the time interval to the lowest time in the time range." + }, + "time_frame": { + "type": "integer", + "format": "int64", + "description": "Duration beetween two points." + }, + "timestamp": { + "type": "string", + "description": "Time of point in format RFC3339." + }, + "load": { + "type": "number", + "format": "float", + "description": "load is query_time / time_range." + }, + "num_queries_per_sec": { + "type": "number", + "format": "float", + "description": "number of queries in bucket." + }, + "num_queries_with_errors_per_sec": { + "type": "number", + "format": "float", + "description": "number of queries with errors." + }, + "num_queries_with_warnings_per_sec": { + "type": "number", + "format": "float", + "description": "number of queries with warnings." + }, + "m_query_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The statement execution time in seconds." + }, + "m_lock_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The time to acquire locks in seconds." + }, + "m_rows_sent_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of rows sent to the client." + }, + "m_rows_examined_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of rows scanned - SELECT." + }, + "m_rows_affected_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of rows changed - UPDATE, DELETE, INSERT." + }, + "m_rows_read_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of rows read from tables." + }, + "m_merge_passes_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of merge passes that the sort algorithm has had to do." + }, + "m_innodb_io_r_ops_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Counts the number of page read operations scheduled." + }, + "m_innodb_io_r_bytes_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Similar to innodb_IO_r_ops, but the unit is bytes." + }, + "m_innodb_io_r_wait_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Shows how long (in seconds) it took InnoDB to actually read the data from storage." + }, + "m_innodb_rec_lock_wait_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Shows how long (in seconds) the query waited for row locks." + }, + "m_innodb_queue_wait_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Shows how long (in seconds) the query spent either waiting to enter the InnoDB queue or inside that queue waiting for execution." + }, + "m_innodb_pages_distinct_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Counts approximately the number of unique pages the query accessed." + }, + "m_query_length_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Shows how long the query is." + }, + "m_bytes_sent_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of bytes sent to all clients." + }, + "m_tmp_tables_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of temporary tables created on memory for the query." + }, + "m_tmp_disk_tables_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of temporary tables created on disk for the query." + }, + "m_tmp_table_sizes_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total Size in bytes for all temporary tables used in the query." + }, + "m_qc_hit_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Query Cache hits." + }, + "m_full_scan_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The query performed a full table scan." + }, + "m_full_join_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The query performed a full join (a join without indexes)." + }, + "m_tmp_table_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The query created an implicit internal temporary table." + }, + "m_tmp_table_on_disk_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The querys temporary table was stored on disk." + }, + "m_filesort_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The query used a filesort." + }, + "m_filesort_on_disk_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The filesort was performed on disk." + }, + "m_select_full_range_join_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of joins that used a range search on a reference table." + }, + "m_select_range_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of joins that used ranges on the first table." + }, + "m_select_range_check_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of joins without keys that check for key usage after each row." + }, + "m_sort_range_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of sorts that were done using ranges." + }, + "m_sort_rows_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of sorted rows." + }, + "m_sort_scan_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of sorts that were done by scanning the table." + }, + "m_no_index_used_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of queries without index." + }, + "m_no_good_index_used_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of queries without good index." + }, + "m_docs_returned_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of returned documents." + }, + "m_response_length_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The response length of the query result in bytes." + }, + "m_docs_scanned_sum_per_sec": { + "type": "number", + "format": "float", + "description": "The number of scanned documents." + }, + "m_docs_examined_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of documents scanned during query execution." + }, + "m_keys_examined_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of index keys scanned during query execution." + }, + "m_locks_global_acquire_count_read_shared_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of times a global read lock was acquired during query execution." + }, + "m_locks_global_acquire_count_write_shared_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of times a global write lock was acquired during query execution." + }, + "m_locks_database_acquire_count_read_shared_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of times a read lock was acquired at the database level during query execution." + }, + "m_locks_database_acquire_wait_count_read_shared_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of times a read lock at the database level was requested but had to wait before being granted." + }, + "m_locks_database_time_acquiring_micros_read_shared_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Indicates the time, spent acquiring a read lock at the database level during an operation." + }, + "m_locks_collection_acquire_count_read_shared_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Number of times a read lock was acquired on a specific collection during operations." + }, + "m_storage_bytes_read_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of bytes read from storage during a specific operation." + }, + "m_storage_time_reading_micros_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Indicates the time, spent reading data from storage during an operation." + }, + "m_shared_blks_hit_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of shared block cache hits by the statement." + }, + "m_shared_blks_read_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of shared blocks read by the statement." + }, + "m_shared_blks_dirtied_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of shared blocks dirtied by the statement." + }, + "m_shared_blks_written_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of shared blocks written by the statement." + }, + "m_shared_blk_read_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time the statement spent reading shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." + }, + "m_shared_blk_write_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time the statement spent writing shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." + }, + "m_local_blk_read_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time the statement spent reading shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." + }, + "m_local_blk_write_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time the statement spent writing shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." + }, + "m_local_blks_hit_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of local block cache hits by the statement." + }, + "m_local_blks_read_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of local blocks read by the statement." + }, + "m_local_blks_dirtied_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of local blocks dirtied by the statement." + }, + "m_local_blks_written_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of local blocks written by the statement." + }, + "m_temp_blks_read_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of temp blocks read by the statement." + }, + "m_temp_blks_written_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of temp blocks written by the statement." + }, + "m_blk_read_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time the statement spent reading blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." + }, + "m_blk_write_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time the statement spent writing blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." + }, + "m_cpu_user_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time user spent in query." + }, + "m_cpu_sys_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total time system spent in query." + }, + "m_plans_calls_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of planned calls." + }, + "m_wal_records_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of WAL (Write-ahead logging) records." + }, + "m_wal_fpi_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of FPI (full page images) in WAL (Write-ahead logging) records." + }, + "m_wal_bytes_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total bytes of WAL (Write-ahead logging) records." + }, + "m_wal_buffers_full_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of times WAL buffers become full." + }, + "m_parallel_workers_to_launch_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of parallel workers to launch." + }, + "m_parallel_workers_launched_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Total number of parallel workers launched." + }, + "m_plan_time_sum_per_sec": { + "type": "number", + "format": "float", + "description": "Plan time in per seconds." + } + }, + "description": "Point contains values that represents abscissa (time) and ordinate (volume etc.)\nof every point in a coordinate system of Sparklines." + }, + "v1QueryExample": { + "type": "object", + "properties": { + "example": { + "type": "string" + }, + "example_type": { + "$ref": "#/definitions/v1ExampleType" + }, + "is_truncated": { + "type": "integer", + "format": "int64" + }, + "placeholders_count": { + "type": "integer", + "format": "int64" + }, + "explain_fingerprint": { + "type": "string" + }, + "query_id": { + "type": "string" + }, + "example_metrics": { + "type": "string" + }, + "service_id": { + "type": "string" + }, + "service_type": { + "type": "string" + }, + "schema": { + "type": "string" + }, + "tables": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "QueryExample shows query examples and their metrics." + }, + "v1QueryExistsRequest": { + "type": "object", + "properties": { + "serviceid": { + "type": "string" + }, + "query": { + "type": "string" + } + }, + "description": "QueryExistsRequest check if provided query exists or not." + }, + "v1QueryExistsResponse": { + "type": "object", + "properties": { + "exists": { + "type": "boolean" + } + }, + "description": "QueryExistsResponse returns true if query exists." + }, + "v1ReportMapFieldEntry": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "ReportMapFieldEntry allows to pass labels/dimentions in form like {\"server\": [\"db1\", \"db2\"...]}." + }, + "v1Row": { + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int64" + }, + "dimension": { + "type": "string" + }, + "database": { + "type": "string" + }, + "metrics": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1Metric" + } + }, + "sparkline": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Point" + } + }, + "fingerprint": { + "type": "string" + }, + "num_queries": { + "type": "integer", + "format": "int64" + }, + "qps": { + "type": "number", + "format": "float" + }, + "load": { + "type": "number", + "format": "float" + } + }, + "description": "Row define metrics for selected dimention." + }, + "v1SchemaByQueryIDRequest": { + "type": "object", + "properties": { + "service_id": { + "type": "string" + }, + "query_id": { + "type": "string" + } + }, + "description": "SchemaByQueryIDRequest returns schema for given query ID and service ID." + }, + "v1SchemaByQueryIDResponse": { + "type": "object", + "properties": { + "schema": { + "type": "string" + } + }, + "description": "SchemaByQueryIDResponse is schema for given query ID and service ID." + }, + "v1Stat": { + "type": "object", + "properties": { + "rate": { + "type": "number", + "format": "float" + }, + "cnt": { + "type": "number", + "format": "float" + }, + "sum": { + "type": "number", + "format": "float" + }, + "min": { + "type": "number", + "format": "float" + }, + "max": { + "type": "number", + "format": "float" + }, + "p99": { + "type": "number", + "format": "float" + }, + "avg": { + "type": "number", + "format": "float" + }, + "sum_per_sec": { + "type": "number", + "format": "float" + } + }, + "description": "Stat is statistics of specific metric." + }, + "v1Values": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "main_metric_percent": { + "type": "number", + "format": "float" + }, + "main_metric_per_sec": { + "type": "number", + "format": "float" + } + }, + "description": "Values is label values and main metric percent and per second." + } + } +} diff --git a/api/realtimeanalytics/v1/collector.pb.go b/api/realtimeanalytics/v1/collector.pb.go index f149de0a6cf..b9b81466e7c 100644 --- a/api/realtimeanalytics/v1/collector.pb.go +++ b/api/realtimeanalytics/v1/collector.pb.go @@ -140,7 +140,6 @@ var ( (*QueryData)(nil), // 2: realtimeanalytics.v1.QueryData } ) - var file_realtimeanalytics_v1_collector_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.CollectRequest.queries:type_name -> realtimeanalytics.v1.QueryData 0, // 1: realtimeanalytics.v1.CollectorService.Collect:input_type -> realtimeanalytics.v1.CollectRequest diff --git a/api/realtimeanalytics/v1/collector.swagger.json b/api/realtimeanalytics/v1/collector.swagger.json new file mode 100644 index 00000000000..0216a29e22a --- /dev/null +++ b/api/realtimeanalytics/v1/collector.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "realtimeanalytics/v1/collector.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/realtimeanalytics/v1/query.pb.go b/api/realtimeanalytics/v1/query.pb.go index 43c4a1bdd5c..b9ab1809d9a 100644 --- a/api/realtimeanalytics/v1/query.pb.go +++ b/api/realtimeanalytics/v1/query.pb.go @@ -331,7 +331,6 @@ var ( (*durationpb.Duration)(nil), // 3: google.protobuf.Duration } ) - var file_realtimeanalytics_v1_query_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.QueryMongoDBData.operation_start_time:type_name -> google.protobuf.Timestamp 3, // 1: realtimeanalytics.v1.QueryData.query_execution_duration:type_name -> google.protobuf.Duration diff --git a/api/realtimeanalytics/v1/query.swagger.json b/api/realtimeanalytics/v1/query.swagger.json new file mode 100644 index 00000000000..6a628f444b1 --- /dev/null +++ b/api/realtimeanalytics/v1/query.swagger.json @@ -0,0 +1,44 @@ +{ + "swagger": "2.0", + "info": { + "title": "realtimeanalytics/v1/query.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/realtimeanalytics/v1/realtimeanalytics.pb.go b/api/realtimeanalytics/v1/realtimeanalytics.pb.go index 8dbdbf8ccff..bd339f4bad9 100644 --- a/api/realtimeanalytics/v1/realtimeanalytics.pb.go +++ b/api/realtimeanalytics/v1/realtimeanalytics.pb.go @@ -718,7 +718,6 @@ var ( (*QueryData)(nil), // 16: realtimeanalytics.v1.QueryData } ) - var file_realtimeanalytics_v1_realtimeanalytics_proto_depIdxs = []int32{ 12, // 0: realtimeanalytics.v1.ListServicesRequest.service_type:type_name -> inventory.v1.ServiceType 13, // 1: realtimeanalytics.v1.ListServicesResponse.mongodb:type_name -> inventory.v1.MongoDBService diff --git a/api/realtimeanalytics/v1/realtimeanalytics.swagger.json b/api/realtimeanalytics/v1/realtimeanalytics.swagger.json new file mode 100644 index 00000000000..59d45b36d7a --- /dev/null +++ b/api/realtimeanalytics/v1/realtimeanalytics.swagger.json @@ -0,0 +1,516 @@ +{ + "swagger": "2.0", + "info": { + "title": "realtimeanalytics/v1/realtimeanalytics.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "RealtimeAnalyticsService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/realtimeanalytics/queries:search": { + "post": { + "summary": "List Running Database Queries in a particular services", + "description": "Returns list of currently running Database queries in a particular services", + "operationId": "SearchQueries", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1SearchQueriesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "SearchQueriesRequest contains optional filters for listing active Real-Time Analytics session Queries.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1SearchQueriesRequest" + } + } + ], + "tags": [ + "RealtimeAnalyticsService" + ] + } + }, + "/v1/realtimeanalytics/services": { + "get": { + "summary": "List Services that support Real-Time Analytics", + "description": "Returns a list of Services that support Real-Time Analytics filtered by type.", + "operationId": "ListServices", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListServicesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "service_type", + "description": "Return only services filtered by service type.", + "in": "query", + "required": false, + "type": "string", + "enum": [ + "SERVICE_TYPE_UNSPECIFIED", + "SERVICE_TYPE_MYSQL_SERVICE", + "SERVICE_TYPE_MONGODB_SERVICE", + "SERVICE_TYPE_POSTGRESQL_SERVICE", + "SERVICE_TYPE_VALKEY_SERVICE", + "SERVICE_TYPE_PROXYSQL_SERVICE", + "SERVICE_TYPE_HAPROXY_SERVICE", + "SERVICE_TYPE_EXTERNAL_SERVICE" + ], + "default": "SERVICE_TYPE_UNSPECIFIED" + } + ], + "tags": [ + "RealtimeAnalyticsService" + ] + } + }, + "/v1/realtimeanalytics/sessions": { + "get": { + "summary": "List Running Real-Time Analytics Sessions", + "description": "Returns the list of all currently running Real-Time Analytics sessions with their details including service, cluster and status information.", + "operationId": "ListSessions", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListSessionsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "cluster_name", + "description": "Optional filter by cluster name.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "RealtimeAnalyticsService" + ] + } + }, + "/v1/realtimeanalytics/sessions:start": { + "post": { + "summary": "Start Real-Time Analytics session", + "description": "Start Real-Time Analytics session for a specified service.", + "operationId": "StartSession", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartSessionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "StartSessionRequest contains parameters for starting Real-Time Analytics session.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StartSessionRequest" + } + } + ], + "tags": [ + "RealtimeAnalyticsService" + ] + } + }, + "/v1/realtimeanalytics/sessions:stop": { + "post": { + "summary": "Stop Real-Time Analytics session", + "description": "Stop Real-Time Analytics session for a specified service.", + "operationId": "StopSession", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StopSessionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "description": "StopSessionRequest contains parameters for stopping Real-Time Analytics session.", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StopSessionRequest" + } + } + ], + "tags": [ + "RealtimeAnalyticsService" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1ListServicesResponse": { + "type": "object", + "properties": { + "mongodb": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1MongoDBService" + } + } + } + }, + "v1ListSessionsResponse": { + "type": "object", + "properties": { + "sessions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Session" + }, + "description": "List of active Real-Time Analytics Sessions." + } + }, + "description": "ListSessionsResponse returns the list of currently active Real-Time Analytics Sessions." + }, + "v1MongoDBService": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Unique randomly generated instance identifier." + }, + "service_name": { + "type": "string", + "description": "Unique across all Services user-defined name." + }, + "node_id": { + "type": "string", + "description": "Node identifier where this instance runs." + }, + "address": { + "type": "string", + "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." + }, + "port": { + "type": "integer", + "format": "int64", + "description": "Access port.\nPort is required when the address present." + }, + "socket": { + "type": "string", + "description": "Access unix socket.\nAddress (and port) or socket is required." + }, + "environment": { + "type": "string", + "description": "Environment name." + }, + "cluster": { + "type": "string", + "description": "Cluster name." + }, + "replication_set": { + "type": "string", + "description": "Replication set name." + }, + "custom_labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom user-assigned labels." + }, + "version": { + "type": "string", + "description": "MongoDB version." + } + }, + "description": "MongoDBService represents a generic MongoDB instance." + }, + "v1QueryData": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "PMM Service identifier that reported the query." + }, + "service_name": { + "type": "string", + "description": "PMM Service name that reported the query." + }, + "query_id": { + "type": "string", + "description": "Unique identifier for the query." + }, + "query_text": { + "type": "string", + "description": "The text of the query." + }, + "query_raw_json": { + "type": "string", + "description": "Raw JSON representation of the query." + }, + "query_execution_duration": { + "type": "string", + "description": "Current query current execution time." + }, + "query_collect_time": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the query data was collected by Real-Time Analytics agent." + }, + "client_address": { + "type": "string", + "description": "Client address (host:port)." + }, + "mongo_db_payload": { + "$ref": "#/definitions/v1QueryMongoDBData", + "description": "MongoDB-specific query data." + } + }, + "description": "QueryData represents a single Real-Time Analytics query data point.\nIt includes general query information and a payload for database-specific details." + }, + "v1QueryMongoDBData": { + "type": "object", + "properties": { + "db_instance_address": { + "type": "string", + "description": "MongoDB instance address(host:port) that processing the query." + }, + "client_app_name": { + "type": "string", + "description": "Client application name from the MongoDB query." + }, + "database_name": { + "type": "string", + "description": "Database name." + }, + "collection": { + "type": "string", + "description": "Collection name." + }, + "operation": { + "type": "string", + "description": "Query operation (\"find\", \"aggregate\", \"update\", etc)." + }, + "operation_start_time": { + "type": "string", + "format": "date-time", + "description": "The start time of the operation." + }, + "username": { + "type": "string", + "description": "MongoDB user name associated with the query." + }, + "plan_summary": { + "type": "string", + "description": "Indicates if an index (COLLSCAN vs IXSCAN) was utilized in the query." + } + }, + "description": "QueryMongoDBData holds MongoDB-specific Real-Time Analytics query information." + }, + "v1SearchQueriesRequest": { + "type": "object", + "properties": { + "service_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional filter by Service identifiers." + }, + "limit": { + "type": "string", + "format": "int64", + "description": "Optional limit the number of queries in response." + } + }, + "description": "SearchQueriesRequest contains optional filters for listing active Real-Time Analytics session Queries." + }, + "v1SearchQueriesResponse": { + "type": "object", + "properties": { + "queries": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1QueryData" + }, + "description": "List of active Real-Time Analytics session Queries." + } + }, + "description": "SearchQueriesResponse returns the list of currently active Real-Time Analytics session Queries." + }, + "v1ServiceType": { + "type": "string", + "enum": [ + "SERVICE_TYPE_UNSPECIFIED", + "SERVICE_TYPE_MYSQL_SERVICE", + "SERVICE_TYPE_MONGODB_SERVICE", + "SERVICE_TYPE_POSTGRESQL_SERVICE", + "SERVICE_TYPE_VALKEY_SERVICE", + "SERVICE_TYPE_PROXYSQL_SERVICE", + "SERVICE_TYPE_HAPROXY_SERVICE", + "SERVICE_TYPE_EXTERNAL_SERVICE" + ], + "default": "SERVICE_TYPE_UNSPECIFIED", + "description": "ServiceType describes supported Service types." + }, + "v1Session": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Service identifier that has enabled Real-Time Analytics session." + }, + "service_name": { + "type": "string", + "description": "Service name." + }, + "cluster_name": { + "type": "string", + "description": "Cluster name the service belongs to." + }, + "start_time": { + "type": "string", + "format": "date-time", + "description": "Timestamp when the Real-Time Analytics session started." + }, + "collect_interval": { + "type": "string", + "description": "Query collect interval." + }, + "status": { + "$ref": "#/definitions/v1SessionStatus", + "description": "Current status of the Real-Time Analytics session." + } + }, + "description": "Session represents an active Real-Time Analytics session." + }, + "v1SessionStatus": { + "type": "string", + "enum": [ + "SESSION_STATUS_UNSPECIFIED", + "SESSION_STATUS_ERROR", + "SESSION_STATUS_RUNNING", + "SESSION_STATUS_DOWN" + ], + "default": "SESSION_STATUS_UNSPECIFIED", + "description": "Status represents actual Real-Time Analytics session status.\n\n - SESSION_STATUS_ERROR: Session encountered an error.\n - SESSION_STATUS_RUNNING: Session is running.\n - SESSION_STATUS_DOWN: Session has been stopped or disabled." + }, + "v1StartSessionRequest": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Required service identifier the Real-Time Analytics session shall be started for." + } + }, + "description": "StartSessionRequest contains parameters for starting Real-Time Analytics session." + }, + "v1StartSessionResponse": { + "type": "object", + "properties": { + "session": { + "$ref": "#/definitions/v1Session" + } + }, + "description": "StartSessionResponse is the response for starting Real-Time Analytics session." + }, + "v1StopSessionRequest": { + "type": "object", + "properties": { + "service_id": { + "type": "string", + "description": "Required service identifier the Real-Time Analytics session shall be stopped for." + } + }, + "description": "StopSessionRequest contains parameters for stopping Real-Time Analytics session." + }, + "v1StopSessionResponse": { + "type": "object", + "description": "StopSessionResponse is the response for stopping Real-Time Analytics session.\n\nEmpty response for now." + } + } +} diff --git a/api/server/v1/httperror.pb.go b/api/server/v1/httperror.pb.go index 8778ad26272..ef269ba2292 100644 --- a/api/server/v1/httperror.pb.go +++ b/api/server/v1/httperror.pb.go @@ -127,7 +127,6 @@ var ( (*anypb.Any)(nil), // 1: google.protobuf.Any } ) - var file_server_v1_httperror_proto_depIdxs = []int32{ 1, // 0: server.v1.HttpError.details:type_name -> google.protobuf.Any 1, // [1:1] is the sub-list for method output_type diff --git a/api/server/v1/httperror.swagger.json b/api/server/v1/httperror.swagger.json new file mode 100644 index 00000000000..7462173f0ff --- /dev/null +++ b/api/server/v1/httperror.swagger.json @@ -0,0 +1,46 @@ +{ + "swagger": "2.0", + "info": { + "title": "server/v1/httperror.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": {}, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + } + }, + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index b5772139c0a..0af6b91d79f 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -1952,7 +1952,6 @@ var ( (*common.StringArray)(nil), // 29: common.StringArray } ) - var file_server_v1_server_proto_depIdxs = []int32{ 27, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo diff --git a/api/server/v1/server.swagger.json b/api/server/v1/server.swagger.json new file mode 100644 index 00000000000..d8ea983f495 --- /dev/null +++ b/api/server/v1/server.swagger.json @@ -0,0 +1,798 @@ +{ + "swagger": "2.0", + "info": { + "title": "server/v1/server.proto", + "version": "version not set" + }, + "tags": [ + { + "name": "ServerService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/server/leaderHealthCheck": { + "get": { + "summary": "Check Leadership", + "description": "Checks if the instance is the leader in a cluster. Returns an error if the instance isn't the leader.", + "operationId": "LeaderHealthCheck", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1LeaderHealthCheckResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/readyz": { + "get": { + "summary": "Check server readiness", + "description": "Returns an error when Server components being restarted are not ready yet. Use this API for checking the health of Docker containers and for probing Kubernetes readiness.", + "operationId": "Readiness", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ReadinessResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/settings": { + "get": { + "summary": "Get settings", + "description": "Returns current PMM Server settings.", + "operationId": "GetSettings", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetSettingsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "ServerService" + ] + }, + "put": { + "summary": "Change settings", + "description": "Changes PMM Server settings.", + "operationId": "ChangeSettings", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ChangeSettingsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1ChangeSettingsRequest" + } + } + ], + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/settings/readonly": { + "get": { + "summary": "Get read-only settings", + "description": "Returns a stripped version of PMM Server settings.", + "operationId": "GetReadOnlySettings", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetReadOnlySettingsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/updates": { + "get": { + "summary": "Check updates", + "description": "Checks for available PMM Server updates.", + "operationId": "CheckUpdates", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1CheckUpdatesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "force", + "description": "If false, cached information may be returned.", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "only_installed_version", + "description": "If true, only installed version will be in response.", + "in": "query", + "required": false, + "type": "boolean" + } + ], + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/updates/changelogs": { + "get": { + "summary": "Get the changelog", + "description": "Display a changelog comparing the installed version to the latest available version.", + "operationId": "ListChangeLogs", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListChangeLogsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/updates:getStatus": { + "post": { + "summary": "Update status", + "description": "Returns PMM Server update status.", + "operationId": "UpdateStatus", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UpdateStatusResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UpdateStatusRequest" + } + } + ], + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/updates:start": { + "post": { + "summary": "Start update", + "description": "Starts PMM Server update.", + "operationId": "StartUpdate", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1StartUpdateResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1StartUpdateRequest" + } + } + ], + "tags": [ + "ServerService" + ] + } + }, + "/v1/server/version": { + "get": { + "summary": "Version", + "description": "Returns PMM Server versions.", + "operationId": "Version", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1VersionResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "dummy", + "description": "Dummy parameter for internal testing. Do not use.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ServerService" + ] + } + } + }, + "definitions": { + "commonStringArray": { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "description": "A wrapper for a string array. This type allows to distinguish between an empty array and a null value." + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." + } + }, + "additionalProperties": {}, + "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1AdvisorRunIntervals": { + "type": "object", + "properties": { + "standard_interval": { + "type": "string", + "description": "Standard check interval." + }, + "rare_interval": { + "type": "string", + "description": "Interval for rare check runs." + }, + "frequent_interval": { + "type": "string", + "description": "Interval for frequent check runs." + } + }, + "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks." + }, + "v1ChangeSettingsRequest": { + "type": "object", + "properties": { + "enable_updates": { + "type": "boolean", + "x-nullable": true + }, + "enable_telemetry": { + "type": "boolean", + "x-nullable": true + }, + "metrics_resolutions": { + "$ref": "#/definitions/v1MetricsResolutions" + }, + "data_retention": { + "type": "string", + "description": "A number of full days for Prometheus and QAN data retention. Should have a suffix in JSON: 2592000s, 43200m, 720h." + }, + "ssh_key": { + "type": "string", + "x-nullable": true + }, + "aws_partitions": { + "$ref": "#/definitions/commonStringArray", + "x-nullable": true + }, + "enable_advisor": { + "type": "boolean", + "x-nullable": true, + "description": "Enable Advisor." + }, + "enable_alerting": { + "type": "boolean", + "x-nullable": true, + "description": "Enable Alerting." + }, + "pmm_public_address": { + "type": "string", + "x-nullable": true, + "description": "PMM Server public address." + }, + "advisor_run_intervals": { + "$ref": "#/definitions/v1AdvisorRunIntervals", + "description": "Intervals between Advisor runs." + }, + "enable_azurediscover": { + "type": "boolean", + "x-nullable": true, + "description": "Enable Azure Discover." + }, + "enable_backup_management": { + "type": "boolean", + "x-nullable": true, + "description": "Enable Backup Management." + }, + "enable_access_control": { + "type": "boolean", + "x-nullable": true, + "title": "Enable Access Control" + }, + "enable_internal_pg_qan": { + "type": "boolean", + "x-nullable": true, + "description": "Enable Query Analytics for PMM's internal PG database." + }, + "update_snooze_duration": { + "type": "string", + "description": "A number of full days for which an update is snoozed, i.e. a multiple of 24h: 2592000s, 43200m, 720h." + } + } + }, + "v1ChangeSettingsResponse": { + "type": "object", + "properties": { + "settings": { + "$ref": "#/definitions/v1Settings" + } + } + }, + "v1CheckUpdatesResponse": { + "type": "object", + "properties": { + "installed": { + "$ref": "#/definitions/v1VersionInfo", + "description": "Currently installed PMM Server version." + }, + "latest": { + "$ref": "#/definitions/v1DockerVersionInfo", + "description": "Latest available PMM Server version." + }, + "update_available": { + "type": "boolean", + "description": "True if there is a PMM Server update available." + }, + "latest_news_url": { + "type": "string", + "description": "Latest available PMM Server release announcement URL." + }, + "last_check": { + "type": "string", + "format": "date-time", + "description": "Last check time." + } + } + }, + "v1DistributionMethod": { + "type": "string", + "enum": [ + "DISTRIBUTION_METHOD_UNSPECIFIED", + "DISTRIBUTION_METHOD_DOCKER", + "DISTRIBUTION_METHOD_OVF", + "DISTRIBUTION_METHOD_AMI", + "DISTRIBUTION_METHOD_AZURE", + "DISTRIBUTION_METHOD_DO" + ], + "default": "DISTRIBUTION_METHOD_UNSPECIFIED", + "description": "DistributionMethod defines PMM Server distribution method: Docker image, OVF/OVA, or AMI." + }, + "v1DockerVersionInfo": { + "type": "object", + "properties": { + "version": { + "type": "string", + "description": "PMM Version." + }, + "tag": { + "type": "string", + "description": "Docker image tag." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Release date." + }, + "release_notes_url": { + "type": "string", + "description": "Release notes URL for the version (if available)." + }, + "release_notes_text": { + "type": "string", + "description": "Release notes text for the version (if available)." + } + } + }, + "v1GetReadOnlySettingsResponse": { + "type": "object", + "properties": { + "settings": { + "$ref": "#/definitions/v1ReadOnlySettings" + } + } + }, + "v1GetSettingsResponse": { + "type": "object", + "properties": { + "settings": { + "$ref": "#/definitions/v1Settings" + } + } + }, + "v1LeaderHealthCheckResponse": { + "type": "object", + "description": "This probe is available without authentication, so it should not contain any data." + }, + "v1ListChangeLogsResponse": { + "type": "object", + "properties": { + "updates": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1DockerVersionInfo" + }, + "description": "List of available updates." + }, + "last_check": { + "type": "string", + "format": "date-time", + "description": "Last check time." + } + } + }, + "v1MetricsResolutions": { + "type": "object", + "properties": { + "hr": { + "type": "string", + "description": "High resolution. Should have a suffix in JSON: 1s, 1m, 1h." + }, + "mr": { + "type": "string", + "description": "Medium resolution. Should have a suffix in JSON: 1s, 1m, 1h." + }, + "lr": { + "type": "string", + "description": "Low resolution. Should have a suffix in JSON: 1s, 1m, 1h." + } + }, + "description": "MetricsResolutions represents Prometheus exporters metrics resolutions." + }, + "v1ReadOnlySettings": { + "type": "object", + "properties": { + "updates_enabled": { + "type": "boolean", + "description": "True if updates are enabled." + }, + "telemetry_enabled": { + "type": "boolean", + "description": "True if telemetry is enabled." + }, + "advisor_enabled": { + "type": "boolean", + "description": "True if Advisor is enabled." + }, + "alerting_enabled": { + "type": "boolean", + "description": "True if Alerting is enabled." + }, + "pmm_public_address": { + "type": "string", + "description": "PMM Server public address." + }, + "backup_management_enabled": { + "type": "boolean", + "description": "True if Backup Management is enabled." + }, + "azurediscover_enabled": { + "type": "boolean", + "description": "True if Azure Discover is enabled." + }, + "enable_access_control": { + "type": "boolean", + "description": "True if Access Control is enabled." + } + }, + "description": "ReadOnlySettings represents a stripped-down version of PMM Server settings that can be accessed by users of all roles." + }, + "v1ReadinessResponse": { + "type": "object", + "description": "This probe is available without authentication, so it should not contain any data." + }, + "v1Settings": { + "type": "object", + "properties": { + "updates_enabled": { + "type": "boolean", + "description": "True if updates are enabled." + }, + "telemetry_enabled": { + "type": "boolean", + "description": "True if telemetry is enabled." + }, + "metrics_resolutions": { + "$ref": "#/definitions/v1MetricsResolutions" + }, + "data_retention": { + "type": "string" + }, + "ssh_key": { + "type": "string" + }, + "aws_partitions": { + "type": "array", + "items": { + "type": "string" + } + }, + "advisor_enabled": { + "type": "boolean", + "description": "True if Advisor is enabled." + }, + "platform_email": { + "type": "string" + }, + "alerting_enabled": { + "type": "boolean", + "description": "True if Alerting is enabled." + }, + "pmm_public_address": { + "type": "string", + "description": "PMM Server public address." + }, + "advisor_run_intervals": { + "$ref": "#/definitions/v1AdvisorRunIntervals", + "description": "Intervals between Advisor runs." + }, + "backup_management_enabled": { + "type": "boolean", + "description": "True if Backup Management is enabled." + }, + "azurediscover_enabled": { + "type": "boolean", + "description": "True if Azure Discover is enabled." + }, + "connected_to_platform": { + "type": "boolean", + "title": "True if the PMM instance is connected to Platform" + }, + "telemetry_summaries": { + "type": "array", + "items": { + "type": "string" + }, + "title": "Includes list of collected telemetry" + }, + "enable_access_control": { + "type": "boolean", + "description": "True if Access Control is enabled." + }, + "default_role_id": { + "type": "integer", + "format": "int64", + "description": "Default Access Control role ID for new users." + }, + "enable_internal_pg_qan": { + "type": "boolean", + "description": "True if Query Analytics for PMM's internal PG database is enabled." + }, + "update_snooze_duration": { + "type": "string", + "title": "Duration for which an update is snoozed" + } + }, + "description": "Settings represents PMM Server settings." + }, + "v1StartUpdateRequest": { + "type": "object", + "properties": { + "new_image": { + "type": "string" + } + } + }, + "v1StartUpdateResponse": { + "type": "object", + "properties": { + "auth_token": { + "type": "string", + "description": "Authentication token for getting update statuses." + }, + "log_offset": { + "type": "integer", + "format": "int64", + "description": "Progress log offset." + } + } + }, + "v1UpdateStatusRequest": { + "type": "object", + "properties": { + "auth_token": { + "type": "string", + "description": "Authentication token." + }, + "log_offset": { + "type": "integer", + "format": "int64", + "description": "Progress log offset." + } + } + }, + "v1UpdateStatusResponse": { + "type": "object", + "properties": { + "log_lines": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Progress log lines." + }, + "log_offset": { + "type": "integer", + "format": "int64", + "description": "Progress log offset for the next request." + }, + "done": { + "type": "boolean", + "description": "True when update is done." + } + } + }, + "v1VersionInfo": { + "type": "object", + "properties": { + "version": { + "type": "string", + "description": "User-visible version." + }, + "full_version": { + "type": "string", + "description": "Full version for debugging." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Build or release date." + } + }, + "description": "VersionInfo describes component version, or PMM Server as a whole." + }, + "v1VersionResponse": { + "type": "object", + "properties": { + "version": { + "type": "string", + "description": "PMM Server version." + }, + "server": { + "$ref": "#/definitions/v1VersionInfo", + "description": "Detailed PMM Server version information." + }, + "managed": { + "$ref": "#/definitions/v1VersionInfo", + "description": "pmm-managed version information for debugging." + }, + "distribution_method": { + "$ref": "#/definitions/v1DistributionMethod", + "description": "PMM Server distribution method.\n\nTODO Versions and statuses of Grafana, Prometheus, PostgreSQL, qan-api2, ClickHouse, pmm-agent, etc." + } + } + } + } +} diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index f521777f744..e24bd8d6f77 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -1724,6 +1724,297 @@ } } }, + "/v1/advisors/checks/history": { + "get": { + "description": "Returns the history of Advisor check runs, including their outcomes.", + "tags": [ + "AdvisorService" + ], + "summary": "List Advisor Check Results History", + "operationId": "ListCheckResultsHistory", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "Maximum number of results per page.", + "name": "page_size", + "in": "query" + }, + { + "type": "integer", + "format": "int32", + "description": "Index of the requested page, starts from 0.", + "name": "page_index", + "in": "query" + }, + { + "type": "string", + "description": "Filter by service ID.", + "name": "service_id", + "in": "query" + }, + { + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "type": "string", + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "description": "Filter by outcome.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", + "name": "status", + "in": "query" + }, + { + "type": "boolean", + "description": "Filter by read state.", + "name": "is_read", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Return only results recorded at or after this time.", + "name": "from", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Return only results recorded at or before this time.", + "name": "to", + "in": "query" + }, + { + "type": "string", + "description": "Filter by service name (partial, case-insensitive match).", + "name": "service_name", + "in": "query" + }, + { + "type": "string", + "description": "Filter by node name (partial, case-insensitive match).", + "name": "node_name", + "in": "query" + }, + { + "type": "string", + "description": "Filter by advisor category.", + "name": "category", + "in": "query" + }, + { + "type": "string", + "description": "Filter by check name.", + "name": "check_name", + "in": "query" + }, + { + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "description": "Filter by severity.", + "name": "severity", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "total_items": { + "description": "Total number of results.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "total_pages": { + "description": "Total number of pages.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "results": { + "description": "History records.", + "type": "array", + "items": { + "description": "CheckResultHistoryItem represents a single persisted Advisor check run against a service.", + "type": "object", + "properties": { + "id": { + "description": "Unique identifier of the history record.", + "type": "string", + "x-order": 0 + }, + "check_name": { + "description": "Name of the check that ran.", + "type": "string", + "x-order": 1 + }, + "advisor_name": { + "description": "Name of the advisor the check belongs to.", + "type": "string", + "x-order": 2 + }, + "category": { + "description": "Category of the advisor the check belongs to.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "service_id": { + "description": "ID of the monitored service on which the check ran.", + "type": "string", + "x-order": 5 + }, + "service_name": { + "description": "Name of the monitored service on which the check ran.", + "type": "string", + "x-order": 6 + }, + "service_type": { + "description": "Type of the monitored service on which the check ran.", + "type": "string", + "x-order": 7 + }, + "node_id": { + "description": "ID of the node the service runs on.", + "type": "string", + "x-order": 8 + }, + "node_name": { + "description": "Name of the node the service runs on.", + "type": "string", + "x-order": 9 + }, + "status": { + "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", + "type": "string", + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "x-order": 10 + }, + "summary": { + "description": "Short human-readable summary of the result.", + "type": "string", + "x-order": 11 + }, + "description": { + "description": "Long human-readable description of the result.", + "type": "string", + "x-order": 12 + }, + "read_more_url": { + "description": "URL containing information on how to resolve a detected issue.", + "type": "string", + "x-order": 13 + }, + "severity": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 14 + }, + "labels": { + "description": "Result labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 15 + }, + "checked_at": { + "description": "Time when the check ran.", + "type": "string", + "format": "date-time", + "x-order": 16 + }, + "is_read": { + "description": "Whether the result has been marked as read.", + "type": "boolean", + "x-order": 17 + } + } + }, + "x-order": 2 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks:batchChange": { "post": { "description": "Enables/disables advisor checks or changes their exec interval.", diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index ae34b9296a5..5dc6a34cbfd 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1207,6 +1207,297 @@ } } }, + "/v1/advisors/checks/history": { + "get": { + "description": "Returns the history of Advisor check runs, including their outcomes.", + "tags": [ + "AdvisorService" + ], + "summary": "List Advisor Check Results History", + "operationId": "ListCheckResultsHistory", + "parameters": [ + { + "type": "integer", + "format": "int32", + "description": "Maximum number of results per page.", + "name": "page_size", + "in": "query" + }, + { + "type": "integer", + "format": "int32", + "description": "Index of the requested page, starts from 0.", + "name": "page_index", + "in": "query" + }, + { + "type": "string", + "description": "Filter by service ID.", + "name": "service_id", + "in": "query" + }, + { + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "type": "string", + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "description": "Filter by outcome.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", + "name": "status", + "in": "query" + }, + { + "type": "boolean", + "description": "Filter by read state.", + "name": "is_read", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Return only results recorded at or after this time.", + "name": "from", + "in": "query" + }, + { + "type": "string", + "format": "date-time", + "description": "Return only results recorded at or before this time.", + "name": "to", + "in": "query" + }, + { + "type": "string", + "description": "Filter by service name (partial, case-insensitive match).", + "name": "service_name", + "in": "query" + }, + { + "type": "string", + "description": "Filter by node name (partial, case-insensitive match).", + "name": "node_name", + "in": "query" + }, + { + "type": "string", + "description": "Filter by advisor category.", + "name": "category", + "in": "query" + }, + { + "type": "string", + "description": "Filter by check name.", + "name": "check_name", + "in": "query" + }, + { + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "description": "Filter by severity.", + "name": "severity", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "total_items": { + "description": "Total number of results.", + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "total_pages": { + "description": "Total number of pages.", + "type": "integer", + "format": "int32", + "x-order": 1 + }, + "results": { + "description": "History records.", + "type": "array", + "items": { + "description": "CheckResultHistoryItem represents a single persisted Advisor check run against a service.", + "type": "object", + "properties": { + "id": { + "description": "Unique identifier of the history record.", + "type": "string", + "x-order": 0 + }, + "check_name": { + "description": "Name of the check that ran.", + "type": "string", + "x-order": 1 + }, + "advisor_name": { + "description": "Name of the advisor the check belongs to.", + "type": "string", + "x-order": 2 + }, + "category": { + "description": "Category of the advisor the check belongs to.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "service_id": { + "description": "ID of the monitored service on which the check ran.", + "type": "string", + "x-order": 5 + }, + "service_name": { + "description": "Name of the monitored service on which the check ran.", + "type": "string", + "x-order": 6 + }, + "service_type": { + "description": "Type of the monitored service on which the check ran.", + "type": "string", + "x-order": 7 + }, + "node_id": { + "description": "ID of the node the service runs on.", + "type": "string", + "x-order": 8 + }, + "node_name": { + "description": "Name of the node the service runs on.", + "type": "string", + "x-order": 9 + }, + "status": { + "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", + "type": "string", + "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", + "ADVISOR_CHECK_RESULT_STATUS_OK", + "ADVISOR_CHECK_RESULT_STATUS_FAILED", + "ADVISOR_CHECK_RESULT_STATUS_ERROR" + ], + "x-order": 10 + }, + "summary": { + "description": "Short human-readable summary of the result.", + "type": "string", + "x-order": 11 + }, + "description": { + "description": "Long human-readable description of the result.", + "type": "string", + "x-order": 12 + }, + "read_more_url": { + "description": "URL containing information on how to resolve a detected issue.", + "type": "string", + "x-order": 13 + }, + "severity": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 14 + }, + "labels": { + "description": "Result labels.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 15 + }, + "checked_at": { + "description": "Time when the check ran.", + "type": "string", + "format": "date-time", + "x-order": 16 + }, + "is_read": { + "description": "Whether the result has been marked as read.", + "type": "boolean", + "x-order": 17 + } + } + }, + "x-order": 2 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks:batchChange": { "post": { "description": "Enables/disables advisor checks or changes their exec interval.", diff --git a/api/user/v1/user.pb.go b/api/user/v1/user.pb.go index 12a954ca3f4..200364a0741 100644 --- a/api/user/v1/user.pb.go +++ b/api/user/v1/user.pb.go @@ -507,7 +507,6 @@ var ( (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp } ) - var file_user_v1_user_proto_depIdxs = []int32{ 7, // 0: user.v1.GetUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp 7, // 1: user.v1.UpdateUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp diff --git a/api/user/v1/user.swagger.json b/api/user/v1/user.swagger.json new file mode 100644 index 00000000000..736cc43bfc0 --- /dev/null +++ b/api/user/v1/user.swagger.json @@ -0,0 +1,243 @@ +{ + "swagger": "2.0", + "info": { + "title": "User API", + "version": "version not set" + }, + "tags": [ + { + "name": "UserService" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/v1/users": { + "get": { + "summary": "List all users", + "description": "Retrieve user details for all users from PMM server", + "operationId": "ListUsers", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ListUsersResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "UserService" + ] + } + }, + "/v1/users/me": { + "get": { + "summary": "Get user details", + "description": "Retrieve user details from PMM server", + "operationId": "GetUser", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetUserResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "tags": [ + "UserService" + ] + }, + "put": { + "summary": "Update a user", + "description": "Update user details in PMM server", + "operationId": "UpdateUser", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UpdateUserResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UpdateUserRequest" + } + } + ], + "tags": [ + "UserService" + ] + } + } + }, + "definitions": { + "ListUsersResponseUserDetail": { + "type": "object", + "properties": { + "user_id": { + "type": "integer", + "format": "int64" + }, + "role_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "description": "List of role IDs assigned to the user." + } + } + }, + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1GetUserResponse": { + "type": "object", + "properties": { + "user_id": { + "type": "integer", + "format": "int64", + "title": "User ID" + }, + "product_tour_completed": { + "type": "boolean", + "title": "Product Tour" + }, + "alerting_tour_completed": { + "type": "boolean", + "title": "Alerting Tour" + }, + "snoozed_pmm_version": { + "type": "string", + "title": "Snoozed PMM version update" + }, + "snoozed_at": { + "type": "string", + "format": "date-time", + "title": "Timestamp of last snooze" + }, + "snooze_count": { + "type": "integer", + "format": "int64", + "title": "Number of times the update was snoozed" + } + } + }, + "v1ListUsersResponse": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/ListUsersResponseUserDetail" + } + } + } + }, + "v1UpdateUserRequest": { + "type": "object", + "properties": { + "product_tour_completed": { + "type": "boolean", + "x-nullable": true, + "title": "Product Tour" + }, + "alerting_tour_completed": { + "type": "boolean", + "x-nullable": true, + "title": "Alerting Tour" + }, + "snoozed_pmm_version": { + "type": "string", + "x-nullable": true, + "title": "Snooze update alert for a PMM version" + } + } + }, + "v1UpdateUserResponse": { + "type": "object", + "properties": { + "user_id": { + "type": "integer", + "format": "int64", + "title": "User ID" + }, + "product_tour_completed": { + "type": "boolean", + "title": "Product Tour" + }, + "alerting_tour_completed": { + "type": "boolean", + "title": "Alerting Tour" + }, + "snoozed_pmm_version": { + "type": "string", + "title": "Snooze update alert for a PMM version" + }, + "snoozed_at": { + "type": "string", + "format": "date-time", + "title": "Timestamp of last snooze" + }, + "snooze_count": { + "type": "integer", + "format": "int64", + "title": "Number of times the update was snoozed" + } + } + } + } +} diff --git a/managed/models/check_result_helpers.go b/managed/models/check_result_helpers.go index 864ffa780dc..459905ca30e 100644 --- a/managed/models/check_result_helpers.go +++ b/managed/models/check_result_helpers.go @@ -16,11 +16,126 @@ package models import ( + "fmt" + "strings" "time" + "github.com/google/uuid" "gopkg.in/reform.v1" ) +// CreateCheckResult inserts a single Advisor check result into the history. +func CreateCheckResult(q *reform.Querier, r *CheckResult) error { + if r.ID == "" { + r.ID = uuid.NewString() + } + return q.Insert(r) +} + +// CheckResultFilters specifies filters for querying Advisor check results history. +type CheckResultFilters struct { + ServiceID string + // ServiceName is matched as a case-insensitive substring. + ServiceName string + // NodeName is matched as a case-insensitive substring. + NodeName string + Category string + CheckName string + Severity *int + Status *CheckResultStatus + IsRead *bool + From *time.Time + To *time.Time +} + +// checkResultConditions builds the WHERE clause and arguments for the given filters. +func checkResultConditions(q *reform.Querier, filters CheckResultFilters) (string, []any) { + var conditions []string + var args []any + + if filters.ServiceID != "" { + conditions = append(conditions, "service_id = "+q.Placeholder(len(args)+1)) + args = append(args, filters.ServiceID) + } + if filters.ServiceName != "" { + conditions = append(conditions, "service_name ILIKE "+q.Placeholder(len(args)+1)) + args = append(args, "%"+filters.ServiceName+"%") + } + if filters.NodeName != "" { + conditions = append(conditions, "node_name ILIKE "+q.Placeholder(len(args)+1)) + args = append(args, "%"+filters.NodeName+"%") + } + if filters.Category != "" { + conditions = append(conditions, "category = "+q.Placeholder(len(args)+1)) + args = append(args, filters.Category) + } + if filters.CheckName != "" { + conditions = append(conditions, "check_name = "+q.Placeholder(len(args)+1)) + args = append(args, filters.CheckName) + } + if filters.Severity != nil { + conditions = append(conditions, "severity = "+q.Placeholder(len(args)+1)) + args = append(args, *filters.Severity) + } + if filters.Status != nil { + conditions = append(conditions, "status = "+q.Placeholder(len(args)+1)) + args = append(args, *filters.Status) + } + if filters.IsRead != nil { + conditions = append(conditions, "is_read = "+q.Placeholder(len(args)+1)) + args = append(args, *filters.IsRead) + } + if filters.From != nil { + conditions = append(conditions, "checked_at >= "+q.Placeholder(len(args)+1)) + args = append(args, *filters.From) + } + if filters.To != nil { + conditions = append(conditions, "checked_at <= "+q.Placeholder(len(args)+1)) + args = append(args, *filters.To) + } + + if len(conditions) == 0 { + return "", args + } + return "WHERE " + strings.Join(conditions, " AND "), args +} + +// FindCheckResults returns Advisor check results history matching the filters, ordered by +// checked_at descending. When pageSize is greater than zero, the results are paginated. +func FindCheckResults(q *reform.Querier, filters CheckResultFilters, pageIndex, pageSize int) ([]*CheckResult, error) { + tail, args := checkResultConditions(q, filters) + tail += " ORDER BY checked_at DESC" + if pageSize > 0 { + tail += " LIMIT " + q.Placeholder(len(args)+1) + args = append(args, pageSize) + tail += " OFFSET " + q.Placeholder(len(args)+1) + args = append(args, pageIndex*pageSize) + } + + rows, err := q.SelectAllFrom(CheckResultTable, tail, args...) + if err != nil { + return nil, fmt.Errorf("failed to select check results: %w", err) + } + + results := make([]*CheckResult, 0, len(rows)) + for _, r := range rows { + results = append(results, r.(*CheckResult)) //nolint:forcetypeassert + } + return results, nil +} + +// CountCheckResults returns the number of Advisor check results history rows matching the filters. +func CountCheckResults(q *reform.Querier, filters CheckResultFilters) (int, error) { + where, args := checkResultConditions(q, filters) + + var count int + err := q.QueryRow("SELECT count(*) FROM "+CheckResultTable.Name()+" "+where, args...).Scan(&count) + if err != nil { + return 0, fmt.Errorf("failed to count check results: %w", err) + } + return count, nil +} + // CleanupOldCheckResults deletes Advisor check results older than a specified date. func CleanupOldCheckResults(q *reform.Querier, olderThan time.Time) error { _, err := q.DeleteFrom(CheckResultTable, " WHERE checked_at <= $1", olderThan) diff --git a/managed/models/check_result_model.go b/managed/models/check_result_model.go index 12cd3ba911d..edb36057ae5 100644 --- a/managed/models/check_result_model.go +++ b/managed/models/check_result_model.go @@ -54,7 +54,7 @@ type CheckResult struct { Summary string `reform:"summary"` Description string `reform:"description"` ReadMoreURL string `reform:"read_more_url"` - Severity int32 `reform:"severity"` + Severity int `reform:"severity"` Labels []byte `reform:"labels"` CheckedAt time.Time `reform:"checked_at"` IsRead bool `reform:"is_read"` diff --git a/managed/models/check_result_model_reform.go b/managed/models/check_result_model_reform.go index 0fa74731ce6..137eb43cf0b 100644 --- a/managed/models/check_result_model_reform.go +++ b/managed/models/check_result_model_reform.go @@ -84,7 +84,7 @@ var CheckResultTable = &checkResultTableType{ {Name: "Summary", Type: "string", Column: "summary"}, {Name: "Description", Type: "string", Column: "description"}, {Name: "ReadMoreURL", Type: "string", Column: "read_more_url"}, - {Name: "Severity", Type: "int32", Column: "severity"}, + {Name: "Severity", Type: "int", Column: "severity"}, {Name: "Labels", Type: "[]uint8", Column: "labels"}, {Name: "CheckedAt", Type: "time.Time", Column: "checked_at"}, {Name: "IsRead", Type: "bool", Column: "is_read"}, diff --git a/managed/models/settings_helpers.go b/managed/models/settings_helpers.go index e6265ad3be6..d88e78f89f5 100644 --- a/managed/models/settings_helpers.go +++ b/managed/models/settings_helpers.go @@ -287,7 +287,7 @@ func ValidateSettings(params *ChangeSettingsParams) error { case validators.MinDurationError: return fmt.Errorf("%s: minimal resolution is 1s", v.fieldName) default: - return fmt.Errorf("%s: unknown error: %w", v.fieldName, err) + return fmt.Errorf("%s: %w", v.fieldName, err) } } } @@ -313,7 +313,7 @@ func ValidateSettings(params *ChangeSettingsParams) error { case validators.MinDurationError: return fmt.Errorf("%s: minimal resolution is 1s", v.fieldName) default: - return fmt.Errorf("%s: unknown error: %w", v.fieldName, err) + return fmt.Errorf("%s: %w", v.fieldName, err) } } } @@ -327,7 +327,7 @@ func ValidateSettings(params *ChangeSettingsParams) error { case validators.MinDurationError: return errors.New("data_retention: minimal resolution is 24h") default: - return fmt.Errorf("data_retention: unknown error: %w", err) + return fmt.Errorf("data_retention: %w", err) } } } diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index 658e420000e..f3fda234e7c 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -247,6 +247,22 @@ func (s *Service) GetChecksResults(_ context.Context, serviceID string) ([]servi return s.alertsRegistry.getCheckResults(serviceID), nil } +// GetCheckResultsHistory returns Advisor check results history matching the filters, +// together with the total number of matching rows (ignoring pagination). +func (s *Service) GetCheckResultsHistory(_ context.Context, filters models.CheckResultFilters, pageIndex, pageSize int) ([]*models.CheckResult, int, error) { + results, err := models.FindCheckResults(s.db.Querier, filters, pageIndex, pageSize) + if err != nil { + return nil, 0, err + } + + total, err := models.CountCheckResults(s.db.Querier, filters) + if err != nil { + return nil, 0, err + } + + return results, total, nil +} + // runChecksGroup downloads and executes Advisors checks that should run in the interval specified by intervalGroup. // All checks are executed if intervalGroup is empty. func (s *Service) runChecksGroup(ctx context.Context, intervalGroup check.Interval) error { @@ -666,6 +682,10 @@ func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interva func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType models.ServiceType, checks map[string]check.Check) []services.CheckResult { var res []services.CheckResult + var history []*models.CheckResult + categories := s.advisorCategories() + checkedAt := models.Now() + for _, c := range checks { s.l.Infof("Executing check: %s with interval: %s", c.Name, c.Interval) pmmAgentVersion := s.minPMMAgentVersion(c) @@ -676,23 +696,101 @@ func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType mo continue } + category := categories[c.Advisor] + for _, target := range targets { results, err := s.executeCheck(ctx, target, c) if err != nil { s.l.Warnf("Failed to execute check %s of type %s on target %s: %+v", c.Name, c.Type, target.AgentID, err) s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name, "error").Inc() + history = append(history, newCheckResultRecord(c, target, category, models.CheckResultError, check.Result{Description: err.Error()}, checkedAt)) continue } res = append(res, results...) s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name, "ok").Inc() + + if len(results) == 0 { + history = append(history, newCheckResultRecord(c, target, category, models.CheckResultOK, check.Result{}, checkedAt)) + continue + } + + for _, finding := range results { + history = append(history, newCheckResultRecord(c, target, category, models.CheckResultFailed, finding.Result, checkedAt)) + } } } + err := s.saveCheckResultsHistory(ctx, history) + if err != nil { + s.l.Warnf("Failed to save Advisor check results history: %+v", err) + } + return res } +// advisorCategories returns a map of advisor name to its category. +func (s *Service) advisorCategories() map[string]string { + s.am.Lock() + defer s.am.Unlock() + + categories := make(map[string]string, len(s.advisors)) + for _, a := range s.advisors { + categories[a.Name] = a.Category + } + return categories +} + +// newCheckResultRecord builds a history record for a single executed (check, target) outcome. +func newCheckResultRecord( + c check.Check, + target services.Target, + category string, + status models.CheckResultStatus, + result check.Result, + checkedAt time.Time, +) *models.CheckResult { + r := &models.CheckResult{ + CheckName: c.Name, + AdvisorName: c.Advisor, + Category: category, + Interval: models.Interval(c.Interval), + ServiceID: target.ServiceID, + ServiceName: target.ServiceName, + ServiceType: target.ServiceType, + NodeID: target.NodeID, + NodeName: target.NodeName, + Status: status, + Summary: result.Summary, + Description: result.Description, + ReadMoreURL: result.ReadMoreURL, + Severity: int(result.Severity), + CheckedAt: checkedAt, + } + if len(result.Labels) != 0 { + _ = r.SetLabels(result.Labels) + } + return r +} + +// saveCheckResultsHistory persists Advisor check results history in a single transaction. +func (s *Service) saveCheckResultsHistory(ctx context.Context, history []*models.CheckResult) error { + if len(history) == 0 { + return nil + } + + return s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + for _, r := range history { + err := models.CreateCheckResult(tx.Querier, r) + if err != nil { + return err + } + } + return nil + }) +} + func (s *Service) executeCheck(ctx context.Context, target services.Target, c check.Check) ([]services.CheckResult, error) { ctx, cancel := context.WithTimeout(ctx, checkExecutionTimeout) defer cancel() diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index c918a778c9c..5ddffb488a5 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -26,9 +26,11 @@ import ( "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" advisorsv1 "github.com/percona/pmm/api/advisors/v1" managementv1 "github.com/percona/pmm/api/management/v1" + "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/pi/check" "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/services" @@ -175,6 +177,94 @@ func (s *ChecksAPIService) GetFailedChecks(ctx context.Context, req *advisorsv1. }, nil } +// ListCheckResultsHistory returns the paginated history of Advisor check runs matching the filters. +func (s *ChecksAPIService) ListCheckResultsHistory( + ctx context.Context, + req *advisorsv1.ListCheckResultsHistoryRequest, +) (*advisorsv1.ListCheckResultsHistoryResponse, error) { + var pageIndex, pageSize int + if req.PageIndex != nil { + pageIndex = int(pointer.GetInt32(req.PageIndex)) + } + if req.PageSize != nil { + pageSize = int(pointer.GetInt32(req.PageSize)) + } + + filters := models.CheckResultFilters{ + ServiceID: req.ServiceId, + ServiceName: req.ServiceName, + NodeName: req.NodeName, + Category: req.Category, + CheckName: req.CheckName, + IsRead: req.IsRead, + } + if req.Status != nil { + if st := convertAPIResultStatus(*req.Status); st != "" { + filters.Status = &st + } + } + if req.Severity != nil { + severity := int(*req.Severity) + filters.Severity = &severity + } + if req.From != nil { + from := req.From.AsTime() + filters.From = &from + } + if req.To != nil { + to := req.To.AsTime() + filters.To = &to + } + + results, totalItems, err := s.checksService.GetCheckResultsHistory(ctx, filters, pageIndex, pageSize) + if err != nil { + return nil, fmt.Errorf("failed to get check results history: %w", err) + } + + items := make([]*advisorsv1.CheckResultHistoryItem, 0, len(results)) + for _, r := range results { + labels, err := r.GetLabels() + if err != nil { + return nil, fmt.Errorf("failed to decode labels for check result '%s': %w", r.ID, err) + } + + items = append(items, &advisorsv1.CheckResultHistoryItem{ + Id: r.ID, + CheckName: r.CheckName, + AdvisorName: r.AdvisorName, + Category: r.Category, + Interval: convertModelInterval(r.Interval), + ServiceId: r.ServiceID, + ServiceName: r.ServiceName, + ServiceType: string(r.ServiceType), + NodeId: r.NodeID, + NodeName: r.NodeName, + Status: convertModelResultStatus(r.Status), + Summary: r.Summary, + Description: r.Description, + ReadMoreUrl: r.ReadMoreURL, + Severity: managementv1.Severity(r.Severity), //nolint:gosec + Labels: labels, + CheckedAt: timestamppb.New(r.CheckedAt), + IsRead: r.IsRead, + }) + } + + totalPages := 1 + if pageSize > 0 { + totalPages = totalItems / pageSize + if totalItems%pageSize > 0 { + totalPages++ + } + } + + return &advisorsv1.ListCheckResultsHistoryResponse{ + Results: items, + TotalItems: int32(totalItems), //nolint:gosec // result count comfortably fits int32 + TotalPages: int32(totalPages), + }, nil +} + // StartAdvisorChecks executes advisor checks and returns when all checks are executed. func (s *ChecksAPIService) StartAdvisorChecks(_ context.Context, req *advisorsv1.StartAdvisorChecksRequest) (*advisorsv1.StartAdvisorChecksResponse, error) { // Start only specified checks from any group. @@ -355,6 +445,49 @@ func convertInterval(interval check.Interval) advisorsv1.AdvisorCheckInterval { } } +// convertModelInterval converts models.Interval type to advisorsv1.AdvisorCheckInterval. +func convertModelInterval(interval models.Interval) advisorsv1.AdvisorCheckInterval { + switch interval { + case models.Standard, "": // empty interval means standard + return advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_STANDARD + case models.Frequent: + return advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_FREQUENT + case models.Rare: + return advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_RARE + default: + return advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_UNSPECIFIED + } +} + +// convertModelResultStatus converts models.CheckResultStatus to advisorsv1.AdvisorCheckResultStatus. +func convertModelResultStatus(status models.CheckResultStatus) advisorsv1.AdvisorCheckResultStatus { + switch status { + case models.CheckResultOK: + return advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_OK + case models.CheckResultFailed: + return advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_FAILED + case models.CheckResultError: + return advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_ERROR + default: + return advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED + } +} + +// convertAPIResultStatus converts advisorsv1.AdvisorCheckResultStatus to models.CheckResultStatus. +// An empty value is returned for an unspecified status, meaning "no filter". +func convertAPIResultStatus(status advisorsv1.AdvisorCheckResultStatus) models.CheckResultStatus { + switch status { + case advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_OK: + return models.CheckResultOK + case advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_FAILED: + return models.CheckResultFailed + case advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_ERROR: + return models.CheckResultError + default: + return "" + } +} + // convertFamily converts check.Family type to advisorsv1.AdvisorCheckFamily. func convertFamily(family check.Family) advisorsv1.AdvisorCheckFamily { switch family { diff --git a/managed/services/management/checks_test.go b/managed/services/management/checks_test.go index 4b7df573ab9..f7edd7559d5 100644 --- a/managed/services/management/checks_test.go +++ b/managed/services/management/checks_test.go @@ -19,15 +19,18 @@ import ( "errors" "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" advisorsv1 "github.com/percona/pmm/api/advisors/v1" managementv1 "github.com/percona/pmm/api/management/v1" + "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/pi/check" "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/services" @@ -205,6 +208,89 @@ func TestGetFailedChecks(t *testing.T) { }) } +func TestListCheckResultsHistory(t *testing.T) { + t.Parallel() + + t.Run("internal error", func(t *testing.T) { + t.Parallel() + + var checksService mockChecksService + checksService.On("GetCheckResultsHistory", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(nil, 0, errors.New("random error")) + + s := NewChecksAPIService(&checksService) + + resp, err := s.ListCheckResultsHistory(t.Context(), &advisorsv1.ListCheckResultsHistoryRequest{}) + require.EqualError(t, err, "failed to get check results history: random error") + assert.Nil(t, resp) + }) + + t.Run("returns converted history with pagination totals", func(t *testing.T) { + t.Parallel() + + checkedAt := time.Date(2026, time.June, 27, 10, 0, 0, 0, time.UTC) + record := &models.CheckResult{ + ID: "id1", + CheckName: "test_check", + AdvisorName: "test_advisor", + Category: "configuration", + Interval: models.Standard, + ServiceID: "test_svc", + ServiceName: "svc", + ServiceType: models.MySQLServiceType, + NodeID: "node1", + NodeName: "node", + Status: models.CheckResultFailed, + Summary: "Check summary", + Description: "Check Description", + ReadMoreURL: "https://www.example.com", + Severity: int(common.Emergency), + CheckedAt: checkedAt, + } + require.NoError(t, record.SetLabels(map[string]string{"label_key": "label_value"})) + + var checksService mockChecksService + checksService.On("GetCheckResultsHistory", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return([]*models.CheckResult{record}, 3, nil) + + s := NewChecksAPIService(&checksService) + + resp, err := s.ListCheckResultsHistory(t.Context(), &advisorsv1.ListCheckResultsHistoryRequest{ + ServiceId: "test_svc", + PageSize: new(int32(2)), + PageIndex: new(int32(0)), + }) + require.NoError(t, err) + + expected := &advisorsv1.ListCheckResultsHistoryResponse{ + Results: []*advisorsv1.CheckResultHistoryItem{ + { + Id: "id1", + CheckName: "test_check", + AdvisorName: "test_advisor", + Category: "configuration", + Interval: advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_STANDARD, + ServiceId: "test_svc", + ServiceName: "svc", + ServiceType: string(models.MySQLServiceType), + NodeId: "node1", + NodeName: "node", + Status: advisorsv1.AdvisorCheckResultStatus_ADVISOR_CHECK_RESULT_STATUS_FAILED, + Summary: "Check summary", + Description: "Check Description", + ReadMoreUrl: "https://www.example.com", + Severity: managementv1.Severity(common.Emergency), + Labels: map[string]string{"label_key": "label_value"}, + CheckedAt: timestamppb.New(checkedAt), + }, + }, + TotalItems: 3, + TotalPages: 2, + } + assert.Equal(t, expected, resp) + }) +} + func TestListFailedServices(t *testing.T) { t.Parallel() diff --git a/managed/services/management/deps.go b/managed/services/management/deps.go index aa94b71a44a..ec87ddbdb0d 100644 --- a/managed/services/management/deps.go +++ b/managed/services/management/deps.go @@ -59,6 +59,7 @@ type checksService interface { GetChecks() (map[string]check.Check, error) GetAdvisors() ([]check.Advisor, error) GetChecksResults(ctx context.Context, serviceID string) ([]services.CheckResult, error) + GetCheckResultsHistory(ctx context.Context, filters models.CheckResultFilters, pageIndex, pageSize int) ([]*models.CheckResult, int, error) GetDisabledChecks() ([]string, error) DisableChecks(checkNames []string) error EnableChecks(checkNames []string) error diff --git a/managed/services/management/mock_checks_service_test.go b/managed/services/management/mock_checks_service_test.go index fc74bcbdb4d..73c35d764d5 100644 --- a/managed/services/management/mock_checks_service_test.go +++ b/managed/services/management/mock_checks_service_test.go @@ -7,6 +7,7 @@ import ( mock "github.com/stretchr/testify/mock" + models "github.com/percona/pmm/managed/models" check "github.com/percona/pmm/managed/pi/check" services "github.com/percona/pmm/managed/services" ) @@ -100,6 +101,43 @@ func (_m *mockChecksService) GetAdvisors() ([]check.Advisor, error) { return r0, r1 } +// GetCheckResultsHistory provides a mock function with given fields: ctx, filters, pageIndex, pageSize +func (_m *mockChecksService) GetCheckResultsHistory(ctx context.Context, filters models.CheckResultFilters, pageIndex int, pageSize int) ([]*models.CheckResult, int, error) { + ret := _m.Called(ctx, filters, pageIndex, pageSize) + + if len(ret) == 0 { + panic("no return value specified for GetCheckResultsHistory") + } + + var r0 []*models.CheckResult + var r1 int + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, models.CheckResultFilters, int, int) ([]*models.CheckResult, int, error)); ok { + return rf(ctx, filters, pageIndex, pageSize) + } + if rf, ok := ret.Get(0).(func(context.Context, models.CheckResultFilters, int, int) []*models.CheckResult); ok { + r0 = rf(ctx, filters, pageIndex, pageSize) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*models.CheckResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, models.CheckResultFilters, int, int) int); ok { + r1 = rf(ctx, filters, pageIndex, pageSize) + } else { + r1 = ret.Get(1).(int) + } + + if rf, ok := ret.Get(2).(func(context.Context, models.CheckResultFilters, int, int) error); ok { + r2 = rf(ctx, filters, pageIndex, pageSize) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // GetChecks provides a mock function with no fields func (_m *mockChecksService) GetChecks() (map[string]check.Check, error) { ret := _m.Called() From 88c525ec806f829bd652abdb1b68ef424158de1d Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sat, 27 Jun 2026 19:45:51 +0300 Subject: [PATCH 006/120] PMM-14109 Update comments ListCheckResultsHistory response --- managed/services/management/checks.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index 5ddffb488a5..3fc20e71af4 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -260,8 +260,8 @@ func (s *ChecksAPIService) ListCheckResultsHistory( return &advisorsv1.ListCheckResultsHistoryResponse{ Results: items, - TotalItems: int32(totalItems), //nolint:gosec // result count comfortably fits int32 - TotalPages: int32(totalPages), + TotalItems: int32(totalItems), //nolint:gosec + TotalPages: int32(totalPages), //nolint:gosec }, nil } From c372ce6bb2af1c24c770867515cd20f4b7115ef6 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 11:25:45 +0300 Subject: [PATCH 007/120] PMM-12345 Add functionality to mark Advisor check results as read - Implemented MarkCheckResultsRead function in the service layer to update the read state of check results. - Added corresponding API endpoint for marking check results as read. - Introduced new parameters and response structures for the API. - Updated settings model to include Advisor notification settings. - Enhanced environment variable parsing to support new Advisor notification feature. - Added tests for the new functionality to ensure proper behavior. --- api/accesscontrol/v1beta1/accesscontrol.pb.go | 1 + api/actions/v1/actions.pb.go | 1 + api/advisors/v1/advisors.pb.go | 166 +++++-- api/advisors/v1/advisors.pb.gw.go | 66 +++ api/advisors/v1/advisors.pb.validate.go | 221 +++++++++ api/advisors/v1/advisors.proto | 20 + api/advisors/v1/advisors.swagger.json | 53 ++ api/advisors/v1/advisors_grpc.pb.go | 41 ++ .../advisor_service/advisor_service_client.go | 46 ++ .../mark_check_results_read_parameters.go | 141 ++++++ .../mark_check_results_read_responses.go | 451 ++++++++++++++++++ api/advisors/v1/json/v1.json | 74 +++ api/agent/v1/agent.pb.go | 1 + api/agent/v1/collector.pb.go | 1 + api/agentlocal/v1/agentlocal.pb.go | 1 + api/alerting/v1/alerting.pb.go | 1 + api/alerting/v1/params.pb.go | 1 + api/backup/v1/artifacts.pb.go | 1 + api/backup/v1/backup.pb.go | 1 + api/backup/v1/common.pb.go | 1 + api/backup/v1/errors.pb.go | 1 + api/backup/v1/locations.pb.go | 1 + api/backup/v1/restores.pb.go | 1 + api/common/common.pb.go | 1 + api/common/metrics_resolutions.pb.go | 1 + api/descriptor.bin | Bin 823750 -> 826121 bytes api/dump/v1beta1/dump.pb.go | 1 + api/extensions/v1/redact.pb.go | 1 + api/ha/v1beta1/ha.pb.go | 1 + api/inventory/v1/agent_status.pb.go | 1 + api/inventory/v1/agents.pb.go | 1 + api/inventory/v1/log_level.pb.go | 1 + api/inventory/v1/nodes.pb.go | 1 + api/inventory/v1/services.pb.go | 1 + api/management/v1/agent.pb.go | 1 + api/management/v1/annotation.pb.go | 1 + api/management/v1/azure.pb.go | 1 + api/management/v1/external.pb.go | 1 + api/management/v1/haproxy.pb.go | 1 + api/management/v1/metrics.pb.go | 1 + api/management/v1/mongodb.pb.go | 1 + api/management/v1/mysql.pb.go | 1 + api/management/v1/node.pb.go | 1 + api/management/v1/postgresql.pb.go | 1 + api/management/v1/proxysql.pb.go | 1 + api/management/v1/rds.pb.go | 1 + api/management/v1/service.pb.go | 1 + api/management/v1/severity.pb.go | 1 + api/management/v1/valkey.pb.go | 1 + api/qan/v1/collector.pb.go | 1 + api/qan/v1/filters.pb.go | 1 + api/qan/v1/object_details.pb.go | 1 + api/qan/v1/profile.pb.go | 1 + api/qan/v1/qan.pb.go | 1 + api/qan/v1/service.pb.go | 1 + api/realtimeanalytics/v1/collector.pb.go | 1 + api/realtimeanalytics/v1/query.pb.go | 1 + .../v1/realtimeanalytics.pb.go | 1 + api/server/v1/httperror.pb.go | 1 + .../change_settings_responses.go | 155 ++++++ .../server_service/get_settings_responses.go | 78 +++ api/server/v1/json/v1.json | 164 +++++-- api/server/v1/server.pb.go | 180 ++++--- api/server/v1/server.pb.validate.go | 72 +++ api/server/v1/server.proto | 13 + api/server/v1/server.swagger.json | 41 ++ api/swagger/swagger-dev.json | 238 +++++++-- api/swagger/swagger.json | 238 +++++++-- api/user/v1/user.pb.go | 1 + .../deployment-options/docker/env_var.md | 1 + managed/models/check_result_helpers.go | 22 + managed/models/settings.go | 23 + managed/models/settings_helpers.go | 21 + managed/services/checks/checks.go | 5 + managed/services/checks/registry.go | 6 +- managed/services/management/checks.go | 13 + managed/services/management/checks_test.go | 38 ++ managed/services/management/deps.go | 1 + .../management/mock_checks_service_test.go | 18 + managed/services/server/server.go | 36 +- managed/utils/envvars/parser.go | 9 + managed/utils/envvars/parser_test.go | 12 +- 82 files changed, 2483 insertions(+), 229 deletions(-) create mode 100644 api/advisors/v1/json/client/advisor_service/mark_check_results_read_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/mark_check_results_read_responses.go diff --git a/api/accesscontrol/v1beta1/accesscontrol.pb.go b/api/accesscontrol/v1beta1/accesscontrol.pb.go index ebec3bf05b7..f5e8ea4b004 100644 --- a/api/accesscontrol/v1beta1/accesscontrol.pb.go +++ b/api/accesscontrol/v1beta1/accesscontrol.pb.go @@ -844,6 +844,7 @@ var ( (*ListRolesResponse_RoleData)(nil), // 14: accesscontrol.v1beta1.ListRolesResponse.RoleData } ) + var file_accesscontrol_v1beta1_accesscontrol_proto_depIdxs = []int32{ 14, // 0: accesscontrol.v1beta1.ListRolesResponse.roles:type_name -> accesscontrol.v1beta1.ListRolesResponse.RoleData 0, // 1: accesscontrol.v1beta1.AccessControlService.CreateRole:input_type -> accesscontrol.v1beta1.CreateRoleRequest diff --git a/api/actions/v1/actions.pb.go b/api/actions/v1/actions.pb.go index 35461ae3739..f1cfdec8cfa 100644 --- a/api/actions/v1/actions.pb.go +++ b/api/actions/v1/actions.pb.go @@ -2649,6 +2649,7 @@ var ( (*StartServiceActionResponse)(nil), // 32: actions.v1.StartServiceActionResponse } ) + var file_actions_v1_actions_proto_depIdxs = []int32{ 3, // 0: actions.v1.StartServiceActionRequest.mysql_explain:type_name -> actions.v1.StartMySQLExplainActionParams 5, // 1: actions.v1.StartServiceActionRequest.mysql_explain_json:type_name -> actions.v1.StartMySQLExplainJSONActionParams diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index 48949e35583..a179ff24f0e 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -1692,6 +1692,96 @@ func (x *ListCheckResultsHistoryResponse) GetResults() []*CheckResultHistoryItem return nil } +type MarkCheckResultsReadRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // IDs of the history records to update. + Ids []string `protobuf:"bytes,1,rep,name=ids,proto3" json:"ids,omitempty"` + // Read state to set on the records. + IsRead bool `protobuf:"varint,2,opt,name=is_read,json=isRead,proto3" json:"is_read,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MarkCheckResultsReadRequest) Reset() { + *x = MarkCheckResultsReadRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MarkCheckResultsReadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkCheckResultsReadRequest) ProtoMessage() {} + +func (x *MarkCheckResultsReadRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MarkCheckResultsReadRequest.ProtoReflect.Descriptor instead. +func (*MarkCheckResultsReadRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{21} +} + +func (x *MarkCheckResultsReadRequest) GetIds() []string { + if x != nil { + return x.Ids + } + return nil +} + +func (x *MarkCheckResultsReadRequest) GetIsRead() bool { + if x != nil { + return x.IsRead + } + return false +} + +type MarkCheckResultsReadResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MarkCheckResultsReadResponse) Reset() { + *x = MarkCheckResultsReadResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MarkCheckResultsReadResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkCheckResultsReadResponse) ProtoMessage() {} + +func (x *MarkCheckResultsReadResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MarkCheckResultsReadResponse.ProtoReflect.Descriptor instead. +func (*MarkCheckResultsReadResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{22} +} + var File_advisors_v1_advisors_proto protoreflect.FileDescriptor const file_advisors_v1_advisors_proto_rawDesc = "" + @@ -1844,7 +1934,11 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "totalItems\x12\x1f\n" + "\vtotal_pages\x18\x02 \x01(\x05R\n" + "totalPages\x12=\n" + - "\aresults\x18\x03 \x03(\v2#.advisors.v1.CheckResultHistoryItemR\aresults*\xa9\x01\n" + + "\aresults\x18\x03 \x03(\v2#.advisors.v1.CheckResultHistoryItemR\aresults\"R\n" + + "\x1bMarkCheckResultsReadRequest\x12\x1a\n" + + "\x03ids\x18\x01 \x03(\tB\b\xfaB\x05\x92\x01\x02\b\x01R\x03ids\x12\x17\n" + + "\ais_read\x18\x02 \x01(\bR\x06isRead\"\x1e\n" + + "\x1cMarkCheckResultsReadResponse*\xa9\x01\n" + "\x14AdvisorCheckInterval\x12&\n" + "\"ADVISOR_CHECK_INTERVAL_UNSPECIFIED\x10\x00\x12#\n" + "\x1fADVISOR_CHECK_INTERVAL_STANDARD\x10\x01\x12#\n" + @@ -1859,11 +1953,12 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "'ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED\x10\x00\x12\"\n" + "\x1eADVISOR_CHECK_RESULT_STATUS_OK\x10\x01\x12&\n" + "\"ADVISOR_CHECK_RESULT_STATUS_FAILED\x10\x02\x12%\n" + - "!ADVISOR_CHECK_RESULT_STATUS_ERROR\x10\x032\xf8\f\n" + + "!ADVISOR_CHECK_RESULT_STATUS_ERROR\x10\x032\xac\x0f\n" + "\x0eAdvisorService\x12\xf3\x01\n" + "\x12ListFailedServices\x12&.advisors.v1.ListFailedServicesRequest\x1a'.advisors.v1.ListFailedServicesResponse\"\x8b\x01\x92Ae\x12\x14List Failed Services\x1aMReturns a list of services with failed checks and a summary of check results.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/failedServices\x12\xd5\x01\n" + "\x0fGetFailedChecks\x12#.advisors.v1.GetFailedChecksRequest\x1a$.advisors.v1.GetFailedChecksResponse\"w\x92AR\x12\x19Get Failed Advisor Checks\x1a5Returns the latest check results for a given service.\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/advisors/checks/failed\x12\x87\x02\n" + - "\x17ListCheckResultsHistory\x12+.advisors.v1.ListCheckResultsHistoryRequest\x1a,.advisors.v1.ListCheckResultsHistoryResponse\"\x90\x01\x92Aj\x12\"List Advisor Check Results History\x1aDReturns the history of Advisor check runs, including their outcomes.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/checks/history\x12\xb0\x02\n" + + "\x17ListCheckResultsHistory\x12+.advisors.v1.ListCheckResultsHistoryRequest\x1a,.advisors.v1.ListCheckResultsHistoryResponse\"\x90\x01\x92Aj\x12\"List Advisor Check Results History\x1aDReturns the history of Advisor check runs, including their outcomes.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/checks/history\x12\xb1\x02\n" + + "\x14MarkCheckResultsRead\x12(.advisors.v1.MarkCheckResultsReadRequest\x1a).advisors.v1.MarkCheckResultsReadResponse\"\xc3\x01\x92A\x90\x01\x12\x1fMark Advisor Check Results Read\x1amSets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.\x82\xd3\xe4\x93\x02):\x01*\"$/v1/advisors/checks/history:markRead\x12\xb0\x02\n" + "\x12StartAdvisorChecks\x12&.advisors.v1.StartAdvisorChecksRequest\x1a'.advisors.v1.StartAdvisorChecksResponse\"\xc8\x01\x92A\xa0\x01\x12\x14Start Advisor Checks\x1a\x87\x01Executes Advisor checks and returns when all checks are executed. All available checks will be started if check names aren't specified.\x82\xd3\xe4\x93\x02\x1e:\x01*\"\x19/v1/advisors/checks:start\x12\xc3\x01\n" + "\x11ListAdvisorChecks\x12%.advisors.v1.ListAdvisorChecksRequest\x1a&.advisors.v1.ListAdvisorChecksResponse\"_\x92AA\x12\x13List Advisor Checks\x1a*List advisor checks available to the user.\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/advisors/checks\x12\xa1\x01\n" + "\fListAdvisors\x12 .advisors.v1.ListAdvisorsRequest\x1a!.advisors.v1.ListAdvisorsResponse\"L\x92A5\x12\rList Advisors\x1a$List advisors available to the user.\x82\xd3\xe4\x93\x02\x0e\x12\f/v1/advisors\x12\xf0\x01\n" + @@ -1884,7 +1979,7 @@ func file_advisors_v1_advisors_proto_rawDescGZIP() []byte { var ( file_advisors_v1_advisors_proto_enumTypes = make([]protoimpl.EnumInfo, 3) - file_advisors_v1_advisors_proto_msgTypes = make([]protoimpl.MessageInfo, 24) + file_advisors_v1_advisors_proto_msgTypes = make([]protoimpl.MessageInfo, 26) file_advisors_v1_advisors_proto_goTypes = []any{ AdvisorCheckInterval(0), // 0: advisors.v1.AdvisorCheckInterval AdvisorCheckFamily(0), // 1: advisors.v1.AdvisorCheckFamily @@ -1910,18 +2005,21 @@ var ( (*CheckResultHistoryItem)(nil), // 21: advisors.v1.CheckResultHistoryItem (*ListCheckResultsHistoryRequest)(nil), // 22: advisors.v1.ListCheckResultsHistoryRequest (*ListCheckResultsHistoryResponse)(nil), // 23: advisors.v1.ListCheckResultsHistoryResponse - nil, // 24: advisors.v1.AdvisorCheckResult.LabelsEntry - nil, // 25: advisors.v1.CheckResult.LabelsEntry - nil, // 26: advisors.v1.CheckResultHistoryItem.LabelsEntry - v1.Severity(0), // 27: management.v1.Severity - (*timestamppb.Timestamp)(nil), // 28: google.protobuf.Timestamp + (*MarkCheckResultsReadRequest)(nil), // 24: advisors.v1.MarkCheckResultsReadRequest + (*MarkCheckResultsReadResponse)(nil), // 25: advisors.v1.MarkCheckResultsReadResponse + nil, // 26: advisors.v1.AdvisorCheckResult.LabelsEntry + nil, // 27: advisors.v1.CheckResult.LabelsEntry + nil, // 28: advisors.v1.CheckResultHistoryItem.LabelsEntry + v1.Severity(0), // 29: management.v1.Severity + (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp } ) + var file_advisors_v1_advisors_proto_depIdxs = []int32{ - 27, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity - 24, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry - 27, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity - 25, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry + 29, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity + 26, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry + 29, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity + 27, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry 0, // 4: advisors.v1.AdvisorCheck.interval:type_name -> advisors.v1.AdvisorCheckInterval 1, // 5: advisors.v1.AdvisorCheck.family:type_name -> advisors.v1.AdvisorCheckFamily 6, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck @@ -1933,30 +2031,32 @@ var file_advisors_v1_advisors_proto_depIdxs = []int32{ 5, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult 0, // 13: advisors.v1.CheckResultHistoryItem.interval:type_name -> advisors.v1.AdvisorCheckInterval 2, // 14: advisors.v1.CheckResultHistoryItem.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 27, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity - 26, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry - 28, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp + 29, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity + 28, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry + 30, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp 2, // 18: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 28, // 19: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp - 28, // 20: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp - 27, // 21: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity + 30, // 19: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp + 30, // 20: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp + 29, // 21: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity 21, // 22: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem 17, // 23: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest 19, // 24: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest 22, // 25: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest - 9, // 26: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest - 11, // 27: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest - 13, // 28: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest - 15, // 29: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest - 18, // 30: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse - 20, // 31: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse - 23, // 32: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse - 10, // 33: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse - 12, // 34: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse - 14, // 35: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse - 16, // 36: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse - 30, // [30:37] is the sub-list for method output_type - 23, // [23:30] is the sub-list for method input_type + 24, // 26: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest + 9, // 27: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest + 11, // 28: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest + 13, // 29: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest + 15, // 30: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest + 18, // 31: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse + 20, // 32: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse + 23, // 33: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse + 25, // 34: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse + 10, // 35: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse + 12, // 36: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse + 14, // 37: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse + 16, // 38: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse + 31, // [31:39] is the sub-list for method output_type + 23, // [23:31] is the sub-list for method input_type 23, // [23:23] is the sub-list for extension type_name 23, // [23:23] is the sub-list for extension extendee 0, // [0:23] is the sub-list for field type_name @@ -1976,7 +2076,7 @@ func file_advisors_v1_advisors_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_advisors_v1_advisors_proto_rawDesc), len(file_advisors_v1_advisors_proto_rawDesc)), NumEnums: 3, - NumMessages: 24, + NumMessages: 26, NumExtensions: 0, NumServices: 1, }, diff --git a/api/advisors/v1/advisors.pb.gw.go b/api/advisors/v1/advisors.pb.gw.go index 367941ad5e4..fff3231a1ab 100644 --- a/api/advisors/v1/advisors.pb.gw.go +++ b/api/advisors/v1/advisors.pb.gw.go @@ -126,6 +126,33 @@ func local_request_AdvisorService_ListCheckResultsHistory_0(ctx context.Context, return msg, metadata, err } +func request_AdvisorService_MarkCheckResultsRead_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq MarkCheckResultsReadRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.MarkCheckResultsRead(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_MarkCheckResultsRead_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq MarkCheckResultsReadRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.MarkCheckResultsRead(ctx, &protoReq) + return msg, metadata, err +} + func request_AdvisorService_StartAdvisorChecks_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq StartAdvisorChecksRequest @@ -288,6 +315,26 @@ func RegisterAdvisorServiceHandlerServer(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ListCheckResultsHistory_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_AdvisorService_MarkCheckResultsRead_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/MarkCheckResultsRead", runtime.WithHTTPPathPattern("/v1/advisors/checks/history:markRead")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_MarkCheckResultsRead_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_MarkCheckResultsRead_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_AdvisorService_StartAdvisorChecks_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -459,6 +506,23 @@ func RegisterAdvisorServiceHandlerClient(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ListCheckResultsHistory_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodPost, pattern_AdvisorService_MarkCheckResultsRead_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/MarkCheckResultsRead", runtime.WithHTTPPathPattern("/v1/advisors/checks/history:markRead")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_MarkCheckResultsRead_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_MarkCheckResultsRead_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_AdvisorService_StartAdvisorChecks_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -534,6 +598,7 @@ var ( pattern_AdvisorService_ListFailedServices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "failedServices"}, "")) pattern_AdvisorService_GetFailedChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "failed"}, "")) pattern_AdvisorService_ListCheckResultsHistory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "")) + pattern_AdvisorService_MarkCheckResultsRead_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "markRead")) pattern_AdvisorService_StartAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "start")) pattern_AdvisorService_ListAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "")) pattern_AdvisorService_ListAdvisors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "advisors"}, "")) @@ -544,6 +609,7 @@ var ( forward_AdvisorService_ListFailedServices_0 = runtime.ForwardResponseMessage forward_AdvisorService_GetFailedChecks_0 = runtime.ForwardResponseMessage forward_AdvisorService_ListCheckResultsHistory_0 = runtime.ForwardResponseMessage + forward_AdvisorService_MarkCheckResultsRead_0 = runtime.ForwardResponseMessage forward_AdvisorService_StartAdvisorChecks_0 = runtime.ForwardResponseMessage forward_AdvisorService_ListAdvisorChecks_0 = runtime.ForwardResponseMessage forward_AdvisorService_ListAdvisors_0 = runtime.ForwardResponseMessage diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 388f67cd9d1..d64096525dd 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -2717,3 +2717,224 @@ var _ interface { Cause() error ErrorName() string } = ListCheckResultsHistoryResponseValidationError{} + +// Validate checks the field values on MarkCheckResultsReadRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *MarkCheckResultsReadRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on MarkCheckResultsReadRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// MarkCheckResultsReadRequestMultiError, or nil if none found. +func (m *MarkCheckResultsReadRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *MarkCheckResultsReadRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(m.GetIds()) < 1 { + err := MarkCheckResultsReadRequestValidationError{ + field: "Ids", + reason: "value must contain at least 1 item(s)", + } + if !all { + return err + } + errors = append(errors, err) + } + + // no validation rules for IsRead + + if len(errors) > 0 { + return MarkCheckResultsReadRequestMultiError(errors) + } + + return nil +} + +// MarkCheckResultsReadRequestMultiError is an error wrapping multiple +// validation errors returned by MarkCheckResultsReadRequest.ValidateAll() if +// the designated constraints aren't met. +type MarkCheckResultsReadRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m MarkCheckResultsReadRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m MarkCheckResultsReadRequestMultiError) AllErrors() []error { return m } + +// MarkCheckResultsReadRequestValidationError is the validation error returned +// by MarkCheckResultsReadRequest.Validate if the designated constraints +// aren't met. +type MarkCheckResultsReadRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e MarkCheckResultsReadRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e MarkCheckResultsReadRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e MarkCheckResultsReadRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e MarkCheckResultsReadRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e MarkCheckResultsReadRequestValidationError) ErrorName() string { + return "MarkCheckResultsReadRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e MarkCheckResultsReadRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sMarkCheckResultsReadRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = MarkCheckResultsReadRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = MarkCheckResultsReadRequestValidationError{} + +// Validate checks the field values on MarkCheckResultsReadResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *MarkCheckResultsReadResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on MarkCheckResultsReadResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// MarkCheckResultsReadResponseMultiError, or nil if none found. +func (m *MarkCheckResultsReadResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *MarkCheckResultsReadResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return MarkCheckResultsReadResponseMultiError(errors) + } + + return nil +} + +// MarkCheckResultsReadResponseMultiError is an error wrapping multiple +// validation errors returned by MarkCheckResultsReadResponse.ValidateAll() if +// the designated constraints aren't met. +type MarkCheckResultsReadResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m MarkCheckResultsReadResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m MarkCheckResultsReadResponseMultiError) AllErrors() []error { return m } + +// MarkCheckResultsReadResponseValidationError is the validation error returned +// by MarkCheckResultsReadResponse.Validate if the designated constraints +// aren't met. +type MarkCheckResultsReadResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e MarkCheckResultsReadResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e MarkCheckResultsReadResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e MarkCheckResultsReadResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e MarkCheckResultsReadResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e MarkCheckResultsReadResponseValidationError) ErrorName() string { + return "MarkCheckResultsReadResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e MarkCheckResultsReadResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sMarkCheckResultsReadResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = MarkCheckResultsReadResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = MarkCheckResultsReadResponseValidationError{} diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index e1bae401213..a0c6d9d2999 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -251,6 +251,15 @@ message ListCheckResultsHistoryResponse { repeated CheckResultHistoryItem results = 3; } +message MarkCheckResultsReadRequest { + // IDs of the history records to update. + repeated string ids = 1 [(validate.rules).repeated.min_items = 1]; + // Read state to set on the records. + bool is_read = 2; +} + +message MarkCheckResultsReadResponse {} + // AdvisorService service provides public Management API methods for Advisor Service. service AdvisorService { // ListFailedServices returns a list of services with failed checks. @@ -277,6 +286,17 @@ service AdvisorService { description: "Returns the history of Advisor check runs, including their outcomes." }; } + // MarkCheckResultsRead sets the read state on Advisor check history records. + rpc MarkCheckResultsRead(MarkCheckResultsReadRequest) returns (MarkCheckResultsReadResponse) { + option (google.api.http) = { + post: "/v1/advisors/checks/history:markRead" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Mark Advisor Check Results Read" + description: "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread." + }; + } // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. rpc StartAdvisorChecks(StartAdvisorChecksRequest) returns (StartAdvisorChecksResponse) { option (google.api.http) = { diff --git a/api/advisors/v1/advisors.swagger.json b/api/advisors/v1/advisors.swagger.json index 2a24c0513a7..82c8d7b202b 100644 --- a/api/advisors/v1/advisors.swagger.json +++ b/api/advisors/v1/advisors.swagger.json @@ -246,6 +246,40 @@ ] } }, + "/v1/advisors/checks/history:markRead": { + "post": { + "summary": "Mark Advisor Check Results Read", + "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", + "operationId": "MarkCheckResultsRead", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1MarkCheckResultsReadResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1MarkCheckResultsReadRequest" + } + } + ], + "tags": [ + "AdvisorService" + ] + } + }, "/v1/advisors/checks:batchChange": { "post": { "summary": "Change Advisor Checks", @@ -753,6 +787,25 @@ } } }, + "v1MarkCheckResultsReadRequest": { + "type": "object", + "properties": { + "ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "IDs of the history records to update." + }, + "is_read": { + "type": "boolean", + "description": "Read state to set on the records." + } + } + }, + "v1MarkCheckResultsReadResponse": { + "type": "object" + }, "v1Severity": { "type": "string", "enum": [ diff --git a/api/advisors/v1/advisors_grpc.pb.go b/api/advisors/v1/advisors_grpc.pb.go index 73e451ce1d5..11092635e35 100644 --- a/api/advisors/v1/advisors_grpc.pb.go +++ b/api/advisors/v1/advisors_grpc.pb.go @@ -23,6 +23,7 @@ const ( AdvisorService_ListFailedServices_FullMethodName = "/advisors.v1.AdvisorService/ListFailedServices" AdvisorService_GetFailedChecks_FullMethodName = "/advisors.v1.AdvisorService/GetFailedChecks" AdvisorService_ListCheckResultsHistory_FullMethodName = "/advisors.v1.AdvisorService/ListCheckResultsHistory" + AdvisorService_MarkCheckResultsRead_FullMethodName = "/advisors.v1.AdvisorService/MarkCheckResultsRead" AdvisorService_StartAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/StartAdvisorChecks" AdvisorService_ListAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisorChecks" AdvisorService_ListAdvisors_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisors" @@ -41,6 +42,8 @@ type AdvisorServiceClient interface { GetFailedChecks(ctx context.Context, in *GetFailedChecksRequest, opts ...grpc.CallOption) (*GetFailedChecksResponse, error) // ListCheckResultsHistory returns the history of Advisor check runs. ListCheckResultsHistory(ctx context.Context, in *ListCheckResultsHistoryRequest, opts ...grpc.CallOption) (*ListCheckResultsHistoryResponse, error) + // MarkCheckResultsRead sets the read state on Advisor check history records. + MarkCheckResultsRead(ctx context.Context, in *MarkCheckResultsReadRequest, opts ...grpc.CallOption) (*MarkCheckResultsReadResponse, error) // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. StartAdvisorChecks(ctx context.Context, in *StartAdvisorChecksRequest, opts ...grpc.CallOption) (*StartAdvisorChecksResponse, error) // ListAdvisorChecks returns a list of advisor checks available to the user.. @@ -89,6 +92,16 @@ func (c *advisorServiceClient) ListCheckResultsHistory(ctx context.Context, in * return out, nil } +func (c *advisorServiceClient) MarkCheckResultsRead(ctx context.Context, in *MarkCheckResultsReadRequest, opts ...grpc.CallOption) (*MarkCheckResultsReadResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(MarkCheckResultsReadResponse) + err := c.cc.Invoke(ctx, AdvisorService_MarkCheckResultsRead_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *advisorServiceClient) StartAdvisorChecks(ctx context.Context, in *StartAdvisorChecksRequest, opts ...grpc.CallOption) (*StartAdvisorChecksResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(StartAdvisorChecksResponse) @@ -141,6 +154,8 @@ type AdvisorServiceServer interface { GetFailedChecks(context.Context, *GetFailedChecksRequest) (*GetFailedChecksResponse, error) // ListCheckResultsHistory returns the history of Advisor check runs. ListCheckResultsHistory(context.Context, *ListCheckResultsHistoryRequest) (*ListCheckResultsHistoryResponse, error) + // MarkCheckResultsRead sets the read state on Advisor check history records. + MarkCheckResultsRead(context.Context, *MarkCheckResultsReadRequest) (*MarkCheckResultsReadResponse, error) // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. StartAdvisorChecks(context.Context, *StartAdvisorChecksRequest) (*StartAdvisorChecksResponse, error) // ListAdvisorChecks returns a list of advisor checks available to the user.. @@ -171,6 +186,10 @@ func (UnimplementedAdvisorServiceServer) ListCheckResultsHistory(context.Context return nil, status.Error(codes.Unimplemented, "method ListCheckResultsHistory not implemented") } +func (UnimplementedAdvisorServiceServer) MarkCheckResultsRead(context.Context, *MarkCheckResultsReadRequest) (*MarkCheckResultsReadResponse, error) { + return nil, status.Error(codes.Unimplemented, "method MarkCheckResultsRead not implemented") +} + func (UnimplementedAdvisorServiceServer) StartAdvisorChecks(context.Context, *StartAdvisorChecksRequest) (*StartAdvisorChecksResponse, error) { return nil, status.Error(codes.Unimplemented, "method StartAdvisorChecks not implemented") } @@ -261,6 +280,24 @@ func _AdvisorService_ListCheckResultsHistory_Handler(srv interface{}, ctx contex return interceptor(ctx, in, info, handler) } +func _AdvisorService_MarkCheckResultsRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MarkCheckResultsReadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).MarkCheckResultsRead(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_MarkCheckResultsRead_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).MarkCheckResultsRead(ctx, req.(*MarkCheckResultsReadRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AdvisorService_StartAdvisorChecks_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(StartAdvisorChecksRequest) if err := dec(in); err != nil { @@ -352,6 +389,10 @@ var AdvisorService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListCheckResultsHistory", Handler: _AdvisorService_ListCheckResultsHistory_Handler, }, + { + MethodName: "MarkCheckResultsRead", + Handler: _AdvisorService_MarkCheckResultsRead_Handler, + }, { MethodName: "StartAdvisorChecks", Handler: _AdvisorService_StartAdvisorChecks_Handler, diff --git a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go index 3a2b067da37..5945cba665d 100644 --- a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go +++ b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go @@ -63,6 +63,8 @@ type ClientService interface { ListFailedServices(params *ListFailedServicesParams, opts ...ClientOption) (*ListFailedServicesOK, error) + MarkCheckResultsRead(params *MarkCheckResultsReadParams, opts ...ClientOption) (*MarkCheckResultsReadOK, error) + StartAdvisorChecks(params *StartAdvisorChecksParams, opts ...ClientOption) (*StartAdvisorChecksOK, error) SetTransport(transport runtime.ClientTransport) @@ -332,6 +334,50 @@ func (a *Client) ListFailedServices(params *ListFailedServicesParams, opts ...Cl return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +MarkCheckResultsRead marks advisor check results read + +Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread. +*/ +func (a *Client) MarkCheckResultsRead(params *MarkCheckResultsReadParams, opts ...ClientOption) (*MarkCheckResultsReadOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewMarkCheckResultsReadParams() + } + op := &runtime.ClientOperation{ + ID: "MarkCheckResultsRead", + Method: "POST", + PathPattern: "/v1/advisors/checks/history:markRead", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &MarkCheckResultsReadReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*MarkCheckResultsReadOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*MarkCheckResultsReadDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* StartAdvisorChecks starts advisor checks diff --git a/api/advisors/v1/json/client/advisor_service/mark_check_results_read_parameters.go b/api/advisors/v1/json/client/advisor_service/mark_check_results_read_parameters.go new file mode 100644 index 00000000000..cbc52e168bd --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/mark_check_results_read_parameters.go @@ -0,0 +1,141 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewMarkCheckResultsReadParams creates a new MarkCheckResultsReadParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewMarkCheckResultsReadParams() *MarkCheckResultsReadParams { + return &MarkCheckResultsReadParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewMarkCheckResultsReadParamsWithTimeout creates a new MarkCheckResultsReadParams object +// with the ability to set a timeout on a request. +func NewMarkCheckResultsReadParamsWithTimeout(timeout time.Duration) *MarkCheckResultsReadParams { + return &MarkCheckResultsReadParams{ + timeout: timeout, + } +} + +// NewMarkCheckResultsReadParamsWithContext creates a new MarkCheckResultsReadParams object +// with the ability to set a context for a request. +func NewMarkCheckResultsReadParamsWithContext(ctx context.Context) *MarkCheckResultsReadParams { + return &MarkCheckResultsReadParams{ + Context: ctx, + } +} + +// NewMarkCheckResultsReadParamsWithHTTPClient creates a new MarkCheckResultsReadParams object +// with the ability to set a custom HTTPClient for a request. +func NewMarkCheckResultsReadParamsWithHTTPClient(client *http.Client) *MarkCheckResultsReadParams { + return &MarkCheckResultsReadParams{ + HTTPClient: client, + } +} + +/* +MarkCheckResultsReadParams contains all the parameters to send to the API endpoint + + for the mark check results read operation. + + Typically these are written to a http.Request. +*/ +type MarkCheckResultsReadParams struct { + // Body. + Body MarkCheckResultsReadBody + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the mark check results read params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *MarkCheckResultsReadParams) WithDefaults() *MarkCheckResultsReadParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the mark check results read params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *MarkCheckResultsReadParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the mark check results read params +func (o *MarkCheckResultsReadParams) WithTimeout(timeout time.Duration) *MarkCheckResultsReadParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the mark check results read params +func (o *MarkCheckResultsReadParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the mark check results read params +func (o *MarkCheckResultsReadParams) WithContext(ctx context.Context) *MarkCheckResultsReadParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the mark check results read params +func (o *MarkCheckResultsReadParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the mark check results read params +func (o *MarkCheckResultsReadParams) WithHTTPClient(client *http.Client) *MarkCheckResultsReadParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the mark check results read params +func (o *MarkCheckResultsReadParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the mark check results read params +func (o *MarkCheckResultsReadParams) WithBody(body MarkCheckResultsReadBody) *MarkCheckResultsReadParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the mark check results read params +func (o *MarkCheckResultsReadParams) SetBody(body MarkCheckResultsReadBody) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *MarkCheckResultsReadParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/mark_check_results_read_responses.go b/api/advisors/v1/json/client/advisor_service/mark_check_results_read_responses.go new file mode 100644 index 00000000000..a82016efbd9 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/mark_check_results_read_responses.go @@ -0,0 +1,451 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// MarkCheckResultsReadReader is a Reader for the MarkCheckResultsRead structure. +type MarkCheckResultsReadReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *MarkCheckResultsReadReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewMarkCheckResultsReadOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewMarkCheckResultsReadDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewMarkCheckResultsReadOK creates a MarkCheckResultsReadOK with default headers values +func NewMarkCheckResultsReadOK() *MarkCheckResultsReadOK { + return &MarkCheckResultsReadOK{} +} + +/* +MarkCheckResultsReadOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type MarkCheckResultsReadOK struct { + Payload any +} + +// IsSuccess returns true when this mark check results read Ok response has a 2xx status code +func (o *MarkCheckResultsReadOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this mark check results read Ok response has a 3xx status code +func (o *MarkCheckResultsReadOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this mark check results read Ok response has a 4xx status code +func (o *MarkCheckResultsReadOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this mark check results read Ok response has a 5xx status code +func (o *MarkCheckResultsReadOK) IsServerError() bool { + return false +} + +// IsCode returns true when this mark check results read Ok response a status code equal to that given +func (o *MarkCheckResultsReadOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the mark check results read Ok response +func (o *MarkCheckResultsReadOK) Code() int { + return 200 +} + +func (o *MarkCheckResultsReadOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks/history:markRead][%d] markCheckResultsReadOk %s", 200, payload) +} + +func (o *MarkCheckResultsReadOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks/history:markRead][%d] markCheckResultsReadOk %s", 200, payload) +} + +func (o *MarkCheckResultsReadOK) GetPayload() any { + return o.Payload +} + +func (o *MarkCheckResultsReadOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewMarkCheckResultsReadDefault creates a MarkCheckResultsReadDefault with default headers values +func NewMarkCheckResultsReadDefault(code int) *MarkCheckResultsReadDefault { + return &MarkCheckResultsReadDefault{ + _statusCode: code, + } +} + +/* +MarkCheckResultsReadDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type MarkCheckResultsReadDefault struct { + _statusCode int + + Payload *MarkCheckResultsReadDefaultBody +} + +// IsSuccess returns true when this mark check results read default response has a 2xx status code +func (o *MarkCheckResultsReadDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this mark check results read default response has a 3xx status code +func (o *MarkCheckResultsReadDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this mark check results read default response has a 4xx status code +func (o *MarkCheckResultsReadDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this mark check results read default response has a 5xx status code +func (o *MarkCheckResultsReadDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this mark check results read default response a status code equal to that given +func (o *MarkCheckResultsReadDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the mark check results read default response +func (o *MarkCheckResultsReadDefault) Code() int { + return o._statusCode +} + +func (o *MarkCheckResultsReadDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks/history:markRead][%d] MarkCheckResultsRead default %s", o._statusCode, payload) +} + +func (o *MarkCheckResultsReadDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks/history:markRead][%d] MarkCheckResultsRead default %s", o._statusCode, payload) +} + +func (o *MarkCheckResultsReadDefault) GetPayload() *MarkCheckResultsReadDefaultBody { + return o.Payload +} + +func (o *MarkCheckResultsReadDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(MarkCheckResultsReadDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +MarkCheckResultsReadBody mark check results read body +swagger:model MarkCheckResultsReadBody +*/ +type MarkCheckResultsReadBody struct { + // IDs of the history records to update. + Ids []string `json:"ids"` + + // Read state to set on the records. + IsRead bool `json:"is_read,omitempty"` +} + +// Validate validates this mark check results read body +func (o *MarkCheckResultsReadBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this mark check results read body based on context it is used +func (o *MarkCheckResultsReadBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *MarkCheckResultsReadBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *MarkCheckResultsReadBody) UnmarshalBinary(b []byte) error { + var res MarkCheckResultsReadBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +MarkCheckResultsReadDefaultBody mark check results read default body +swagger:model MarkCheckResultsReadDefaultBody +*/ +type MarkCheckResultsReadDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*MarkCheckResultsReadDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this mark check results read default body +func (o *MarkCheckResultsReadDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *MarkCheckResultsReadDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("MarkCheckResultsRead default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("MarkCheckResultsRead default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this mark check results read default body based on the context it is used +func (o *MarkCheckResultsReadDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *MarkCheckResultsReadDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("MarkCheckResultsRead default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("MarkCheckResultsRead default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *MarkCheckResultsReadDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *MarkCheckResultsReadDefaultBody) UnmarshalBinary(b []byte) error { + var res MarkCheckResultsReadDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +MarkCheckResultsReadDefaultBodyDetailsItems0 mark check results read default body details items0 +swagger:model MarkCheckResultsReadDefaultBodyDetailsItems0 +*/ +type MarkCheckResultsReadDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // mark check results read default body details items0 + MarkCheckResultsReadDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *MarkCheckResultsReadDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv MarkCheckResultsReadDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.MarkCheckResultsReadDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o MarkCheckResultsReadDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.MarkCheckResultsReadDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.MarkCheckResultsReadDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this mark check results read default body details items0 +func (o *MarkCheckResultsReadDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this mark check results read default body details items0 based on context it is used +func (o *MarkCheckResultsReadDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *MarkCheckResultsReadDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *MarkCheckResultsReadDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res MarkCheckResultsReadDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index d6b7d30d4c3..dba0e99f7fa 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -702,6 +702,80 @@ } } }, + "/v1/advisors/checks/history:markRead": { + "post": { + "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", + "tags": [ + "AdvisorService" + ], + "summary": "Mark Advisor Check Results Read", + "operationId": "MarkCheckResultsRead", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "ids": { + "description": "IDs of the history records to update.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "is_read": { + "description": "Read state to set on the records.", + "type": "boolean", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks:batchChange": { "post": { "description": "Enables/disables advisor checks or changes their exec interval.", diff --git a/api/agent/v1/agent.pb.go b/api/agent/v1/agent.pb.go index 7f5d935624b..c2f2a8b6a9e 100644 --- a/api/agent/v1/agent.pb.go +++ b/api/agent/v1/agent.pb.go @@ -7221,6 +7221,7 @@ var ( (*v11.Metadata)(nil), // 104: backup.v1.Metadata } ) + var file_agent_v1_agent_proto_depIdxs = []int32{ 44, // 0: agent.v1.TextFiles.files:type_name -> agent.v1.TextFiles.FilesEntry 94, // 1: agent.v1.Pong.current_time:type_name -> google.protobuf.Timestamp diff --git a/api/agent/v1/collector.pb.go b/api/agent/v1/collector.pb.go index da17db39c64..65633c05d17 100644 --- a/api/agent/v1/collector.pb.go +++ b/api/agent/v1/collector.pb.go @@ -2827,6 +2827,7 @@ var ( v1.AgentType(0), // 9: inventory.v1.AgentType } ) + var file_agent_v1_collector_proto_depIdxs = []int32{ 3, // 0: agent.v1.MetricsBucket.common:type_name -> agent.v1.MetricsBucket.Common 4, // 1: agent.v1.MetricsBucket.mysql:type_name -> agent.v1.MetricsBucket.MySQL diff --git a/api/agentlocal/v1/agentlocal.pb.go b/api/agentlocal/v1/agentlocal.pb.go index 12053d57921..7bb13a7cb58 100644 --- a/api/agentlocal/v1/agentlocal.pb.go +++ b/api/agentlocal/v1/agentlocal.pb.go @@ -485,6 +485,7 @@ var ( v1.AgentStatus(0), // 8: inventory.v1.AgentStatus } ) + var file_agentlocal_v1_agentlocal_proto_depIdxs = []int32{ 6, // 0: agentlocal.v1.ServerInfo.latency:type_name -> google.protobuf.Duration 6, // 1: agentlocal.v1.ServerInfo.clock_drift:type_name -> google.protobuf.Duration diff --git a/api/alerting/v1/alerting.pb.go b/api/alerting/v1/alerting.pb.go index bccb6659d24..3b2c47d73ec 100644 --- a/api/alerting/v1/alerting.pb.go +++ b/api/alerting/v1/alerting.pb.go @@ -1459,6 +1459,7 @@ var ( (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp } ) + var file_alerting_v1_alerting_proto_depIdxs = []int32{ 22, // 0: alerting.v1.ParamDefinition.unit:type_name -> alerting.v1.ParamUnit 23, // 1: alerting.v1.ParamDefinition.type:type_name -> alerting.v1.ParamType diff --git a/api/alerting/v1/params.pb.go b/api/alerting/v1/params.pb.go index eb001a606db..69d88497102 100644 --- a/api/alerting/v1/params.pb.go +++ b/api/alerting/v1/params.pb.go @@ -163,6 +163,7 @@ var ( ParamType(0), // 1: alerting.v1.ParamType } ) + var file_alerting_v1_params_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/backup/v1/artifacts.pb.go b/api/backup/v1/artifacts.pb.go index e2352f61cd1..dde03ceefef 100644 --- a/api/backup/v1/artifacts.pb.go +++ b/api/backup/v1/artifacts.pb.go @@ -656,6 +656,7 @@ var ( (*Metadata)(nil), // 12: backup.v1.Metadata } ) + var file_backup_v1_artifacts_proto_depIdxs = []int32{ 9, // 0: backup.v1.Artifact.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.Artifact.status:type_name -> backup.v1.BackupStatus diff --git a/api/backup/v1/backup.pb.go b/api/backup/v1/backup.pb.go index 19241fc6afd..4d587217600 100644 --- a/api/backup/v1/backup.pb.go +++ b/api/backup/v1/backup.pb.go @@ -1276,6 +1276,7 @@ var ( (*ListPitrTimerangesResponse)(nil), // 27: backup.v1.ListPitrTimerangesResponse } ) + var file_backup_v1_backup_proto_depIdxs = []int32{ 15, // 0: backup.v1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration 16, // 1: backup.v1.StartBackupRequest.data_model:type_name -> backup.v1.DataModel diff --git a/api/backup/v1/common.pb.go b/api/backup/v1/common.pb.go index f84ca11de32..c8274024e38 100644 --- a/api/backup/v1/common.pb.go +++ b/api/backup/v1/common.pb.go @@ -423,6 +423,7 @@ var ( (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp } ) + var file_backup_v1_common_proto_depIdxs = []int32{ 2, // 0: backup.v1.Metadata.file_list:type_name -> backup.v1.File 6, // 1: backup.v1.Metadata.restore_to:type_name -> google.protobuf.Timestamp diff --git a/api/backup/v1/errors.pb.go b/api/backup/v1/errors.pb.go index 5709e5ac243..902adc277c1 100644 --- a/api/backup/v1/errors.pb.go +++ b/api/backup/v1/errors.pb.go @@ -169,6 +169,7 @@ var ( (*Error)(nil), // 1: backup.v1.Error } ) + var file_backup_v1_errors_proto_depIdxs = []int32{ 0, // 0: backup.v1.Error.code:type_name -> backup.v1.ErrorCode 1, // [1:1] is the sub-list for method output_type diff --git a/api/backup/v1/locations.pb.go b/api/backup/v1/locations.pb.go index 72c13dece43..396b552ee80 100644 --- a/api/backup/v1/locations.pb.go +++ b/api/backup/v1/locations.pb.go @@ -833,6 +833,7 @@ var ( (*TestLocationConfigResponse)(nil), // 12: backup.v1.TestLocationConfigResponse } ) + var file_backup_v1_locations_proto_depIdxs = []int32{ 0, // 0: backup.v1.Location.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig 1, // 1: backup.v1.Location.s3_config:type_name -> backup.v1.S3LocationConfig diff --git a/api/backup/v1/restores.pb.go b/api/backup/v1/restores.pb.go index 580c158b119..ee12d6b9285 100644 --- a/api/backup/v1/restores.pb.go +++ b/api/backup/v1/restores.pb.go @@ -625,6 +625,7 @@ var ( (*LogChunk)(nil), // 10: backup.v1.LogChunk } ) + var file_backup_v1_restores_proto_depIdxs = []int32{ 8, // 0: backup.v1.RestoreHistoryItem.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.RestoreHistoryItem.status:type_name -> backup.v1.RestoreStatus diff --git a/api/common/common.pb.go b/api/common/common.pb.go index 2303ccd29ab..0d05883daa1 100644 --- a/api/common/common.pb.go +++ b/api/common/common.pb.go @@ -147,6 +147,7 @@ var ( nil, // 2: common.StringMap.ValuesEntry } ) + var file_common_common_proto_depIdxs = []int32{ 2, // 0: common.StringMap.values:type_name -> common.StringMap.ValuesEntry 1, // [1:1] is the sub-list for method output_type diff --git a/api/common/metrics_resolutions.pb.go b/api/common/metrics_resolutions.pb.go index 389e4572992..75e587ba9a5 100644 --- a/api/common/metrics_resolutions.pb.go +++ b/api/common/metrics_resolutions.pb.go @@ -118,6 +118,7 @@ var ( (*durationpb.Duration)(nil), // 1: google.protobuf.Duration } ) + var file_common_metrics_resolutions_proto_depIdxs = []int32{ 1, // 0: common.MetricsResolutions.hr:type_name -> google.protobuf.Duration 1, // 1: common.MetricsResolutions.mr:type_name -> google.protobuf.Duration diff --git a/api/descriptor.bin b/api/descriptor.bin index 4e17e1f01dc4a132ec9ea22974b6bd2613802e6f..7b4a8888ada22cb99259f8f7dd79f7d72b0f83bd 100644 GIT binary patch delta 11307 zcmbtaYm`*gm9Dez?ORp1Zoh8RP+k4t+B_N>n)e$G?}rABf=EyzG;{$i*sWBzL}Mt) z_|_;8^e6!Z1V<;RAxc_@xX@98N{pj8#?g$%*UC6q>S7p|%eWlp+vib*6DD!3`BAHT z@4NRt-`;1RbN0Pw|N6dBH~n(dHP?!3=`rWK7t^bE^;~$d^V^Di<9xsN?ACQ_W~|Px zSTjGH>t5THo1blMo1eYBJDckYGrrT_mP?Ds8I+u!`1ACVErJqaJ~P8Ue!M-mbRDGA z6p2BJ`ChxyZEW!CPHi)HS!YKs+x(#LdrfP*qCM9sUu$>DdZu+cp9~fUrYVFEKogIpkyDYn+ePw&LO<7$Ih>h@e$=ejGQv7&Qb zTW(kc8<7cG)YTcSY+akn@;{gI=&*fh)Lq%Z_J{rG*!w@B!IMODV}H4My;D^=+!&k0 zvW%!F>T)(a{%@B1@vtNodzs`PMkIRmytLlQH01-I-0IN#QpA2l!cX~*TP;HOOOfd3 zm-;1cHO1V}{YsGUkM&(96*V){6rDLU7j>>wZv8L#47B^QHuycvw^mA6FI8ztjPaES ztNpwg#9=yJV;?7&%*^mB{Unc>cq9=jjoRr(LcrceBF`VGP~jn{s!TsM1t#V|kwX|w z=xt~%BB6A~#mlTkK-fr?q3roSg|1d`WsoUr5p z@_r=zl`2NCvybS2%)AKJp=qHN{unVH48?bqG+@M?g9AI zWi=gDg^4rv~8=!Ieqv9(FR zA@`+%M{(uRZz%OrA%~a+OfQl*&^W{#!20bC`|o$~bMY&|&%-Z{Ujn}*etysX`%^n_ zqrJQ3g0aB?8B9qu^d!awAH?a;N%_ec!HI^2evPSymYQQ4rC3+CqpQ8MBV8?zFQF*k z$4Jc8WypN{Je=;=Tjh?tcnT3Ii*G~3a-d~LQZ-CGrOwMOWilVxUUk+8#WI+cy3 zx$G6$b?seOF75JHugm6Ecdl(q_mQ2`6Ac6UpTgb(BYwUW?s?~1L0bvko9dY}Gw{S; zceLVfI6BL((=IJN71mt3lKq@Z^D|m%nyxRu=I@QDDE@}8rEu25Plw9a3E#-qu+ER? za;ulF$zGW*0hHuiM=qTeOcbuXdsZ++l*q%gf}z5b|2ZodA>y*%?BGU`ko#r_lSNYg zJOA-z|2a@d$&2R%TcW;xy_v&PJKXchoZ#uC|Hn36Grq5DMtNv+A|?OzykLBvfqv2_ z#|s@lHo;%zQwa*g(pWE9H$PbAl$P|7uV?*n`8rfkZV3+d&?%?W{J<|^fqgbjU-N$kW< z6{XGCB}~}Suq!)NwRNbJ$c1ZtVh!?!1;M#>eG*ly?4nwOd<`Z1{-{8?0CZ~Pi3P#H z=9*-Ml>o?^s$Pad$?DWXzFEm*@=Fn7u(Q)*l=x!r)EH+kCGx~rwMi%VFy&`G*NY?TE4R|sFFJt2BpnS#&JA^!6xH4 zk$@wEsnj2@6k&6)e05rg1nMnJ~z{aLMIyP1wUlc4E z%(*f;QKQ5$KjUNllsG5G_(Y_{z0jQ)o6O?N#!O6{rlO5K{*2gk9VHwt&KZeXHGW)0 zX$toG(}56F=uDB-zmxz3R|aaK%&{0t=zQ`6)}-wkHvr^Qt!!UhLt zTBOItd(q6;cl5Xk2+ss`p5=rZcQ$6H7Ir{|&TPz1S#<8%XGa%g*X6Kj<6X>%LUFd4 zD~Q7UY%^C01!peI_>r;$$+`02;-Im4Zc^ii2o&ZT{0Y2*h0a;X(mExN$vR8MFAN%* z&oWsG3CN#?EY*WM@OPfc#soi_C%cxX%|wJKU&Gd)I#c;87MoK1oiTxg+ZKCK0X3+{HT}44hl9F8th3TU|)o} z{g$$U*esG_Niel}QQVHn0a#QRlVh_OzRpzgc(hoqSrW`{UYyiRBT1ayi?J(lER*EI zr;8B#zDgdkxk$dbBsgvHMRfzM1mrIo+^o{u51or+kxFkLpf66;tB|EacUf$u4p|EP zWeFYn6u`hw719lJzh2_UsPp#vMJ^lnFJaGbcHLZ_W{3_(D!JsBzxpkS`O zy0*Soy+9Wr9t1h_@9Y_QTF;W7-g@^ zLN^!tzJ^%_shrtN$`s0OSmPrGROoceB};>WXLcJq;K5F}0S5};x(zs{6u52!u1tYj zZ@_^Ho%IZEz>M_;a|~-e%%uRUJS@2?wozzY<&eJ0ET(dm8CN4S_$UAsI#52^7p;txsJ%<1KFkU`$Zj5ZoYdUlvTtZ!j<*0r?Gp!5@dpc^SFa z2&^McM39QA$kayXuj|f6>sMzx%-1G-F^k$dJM32{h~iYdM#NLr5Gv|xL|M7N2<}yc z-nAljix8PJqqDPJ>)Pea)?i-4wE{WE<5uvN;a)E&nnao8|81!MFR~TvWj} z0U4+)0r1MuyG_LIkim-JqK4Z9l7+{vRB$)3p+PVNGITe|>sAEKEt^EG`jo>=7}_L; zt9MP13>P12Gk%Lw0o*O}_bYp2Q^?)UDhwPXC^;z`49{;DarNnqnNZm-uvv0=LO!V69fG*zU=;ud z)nXsQ!VZBV!pK5(hxIw+GS|I_eb%aY2x^#-vL zmkh|}%qYD`+E*6F%U;^rzBc;W+g#MTE*qIQy25z;m14Ju_qPLJyxpQnyBU%PxAq8> z&YZO%6*W7PpB&B0w&uE8)XQBqT8o#qwfIEb+7)4ity+ajBx>y_U^y8@VPO8sut(HP zH3NGXc#oK&J}Y3PI6T{ny9F~BD8xXi510Hf58b^2wT+%fezV^zP~2!Tf#~1QpR)Bl zqL>0Tz&?cG`|TI%5SJHBhLL>=OZSU@HX2C?Kfw7nM7fW$15|CMUf#Jf=$}XB0lJX8 zN$5UM%v~S44;DS}6{S~XNI04CFsZjbkWhV4pg_n65ex%ToPwa^c8oIU?ic;+OqE0TQPv%$bjv}>gR6rPBXLOKLEL&& z4z))`U%fYnQ~|XEtj47zNKmq_J(zNC1=J1{)heKN;3PG~{D5d2Yhqr(F+U*s*>zZn zoa*768l$XMf|5UL4@OO`#Be>ue5%ACJtDL|RKiM+7}RW{6GHfjqDvttS$_#!;%kp5 zirDb-3bNo*71R#$objttNL8TZhD(CUBdefxP@rtob5;elgZ4NHsTb6ql&UBcn4$SRchBi%piEz2N}ADdDkB#Z(kdDEr;#$!4sG} zY?n`!+WL>M9&i01L-z=8{ews2e;X`v%82J#k=HCpe7cjHR|ZW`WGl}X zN96PC`QnHu%iW_zqH%lM>mt#J9hNWAyf;Mb_oyIQhp*Azu+>U$Rjs^f_hOKt3ktcBM{PkbKMDR`yY5-^K?fwZ(%BT~OL*P>_9FROy`z zB&@#8ac8jU(0iBfK=T@H8lvwCydrV5(&`fQJ&P7(=z`KWq@WPW_e84P%0l%$QPE&Y zjPjm1O)sJ}uDC+?{h}qvg3`MJ9+rf8&;?VR(C>>1jUSI;>U}%wX;smDU@IDsp$kga z9iX84fvspjLiGb%(WF&H^G9CFxN~vgAD)67mg$P*X_p5ZM*h(jG_#oi`~IQb+PlIEofjE<9uifnlvsaLibM`Cw>73si;wz0g?W! zTqq$`ON}4p`iopH2m=aiupltf^I{nxlBanruk4302%0a@^#{yqIb((U4^GVSX zPA*W^zXUw`M5L_jNUm@`5e+6B#OK;4_SGOwNtim$rugFmNKkUwx}bh4mp;dfDay6Z z@nW`ft#iDX?LMrWU@QDNDNU$#PRJ+M1r1ZV2s%-;!e!41QK7d$$id19(P$S~3Rckg z;j7XlO(<(Vm9@EG&{QsXJ}m}^3!G0ysEahn!OEusA0%{e0{H)#tyI!n;C#lF%8=3c zABvyZS_LE&KeM$;no2SJ=REvCqalSE54Q z@L@ErjJ^_sbxD_|N(2;L7a6}>SwZOoYJ6suj4lsq<)huff;?9}8_84#(13xBgvx+- z+#0-qQ|x-u8*U9G(Pg32zDDii*Ae{WQXORIg3_e}D9Bz%=5zoFtJe`uhdH`I<0gu| zPa-ohS|G2xBA6Q9M2Twt?uVN{v}xQzv|0Y{iePO17V=6tH<*vj^A;*ol_Qg|cndYz zYjbXaxs}|><|@;+Y1~SwN#^EHvtZ;_iYA(SL}+f&z%-@(T8 z%^!L>(&pxmIT-$S@<#g4VRwcQ`ZTr@ZIcJr2S@T~j!@IXdh2pqQ= zyU05v{0kInG-_-o+AT+387$1BC&J!$^Fg(}c;C%u&-UVdH`hu#$em?S+xCndl$vQ! z7uqv+P&C7!hL(2^ap!}HH6e=3O6^jpRZ9%>F!sIVon~Uq91OpcysMBr9BQ;@>_K~m z9CKALJCEiDd)JK{CiFTK?z;I<+*7>kM&|>%C<+N;+9<#(B#36g$lhXt{H=Zo1-jTU zVeh(`gW=IIaRz@>0BAUmeu-bmK|ct_=g}*n-glXg@%B-*ddXlCTKj11w@rSahIi2` zG22AibV`7gnq?xbSupYtMKevLq2)bH?*2lgbxXvSHA()m&^MaiVZj^YTI2T-Pyufpz zH%+cvjuu-}Oq&E)h1L|!f{~-e))a1t_-p+TYFjKeMA(?yh6wKP;Gz|tVS&Fw^t$}- z4Z+6zE5-H>UgWP7+dFuwUg7o*jhbtuW5o?7Vfs>z6*m~of{|mz4F+1?tK|N!5a|SR zfLW>E71N%1Q2Q6&7Iljab1?jCX*Adj5^#T1`UnjpAD6I_eEx zt2$Fqjd^d9`&J=SlBOr+O-j90$P~?l=I_aiOxkN6(*ECyX~WjuCimTO1#gndo3|MQQIq)q^c;gpnxKw*q34vSp=j32bDoYMM@D+Td@J@v6W6x z5U`tOQ$t!5SyTj6255>_LE2WN8JD5e);XfnI*!NjIKpw9)6O{_obSex&;G%&z8m-6 z_#)!Qz47w8?#RHCy9TaUC05a4Z`K_8WMkXxIo?~9ZQB-kq` z3s=qwQ&BRJI7X`Kg>*aB@A7oE?cTe*ik{gULJAU5a6u%Fsn>RRtVxY6@VN(n_1tEXuB?WLO#YOIsPt?xUbPL{5U~S5a_7I9-z# zQLvWiH>zcq_YcLj6tuUr1Ps?whdvI%YAp@B%t4S|NB($AT3FKSC_B!QHX=A#NBOaq zv;gS`$X{O~Eqo^Z0A<%}(u0{I%V72^3JR7qOECSfDfme^LzAW`*hus+c{P{h)rKWr zM|JsbZ&-071)VKHf{Tq*KgvPaZ=^}{9R&SN@t%{VzbW2xBZ8An@tzatZzlht5`EJ2 zH&gbZc+Xh|vn>=1vh-Pk=^v!v>TtfM??u5QL_5^1r@YppCnEomI9NOwKN1Iv2g^q| zSj@3|psk}%#!)jb@9nrC^$s)lKRy%-rQmU;)f{cWT^!(K14Nx9fai}x_Gvw5P-sA^4m%=6xbL#OxdhKT_&W-k?ShO9F?1x3A@(-nDETjzRut$J9i{Axr5IunIQ^c29(F-20j(F-?B46) zpO1e@{0s0eg@0-M%iv$wwtH{(iQmwBN=+Otf2aDMPxouPbc8&TqI0Q-$I1U`yD(nf znDo!5!}jWqt7Loii^=j_R2Qa}ELnK{tvB73OXfvW=2BAYrpV#KQ-7QydkbHknHr#h>s zL4zBDVtJRmMTD^m>SPr$R6+G_h*4eVuxRE+TJb7NnjQnEi4@~iLenVXwt7`mYhC&b z+-$hHUR8Y;tBBj-MU=CONe0dbZi*Mx)}f>j3Ss1TNOV>oT`i~Abx2pUwU5=qAV=x2 zG4vS$sL8Wsk3ud}=`=txSKZDc0sR{27qmX6u2EZO%RXvmnCes&L|z>zch_T>yH1^( zEqjiutJ50_{{&xkO})Ypgm5>yB)SUx?fJaXT~M%@lhB+RFvl490gAi^HR~EVZd^mA z+-bm1Llv?r{2+iE6Mc;zK8MD%K4+h_pC0hj6@GvsuZKE&jchFRuxo=1etOuo5ee{b zqOx$9)`zPmRk&6TFEo{#)k6dNO&xQZ1rbt`SAhOSS|95zsP)&%i~AMI+dB>D7jm5} z@}S>`+Jz4bZGf>p)Lhe`HqMe=RLynr&Ov?JH#uD%?cFELV1@Xzf1*}z6o*g$bS|6= zF_OT*#9%dPj=Z)PN6Wx;C#{YX8k*>))j2kXrt?}oi2Rns2v(mvxFy}7_YOH@RAQ{z zyA*UsrEB&4DZO{2kvm3#Dp2H&Rv*rhqYI-`(rJL!=n4}hDdM;o1O4$@AFjrz@z=`< zU{QTJ?{jZSuOkkMcxE;`g+;9Fu|S~WbiY= zo>^MYI|=%Etq)g|RMlMBwJ<4TctQjElPu4)KC{V)(K@YdCosTwzM4#%Zvyv%bV&>_dMV^v7!dxVF<&RjV97Zd%6dEHt1$ z4Y!wLHxv2O6W5r1$bkIxbe;B^p#);(3dGh>_yGb?54Xye!WHEvx*>y~D{73_jE>zI zR2>e|`fxQveb*|76lSzDJfQ*o8J1^;2s~%vyhdw%?88iT)eUk?VP?wt=f%z}`R9F@ zg>_w`^)WO{{ow{Vu`nxRZbOFfB=Tk<+3>z)kZ&SyHukxT*2g}~Rs(L74Oh>u)2Ws< zpg+4;L5FM@dDkWKI%Gp|zb@TbZ%;PzuTR`$wkHeu^=Y%sSv8H7V$R&OA!cG^FWc0N=E*I#Lb3_ zgw}$z*;uJVb|JO~<-`YyyoF@;5CDn`Gm$0%1a}MDchK(2BLCLJ9mZW5v~I=C%kkEg zX@9rbkOPXm+ti79a@^$GGA3z521mDbFp~hKfpQb^j7YO}`po@2+-ZWIwM^fTMR3;* z^nfC7k!qMPyIhLD8I+vzVi&h1H>pC6jNC{FW;kLc|~{?7El=l z_ld*<>cItaX8nBvA%ss+zmjjezgkdD_!Bq;1XAgRa%%HxQL8_lScrGoYJmi5Oi--+ zHEc3fo1mJmQ7ae9%bM53CLj%+k_qaSzm82NYZDaCb?W2Bd!T0l370wof^ zSD)P?ht(^QuGD@bj#+=Jz;X3~BS0Wku~aqN1a+WhHwe>h0+rtC!gQNkbwqe1 z_>b|bjVT6!`dVH7D1A)S7JE6Yhx<6sC_et<0?@jw95zZ`%QKe!$jD5GXtq+dYP zQ3Ju+-!5>0j42!eb$5dr;wD+${&2NjM0tndYP;yxXkh^D9lUG3_2RLf9cuXP*fstf z+7WMd0J9zOW~X4bGbWFx36Ke&i10W8%;;}dtR)50odU(l5K7@au~XFb3(G@%_fU#I zVRnknZr9TAyjzfT0RZjY>c4N7g~51xU<4)4_+h)2P9#(pUnnpGt?@eu4?2m*&9qzu7Fc+SrWGU zMHiDuA}WLJb8O2`7C<2N>K*dp=_pGWD4CVP?71JAVHckhU5D5`FXO#?PIS{Bw{TOA zcsjuGG+28@K{=qV{Fxj$z8upX5T#f`bpedrLdxOgfM_b%-Kl``!FXL28g*6M%(_qk zFj^v50o#Ky!AjU3=F{Wnc|?^!s>fnEazG`_4hy_n%)wQ{?66CK5mmwL2v2#1Hmd?s zn-|OJ1FB$lMBq7V%&K5^MC7|#7~#B+^0noUhlnB|RlP(GX^dcYRMZY|dN4aG1`iGI z7sy!EQSg#Tys3V=M6RxXN#J46&Z~9CI?g2ez#CxXALoqKxB0lcJ`lpwad&;Hb*?(W zCY-APBmV^Fs(#HUT$X|mCMR5$s^%)@zrrSbQ2~MYqV^nwzhVDMJQt_gSK_(w81!F_ z>0$6ymA_N=?f3L8sY-F9aZvYFQ=+H=lO#0wGLJ3w*gD$G?x(o~$`9KJWA|e71%I}J7wI&M)BJT?Q9wEPD z6ud7I|7P8Ggy#Dq-A!wD)NVh(uf{sD14cfOSu+rHKM>U>hXKOt2fXi0HWvjSip2kl zqG6kZ>W2akbKb2SzqkCejxC@@W=_r&mX==){o(P^m*)sEBEK3(%faJf#T<)tBaI0oP5DfxWwXjC?GZG z9@#X8YxWoMo^hf6LPX|?0X=y6Lg0JO>{$j&`_dKL92e>@x!Cp|guh|23&D^YgA^=BNx_zF{vDwHH)#pguJ%_RQ7x#j>AT|4W$}%XR;o*ezH4Z$zd3RUOlF zwf{!+GS8G8m1Bp$mHTdr@MLOMmk-$dg7Y+~vJ z&A$nJ!tpKhky$T(|EB zksV=wWH%x>`9b7|+n?-_1kqaLMjq_qZr=*Z-lubi0-m>N{A9{mm*ICx2`x)pB zKB!si&MM0=_ht$j>|V13({G{R7YH8SYIOM&(PQf8_sNMxg{){dlRJDWZYyzuS8-bj z9X>StN&#Z~dk~cZ#E9VJ5h?}9kNScpKujagb_H!a*mm;J6m)GR)5+tO;6?nC1W04? z+lii3x2}@IisS^ldTIk%0+e2vSxn8Pm;X#<)2Lh&-YJ^zdGu*uTu?&T1Z`=oC zZ)gWTKdH1D)7e8m@Oix&zM{6V_bm6R%@wtcJ+%7zavK6VXzU#%dQnZiUtU~17>5lv z^$x~i!;i{?95$vg%x$Vr*0IXdF(qsfRY-&~ThyOezYF5&cnJzDABM9*a*Vg~c3;Plk*2F+LfS zjJV<-k9)!?+gd#y_k@iIPL9VtVORw(lmANT08;wmzD(IyG-sV8Sq8Hc@d>a5)Bk~6 ztNbRz5#awxc#Y^^)Y!FhW%0GRugaFM#eG#adyV_5hBZGiPR8jbZCRg;(~S|q$;mj~ zz$$p1{L>}YY0dg|%AVG&b-H00%uaEVG;zZcO#deeCh>PCNN1wpO`^Z3JJ!ij#W&-d zn}Ok*@y+Fj$(ww0P26NK{afUpDaB33HiO@y?3q&B7$Gd*rXX+Q#>j99{xyyp_V#D; l-y2$5O-8Tg&y; dump.v1beta1.DumpStatus 14, // 1: dump.v1beta1.Dump.start_time:type_name -> google.protobuf.Timestamp diff --git a/api/extensions/v1/redact.pb.go b/api/extensions/v1/redact.pb.go index c850a90df3c..738ce213118 100644 --- a/api/extensions/v1/redact.pb.go +++ b/api/extensions/v1/redact.pb.go @@ -135,6 +135,7 @@ var ( (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions } ) + var file_extensions_v1_redact_proto_depIdxs = []int32{ 1, // 0: extensions.v1.sensitive:extendee -> google.protobuf.FieldOptions 0, // 1: extensions.v1.sensitive:type_name -> extensions.v1.RedactType diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index 655996ccdbc..f798cccbcc0 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -351,6 +351,7 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) + var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/inventory/v1/agent_status.pb.go b/api/inventory/v1/agent_status.pb.go index ace1432a5e8..1e23074d2fc 100644 --- a/api/inventory/v1/agent_status.pb.go +++ b/api/inventory/v1/agent_status.pb.go @@ -128,6 +128,7 @@ var ( AgentStatus(0), // 0: inventory.v1.AgentStatus } ) + var file_inventory_v1_agent_status_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/agents.pb.go b/api/inventory/v1/agents.pb.go index f5d83515360..3784fc8b7fc 100644 --- a/api/inventory/v1/agents.pb.go +++ b/api/inventory/v1/agents.pb.go @@ -12513,6 +12513,7 @@ var ( (*common.StringMap)(nil), // 112: common.StringMap } ) + var file_inventory_v1_agents_proto_depIdxs = []int32{ 68, // 0: inventory.v1.PMMAgent.custom_labels:type_name -> inventory.v1.PMMAgent.CustomLabelsEntry 108, // 1: inventory.v1.VMAgent.status:type_name -> inventory.v1.AgentStatus diff --git a/api/inventory/v1/log_level.pb.go b/api/inventory/v1/log_level.pb.go index 47f0373d578..ff4d79ca3f2 100644 --- a/api/inventory/v1/log_level.pb.go +++ b/api/inventory/v1/log_level.pb.go @@ -114,6 +114,7 @@ var ( LogLevel(0), // 0: inventory.v1.LogLevel } ) + var file_inventory_v1_log_level_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/nodes.pb.go b/api/inventory/v1/nodes.pb.go index e0186c91815..447663477a9 100644 --- a/api/inventory/v1/nodes.pb.go +++ b/api/inventory/v1/nodes.pb.go @@ -2043,6 +2043,7 @@ var ( nil, // 28: inventory.v1.AddRemoteAzureNodeParams.CustomLabelsEntry } ) + var file_inventory_v1_nodes_proto_depIdxs = []int32{ 19, // 0: inventory.v1.GenericNode.custom_labels:type_name -> inventory.v1.GenericNode.CustomLabelsEntry 20, // 1: inventory.v1.ContainerNode.custom_labels:type_name -> inventory.v1.ContainerNode.CustomLabelsEntry diff --git a/api/inventory/v1/services.pb.go b/api/inventory/v1/services.pb.go index 23eeeb28b81..a8d1519b61f 100644 --- a/api/inventory/v1/services.pb.go +++ b/api/inventory/v1/services.pb.go @@ -3334,6 +3334,7 @@ var ( (*common.StringMap)(nil), // 43: common.StringMap } ) + var file_inventory_v1_services_proto_depIdxs = []int32{ 27, // 0: inventory.v1.MySQLService.custom_labels:type_name -> inventory.v1.MySQLService.CustomLabelsEntry 28, // 1: inventory.v1.MySQLService.extra_dsn_params:type_name -> inventory.v1.MySQLService.ExtraDsnParamsEntry diff --git a/api/management/v1/agent.pb.go b/api/management/v1/agent.pb.go index 8a745a48910..c76c750f869 100644 --- a/api/management/v1/agent.pb.go +++ b/api/management/v1/agent.pb.go @@ -1241,6 +1241,7 @@ var ( (*durationpb.Duration)(nil), // 17: google.protobuf.Duration } ) + var file_management_v1_agent_proto_depIdxs = []int32{ 8, // 0: management.v1.UniversalAgent.azure_options:type_name -> management.v1.UniversalAgent.AzureOptions 14, // 1: management.v1.UniversalAgent.created_at:type_name -> google.protobuf.Timestamp diff --git a/api/management/v1/annotation.pb.go b/api/management/v1/annotation.pb.go index 53bbe233c1b..ec781561e4c 100644 --- a/api/management/v1/annotation.pb.go +++ b/api/management/v1/annotation.pb.go @@ -164,6 +164,7 @@ var ( (*AddAnnotationResponse)(nil), // 1: management.v1.AddAnnotationResponse } ) + var file_management_v1_annotation_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/azure.pb.go b/api/management/v1/azure.pb.go index 863cff6d5ab..04a05c47ec1 100644 --- a/api/management/v1/azure.pb.go +++ b/api/management/v1/azure.pb.go @@ -726,6 +726,7 @@ var ( (*durationpb.Duration)(nil), // 7: google.protobuf.Duration } ) + var file_management_v1_azure_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverAzureDatabaseInstance.type:type_name -> management.v1.DiscoverAzureDatabaseType 2, // 1: management.v1.DiscoverAzureDatabaseResponse.azure_database_instance:type_name -> management.v1.DiscoverAzureDatabaseInstance diff --git a/api/management/v1/external.pb.go b/api/management/v1/external.pb.go index d990cb53abe..3632121e1c2 100644 --- a/api/management/v1/external.pb.go +++ b/api/management/v1/external.pb.go @@ -355,6 +355,7 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) + var file_management_v1_external_proto_depIdxs = []int32{ 3, // 0: management.v1.AddExternalServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddExternalServiceParams.custom_labels:type_name -> management.v1.AddExternalServiceParams.CustomLabelsEntry diff --git a/api/management/v1/haproxy.pb.go b/api/management/v1/haproxy.pb.go index 95cad534323..f3de5158762 100644 --- a/api/management/v1/haproxy.pb.go +++ b/api/management/v1/haproxy.pb.go @@ -333,6 +333,7 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) + var file_management_v1_haproxy_proto_depIdxs = []int32{ 3, // 0: management.v1.AddHAProxyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddHAProxyServiceParams.custom_labels:type_name -> management.v1.AddHAProxyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/metrics.pb.go b/api/management/v1/metrics.pb.go index b552c7955fb..748642db7cb 100644 --- a/api/management/v1/metrics.pb.go +++ b/api/management/v1/metrics.pb.go @@ -103,6 +103,7 @@ var ( MetricsMode(0), // 0: management.v1.MetricsMode } ) + var file_management_v1_metrics_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/mongodb.pb.go b/api/management/v1/mongodb.pb.go index aad151306df..c25cc4f8282 100644 --- a/api/management/v1/mongodb.pb.go +++ b/api/management/v1/mongodb.pb.go @@ -559,6 +559,7 @@ var ( (*v1.RTAMongoDBAgent)(nil), // 11: inventory.v1.RTAMongoDBAgent } ) + var file_management_v1_mongodb_proto_depIdxs = []int32{ 3, // 0: management.v1.AddMongoDBServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMongoDBServiceParams.custom_labels:type_name -> management.v1.AddMongoDBServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mysql.pb.go b/api/management/v1/mysql.pb.go index 70660a14379..18f64740d99 100644 --- a/api/management/v1/mysql.pb.go +++ b/api/management/v1/mysql.pb.go @@ -545,6 +545,7 @@ var ( (*v1.QANMySQLSlowlogAgent)(nil), // 11: inventory.v1.QANMySQLSlowlogAgent } ) + var file_management_v1_mysql_proto_depIdxs = []int32{ 4, // 0: management.v1.AddMySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMySQLServiceParams.custom_labels:type_name -> management.v1.AddMySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/node.pb.go b/api/management/v1/node.pb.go index 53bb2be68db..149fb30ad94 100644 --- a/api/management/v1/node.pb.go +++ b/api/management/v1/node.pb.go @@ -1255,6 +1255,7 @@ var ( (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp } ) + var file_management_v1_node_proto_depIdxs = []int32{ 16, // 0: management.v1.AddNodeParams.node_type:type_name -> inventory.v1.NodeType 11, // 1: management.v1.AddNodeParams.custom_labels:type_name -> management.v1.AddNodeParams.CustomLabelsEntry diff --git a/api/management/v1/postgresql.pb.go b/api/management/v1/postgresql.pb.go index 0e6f54ad033..0271ba48788 100644 --- a/api/management/v1/postgresql.pb.go +++ b/api/management/v1/postgresql.pb.go @@ -535,6 +535,7 @@ var ( (*v1.QANPostgreSQLPgStatMonitorAgent)(nil), // 10: inventory.v1.QANPostgreSQLPgStatMonitorAgent } ) + var file_management_v1_postgresql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddPostgreSQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddPostgreSQLServiceParams.custom_labels:type_name -> management.v1.AddPostgreSQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/proxysql.pb.go b/api/management/v1/proxysql.pb.go index 7d9dbbcfc07..e3142ed85df 100644 --- a/api/management/v1/proxysql.pb.go +++ b/api/management/v1/proxysql.pb.go @@ -395,6 +395,7 @@ var ( (*v1.ProxySQLExporter)(nil), // 8: inventory.v1.ProxySQLExporter } ) + var file_management_v1_proxysql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddProxySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddProxySQLServiceParams.custom_labels:type_name -> management.v1.AddProxySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/rds.pb.go b/api/management/v1/rds.pb.go index fb882ea8de5..d338efd3738 100644 --- a/api/management/v1/rds.pb.go +++ b/api/management/v1/rds.pb.go @@ -854,6 +854,7 @@ var ( (*v1.QANPostgreSQLPgStatementsAgent)(nil), // 16: inventory.v1.QANPostgreSQLPgStatementsAgent } ) + var file_management_v1_rds_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverRDSInstance.engine:type_name -> management.v1.DiscoverRDSEngine 1, // 1: management.v1.DiscoverRDSResponse.rds_instances:type_name -> management.v1.DiscoverRDSInstance diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index 6ea52fbc973..cbad04b7f53 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -1005,6 +1005,7 @@ var ( (*AddAzureDatabaseResponse)(nil), // 47: management.v1.AddAzureDatabaseResponse } ) + var file_management_v1_service_proto_depIdxs = []int32{ 9, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams 10, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams diff --git a/api/management/v1/severity.pb.go b/api/management/v1/severity.pb.go index 51c04a93a0e..6a14d366aa6 100644 --- a/api/management/v1/severity.pb.go +++ b/api/management/v1/severity.pb.go @@ -125,6 +125,7 @@ var ( Severity(0), // 0: management.v1.Severity } ) + var file_management_v1_severity_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/valkey.pb.go b/api/management/v1/valkey.pb.go index 26cc4db7f99..a0fc2f73fe2 100644 --- a/api/management/v1/valkey.pb.go +++ b/api/management/v1/valkey.pb.go @@ -417,6 +417,7 @@ var ( (*v1.ValkeyExporter)(nil), // 8: inventory.v1.ValkeyExporter } ) + var file_management_v1_valkey_proto_depIdxs = []int32{ 3, // 0: management.v1.AddValkeyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddValkeyServiceParams.custom_labels:type_name -> management.v1.AddValkeyServiceParams.CustomLabelsEntry diff --git a/api/qan/v1/collector.pb.go b/api/qan/v1/collector.pb.go index 3716a3a24d1..b680bbd8f77 100644 --- a/api/qan/v1/collector.pb.go +++ b/api/qan/v1/collector.pb.go @@ -2757,6 +2757,7 @@ var ( ExampleType(0), // 7: qan.v1.ExampleType } ) + var file_qan_v1_collector_proto_depIdxs = []int32{ 1, // 0: qan.v1.CollectRequest.metrics_bucket:type_name -> qan.v1.MetricsBucket 6, // 1: qan.v1.MetricsBucket.agent_type:type_name -> inventory.v1.AgentType diff --git a/api/qan/v1/filters.pb.go b/api/qan/v1/filters.pb.go index 390a687dbc4..fcbf5e7aead 100644 --- a/api/qan/v1/filters.pb.go +++ b/api/qan/v1/filters.pb.go @@ -293,6 +293,7 @@ var ( (*MapFieldEntry)(nil), // 6: qan.v1.MapFieldEntry } ) + var file_qan_v1_filters_proto_depIdxs = []int32{ 5, // 0: qan.v1.GetFilteredMetricsNamesRequest.period_start_from:type_name -> google.protobuf.Timestamp 5, // 1: qan.v1.GetFilteredMetricsNamesRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/object_details.pb.go b/api/qan/v1/object_details.pb.go index 53e6c06150b..f004bc0ec60 100644 --- a/api/qan/v1/object_details.pb.go +++ b/api/qan/v1/object_details.pb.go @@ -1645,6 +1645,7 @@ var ( ExampleType(0), // 29: qan.v1.ExampleType } ) + var file_qan_v1_object_details_proto_depIdxs = []int32{ 26, // 0: qan.v1.GetMetricsRequest.period_start_from:type_name -> google.protobuf.Timestamp 26, // 1: qan.v1.GetMetricsRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/profile.pb.go b/api/qan/v1/profile.pb.go index 7700b76dcd3..03ab97e871a 100644 --- a/api/qan/v1/profile.pb.go +++ b/api/qan/v1/profile.pb.go @@ -598,6 +598,7 @@ var ( (*Point)(nil), // 8: qan.v1.Point } ) + var file_qan_v1_profile_proto_depIdxs = []int32{ 7, // 0: qan.v1.GetReportRequest.period_start_from:type_name -> google.protobuf.Timestamp 7, // 1: qan.v1.GetReportRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/qan.pb.go b/api/qan/v1/qan.pb.go index 2d37431a7c0..c1d3bc6bb2e 100644 --- a/api/qan/v1/qan.pb.go +++ b/api/qan/v1/qan.pb.go @@ -1000,6 +1000,7 @@ var ( (*MapFieldEntry)(nil), // 2: qan.v1.MapFieldEntry } ) + var file_qan_v1_qan_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/qan/v1/service.pb.go b/api/qan/v1/service.pb.go index c5c688d9000..0e52423aa51 100644 --- a/api/qan/v1/service.pb.go +++ b/api/qan/v1/service.pb.go @@ -258,6 +258,7 @@ var ( (*GetQueryExampleResponse)(nil), // 24: qan.v1.GetQueryExampleResponse } ) + var file_qan_v1_service_proto_depIdxs = []int32{ 4, // 0: qan.v1.GetMetricsNamesResponse.data:type_name -> qan.v1.GetMetricsNamesResponse.DataEntry 5, // 1: qan.v1.QANService.GetReport:input_type -> qan.v1.GetReportRequest diff --git a/api/realtimeanalytics/v1/collector.pb.go b/api/realtimeanalytics/v1/collector.pb.go index b9b81466e7c..f149de0a6cf 100644 --- a/api/realtimeanalytics/v1/collector.pb.go +++ b/api/realtimeanalytics/v1/collector.pb.go @@ -140,6 +140,7 @@ var ( (*QueryData)(nil), // 2: realtimeanalytics.v1.QueryData } ) + var file_realtimeanalytics_v1_collector_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.CollectRequest.queries:type_name -> realtimeanalytics.v1.QueryData 0, // 1: realtimeanalytics.v1.CollectorService.Collect:input_type -> realtimeanalytics.v1.CollectRequest diff --git a/api/realtimeanalytics/v1/query.pb.go b/api/realtimeanalytics/v1/query.pb.go index b9ab1809d9a..43c4a1bdd5c 100644 --- a/api/realtimeanalytics/v1/query.pb.go +++ b/api/realtimeanalytics/v1/query.pb.go @@ -331,6 +331,7 @@ var ( (*durationpb.Duration)(nil), // 3: google.protobuf.Duration } ) + var file_realtimeanalytics_v1_query_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.QueryMongoDBData.operation_start_time:type_name -> google.protobuf.Timestamp 3, // 1: realtimeanalytics.v1.QueryData.query_execution_duration:type_name -> google.protobuf.Duration diff --git a/api/realtimeanalytics/v1/realtimeanalytics.pb.go b/api/realtimeanalytics/v1/realtimeanalytics.pb.go index bd339f4bad9..8dbdbf8ccff 100644 --- a/api/realtimeanalytics/v1/realtimeanalytics.pb.go +++ b/api/realtimeanalytics/v1/realtimeanalytics.pb.go @@ -718,6 +718,7 @@ var ( (*QueryData)(nil), // 16: realtimeanalytics.v1.QueryData } ) + var file_realtimeanalytics_v1_realtimeanalytics_proto_depIdxs = []int32{ 12, // 0: realtimeanalytics.v1.ListServicesRequest.service_type:type_name -> inventory.v1.ServiceType 13, // 1: realtimeanalytics.v1.ListServicesResponse.mongodb:type_name -> inventory.v1.MongoDBService diff --git a/api/server/v1/httperror.pb.go b/api/server/v1/httperror.pb.go index ef269ba2292..8778ad26272 100644 --- a/api/server/v1/httperror.pb.go +++ b/api/server/v1/httperror.pb.go @@ -127,6 +127,7 @@ var ( (*anypb.Any)(nil), // 1: google.protobuf.Any } ) + var file_server_v1_httperror_proto_depIdxs = []int32{ 1, // 0: server.v1.HttpError.details:type_name -> google.protobuf.Any 1, // [1:1] is the sub-list for method output_type diff --git a/api/server/v1/json/client/server_service/change_settings_responses.go b/api/server/v1/json/client/server_service/change_settings_responses.go index 1d956a34756..dbc92c537cd 100644 --- a/api/server/v1/json/client/server_service/change_settings_responses.go +++ b/api/server/v1/json/client/server_service/change_settings_responses.go @@ -14,6 +14,7 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" + "github.com/go-openapi/validate" ) // ChangeSettingsReader is a Reader for the ChangeSettings structure. @@ -198,6 +199,16 @@ type ChangeSettingsBody struct { // A number of full days for Prometheus and QAN data retention. Should have a suffix in JSON: 2592000s, 43200m, 720h. DataRetention string `json:"data_retention,omitempty"` + // A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h. + AdvisorHistoryRetention string `json:"advisor_history_retention,omitempty"` + + // Enable Advisor email notifications. + EnableAdvisorNotifications *bool `json:"enable_advisor_notifications,omitempty"` + + // Severity represents severity level of the check result or alert. + // Enum: ["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"] + AdvisorNotificationSeverityThreshold *string `json:"advisor_notification_severity_threshold,omitempty"` + // ssh key SSHKey *string `json:"ssh_key,omitempty"` @@ -239,6 +250,10 @@ type ChangeSettingsBody struct { func (o *ChangeSettingsBody) Validate(formats strfmt.Registry) error { var res []error + if err := o.validateAdvisorNotificationSeverityThreshold(formats); err != nil { + res = append(res, err) + } + if err := o.validateAdvisorRunIntervals(formats); err != nil { res = append(res, err) } @@ -257,6 +272,69 @@ func (o *ChangeSettingsBody) Validate(formats strfmt.Registry) error { return nil } +var changeSettingsBodyTypeAdvisorNotificationSeverityThresholdPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + changeSettingsBodyTypeAdvisorNotificationSeverityThresholdPropEnum = append(changeSettingsBodyTypeAdvisorNotificationSeverityThresholdPropEnum, v) + } +} + +const ( + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYUNSPECIFIED captures enum value "SEVERITY_UNSPECIFIED" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYUNSPECIFIED string = "SEVERITY_UNSPECIFIED" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYEMERGENCY captures enum value "SEVERITY_EMERGENCY" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYEMERGENCY string = "SEVERITY_EMERGENCY" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYALERT captures enum value "SEVERITY_ALERT" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYALERT string = "SEVERITY_ALERT" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYCRITICAL captures enum value "SEVERITY_CRITICAL" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYCRITICAL string = "SEVERITY_CRITICAL" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYERROR captures enum value "SEVERITY_ERROR" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYERROR string = "SEVERITY_ERROR" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYWARNING captures enum value "SEVERITY_WARNING" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYWARNING string = "SEVERITY_WARNING" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYNOTICE captures enum value "SEVERITY_NOTICE" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYNOTICE string = "SEVERITY_NOTICE" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYINFO captures enum value "SEVERITY_INFO" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYINFO string = "SEVERITY_INFO" + + // ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYDEBUG captures enum value "SEVERITY_DEBUG" + ChangeSettingsBodyAdvisorNotificationSeverityThresholdSEVERITYDEBUG string = "SEVERITY_DEBUG" +) + +// prop value enum +func (o *ChangeSettingsBody) validateAdvisorNotificationSeverityThresholdEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, changeSettingsBodyTypeAdvisorNotificationSeverityThresholdPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ChangeSettingsBody) validateAdvisorNotificationSeverityThreshold(formats strfmt.Registry) error { + if swag.IsZero(o.AdvisorNotificationSeverityThreshold) { // not required + return nil + } + + // value enum + if err := o.validateAdvisorNotificationSeverityThresholdEnum("body"+"."+"advisor_notification_severity_threshold", "body", *o.AdvisorNotificationSeverityThreshold); err != nil { + return err + } + + return nil +} + func (o *ChangeSettingsBody) validateAdvisorRunIntervals(formats strfmt.Registry) error { if swag.IsZero(o.AdvisorRunIntervals) { // not required return nil @@ -947,6 +1025,16 @@ type ChangeSettingsOKBodySettings struct { // data retention DataRetention string `json:"data_retention,omitempty"` + // Advisor check results history retention. + AdvisorHistoryRetention string `json:"advisor_history_retention,omitempty"` + + // True if Advisor email notifications are enabled. + AdvisorNotificationsEnabled bool `json:"advisor_notifications_enabled,omitempty"` + + // Severity represents severity level of the check result or alert. + // Enum: ["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"] + AdvisorNotificationSeverityThreshold *string `json:"advisor_notification_severity_threshold,omitempty"` + // ssh key SSHKey string `json:"ssh_key,omitempty"` @@ -1000,6 +1088,10 @@ type ChangeSettingsOKBodySettings struct { func (o *ChangeSettingsOKBodySettings) Validate(formats strfmt.Registry) error { var res []error + if err := o.validateAdvisorNotificationSeverityThreshold(formats); err != nil { + res = append(res, err) + } + if err := o.validateAdvisorRunIntervals(formats); err != nil { res = append(res, err) } @@ -1014,6 +1106,69 @@ func (o *ChangeSettingsOKBodySettings) Validate(formats strfmt.Registry) error { return nil } +var changeSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + changeSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum = append(changeSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum, v) + } +} + +const ( + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYUNSPECIFIED captures enum value "SEVERITY_UNSPECIFIED" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYUNSPECIFIED string = "SEVERITY_UNSPECIFIED" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYEMERGENCY captures enum value "SEVERITY_EMERGENCY" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYEMERGENCY string = "SEVERITY_EMERGENCY" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYALERT captures enum value "SEVERITY_ALERT" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYALERT string = "SEVERITY_ALERT" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYCRITICAL captures enum value "SEVERITY_CRITICAL" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYCRITICAL string = "SEVERITY_CRITICAL" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYERROR captures enum value "SEVERITY_ERROR" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYERROR string = "SEVERITY_ERROR" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYWARNING captures enum value "SEVERITY_WARNING" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYWARNING string = "SEVERITY_WARNING" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYNOTICE captures enum value "SEVERITY_NOTICE" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYNOTICE string = "SEVERITY_NOTICE" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYINFO captures enum value "SEVERITY_INFO" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYINFO string = "SEVERITY_INFO" + + // ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYDEBUG captures enum value "SEVERITY_DEBUG" + ChangeSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYDEBUG string = "SEVERITY_DEBUG" +) + +// prop value enum +func (o *ChangeSettingsOKBodySettings) validateAdvisorNotificationSeverityThresholdEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, changeSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ChangeSettingsOKBodySettings) validateAdvisorNotificationSeverityThreshold(formats strfmt.Registry) error { + if swag.IsZero(o.AdvisorNotificationSeverityThreshold) { // not required + return nil + } + + // value enum + if err := o.validateAdvisorNotificationSeverityThresholdEnum("changeSettingsOk"+"."+"settings"+"."+"advisor_notification_severity_threshold", "body", *o.AdvisorNotificationSeverityThreshold); err != nil { + return err + } + + return nil +} + func (o *ChangeSettingsOKBodySettings) validateAdvisorRunIntervals(formats strfmt.Registry) error { if swag.IsZero(o.AdvisorRunIntervals) { // not required return nil diff --git a/api/server/v1/json/client/server_service/get_settings_responses.go b/api/server/v1/json/client/server_service/get_settings_responses.go index 58945eeca44..dc38d036843 100644 --- a/api/server/v1/json/client/server_service/get_settings_responses.go +++ b/api/server/v1/json/client/server_service/get_settings_responses.go @@ -14,6 +14,7 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" + "github.com/go-openapi/validate" ) // GetSettingsReader is a Reader for the GetSettings structure. @@ -693,6 +694,16 @@ type GetSettingsOKBodySettings struct { // data retention DataRetention string `json:"data_retention,omitempty"` + // Advisor check results history retention. + AdvisorHistoryRetention string `json:"advisor_history_retention,omitempty"` + + // True if Advisor email notifications are enabled. + AdvisorNotificationsEnabled bool `json:"advisor_notifications_enabled,omitempty"` + + // Severity represents severity level of the check result or alert. + // Enum: ["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"] + AdvisorNotificationSeverityThreshold *string `json:"advisor_notification_severity_threshold,omitempty"` + // ssh key SSHKey string `json:"ssh_key,omitempty"` @@ -746,6 +757,10 @@ type GetSettingsOKBodySettings struct { func (o *GetSettingsOKBodySettings) Validate(formats strfmt.Registry) error { var res []error + if err := o.validateAdvisorNotificationSeverityThreshold(formats); err != nil { + res = append(res, err) + } + if err := o.validateAdvisorRunIntervals(formats); err != nil { res = append(res, err) } @@ -760,6 +775,69 @@ func (o *GetSettingsOKBodySettings) Validate(formats strfmt.Registry) error { return nil } +var getSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum = append(getSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum, v) + } +} + +const ( + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYUNSPECIFIED captures enum value "SEVERITY_UNSPECIFIED" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYUNSPECIFIED string = "SEVERITY_UNSPECIFIED" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYEMERGENCY captures enum value "SEVERITY_EMERGENCY" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYEMERGENCY string = "SEVERITY_EMERGENCY" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYALERT captures enum value "SEVERITY_ALERT" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYALERT string = "SEVERITY_ALERT" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYCRITICAL captures enum value "SEVERITY_CRITICAL" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYCRITICAL string = "SEVERITY_CRITICAL" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYERROR captures enum value "SEVERITY_ERROR" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYERROR string = "SEVERITY_ERROR" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYWARNING captures enum value "SEVERITY_WARNING" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYWARNING string = "SEVERITY_WARNING" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYNOTICE captures enum value "SEVERITY_NOTICE" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYNOTICE string = "SEVERITY_NOTICE" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYINFO captures enum value "SEVERITY_INFO" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYINFO string = "SEVERITY_INFO" + + // GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYDEBUG captures enum value "SEVERITY_DEBUG" + GetSettingsOKBodySettingsAdvisorNotificationSeverityThresholdSEVERITYDEBUG string = "SEVERITY_DEBUG" +) + +// prop value enum +func (o *GetSettingsOKBodySettings) validateAdvisorNotificationSeverityThresholdEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getSettingsOkBodySettingsTypeAdvisorNotificationSeverityThresholdPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetSettingsOKBodySettings) validateAdvisorNotificationSeverityThreshold(formats strfmt.Registry) error { + if swag.IsZero(o.AdvisorNotificationSeverityThreshold) { // not required + return nil + } + + // value enum + if err := o.validateAdvisorNotificationSeverityThresholdEnum("getSettingsOk"+"."+"settings"+"."+"advisor_notification_severity_threshold", "body", *o.AdvisorNotificationSeverityThreshold); err != nil { + return err + } + + return nil +} + func (o *GetSettingsOKBodySettings) validateAdvisorRunIntervals(formats strfmt.Registry) error { if swag.IsZero(o.AdvisorRunIntervals) { // not required return nil diff --git a/api/server/v1/json/v1.json b/api/server/v1/json/v1.json index bf2ad5c8718..1ca9903bb4a 100644 --- a/api/server/v1/json/v1.json +++ b/api/server/v1/json/v1.json @@ -221,35 +221,62 @@ "type": "string", "x-order": 3 }, - "ssh_key": { + "advisor_history_retention": { + "description": "Advisor check results history retention.", "type": "string", "x-order": 4 }, + "advisor_notifications_enabled": { + "description": "True if Advisor email notifications are enabled.", + "type": "boolean", + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, + "ssh_key": { + "type": "string", + "x-order": 7 + }, "aws_partitions": { "type": "array", "items": { "type": "string" }, - "x-order": 5 + "x-order": 8 }, "advisor_enabled": { "description": "True if Advisor is enabled.", "type": "boolean", - "x-order": 6 + "x-order": 9 }, "platform_email": { "type": "string", - "x-order": 7 + "x-order": 10 }, "alerting_enabled": { "description": "True if Alerting is enabled.", "type": "boolean", - "x-order": 8 + "x-order": 11 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", - "x-order": 9 + "x-order": 12 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -271,22 +298,22 @@ "x-order": 2 } }, - "x-order": 10 + "x-order": 13 }, "backup_management_enabled": { "description": "True if Backup Management is enabled.", "type": "boolean", - "x-order": 11 + "x-order": 14 }, "azurediscover_enabled": { "description": "True if Azure Discover is enabled.", "type": "boolean", - "x-order": 12 + "x-order": 15 }, "connected_to_platform": { "type": "boolean", "title": "True if the PMM instance is connected to Platform", - "x-order": 13 + "x-order": 16 }, "telemetry_summaries": { "type": "array", @@ -294,28 +321,28 @@ "items": { "type": "string" }, - "x-order": 14 + "x-order": 17 }, "enable_access_control": { "description": "True if Access Control is enabled.", "type": "boolean", - "x-order": 15 + "x-order": 18 }, "default_role_id": { "description": "Default Access Control role ID for new users.", "type": "integer", "format": "int64", - "x-order": 16 + "x-order": 19 }, "enable_internal_pg_qan": { "description": "True if Query Analytics for PMM's internal PG database is enabled.", "type": "boolean", - "x-order": 17 + "x-order": 20 }, "update_snooze_duration": { "type": "string", "title": "Duration for which an update is snoozed", - "x-order": 18 + "x-order": 21 } }, "x-order": 0 @@ -410,10 +437,38 @@ "type": "string", "x-order": 3 }, + "advisor_history_retention": { + "description": "A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h.", + "type": "string", + "x-order": 4 + }, + "enable_advisor_notifications": { + "description": "Enable Advisor email notifications.", + "type": "boolean", + "x-nullable": true, + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, "ssh_key": { "type": "string", "x-nullable": true, - "x-order": 4 + "x-order": 7 }, "aws_partitions": { "description": "A wrapper for a string array. This type allows to distinguish between an empty array and a null value.", @@ -428,25 +483,25 @@ } }, "x-nullable": true, - "x-order": 5 + "x-order": 8 }, "enable_advisor": { "description": "Enable Advisor.", "type": "boolean", "x-nullable": true, - "x-order": 6 + "x-order": 9 }, "enable_alerting": { "description": "Enable Alerting.", "type": "boolean", "x-nullable": true, - "x-order": 7 + "x-order": 10 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", "x-nullable": true, - "x-order": 8 + "x-order": 11 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -468,36 +523,36 @@ "x-order": 2 } }, - "x-order": 9 + "x-order": 12 }, "enable_azurediscover": { "description": "Enable Azure Discover.", "type": "boolean", "x-nullable": true, - "x-order": 10 + "x-order": 13 }, "enable_backup_management": { "description": "Enable Backup Management.", "type": "boolean", "x-nullable": true, - "x-order": 11 + "x-order": 14 }, "enable_access_control": { "type": "boolean", "title": "Enable Access Control", "x-nullable": true, - "x-order": 12 + "x-order": 15 }, "enable_internal_pg_qan": { "description": "Enable Query Analytics for PMM's internal PG database.", "type": "boolean", "x-nullable": true, - "x-order": 13 + "x-order": 16 }, "update_snooze_duration": { "description": "A number of full days for which an update is snoozed, i.e. a multiple of 24h: 2592000s, 43200m, 720h.", "type": "string", - "x-order": 14 + "x-order": 17 } } } @@ -549,35 +604,62 @@ "type": "string", "x-order": 3 }, - "ssh_key": { + "advisor_history_retention": { + "description": "Advisor check results history retention.", "type": "string", "x-order": 4 }, + "advisor_notifications_enabled": { + "description": "True if Advisor email notifications are enabled.", + "type": "boolean", + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, + "ssh_key": { + "type": "string", + "x-order": 7 + }, "aws_partitions": { "type": "array", "items": { "type": "string" }, - "x-order": 5 + "x-order": 8 }, "advisor_enabled": { "description": "True if Advisor is enabled.", "type": "boolean", - "x-order": 6 + "x-order": 9 }, "platform_email": { "type": "string", - "x-order": 7 + "x-order": 10 }, "alerting_enabled": { "description": "True if Alerting is enabled.", "type": "boolean", - "x-order": 8 + "x-order": 11 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", - "x-order": 9 + "x-order": 12 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -599,22 +681,22 @@ "x-order": 2 } }, - "x-order": 10 + "x-order": 13 }, "backup_management_enabled": { "description": "True if Backup Management is enabled.", "type": "boolean", - "x-order": 11 + "x-order": 14 }, "azurediscover_enabled": { "description": "True if Azure Discover is enabled.", "type": "boolean", - "x-order": 12 + "x-order": 15 }, "connected_to_platform": { "type": "boolean", "title": "True if the PMM instance is connected to Platform", - "x-order": 13 + "x-order": 16 }, "telemetry_summaries": { "type": "array", @@ -622,28 +704,28 @@ "items": { "type": "string" }, - "x-order": 14 + "x-order": 17 }, "enable_access_control": { "description": "True if Access Control is enabled.", "type": "boolean", - "x-order": 15 + "x-order": 18 }, "default_role_id": { "description": "Default Access Control role ID for new users.", "type": "integer", "format": "int64", - "x-order": 16 + "x-order": 19 }, "enable_internal_pg_qan": { "description": "True if Query Analytics for PMM's internal PG database is enabled.", "type": "boolean", - "x-order": 17 + "x-order": 20 }, "update_snooze_duration": { "type": "string", "title": "Duration for which an update is snoozed", - "x-order": 18 + "x-order": 21 } }, "x-order": 0 diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index 0af6b91d79f..ab1ab9b07ae 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -20,6 +20,7 @@ import ( common "github.com/percona/pmm/api/common" _ "github.com/percona/pmm/api/extensions/v1" + v1 "github.com/percona/pmm/api/management/v1" ) const ( @@ -1071,8 +1072,14 @@ type Settings struct { TelemetryEnabled bool `protobuf:"varint,2,opt,name=telemetry_enabled,json=telemetryEnabled,proto3" json:"telemetry_enabled,omitempty"` MetricsResolutions *MetricsResolutions `protobuf:"bytes,3,opt,name=metrics_resolutions,json=metricsResolutions,proto3" json:"metrics_resolutions,omitempty"` DataRetention *durationpb.Duration `protobuf:"bytes,4,opt,name=data_retention,json=dataRetention,proto3" json:"data_retention,omitempty"` - SshKey string `protobuf:"bytes,5,opt,name=ssh_key,json=sshKey,proto3" json:"ssh_key,omitempty"` - AwsPartitions []string `protobuf:"bytes,6,rep,name=aws_partitions,json=awsPartitions,proto3" json:"aws_partitions,omitempty"` + // Advisor check results history retention. + AdvisorHistoryRetention *durationpb.Duration `protobuf:"bytes,21,opt,name=advisor_history_retention,json=advisorHistoryRetention,proto3" json:"advisor_history_retention,omitempty"` + // True if Advisor email notifications are enabled. + AdvisorNotificationsEnabled bool `protobuf:"varint,22,opt,name=advisor_notifications_enabled,json=advisorNotificationsEnabled,proto3" json:"advisor_notifications_enabled,omitempty"` + // Least-severe level that triggers an Advisor notification. + AdvisorNotificationSeverityThreshold v1.Severity `protobuf:"varint,23,opt,name=advisor_notification_severity_threshold,json=advisorNotificationSeverityThreshold,proto3,enum=management.v1.Severity" json:"advisor_notification_severity_threshold,omitempty"` + SshKey string `protobuf:"bytes,5,opt,name=ssh_key,json=sshKey,proto3" json:"ssh_key,omitempty"` + AwsPartitions []string `protobuf:"bytes,6,rep,name=aws_partitions,json=awsPartitions,proto3" json:"aws_partitions,omitempty"` // True if Advisor is enabled. AdvisorEnabled bool `protobuf:"varint,7,opt,name=advisor_enabled,json=advisorEnabled,proto3" json:"advisor_enabled,omitempty"` // Deprecated: Marked as deprecated in server/v1/server.proto. @@ -1163,6 +1170,27 @@ func (x *Settings) GetDataRetention() *durationpb.Duration { return nil } +func (x *Settings) GetAdvisorHistoryRetention() *durationpb.Duration { + if x != nil { + return x.AdvisorHistoryRetention + } + return nil +} + +func (x *Settings) GetAdvisorNotificationsEnabled() bool { + if x != nil { + return x.AdvisorNotificationsEnabled + } + return false +} + +func (x *Settings) GetAdvisorNotificationSeverityThreshold() v1.Severity { + if x != nil { + return x.AdvisorNotificationSeverityThreshold + } + return v1.Severity(0) +} + func (x *Settings) GetSshKey() string { if x != nil { return x.SshKey @@ -1546,8 +1574,14 @@ type ChangeSettingsRequest struct { MetricsResolutions *MetricsResolutions `protobuf:"bytes,3,opt,name=metrics_resolutions,json=metricsResolutions,proto3" json:"metrics_resolutions,omitempty"` // A number of full days for Prometheus and QAN data retention. Should have a suffix in JSON: 2592000s, 43200m, 720h. DataRetention *durationpb.Duration `protobuf:"bytes,4,opt,name=data_retention,json=dataRetention,proto3" json:"data_retention,omitempty"` - SshKey *string `protobuf:"bytes,5,opt,name=ssh_key,json=sshKey,proto3,oneof" json:"ssh_key,omitempty"` - AwsPartitions *common.StringArray `protobuf:"bytes,6,opt,name=aws_partitions,json=awsPartitions,proto3,oneof" json:"aws_partitions,omitempty"` + // A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h. + AdvisorHistoryRetention *durationpb.Duration `protobuf:"bytes,16,opt,name=advisor_history_retention,json=advisorHistoryRetention,proto3" json:"advisor_history_retention,omitempty"` + // Enable Advisor email notifications. + EnableAdvisorNotifications *bool `protobuf:"varint,17,opt,name=enable_advisor_notifications,json=enableAdvisorNotifications,proto3,oneof" json:"enable_advisor_notifications,omitempty"` + // Least-severe level that triggers an Advisor notification. + AdvisorNotificationSeverityThreshold v1.Severity `protobuf:"varint,18,opt,name=advisor_notification_severity_threshold,json=advisorNotificationSeverityThreshold,proto3,enum=management.v1.Severity" json:"advisor_notification_severity_threshold,omitempty"` + SshKey *string `protobuf:"bytes,5,opt,name=ssh_key,json=sshKey,proto3,oneof" json:"ssh_key,omitempty"` + AwsPartitions *common.StringArray `protobuf:"bytes,6,opt,name=aws_partitions,json=awsPartitions,proto3,oneof" json:"aws_partitions,omitempty"` // Enable Advisor. EnableAdvisor *bool `protobuf:"varint,7,opt,name=enable_advisor,json=enableAdvisor,proto3,oneof" json:"enable_advisor,omitempty"` // Enable Alerting. @@ -1628,6 +1662,27 @@ func (x *ChangeSettingsRequest) GetDataRetention() *durationpb.Duration { return nil } +func (x *ChangeSettingsRequest) GetAdvisorHistoryRetention() *durationpb.Duration { + if x != nil { + return x.AdvisorHistoryRetention + } + return nil +} + +func (x *ChangeSettingsRequest) GetEnableAdvisorNotifications() bool { + if x != nil && x.EnableAdvisorNotifications != nil { + return *x.EnableAdvisorNotifications + } + return false +} + +func (x *ChangeSettingsRequest) GetAdvisorNotificationSeverityThreshold() v1.Severity { + if x != nil { + return x.AdvisorNotificationSeverityThreshold + } + return v1.Severity(0) +} + func (x *ChangeSettingsRequest) GetSshKey() string { if x != nil && x.SshKey != nil { return *x.SshKey @@ -1753,7 +1808,7 @@ var File_server_v1_server_proto protoreflect.FileDescriptor const file_server_v1_server_proto_rawDesc = "" + "\n" + - "\x16server/v1/server.proto\x12\tserver.v1\x1a\x13common/common.proto\x1a\x1aextensions/v1/redact.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\"\x84\x01\n" + + "\x16server/v1/server.proto\x12\tserver.v1\x1a\x13common/common.proto\x1a\x1aextensions/v1/redact.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1cmanagement/v1/severity.proto\x1a.protoc-gen-openapiv2/options/annotations.proto\"\x84\x01\n" + "\vVersionInfo\x12\x18\n" + "\aversion\x18\x01 \x01(\tR\aversion\x12!\n" + "\ffull_version\x18\x02 \x01(\tR\vfullVersion\x128\n" + @@ -1814,12 +1869,15 @@ const file_server_v1_server_proto_rawDesc = "" + "\x13AdvisorRunIntervals\x12F\n" + "\x11standard_interval\x18\x01 \x01(\v2\x19.google.protobuf.DurationR\x10standardInterval\x12>\n" + "\rrare_interval\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\frareInterval\x12F\n" + - "\x11frequent_interval\x18\x03 \x01(\v2\x19.google.protobuf.DurationR\x10frequentInterval\"\xef\a\n" + + "\x11frequent_interval\x18\x03 \x01(\v2\x19.google.protobuf.DurationR\x10frequentInterval\"\xfa\t\n" + "\bSettings\x12'\n" + "\x0fupdates_enabled\x18\x01 \x01(\bR\x0eupdatesEnabled\x12+\n" + "\x11telemetry_enabled\x18\x02 \x01(\bR\x10telemetryEnabled\x12N\n" + "\x13metrics_resolutions\x18\x03 \x01(\v2\x1d.server.v1.MetricsResolutionsR\x12metricsResolutions\x12@\n" + - "\x0edata_retention\x18\x04 \x01(\v2\x19.google.protobuf.DurationR\rdataRetention\x12\x17\n" + + "\x0edata_retention\x18\x04 \x01(\v2\x19.google.protobuf.DurationR\rdataRetention\x12U\n" + + "\x19advisor_history_retention\x18\x15 \x01(\v2\x19.google.protobuf.DurationR\x17advisorHistoryRetention\x12B\n" + + "\x1dadvisor_notifications_enabled\x18\x16 \x01(\bR\x1badvisorNotificationsEnabled\x12n\n" + + "'advisor_notification_severity_threshold\x18\x17 \x01(\x0e2\x17.management.v1.SeverityR$advisorNotificationSeverityThreshold\x12\x17\n" + "\assh_key\x18\x05 \x01(\tR\x06sshKey\x12%\n" + "\x0eaws_partitions\x18\x06 \x03(\tR\rawsPartitions\x12'\n" + "\x0fadvisor_enabled\x18\a \x01(\bR\x0eadvisorEnabled\x12)\n" + @@ -1850,27 +1908,31 @@ const file_server_v1_server_proto_rawDesc = "" + "\x13GetSettingsResponse\x12/\n" + "\bsettings\x18\x01 \x01(\v2\x13.server.v1.SettingsR\bsettings\"V\n" + "\x1bGetReadOnlySettingsResponse\x127\n" + - "\bsettings\x18\x01 \x01(\v2\x1b.server.v1.ReadOnlySettingsR\bsettings\"\xf0\b\n" + + "\bsettings\x18\x01 \x01(\v2\x1b.server.v1.ReadOnlySettingsR\bsettings\"\x9f\v\n" + "\x15ChangeSettingsRequest\x12*\n" + "\x0eenable_updates\x18\x01 \x01(\bH\x00R\renableUpdates\x88\x01\x01\x12.\n" + "\x10enable_telemetry\x18\x02 \x01(\bH\x01R\x0fenableTelemetry\x88\x01\x01\x12N\n" + "\x13metrics_resolutions\x18\x03 \x01(\v2\x1d.server.v1.MetricsResolutionsR\x12metricsResolutions\x12@\n" + - "\x0edata_retention\x18\x04 \x01(\v2\x19.google.protobuf.DurationR\rdataRetention\x12\x1c\n" + - "\assh_key\x18\x05 \x01(\tH\x02R\x06sshKey\x88\x01\x01\x12?\n" + - "\x0eaws_partitions\x18\x06 \x01(\v2\x13.common.StringArrayH\x03R\rawsPartitions\x88\x01\x01\x12*\n" + - "\x0eenable_advisor\x18\a \x01(\bH\x04R\renableAdvisor\x88\x01\x01\x12,\n" + - "\x0fenable_alerting\x18\b \x01(\bH\x05R\x0eenableAlerting\x88\x01\x01\x121\n" + - "\x12pmm_public_address\x18\t \x01(\tH\x06R\x10pmmPublicAddress\x88\x01\x01\x12R\n" + + "\x0edata_retention\x18\x04 \x01(\v2\x19.google.protobuf.DurationR\rdataRetention\x12U\n" + + "\x19advisor_history_retention\x18\x10 \x01(\v2\x19.google.protobuf.DurationR\x17advisorHistoryRetention\x12E\n" + + "\x1cenable_advisor_notifications\x18\x11 \x01(\bH\x02R\x1aenableAdvisorNotifications\x88\x01\x01\x12n\n" + + "'advisor_notification_severity_threshold\x18\x12 \x01(\x0e2\x17.management.v1.SeverityR$advisorNotificationSeverityThreshold\x12\x1c\n" + + "\assh_key\x18\x05 \x01(\tH\x03R\x06sshKey\x88\x01\x01\x12?\n" + + "\x0eaws_partitions\x18\x06 \x01(\v2\x13.common.StringArrayH\x04R\rawsPartitions\x88\x01\x01\x12*\n" + + "\x0eenable_advisor\x18\a \x01(\bH\x05R\renableAdvisor\x88\x01\x01\x12,\n" + + "\x0fenable_alerting\x18\b \x01(\bH\x06R\x0eenableAlerting\x88\x01\x01\x121\n" + + "\x12pmm_public_address\x18\t \x01(\tH\aR\x10pmmPublicAddress\x88\x01\x01\x12R\n" + "\x15advisor_run_intervals\x18\n" + " \x01(\v2\x1e.server.v1.AdvisorRunIntervalsR\x13advisorRunIntervals\x126\n" + - "\x14enable_azurediscover\x18\v \x01(\bH\aR\x13enableAzurediscover\x88\x01\x01\x12=\n" + - "\x18enable_backup_management\x18\f \x01(\bH\bR\x16enableBackupManagement\x88\x01\x01\x127\n" + - "\x15enable_access_control\x18\r \x01(\bH\tR\x13enableAccessControl\x88\x01\x01\x128\n" + - "\x16enable_internal_pg_qan\x18\x0e \x01(\bH\n" + - "R\x13enableInternalPgQan\x88\x01\x01\x12O\n" + + "\x14enable_azurediscover\x18\v \x01(\bH\bR\x13enableAzurediscover\x88\x01\x01\x12=\n" + + "\x18enable_backup_management\x18\f \x01(\bH\tR\x16enableBackupManagement\x88\x01\x01\x127\n" + + "\x15enable_access_control\x18\r \x01(\bH\n" + + "R\x13enableAccessControl\x88\x01\x01\x128\n" + + "\x16enable_internal_pg_qan\x18\x0e \x01(\bH\vR\x13enableInternalPgQan\x88\x01\x01\x12O\n" + "\x16update_snooze_duration\x18\x0f \x01(\v2\x19.google.protobuf.DurationR\x14updateSnoozeDurationB\x11\n" + "\x0f_enable_updatesB\x13\n" + - "\x11_enable_telemetryB\n" + + "\x11_enable_telemetryB\x1f\n" + + "\x1d_enable_advisor_notificationsB\n" + "\n" + "\b_ssh_keyB\x11\n" + "\x0f_aws_partitionsB\x11\n" + @@ -1949,9 +2011,11 @@ var ( (*ChangeSettingsResponse)(nil), // 26: server.v1.ChangeSettingsResponse (*timestamppb.Timestamp)(nil), // 27: google.protobuf.Timestamp (*durationpb.Duration)(nil), // 28: google.protobuf.Duration - (*common.StringArray)(nil), // 29: common.StringArray + v1.Severity(0), // 29: management.v1.Severity + (*common.StringArray)(nil), // 30: common.StringArray } ) + var file_server_v1_server_proto_depIdxs = []int32{ 27, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo @@ -1971,41 +2035,45 @@ var file_server_v1_server_proto_depIdxs = []int32{ 28, // 15: server.v1.AdvisorRunIntervals.frequent_interval:type_name -> google.protobuf.Duration 17, // 16: server.v1.Settings.metrics_resolutions:type_name -> server.v1.MetricsResolutions 28, // 17: server.v1.Settings.data_retention:type_name -> google.protobuf.Duration - 18, // 18: server.v1.Settings.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals - 28, // 19: server.v1.Settings.update_snooze_duration:type_name -> google.protobuf.Duration - 19, // 20: server.v1.GetSettingsResponse.settings:type_name -> server.v1.Settings - 20, // 21: server.v1.GetReadOnlySettingsResponse.settings:type_name -> server.v1.ReadOnlySettings - 17, // 22: server.v1.ChangeSettingsRequest.metrics_resolutions:type_name -> server.v1.MetricsResolutions - 28, // 23: server.v1.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration - 29, // 24: server.v1.ChangeSettingsRequest.aws_partitions:type_name -> common.StringArray - 18, // 25: server.v1.ChangeSettingsRequest.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals - 28, // 26: server.v1.ChangeSettingsRequest.update_snooze_duration:type_name -> google.protobuf.Duration - 19, // 27: server.v1.ChangeSettingsResponse.settings:type_name -> server.v1.Settings - 2, // 28: server.v1.ServerService.Version:input_type -> server.v1.VersionRequest - 4, // 29: server.v1.ServerService.Readiness:input_type -> server.v1.ReadinessRequest - 6, // 30: server.v1.ServerService.LeaderHealthCheck:input_type -> server.v1.LeaderHealthCheckRequest - 8, // 31: server.v1.ServerService.CheckUpdates:input_type -> server.v1.CheckUpdatesRequest - 11, // 32: server.v1.ServerService.ListChangeLogs:input_type -> server.v1.ListChangeLogsRequest - 13, // 33: server.v1.ServerService.StartUpdate:input_type -> server.v1.StartUpdateRequest - 15, // 34: server.v1.ServerService.UpdateStatus:input_type -> server.v1.UpdateStatusRequest - 21, // 35: server.v1.ServerService.GetSettings:input_type -> server.v1.GetSettingsRequest - 22, // 36: server.v1.ServerService.GetReadOnlySettings:input_type -> server.v1.GetReadOnlySettingsRequest - 25, // 37: server.v1.ServerService.ChangeSettings:input_type -> server.v1.ChangeSettingsRequest - 3, // 38: server.v1.ServerService.Version:output_type -> server.v1.VersionResponse - 5, // 39: server.v1.ServerService.Readiness:output_type -> server.v1.ReadinessResponse - 7, // 40: server.v1.ServerService.LeaderHealthCheck:output_type -> server.v1.LeaderHealthCheckResponse - 10, // 41: server.v1.ServerService.CheckUpdates:output_type -> server.v1.CheckUpdatesResponse - 12, // 42: server.v1.ServerService.ListChangeLogs:output_type -> server.v1.ListChangeLogsResponse - 14, // 43: server.v1.ServerService.StartUpdate:output_type -> server.v1.StartUpdateResponse - 16, // 44: server.v1.ServerService.UpdateStatus:output_type -> server.v1.UpdateStatusResponse - 23, // 45: server.v1.ServerService.GetSettings:output_type -> server.v1.GetSettingsResponse - 24, // 46: server.v1.ServerService.GetReadOnlySettings:output_type -> server.v1.GetReadOnlySettingsResponse - 26, // 47: server.v1.ServerService.ChangeSettings:output_type -> server.v1.ChangeSettingsResponse - 38, // [38:48] is the sub-list for method output_type - 28, // [28:38] is the sub-list for method input_type - 28, // [28:28] is the sub-list for extension type_name - 28, // [28:28] is the sub-list for extension extendee - 0, // [0:28] is the sub-list for field type_name + 28, // 18: server.v1.Settings.advisor_history_retention:type_name -> google.protobuf.Duration + 29, // 19: server.v1.Settings.advisor_notification_severity_threshold:type_name -> management.v1.Severity + 18, // 20: server.v1.Settings.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals + 28, // 21: server.v1.Settings.update_snooze_duration:type_name -> google.protobuf.Duration + 19, // 22: server.v1.GetSettingsResponse.settings:type_name -> server.v1.Settings + 20, // 23: server.v1.GetReadOnlySettingsResponse.settings:type_name -> server.v1.ReadOnlySettings + 17, // 24: server.v1.ChangeSettingsRequest.metrics_resolutions:type_name -> server.v1.MetricsResolutions + 28, // 25: server.v1.ChangeSettingsRequest.data_retention:type_name -> google.protobuf.Duration + 28, // 26: server.v1.ChangeSettingsRequest.advisor_history_retention:type_name -> google.protobuf.Duration + 29, // 27: server.v1.ChangeSettingsRequest.advisor_notification_severity_threshold:type_name -> management.v1.Severity + 30, // 28: server.v1.ChangeSettingsRequest.aws_partitions:type_name -> common.StringArray + 18, // 29: server.v1.ChangeSettingsRequest.advisor_run_intervals:type_name -> server.v1.AdvisorRunIntervals + 28, // 30: server.v1.ChangeSettingsRequest.update_snooze_duration:type_name -> google.protobuf.Duration + 19, // 31: server.v1.ChangeSettingsResponse.settings:type_name -> server.v1.Settings + 2, // 32: server.v1.ServerService.Version:input_type -> server.v1.VersionRequest + 4, // 33: server.v1.ServerService.Readiness:input_type -> server.v1.ReadinessRequest + 6, // 34: server.v1.ServerService.LeaderHealthCheck:input_type -> server.v1.LeaderHealthCheckRequest + 8, // 35: server.v1.ServerService.CheckUpdates:input_type -> server.v1.CheckUpdatesRequest + 11, // 36: server.v1.ServerService.ListChangeLogs:input_type -> server.v1.ListChangeLogsRequest + 13, // 37: server.v1.ServerService.StartUpdate:input_type -> server.v1.StartUpdateRequest + 15, // 38: server.v1.ServerService.UpdateStatus:input_type -> server.v1.UpdateStatusRequest + 21, // 39: server.v1.ServerService.GetSettings:input_type -> server.v1.GetSettingsRequest + 22, // 40: server.v1.ServerService.GetReadOnlySettings:input_type -> server.v1.GetReadOnlySettingsRequest + 25, // 41: server.v1.ServerService.ChangeSettings:input_type -> server.v1.ChangeSettingsRequest + 3, // 42: server.v1.ServerService.Version:output_type -> server.v1.VersionResponse + 5, // 43: server.v1.ServerService.Readiness:output_type -> server.v1.ReadinessResponse + 7, // 44: server.v1.ServerService.LeaderHealthCheck:output_type -> server.v1.LeaderHealthCheckResponse + 10, // 45: server.v1.ServerService.CheckUpdates:output_type -> server.v1.CheckUpdatesResponse + 12, // 46: server.v1.ServerService.ListChangeLogs:output_type -> server.v1.ListChangeLogsResponse + 14, // 47: server.v1.ServerService.StartUpdate:output_type -> server.v1.StartUpdateResponse + 16, // 48: server.v1.ServerService.UpdateStatus:output_type -> server.v1.UpdateStatusResponse + 23, // 49: server.v1.ServerService.GetSettings:output_type -> server.v1.GetSettingsResponse + 24, // 50: server.v1.ServerService.GetReadOnlySettings:output_type -> server.v1.GetReadOnlySettingsResponse + 26, // 51: server.v1.ServerService.ChangeSettings:output_type -> server.v1.ChangeSettingsResponse + 42, // [42:52] is the sub-list for method output_type + 32, // [32:42] is the sub-list for method input_type + 32, // [32:32] is the sub-list for extension type_name + 32, // [32:32] is the sub-list for extension extendee + 0, // [0:32] is the sub-list for field type_name } func init() { file_server_v1_server_proto_init() } diff --git a/api/server/v1/server.pb.validate.go b/api/server/v1/server.pb.validate.go index e2643c4aa5b..1dac2e0bad0 100644 --- a/api/server/v1/server.pb.validate.go +++ b/api/server/v1/server.pb.validate.go @@ -17,6 +17,8 @@ import ( "unicode/utf8" "google.golang.org/protobuf/types/known/anypb" + + managementv1 "github.com/percona/pmm/api/management/v1" ) // ensure the imports are used @@ -33,6 +35,8 @@ var ( _ = (*mail.Address)(nil) _ = anypb.Any{} _ = sort.Sort + + _ = managementv1.Severity(0) ) // Validate checks the field values on VersionInfo with the rules defined in @@ -2444,6 +2448,39 @@ func (m *Settings) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetAdvisorHistoryRetention()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, SettingsValidationError{ + field: "AdvisorHistoryRetention", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, SettingsValidationError{ + field: "AdvisorHistoryRetention", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetAdvisorHistoryRetention()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return SettingsValidationError{ + field: "AdvisorHistoryRetention", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for AdvisorNotificationsEnabled + + // no validation rules for AdvisorNotificationSeverityThreshold + // no validation rules for SshKey // no validation rules for AdvisorEnabled @@ -3270,6 +3307,37 @@ func (m *ChangeSettingsRequest) validate(all bool) error { } } + if all { + switch v := interface{}(m.GetAdvisorHistoryRetention()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, ChangeSettingsRequestValidationError{ + field: "AdvisorHistoryRetention", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, ChangeSettingsRequestValidationError{ + field: "AdvisorHistoryRetention", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetAdvisorHistoryRetention()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return ChangeSettingsRequestValidationError{ + field: "AdvisorHistoryRetention", + reason: "embedded message failed validation", + cause: err, + } + } + } + + // no validation rules for AdvisorNotificationSeverityThreshold + if all { switch v := interface{}(m.GetAdvisorRunIntervals()).(type) { case interface{ ValidateAll() error }: @@ -3336,6 +3404,10 @@ func (m *ChangeSettingsRequest) validate(all bool) error { // no validation rules for EnableTelemetry } + if m.EnableAdvisorNotifications != nil { + // no validation rules for EnableAdvisorNotifications + } + if m.SshKey != nil { // no validation rules for SshKey } diff --git a/api/server/v1/server.proto b/api/server/v1/server.proto index 51dc8b8f975..dc4217b2927 100644 --- a/api/server/v1/server.proto +++ b/api/server/v1/server.proto @@ -7,6 +7,7 @@ import "extensions/v1/redact.proto"; import "google/api/annotations.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; +import "management/v1/severity.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; // DistributionMethod defines PMM Server distribution method: Docker image, OVF/OVA, or AMI. @@ -156,6 +157,12 @@ message Settings { bool telemetry_enabled = 2; MetricsResolutions metrics_resolutions = 3; google.protobuf.Duration data_retention = 4; + // Advisor check results history retention. + google.protobuf.Duration advisor_history_retention = 21; + // True if Advisor email notifications are enabled. + bool advisor_notifications_enabled = 22; + // Least-severe level that triggers an Advisor notification. + management.v1.Severity advisor_notification_severity_threshold = 23; string ssh_key = 5; repeated string aws_partitions = 6; // True if Advisor is enabled. @@ -223,6 +230,12 @@ message ChangeSettingsRequest { MetricsResolutions metrics_resolutions = 3; // A number of full days for Prometheus and QAN data retention. Should have a suffix in JSON: 2592000s, 43200m, 720h. google.protobuf.Duration data_retention = 4; + // A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h. + google.protobuf.Duration advisor_history_retention = 16; + // Enable Advisor email notifications. + optional bool enable_advisor_notifications = 17; + // Least-severe level that triggers an Advisor notification. + management.v1.Severity advisor_notification_severity_threshold = 18; optional string ssh_key = 5; optional common.StringArray aws_partitions = 6; // Enable Advisor. diff --git a/api/server/v1/server.swagger.json b/api/server/v1/server.swagger.json index d8ea983f495..3de137856a3 100644 --- a/api/server/v1/server.swagger.json +++ b/api/server/v1/server.swagger.json @@ -389,6 +389,19 @@ "type": "string", "description": "A number of full days for Prometheus and QAN data retention. Should have a suffix in JSON: 2592000s, 43200m, 720h." }, + "advisor_history_retention": { + "type": "string", + "description": "A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h." + }, + "enable_advisor_notifications": { + "type": "boolean", + "x-nullable": true, + "description": "Enable Advisor email notifications." + }, + "advisor_notification_severity_threshold": { + "$ref": "#/definitions/v1Severity", + "description": "Least-severe level that triggers an Advisor notification." + }, "ssh_key": { "type": "string", "x-nullable": true @@ -630,6 +643,18 @@ "data_retention": { "type": "string" }, + "advisor_history_retention": { + "type": "string", + "description": "Advisor check results history retention." + }, + "advisor_notifications_enabled": { + "type": "boolean", + "description": "True if Advisor email notifications are enabled." + }, + "advisor_notification_severity_threshold": { + "$ref": "#/definitions/v1Severity", + "description": "Least-severe level that triggers an Advisor notification." + }, "ssh_key": { "type": "string" }, @@ -697,6 +722,22 @@ }, "description": "Settings represents PMM Server settings." }, + "v1Severity": { + "type": "string", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "default": "SEVERITY_UNSPECIFIED", + "description": "Severity represents severity level of the check result or alert." + }, "v1StartUpdateRequest": { "type": "object", "properties": { diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index e24bd8d6f77..1362b026a43 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -2015,6 +2015,80 @@ } } }, + "/v1/advisors/checks/history:markRead": { + "post": { + "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", + "tags": [ + "AdvisorService" + ], + "summary": "Mark Advisor Check Results Read", + "operationId": "MarkCheckResultsRead", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "ids": { + "description": "IDs of the history records to update.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "is_read": { + "description": "Read state to set on the records.", + "type": "boolean", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks:batchChange": { "post": { "description": "Enables/disables advisor checks or changes their exec interval.", @@ -32455,35 +32529,62 @@ "type": "string", "x-order": 3 }, - "ssh_key": { + "advisor_history_retention": { + "description": "Advisor check results history retention.", "type": "string", "x-order": 4 }, + "advisor_notifications_enabled": { + "description": "True if Advisor email notifications are enabled.", + "type": "boolean", + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, + "ssh_key": { + "type": "string", + "x-order": 7 + }, "aws_partitions": { "type": "array", "items": { "type": "string" }, - "x-order": 5 + "x-order": 8 }, "advisor_enabled": { "description": "True if Advisor is enabled.", "type": "boolean", - "x-order": 6 + "x-order": 9 }, "platform_email": { "type": "string", - "x-order": 7 + "x-order": 10 }, "alerting_enabled": { "description": "True if Alerting is enabled.", "type": "boolean", - "x-order": 8 + "x-order": 11 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", - "x-order": 9 + "x-order": 12 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -32505,22 +32606,22 @@ "x-order": 2 } }, - "x-order": 10 + "x-order": 13 }, "backup_management_enabled": { "description": "True if Backup Management is enabled.", "type": "boolean", - "x-order": 11 + "x-order": 14 }, "azurediscover_enabled": { "description": "True if Azure Discover is enabled.", "type": "boolean", - "x-order": 12 + "x-order": 15 }, "connected_to_platform": { "type": "boolean", "title": "True if the PMM instance is connected to Platform", - "x-order": 13 + "x-order": 16 }, "telemetry_summaries": { "type": "array", @@ -32528,28 +32629,28 @@ "items": { "type": "string" }, - "x-order": 14 + "x-order": 17 }, "enable_access_control": { "description": "True if Access Control is enabled.", "type": "boolean", - "x-order": 15 + "x-order": 18 }, "default_role_id": { "description": "Default Access Control role ID for new users.", "type": "integer", "format": "int64", - "x-order": 16 + "x-order": 19 }, "enable_internal_pg_qan": { "description": "True if Query Analytics for PMM's internal PG database is enabled.", "type": "boolean", - "x-order": 17 + "x-order": 20 }, "update_snooze_duration": { "type": "string", "title": "Duration for which an update is snoozed", - "x-order": 18 + "x-order": 21 } }, "x-order": 0 @@ -32644,10 +32745,38 @@ "type": "string", "x-order": 3 }, + "advisor_history_retention": { + "description": "A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h.", + "type": "string", + "x-order": 4 + }, + "enable_advisor_notifications": { + "description": "Enable Advisor email notifications.", + "type": "boolean", + "x-nullable": true, + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, "ssh_key": { "type": "string", "x-nullable": true, - "x-order": 4 + "x-order": 7 }, "aws_partitions": { "description": "A wrapper for a string array. This type allows to distinguish between an empty array and a null value.", @@ -32662,25 +32791,25 @@ } }, "x-nullable": true, - "x-order": 5 + "x-order": 8 }, "enable_advisor": { "description": "Enable Advisor.", "type": "boolean", "x-nullable": true, - "x-order": 6 + "x-order": 9 }, "enable_alerting": { "description": "Enable Alerting.", "type": "boolean", "x-nullable": true, - "x-order": 7 + "x-order": 10 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", "x-nullable": true, - "x-order": 8 + "x-order": 11 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -32702,36 +32831,36 @@ "x-order": 2 } }, - "x-order": 9 + "x-order": 12 }, "enable_azurediscover": { "description": "Enable Azure Discover.", "type": "boolean", "x-nullable": true, - "x-order": 10 + "x-order": 13 }, "enable_backup_management": { "description": "Enable Backup Management.", "type": "boolean", "x-nullable": true, - "x-order": 11 + "x-order": 14 }, "enable_access_control": { "type": "boolean", "title": "Enable Access Control", "x-nullable": true, - "x-order": 12 + "x-order": 15 }, "enable_internal_pg_qan": { "description": "Enable Query Analytics for PMM's internal PG database.", "type": "boolean", "x-nullable": true, - "x-order": 13 + "x-order": 16 }, "update_snooze_duration": { "description": "A number of full days for which an update is snoozed, i.e. a multiple of 24h: 2592000s, 43200m, 720h.", "type": "string", - "x-order": 14 + "x-order": 17 } } } @@ -32783,35 +32912,62 @@ "type": "string", "x-order": 3 }, - "ssh_key": { + "advisor_history_retention": { + "description": "Advisor check results history retention.", "type": "string", "x-order": 4 }, + "advisor_notifications_enabled": { + "description": "True if Advisor email notifications are enabled.", + "type": "boolean", + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, + "ssh_key": { + "type": "string", + "x-order": 7 + }, "aws_partitions": { "type": "array", "items": { "type": "string" }, - "x-order": 5 + "x-order": 8 }, "advisor_enabled": { "description": "True if Advisor is enabled.", "type": "boolean", - "x-order": 6 + "x-order": 9 }, "platform_email": { "type": "string", - "x-order": 7 + "x-order": 10 }, "alerting_enabled": { "description": "True if Alerting is enabled.", "type": "boolean", - "x-order": 8 + "x-order": 11 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", - "x-order": 9 + "x-order": 12 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -32833,22 +32989,22 @@ "x-order": 2 } }, - "x-order": 10 + "x-order": 13 }, "backup_management_enabled": { "description": "True if Backup Management is enabled.", "type": "boolean", - "x-order": 11 + "x-order": 14 }, "azurediscover_enabled": { "description": "True if Azure Discover is enabled.", "type": "boolean", - "x-order": 12 + "x-order": 15 }, "connected_to_platform": { "type": "boolean", "title": "True if the PMM instance is connected to Platform", - "x-order": 13 + "x-order": 16 }, "telemetry_summaries": { "type": "array", @@ -32856,28 +33012,28 @@ "items": { "type": "string" }, - "x-order": 14 + "x-order": 17 }, "enable_access_control": { "description": "True if Access Control is enabled.", "type": "boolean", - "x-order": 15 + "x-order": 18 }, "default_role_id": { "description": "Default Access Control role ID for new users.", "type": "integer", "format": "int64", - "x-order": 16 + "x-order": 19 }, "enable_internal_pg_qan": { "description": "True if Query Analytics for PMM's internal PG database is enabled.", "type": "boolean", - "x-order": 17 + "x-order": 20 }, "update_snooze_duration": { "type": "string", "title": "Duration for which an update is snoozed", - "x-order": 18 + "x-order": 21 } }, "x-order": 0 diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 5dc6a34cbfd..176a7733798 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1498,6 +1498,80 @@ } } }, + "/v1/advisors/checks/history:markRead": { + "post": { + "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", + "tags": [ + "AdvisorService" + ], + "summary": "Mark Advisor Check Results Read", + "operationId": "MarkCheckResultsRead", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "ids": { + "description": "IDs of the history records to update.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "is_read": { + "description": "Read state to set on the records.", + "type": "boolean", + "x-order": 1 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks:batchChange": { "post": { "description": "Enables/disables advisor checks or changes their exec interval.", @@ -31482,35 +31556,62 @@ "type": "string", "x-order": 3 }, - "ssh_key": { + "advisor_history_retention": { + "description": "Advisor check results history retention.", "type": "string", "x-order": 4 }, + "advisor_notifications_enabled": { + "description": "True if Advisor email notifications are enabled.", + "type": "boolean", + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, + "ssh_key": { + "type": "string", + "x-order": 7 + }, "aws_partitions": { "type": "array", "items": { "type": "string" }, - "x-order": 5 + "x-order": 8 }, "advisor_enabled": { "description": "True if Advisor is enabled.", "type": "boolean", - "x-order": 6 + "x-order": 9 }, "platform_email": { "type": "string", - "x-order": 7 + "x-order": 10 }, "alerting_enabled": { "description": "True if Alerting is enabled.", "type": "boolean", - "x-order": 8 + "x-order": 11 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", - "x-order": 9 + "x-order": 12 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -31532,22 +31633,22 @@ "x-order": 2 } }, - "x-order": 10 + "x-order": 13 }, "backup_management_enabled": { "description": "True if Backup Management is enabled.", "type": "boolean", - "x-order": 11 + "x-order": 14 }, "azurediscover_enabled": { "description": "True if Azure Discover is enabled.", "type": "boolean", - "x-order": 12 + "x-order": 15 }, "connected_to_platform": { "type": "boolean", "title": "True if the PMM instance is connected to Platform", - "x-order": 13 + "x-order": 16 }, "telemetry_summaries": { "type": "array", @@ -31555,28 +31656,28 @@ "items": { "type": "string" }, - "x-order": 14 + "x-order": 17 }, "enable_access_control": { "description": "True if Access Control is enabled.", "type": "boolean", - "x-order": 15 + "x-order": 18 }, "default_role_id": { "description": "Default Access Control role ID for new users.", "type": "integer", "format": "int64", - "x-order": 16 + "x-order": 19 }, "enable_internal_pg_qan": { "description": "True if Query Analytics for PMM's internal PG database is enabled.", "type": "boolean", - "x-order": 17 + "x-order": 20 }, "update_snooze_duration": { "type": "string", "title": "Duration for which an update is snoozed", - "x-order": 18 + "x-order": 21 } }, "x-order": 0 @@ -31671,10 +31772,38 @@ "type": "string", "x-order": 3 }, + "advisor_history_retention": { + "description": "A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h.", + "type": "string", + "x-order": 4 + }, + "enable_advisor_notifications": { + "description": "Enable Advisor email notifications.", + "type": "boolean", + "x-nullable": true, + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, "ssh_key": { "type": "string", "x-nullable": true, - "x-order": 4 + "x-order": 7 }, "aws_partitions": { "description": "A wrapper for a string array. This type allows to distinguish between an empty array and a null value.", @@ -31689,25 +31818,25 @@ } }, "x-nullable": true, - "x-order": 5 + "x-order": 8 }, "enable_advisor": { "description": "Enable Advisor.", "type": "boolean", "x-nullable": true, - "x-order": 6 + "x-order": 9 }, "enable_alerting": { "description": "Enable Alerting.", "type": "boolean", "x-nullable": true, - "x-order": 7 + "x-order": 10 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", "x-nullable": true, - "x-order": 8 + "x-order": 11 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -31729,36 +31858,36 @@ "x-order": 2 } }, - "x-order": 9 + "x-order": 12 }, "enable_azurediscover": { "description": "Enable Azure Discover.", "type": "boolean", "x-nullable": true, - "x-order": 10 + "x-order": 13 }, "enable_backup_management": { "description": "Enable Backup Management.", "type": "boolean", "x-nullable": true, - "x-order": 11 + "x-order": 14 }, "enable_access_control": { "type": "boolean", "title": "Enable Access Control", "x-nullable": true, - "x-order": 12 + "x-order": 15 }, "enable_internal_pg_qan": { "description": "Enable Query Analytics for PMM's internal PG database.", "type": "boolean", "x-nullable": true, - "x-order": 13 + "x-order": 16 }, "update_snooze_duration": { "description": "A number of full days for which an update is snoozed, i.e. a multiple of 24h: 2592000s, 43200m, 720h.", "type": "string", - "x-order": 14 + "x-order": 17 } } } @@ -31810,35 +31939,62 @@ "type": "string", "x-order": 3 }, - "ssh_key": { + "advisor_history_retention": { + "description": "Advisor check results history retention.", "type": "string", "x-order": 4 }, + "advisor_notifications_enabled": { + "description": "True if Advisor email notifications are enabled.", + "type": "boolean", + "x-order": 5 + }, + "advisor_notification_severity_threshold": { + "description": "Severity represents severity level of the check result or alert.", + "type": "string", + "default": "SEVERITY_UNSPECIFIED", + "enum": [ + "SEVERITY_UNSPECIFIED", + "SEVERITY_EMERGENCY", + "SEVERITY_ALERT", + "SEVERITY_CRITICAL", + "SEVERITY_ERROR", + "SEVERITY_WARNING", + "SEVERITY_NOTICE", + "SEVERITY_INFO", + "SEVERITY_DEBUG" + ], + "x-order": 6 + }, + "ssh_key": { + "type": "string", + "x-order": 7 + }, "aws_partitions": { "type": "array", "items": { "type": "string" }, - "x-order": 5 + "x-order": 8 }, "advisor_enabled": { "description": "True if Advisor is enabled.", "type": "boolean", - "x-order": 6 + "x-order": 9 }, "platform_email": { "type": "string", - "x-order": 7 + "x-order": 10 }, "alerting_enabled": { "description": "True if Alerting is enabled.", "type": "boolean", - "x-order": 8 + "x-order": 11 }, "pmm_public_address": { "description": "PMM Server public address.", "type": "string", - "x-order": 9 + "x-order": 12 }, "advisor_run_intervals": { "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks.", @@ -31860,22 +32016,22 @@ "x-order": 2 } }, - "x-order": 10 + "x-order": 13 }, "backup_management_enabled": { "description": "True if Backup Management is enabled.", "type": "boolean", - "x-order": 11 + "x-order": 14 }, "azurediscover_enabled": { "description": "True if Azure Discover is enabled.", "type": "boolean", - "x-order": 12 + "x-order": 15 }, "connected_to_platform": { "type": "boolean", "title": "True if the PMM instance is connected to Platform", - "x-order": 13 + "x-order": 16 }, "telemetry_summaries": { "type": "array", @@ -31883,28 +32039,28 @@ "items": { "type": "string" }, - "x-order": 14 + "x-order": 17 }, "enable_access_control": { "description": "True if Access Control is enabled.", "type": "boolean", - "x-order": 15 + "x-order": 18 }, "default_role_id": { "description": "Default Access Control role ID for new users.", "type": "integer", "format": "int64", - "x-order": 16 + "x-order": 19 }, "enable_internal_pg_qan": { "description": "True if Query Analytics for PMM's internal PG database is enabled.", "type": "boolean", - "x-order": 17 + "x-order": 20 }, "update_snooze_duration": { "type": "string", "title": "Duration for which an update is snoozed", - "x-order": 18 + "x-order": 21 } }, "x-order": 0 diff --git a/api/user/v1/user.pb.go b/api/user/v1/user.pb.go index 200364a0741..12a954ca3f4 100644 --- a/api/user/v1/user.pb.go +++ b/api/user/v1/user.pb.go @@ -507,6 +507,7 @@ var ( (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp } ) + var file_user_v1_user_proto_depIdxs = []int32{ 7, // 0: user.v1.GetUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp 7, // 1: user.v1.UpdateUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp diff --git a/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md b/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md index 4e39ccd9ee7..0d566ddb03a 100644 --- a/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md +++ b/documentation/docs/install-pmm/install-pmm-server/deployment-options/docker/env_var.md @@ -45,6 +45,7 @@ Enable or disable specific PMM features: | `PMM_ENABLE_UPDATES` | `true` | Allows version checks and UI updates | | `PMM_ENABLE_TELEMETRY` | `true` | Enables usage data collection | | `PMM_ENABLE_ALERTING` | `true` | Enables Percona Alerting system | +| `PMM_ENABLE_ADVISOR_NOTIFICATIONS` | `false` | Enables email notifications for Advisor check results (requires a configured Grafana email contact point) | | `PMM_ENABLE_BACKUP_MANAGEMENT` | `true` | Enables backup features | | `PMM_ENABLE_AZURE_DISCOVER` | `false` | Enables Azure database discovery | | `PMM_ENABLE_INTERNAL_PG_QAN` | `0` (disabled) | Enables Query Analytics for PMM Server's internal PostgreSQL. Useful for troubleshooting or HA scenarios. Set to `1` to enable. Can also be controlled via **Configuration > Settings > Advanced settings**. See [QAN for PMM Server's internal PostgreSQL](../../../../use/qan/QAN-stored-metrics.md#monitor-pmm-servers-internal-postgresql) diff --git a/managed/models/check_result_helpers.go b/managed/models/check_result_helpers.go index 459905ca30e..1f54db188d4 100644 --- a/managed/models/check_result_helpers.go +++ b/managed/models/check_result_helpers.go @@ -136,6 +136,28 @@ func CountCheckResults(q *reform.Querier, filters CheckResultFilters) (int, erro return count, nil } +// MarkCheckResultsRead sets the read state on the check results with the given IDs. +func MarkCheckResultsRead(q *reform.Querier, ids []string, isRead bool) error { + if len(ids) == 0 { + return nil + } + + args := []any{isRead} + placeholders := make([]string, 0, len(ids)) + for _, id := range ids { + placeholders = append(placeholders, q.Placeholder(len(args)+1)) + args = append(args, id) + } + + query := "UPDATE " + CheckResultTable.Name() + " SET is_read = " + q.Placeholder(1) + + " WHERE id IN (" + strings.Join(placeholders, ", ") + ")" + _, err := q.Exec(query, args...) + if err != nil { + return fmt.Errorf("failed to mark check results as read: %w", err) + } + return nil +} + // CleanupOldCheckResults deletes Advisor check results older than a specified date. func CleanupOldCheckResults(q *reform.Querier, olderThan time.Time) error { _, err := q.DeleteFrom(CheckResultTable, " WHERE checked_at <= $1", olderThan) diff --git a/managed/models/settings.go b/managed/models/settings.go index 08ab7c453d9..8004d0823d2 100644 --- a/managed/models/settings.go +++ b/managed/models/settings.go @@ -20,6 +20,8 @@ import ( "time" "github.com/AlekSi/pointer" + + "github.com/percona/pmm/managed/pi/common" ) // Default values for settings. These values are used when settings are not set. @@ -33,6 +35,8 @@ const ( AzureDiscoverEnabledDefault = false AccessControlEnabledDefault = false InternalPgQANEnabledDefault = false + AdvisorNotificationsEnabledDefault = false + AdvisorNotificationSeverityDefault = common.Error awsPartitionID = "aws" ) @@ -99,6 +103,13 @@ type Settings struct { Enabled *bool `json:"enabled"` } `json:"alerting"` + // AdvisorNotifications controls email notifications for Advisor check results. + AdvisorNotifications struct { + Enabled *bool `json:"enabled"` + // SeverityThreshold is the least-severe level that triggers a notification. + SeverityThreshold common.Severity `json:"severity_threshold"` + } `json:"advisor_notifications"` + Azurediscover struct { Enabled *bool `json:"enabled"` } `json:"azure"` @@ -131,6 +142,14 @@ func (s *Settings) IsAlertingEnabled() bool { return AlertingEnabledDefault } +// IsAdvisorNotificationsEnabled returns true if Advisor email notifications are enabled. +func (s *Settings) IsAdvisorNotificationsEnabled() bool { + if s.AdvisorNotifications.Enabled != nil { + return *s.AdvisorNotifications.Enabled + } + return AdvisorNotificationsEnabledDefault +} + // IsTelemetryEnabled returns true if telemetry is enabled. func (s *Settings) IsTelemetryEnabled() bool { if s.Telemetry.Enabled != nil { @@ -223,6 +242,10 @@ func (s *Settings) fillDefaults() { s.AdvisorHistoryRetention = 30 * 24 * time.Hour //nolint:mnd } + if s.AdvisorNotifications.SeverityThreshold == common.Unknown { + s.AdvisorNotifications.SeverityThreshold = AdvisorNotificationSeverityDefault + } + if len(s.AWSPartitions) == 0 { s.AWSPartitions = []string{awsPartitionID} } diff --git a/managed/models/settings_helpers.go b/managed/models/settings_helpers.go index d88e78f89f5..86e49a91985 100644 --- a/managed/models/settings_helpers.go +++ b/managed/models/settings_helpers.go @@ -25,6 +25,7 @@ import ( "github.com/google/uuid" "gopkg.in/reform.v1" + "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/utils/validators" ) @@ -62,6 +63,11 @@ type ChangeSettingsParams struct { AdvisorHistoryRetention time.Duration + // Enable Advisor email notifications. + EnableAdvisorNotifications *bool + // Least-severe level that triggers an Advisor notification. Unknown means "do not change". + AdvisorNotificationSeverityThreshold common.Severity + // List of AWS partitions to use. If empty - default partitions will be used. If nil - no changes will be made. AWSPartitions []string @@ -179,6 +185,14 @@ func UpdateSettings(q reform.DBTX, params *ChangeSettingsParams) (*Settings, err settings.AdvisorHistoryRetention = params.AdvisorHistoryRetention } + if params.EnableAdvisorNotifications != nil { + settings.AdvisorNotifications.Enabled = params.EnableAdvisorNotifications + } + + if params.AdvisorNotificationSeverityThreshold != common.Unknown { + settings.AdvisorNotifications.SeverityThreshold = params.AdvisorNotificationSeverityThreshold + } + if params.AWSPartitions != nil { settings.AWSPartitions = deduplicateStrings(params.AWSPartitions) } @@ -346,6 +360,13 @@ func ValidateSettings(params *ChangeSettingsParams) error { } } + if params.AdvisorNotificationSeverityThreshold != common.Unknown { + err := params.AdvisorNotificationSeverityThreshold.Validate() + if err != nil { + return fmt.Errorf("advisor_notification_severity_threshold: %w", err) + } + } + err := validators.ValidateAWSPartitions(params.AWSPartitions) if err != nil { return err diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index f3fda234e7c..aca46a3071d 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -263,6 +263,11 @@ func (s *Service) GetCheckResultsHistory(_ context.Context, filters models.Check return results, total, nil } +// MarkCheckResultsRead sets the read state on the check results history with the given IDs. +func (s *Service) MarkCheckResultsRead(_ context.Context, ids []string, isRead bool) error { + return models.MarkCheckResultsRead(s.db.Querier, ids, isRead) +} + // runChecksGroup downloads and executes Advisors checks that should run in the interval specified by intervalGroup. // All checks are executed if intervalGroup is empty. func (s *Service) runChecksGroup(ctx context.Context, intervalGroup check.Interval) error { diff --git a/managed/services/checks/registry.go b/managed/services/checks/registry.go index 16ece09a879..fb626e27380 100644 --- a/managed/services/checks/registry.go +++ b/managed/services/checks/registry.go @@ -40,8 +40,8 @@ func newRegistry() *registry { Namespace: prometheusNamespace, Subsystem: prometheusSubsystem, Name: "check_insights", - Help: "Number of advisor insights per service type, advisor and check name", - }, []string{"service_type", "advisor", "check_name"}), + Help: "Number of advisor insights per service type, service name, advisor, check name and severity", + }, []string{"service_type", "service_name", "advisor", "check_name", "severity"}), } } @@ -120,7 +120,7 @@ func (r *registry) Collect(ch chan<- prom.Metric) { r.mInsights.Reset() res := r.getCheckResults("") for _, re := range res { - r.mInsights.WithLabelValues(string(re.Target.ServiceType), re.AdvisorName, re.CheckName).Inc() + r.mInsights.WithLabelValues(string(re.Target.ServiceType), re.Target.ServiceName, re.AdvisorName, re.CheckName, re.Result.Severity.String()).Inc() } r.mInsights.Collect(ch) } diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index 3fc20e71af4..167d651e4a0 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -265,6 +265,19 @@ func (s *ChecksAPIService) ListCheckResultsHistory( }, nil } +// MarkCheckResultsRead sets the read state on the specified Advisor check history records. +func (s *ChecksAPIService) MarkCheckResultsRead( + ctx context.Context, + req *advisorsv1.MarkCheckResultsReadRequest, +) (*advisorsv1.MarkCheckResultsReadResponse, error) { + err := s.checksService.MarkCheckResultsRead(ctx, req.Ids, req.IsRead) + if err != nil { + return nil, fmt.Errorf("failed to mark check results read: %w", err) + } + + return &advisorsv1.MarkCheckResultsReadResponse{}, nil +} + // StartAdvisorChecks executes advisor checks and returns when all checks are executed. func (s *ChecksAPIService) StartAdvisorChecks(_ context.Context, req *advisorsv1.StartAdvisorChecksRequest) (*advisorsv1.StartAdvisorChecksResponse, error) { // Start only specified checks from any group. diff --git a/managed/services/management/checks_test.go b/managed/services/management/checks_test.go index f7edd7559d5..1f92cb90092 100644 --- a/managed/services/management/checks_test.go +++ b/managed/services/management/checks_test.go @@ -291,6 +291,44 @@ func TestListCheckResultsHistory(t *testing.T) { }) } +func TestMarkCheckResultsRead(t *testing.T) { + t.Parallel() + + t.Run("internal error", func(t *testing.T) { + t.Parallel() + + var checksService mockChecksService + checksService.On("MarkCheckResultsRead", mock.Anything, mock.Anything, mock.Anything). + Return(errors.New("random error")) + + s := NewChecksAPIService(&checksService) + + resp, err := s.MarkCheckResultsRead(t.Context(), &advisorsv1.MarkCheckResultsReadRequest{ + Ids: []string{"id1"}, + IsRead: true, + }) + require.EqualError(t, err, "failed to mark check results read: random error") + assert.Nil(t, resp) + }) + + t.Run("passes ids and read state through", func(t *testing.T) { + t.Parallel() + + var checksService mockChecksService + checksService.On("MarkCheckResultsRead", mock.Anything, []string{"id1", "id2"}, true).Return(nil) + + s := NewChecksAPIService(&checksService) + + resp, err := s.MarkCheckResultsRead(t.Context(), &advisorsv1.MarkCheckResultsReadRequest{ + Ids: []string{"id1", "id2"}, + IsRead: true, + }) + require.NoError(t, err) + assert.Equal(t, &advisorsv1.MarkCheckResultsReadResponse{}, resp) + checksService.AssertExpectations(t) + }) +} + func TestListFailedServices(t *testing.T) { t.Parallel() diff --git a/managed/services/management/deps.go b/managed/services/management/deps.go index ec87ddbdb0d..a649bcb8235 100644 --- a/managed/services/management/deps.go +++ b/managed/services/management/deps.go @@ -60,6 +60,7 @@ type checksService interface { GetAdvisors() ([]check.Advisor, error) GetChecksResults(ctx context.Context, serviceID string) ([]services.CheckResult, error) GetCheckResultsHistory(ctx context.Context, filters models.CheckResultFilters, pageIndex, pageSize int) ([]*models.CheckResult, int, error) + MarkCheckResultsRead(ctx context.Context, ids []string, isRead bool) error GetDisabledChecks() ([]string, error) DisableChecks(checkNames []string) error EnableChecks(checkNames []string) error diff --git a/managed/services/management/mock_checks_service_test.go b/managed/services/management/mock_checks_service_test.go index 73c35d764d5..6364dc1ce90 100644 --- a/managed/services/management/mock_checks_service_test.go +++ b/managed/services/management/mock_checks_service_test.go @@ -228,6 +228,24 @@ func (_m *mockChecksService) GetDisabledChecks() ([]string, error) { return r0, r1 } +// MarkCheckResultsRead provides a mock function with given fields: ctx, ids, isRead +func (_m *mockChecksService) MarkCheckResultsRead(ctx context.Context, ids []string, isRead bool) error { + ret := _m.Called(ctx, ids, isRead) + + if len(ret) == 0 { + panic("no return value specified for MarkCheckResultsRead") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, []string, bool) error); ok { + r0 = rf(ctx, ids, isRead) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // StartChecks provides a mock function with given fields: checkNames func (_m *mockChecksService) StartChecks(checkNames []string) error { ret := _m.Called(checkNames) diff --git a/managed/services/server/server.go b/managed/services/server/server.go index e093f173675..836fcf0dfee 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -41,8 +41,10 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" "gopkg.in/reform.v1" + managementv1 "github.com/percona/pmm/api/management/v1" serverv1 "github.com/percona/pmm/api/server/v1" "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/services" "github.com/percona/pmm/managed/utils/distribution" "github.com/percona/pmm/managed/utils/envvars" @@ -502,13 +504,17 @@ func (s *Server) convertSettings(settings *models.Settings, disableInternalPgQan StandardInterval: durationpb.New(settings.SaaS.AdvisorRunIntervals.StandardInterval), FrequentInterval: durationpb.New(settings.SaaS.AdvisorRunIntervals.FrequentInterval), }, - DataRetention: durationpb.New(settings.DataRetention), - SshKey: settings.SSHKey, - AwsPartitions: settings.AWSPartitions, - AdvisorEnabled: settings.IsAdvisorsEnabled(), - AzurediscoverEnabled: settings.IsAzureDiscoverEnabled(), - PmmPublicAddress: settings.PMMPublicAddress, - EnableInternalPgQan: !disableInternalPgQan, + DataRetention: durationpb.New(settings.DataRetention), + AdvisorHistoryRetention: durationpb.New(settings.AdvisorHistoryRetention), + //nolint:gosec // severity is a small bounded enum value + AdvisorNotificationSeverityThreshold: managementv1.Severity(settings.AdvisorNotifications.SeverityThreshold), + AdvisorNotificationsEnabled: settings.IsAdvisorNotificationsEnabled(), + SshKey: settings.SSHKey, + AwsPartitions: settings.AWSPartitions, + AdvisorEnabled: settings.IsAdvisorsEnabled(), + AzurediscoverEnabled: settings.IsAzureDiscoverEnabled(), + PmmPublicAddress: settings.PMMPublicAddress, + EnableInternalPgQan: !disableInternalPgQan, AlertingEnabled: settings.IsAlertingEnabled(), BackupManagementEnabled: settings.IsBackupManagementEnabled(), @@ -615,6 +621,11 @@ func (s *Server) validateChangeSettingsRequest(ctx context.Context, req *serverv return status.Error(codes.FailedPrecondition, "Azure Discover is configured via PMM_ENABLE_AZURE_DISCOVER environment variable.") } + if req.EnableAdvisorNotifications != nil && s.envSettings.EnableAdvisorNotifications != nil && + *req.EnableAdvisorNotifications != *s.envSettings.EnableAdvisorNotifications { + return status.Error(codes.FailedPrecondition, "Advisor notifications are configured via PMM_ENABLE_ADVISOR_NOTIFICATIONS environment variable.") + } + if !canUpdateDurationSetting(metricsRes.GetHr().AsDuration(), s.envSettings.MetricsResolutions.HR) { return status.Error( codes.FailedPrecondition, @@ -634,6 +645,10 @@ func (s *Server) validateChangeSettingsRequest(ctx context.Context, req *serverv return status.Error(codes.FailedPrecondition, "Data retention for queries is set via PMM_DATA_RETENTION environment variable.") } + if !canUpdateDurationSetting(req.AdvisorHistoryRetention.AsDuration(), s.envSettings.AdvisorHistoryRetention) { + return status.Error(codes.FailedPrecondition, "Advisor check results history retention is set via PMM_ADVISOR_HISTORY_RETENTION environment variable.") + } + if !canUpdateDurationSetting(req.UpdateSnoozeDuration.AsDuration(), s.envSettings.UpdateSnoozeDuration) { return status.Error(codes.FailedPrecondition, "Update snooze duration is set via PMM_UPDATE_SNOOZE_DURATION environment variable.") } @@ -681,8 +696,11 @@ func (s *Server) ChangeSettings(ctx context.Context, req *serverv1.ChangeSetting MR: metricsRes.GetMr().AsDuration(), LR: metricsRes.GetLr().AsDuration(), }, - DataRetention: req.DataRetention.AsDuration(), - SSHKey: req.SshKey, + DataRetention: req.DataRetention.AsDuration(), + AdvisorHistoryRetention: req.AdvisorHistoryRetention.AsDuration(), + EnableAdvisorNotifications: req.EnableAdvisorNotifications, + AdvisorNotificationSeverityThreshold: common.Severity(req.AdvisorNotificationSeverityThreshold), + SSHKey: req.SshKey, } if req.AwsPartitions != nil { diff --git a/managed/utils/envvars/parser.go b/managed/utils/envvars/parser.go index 3b3d8baddf4..4bc073d52b1 100644 --- a/managed/utils/envvars/parser.go +++ b/managed/utils/envvars/parser.go @@ -64,6 +64,7 @@ func (e InvalidDurationError) Error() string { return string(e) } // - PMM_METRICS_RESOLUTION, PMM_METRICS_RESOLUTION_MR, PMM_METRICS_RESOLUTION_HR, PMM_METRICS_RESOLUTION_LR are durations of metrics resolution; // - PMM_DATA_RETENTION is the duration of how long keep time-series data in ClickHouse; // - PMM_ADVISOR_HISTORY_RETENTION is the duration of how long to keep Advisor check results history; +// - PMM_ENABLE_ADVISOR_NOTIFICATIONS enables Advisor email notifications; // - PMM_ENABLE_AZURE_DISCOVER enables Azure Discover; // - PMM_ENABLE_ACCESS_CONTROL enables Access control; // - the environment variables prefixed with GF_ passed as related to Grafana. @@ -199,6 +200,14 @@ func ParseEnvVars(envs []string) (*models.ChangeSettingsParams, []error, []strin } envSettings.EnableAlerting = &b + case "PMM_ENABLE_ADVISOR_NOTIFICATIONS": + b, err := strconv.ParseBool(v) + if err != nil { + errs = append(errs, fmt.Errorf("invalid value %q for environment variable %q", v, k)) + continue + } + envSettings.EnableAdvisorNotifications = &b + case "PMM_ENABLE_AZURE_DISCOVER": b, err := strconv.ParseBool(v) if err != nil { diff --git a/managed/utils/envvars/parser_test.go b/managed/utils/envvars/parser_test.go index 2ee86dd508e..28ecc8f90cf 100644 --- a/managed/utils/envvars/parser_test.go +++ b/managed/utils/envvars/parser_test.go @@ -39,14 +39,16 @@ func TestEnvVarValidator(t *testing.T) { "PMM_METRICS_RESOLUTION_LR=1h", "PMM_DATA_RETENTION=72h", "PMM_ADVISOR_HISTORY_RETENTION=48h", + "PMM_ENABLE_ADVISOR_NOTIFICATIONS=true", "PMM_UPDATE_SNOOZE_DURATION=1h", } expectedEnvVars := &models.ChangeSettingsParams{ - DataRetention: 72 * time.Hour, - AdvisorHistoryRetention: 48 * time.Hour, - EnableTelemetry: new(true), - EnableUpdates: new(false), - EnableAdvisors: nil, + DataRetention: 72 * time.Hour, + AdvisorHistoryRetention: 48 * time.Hour, + EnableAdvisorNotifications: new(true), + EnableTelemetry: new(true), + EnableUpdates: new(false), + EnableAdvisors: nil, MetricsResolutions: models.MetricsResolutions{ HR: 5 * time.Minute, MR: 5 * time.Second, From 6478c956885cc60575e96b4e61e74506cb82c48b Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 14:34:46 +0300 Subject: [PATCH 008/120] PMM-14109 Implement advisor notifications management with Grafana alert rules --- managed/services/grafana/client.go | 28 ++++ .../services/server/advisor_notifications.go | 130 ++++++++++++++++++ .../server/advisor_notifications_test.go | 48 +++++++ managed/services/server/deps.go | 5 + .../server/mock_grafana_client_test.go | 84 +++++++++++ managed/services/server/server.go | 10 ++ 6 files changed, 305 insertions(+) create mode 100644 managed/services/server/advisor_notifications.go create mode 100644 managed/services/server/advisor_notifications_test.go diff --git a/managed/services/grafana/client.go b/managed/services/grafana/client.go index 39ddc5c05a6..43529cb2165 100644 --- a/managed/services/grafana/client.go +++ b/managed/services/grafana/client.go @@ -759,6 +759,16 @@ func (c *Client) CreateAlertRule(ctx context.Context, folderUID, groupName, inte return nil } +// DeleteAlertRuleGroup deletes a Grafana-managed alert rule group from the given folder. +func (c *Client) DeleteAlertRuleGroup(ctx context.Context, folderUID, groupName string) error { + authHeaders, err := auth.GetHeadersFromContext(ctx) + if err != nil { + return err + } + + return c.do(ctx, http.MethodDelete, fmt.Sprintf("/api/ruler/grafana/api/v1/rules/%s/%s", folderUID, groupName), "", authHeaders, nil, nil) +} + func validateDurations(intervalD, forD string) error { i, err := time.ParseDuration(intervalD) if err != nil { @@ -806,6 +816,24 @@ func (c *Client) CreateFolder(ctx context.Context, title string) (*gapi.Folder, return &folder, nil } +// CreateFolderWithUID creates a grafana folder with a specific UID. +func (c *Client) CreateFolderWithUID(ctx context.Context, title, uid string) error { + authHeaders, err := auth.GetHeadersFromContext(ctx) + if err != nil { + return err + } + + body, err := json.Marshal(struct { + UID string `json:"uid"` + Title string `json:"title"` + }{UID: uid, Title: title}) + if err != nil { + return err + } + + return c.do(ctx, http.MethodPost, "/api/folders", "", authHeaders, body, nil) +} + // DeleteFolder deletes grafana folder. func (c *Client) DeleteFolder(ctx context.Context, id string, force bool) error { grafanaClient, err := c.createGrafanaClient(ctx) diff --git a/managed/services/server/advisor_notifications.go b/managed/services/server/advisor_notifications.go new file mode 100644 index 00000000000..d47c24f3a9d --- /dev/null +++ b/managed/services/server/advisor_notifications.go @@ -0,0 +1,130 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package server + +import ( + "context" + "fmt" + "strings" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/pi/common" + "github.com/percona/pmm/managed/services" +) + +const ( + advisorNotificationsFolderUID = "pmm-advisor-notifications" + advisorNotificationsFolderTitle = "PMM Advisor Notifications" + advisorNotificationsRuleGroup = "pmm_advisor_notifications" + advisorNotificationsRuleTitle = "Advisor check failing" + advisorNotificationsRuleInterval = "1m" + advisorNotificationsRuleFor = "5m" + advisorInsightsMetric = "pmm_managed_advisor_check_insights" + // Look-back window (seconds) for the instant query. + advisorNotificationsQueryRangeSeconds = 600 + // Added to fired alerts so operators can route them via a Grafana notification policy. + advisorNotificationLabel = "advisor_notification" +) + +// advisorNotificationSeverityRegex builds a label-value regex matching every severity at least as +// severe as the given threshold (e.g. Error -> "emergency|alert|critical|error"). +func advisorNotificationSeverityRegex(threshold common.Severity) string { + if threshold == common.Unknown { + threshold = common.Error + } + + var names []string + for s := common.Emergency; s <= threshold; s++ { + names = append(names, s.String()) + } + return strings.Join(names, "|") +} + +// buildAdvisorNotificationRule builds the Grafana alert rule that fires for advisor insights at or +// above the configured severity threshold. +func buildAdvisorNotificationRule(datasourceUID string, threshold common.Severity) *services.Rule { + expr := fmt.Sprintf(`%s{severity=~"%s"} > 0`, advisorInsightsMetric, advisorNotificationSeverityRegex(threshold)) + + return &services.Rule{ + GrafanaAlert: services.GrafanaAlert{ + Title: advisorNotificationsRuleTitle, + Condition: "A", + NoDataState: "OK", + ExecErrState: "Alerting", + Data: []services.Data{ + { + RefID: "A", + DatasourceUID: datasourceUID, + RelativeTimeRange: services.RelativeTimeRange{From: advisorNotificationsQueryRangeSeconds, To: 0}, + Model: services.Model{ + RefID: "A", + Expr: expr, + Instant: true, + }, + }, + }, + }, + For: advisorNotificationsRuleFor, + Annotations: map[string]string{ + "summary": "Advisor check {{ $labels.check_name }} is failing on service {{ $labels.service_name }}", + "description": "Advisor {{ $labels.advisor }} check {{ $labels.check_name }} reported a {{ $labels.severity }} issue on service {{ $labels.service_name }}.", + }, + Labels: map[string]string{ + advisorNotificationLabel: "1", + }, + } +} + +// reconcileAdvisorNotifications creates or removes the Grafana alert rule that drives advisor email +// notifications, based on the current settings. +// +// It talks to Grafana on the caller's behalf, so it must be called within an authenticated request +// context (e.g. ChangeSettings) - background contexts have no Grafana credentials. +func (s *Server) reconcileAdvisorNotifications(ctx context.Context, settings *models.Settings) error { + if !settings.IsAdvisorNotificationsEnabled() { + err := s.grafanaClient.DeleteAlertRuleGroup(ctx, advisorNotificationsFolderUID, advisorNotificationsRuleGroup) + if err != nil { + s.l.Debugf("Failed to delete advisor notifications rule group (ignored): %v", err) + } + return nil + } + + // Best-effort folder creation; an error here usually means the folder already exists. A genuine + // problem (auth, connectivity) surfaces below when creating the rule. + err := s.grafanaClient.CreateFolderWithUID(ctx, advisorNotificationsFolderTitle, advisorNotificationsFolderUID) + if err != nil { + s.l.Debugf("Failed to create advisor notifications folder (ignored, may already exist): %v", err) + } + + // Remove any existing rule so we always reflect the latest settings (idempotent replace). + err = s.grafanaClient.DeleteAlertRuleGroup(ctx, advisorNotificationsFolderUID, advisorNotificationsRuleGroup) + if err != nil { + s.l.Debugf("Failed to delete existing advisor notifications rule group (ignored): %v", err) + } + + datasourceUID, err := s.grafanaClient.GetDatasourceUIDByID(ctx, 1) // 1 is the Metrics datasource ID in PMM. + if err != nil { + return fmt.Errorf("failed to get metrics datasource UID: %w", err) + } + + rule := buildAdvisorNotificationRule(datasourceUID, settings.AdvisorNotifications.SeverityThreshold) + err = s.grafanaClient.CreateAlertRule(ctx, advisorNotificationsFolderUID, advisorNotificationsRuleGroup, advisorNotificationsRuleInterval, rule) + if err != nil { + return fmt.Errorf("failed to create advisor notifications rule: %w", err) + } + + return nil +} diff --git a/managed/services/server/advisor_notifications_test.go b/managed/services/server/advisor_notifications_test.go new file mode 100644 index 00000000000..3a99882ac75 --- /dev/null +++ b/managed/services/server/advisor_notifications_test.go @@ -0,0 +1,48 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package server + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/percona/pmm/managed/pi/common" +) + +func TestAdvisorNotificationSeverityRegex(t *testing.T) { + t.Parallel() + + assert.Equal(t, "emergency", advisorNotificationSeverityRegex(common.Emergency)) + assert.Equal(t, "emergency|alert|critical|error", advisorNotificationSeverityRegex(common.Error)) + assert.Equal(t, "emergency|alert|critical|error|warning|notice|info|debug", advisorNotificationSeverityRegex(common.Debug)) + // Unknown falls back to the Error threshold. + assert.Equal(t, "emergency|alert|critical|error", advisorNotificationSeverityRegex(common.Unknown)) +} + +func TestBuildAdvisorNotificationRule(t *testing.T) { + t.Parallel() + + rule := buildAdvisorNotificationRule("ds-uid", common.Error) + + require.Len(t, rule.GrafanaAlert.Data, 1) + assert.Equal(t, advisorNotificationsRuleTitle, rule.GrafanaAlert.Title) + assert.Equal(t, "ds-uid", rule.GrafanaAlert.Data[0].DatasourceUID) + assert.Equal(t, `pmm_managed_advisor_check_insights{severity=~"emergency|alert|critical|error"} > 0`, rule.GrafanaAlert.Data[0].Model.Expr) + assert.True(t, rule.GrafanaAlert.Data[0].Model.Instant) + assert.Equal(t, "1", rule.Labels[advisorNotificationLabel]) +} diff --git a/managed/services/server/deps.go b/managed/services/server/deps.go index 5d1c510130b..33f9d9408b4 100644 --- a/managed/services/server/deps.go +++ b/managed/services/server/deps.go @@ -22,6 +22,7 @@ import ( serverv1 "github.com/percona/pmm/api/server/v1" "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/services" ) // healthChecker interface wraps all services that implements the IsReady method to report the @@ -34,6 +35,10 @@ type healthChecker interface { //nolint:iface // We use it instead of real type for testing and to avoid dependency cycle. type grafanaClient interface { //nolint:iface healthChecker + GetDatasourceUIDByID(ctx context.Context, id int64) (string, error) + CreateFolderWithUID(ctx context.Context, title, uid string) error + CreateAlertRule(ctx context.Context, folderUID, groupName, interval string, rule *services.Rule) error + DeleteAlertRuleGroup(ctx context.Context, folderUID, groupName string) error } // prometheusService is a subset of methods of victoriametrics.Service used by this package. diff --git a/managed/services/server/mock_grafana_client_test.go b/managed/services/server/mock_grafana_client_test.go index ae782b1e407..119975c57e0 100644 --- a/managed/services/server/mock_grafana_client_test.go +++ b/managed/services/server/mock_grafana_client_test.go @@ -6,6 +6,8 @@ import ( context "context" mock "github.com/stretchr/testify/mock" + + services "github.com/percona/pmm/managed/services" ) // mockGrafanaClient is an autogenerated mock type for the grafanaClient type @@ -13,6 +15,88 @@ type mockGrafanaClient struct { mock.Mock } +// CreateAlertRule provides a mock function with given fields: ctx, folderUID, groupName, interval, rule +func (_m *mockGrafanaClient) CreateAlertRule(ctx context.Context, folderUID string, groupName string, interval string, rule *services.Rule) error { + ret := _m.Called(ctx, folderUID, groupName, interval, rule) + + if len(ret) == 0 { + panic("no return value specified for CreateAlertRule") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *services.Rule) error); ok { + r0 = rf(ctx, folderUID, groupName, interval, rule) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreateFolderWithUID provides a mock function with given fields: ctx, title, uid +func (_m *mockGrafanaClient) CreateFolderWithUID(ctx context.Context, title string, uid string) error { + ret := _m.Called(ctx, title, uid) + + if len(ret) == 0 { + panic("no return value specified for CreateFolderWithUID") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, title, uid) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteAlertRuleGroup provides a mock function with given fields: ctx, folderUID, groupName +func (_m *mockGrafanaClient) DeleteAlertRuleGroup(ctx context.Context, folderUID string, groupName string) error { + ret := _m.Called(ctx, folderUID, groupName) + + if len(ret) == 0 { + panic("no return value specified for DeleteAlertRuleGroup") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, folderUID, groupName) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetDatasourceUIDByID provides a mock function with given fields: ctx, id +func (_m *mockGrafanaClient) GetDatasourceUIDByID(ctx context.Context, id int64) (string, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for GetDatasourceUIDByID") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (string, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) string); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // IsReady provides a mock function with given fields: ctx func (_m *mockGrafanaClient) IsReady(ctx context.Context) error { ret := _m.Called(ctx) diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 836fcf0dfee..d3538f53883 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -780,6 +780,16 @@ func (s *Server) ChangeSettings(ctx context.Context, req *serverv1.ChangeSetting } } + // When Advisor notification settings change, reconcile the Grafana alert rule that drives them. + // This runs in the request context, which carries the Grafana credentials needed to manage rules. + if oldSettings.IsAdvisorNotificationsEnabled() != newSettings.IsAdvisorNotificationsEnabled() || + oldSettings.AdvisorNotifications.SeverityThreshold != newSettings.AdvisorNotifications.SeverityThreshold { + err := s.reconcileAdvisorNotifications(ctx, newSettings) + if err != nil { + s.l.Errorf("Failed to reconcile Advisor notifications: %v", err) + } + } + return &serverv1.ChangeSettingsResponse{ Settings: s.convertSettings(newSettings, disableInternalPgQan), }, nil From cc61ccde7964bde8878905dbb8166203cfb9274c Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 14:38:08 +0300 Subject: [PATCH 009/120] PMM-14109 Remove unused Swagger files and clean up code --- api/accesscontrol/v1beta1/accesscontrol.pb.go | 1 - .../v1beta1/accesscontrol.swagger.json | 410 -- api/actions/v1/actions.pb.go | 1 - api/actions/v1/actions.swagger.json | 737 --- api/advisors/v1/advisors.pb.go | 1 - api/advisors/v1/advisors.swagger.json | 841 --- api/agent/pb/agent.swagger.json | 55 - api/agent/v1/agent.pb.go | 1 - api/agent/v1/agent.swagger.json | 55 - api/agent/v1/collector.pb.go | 1 - api/agent/v1/collector.swagger.json | 50 - api/agentlocal/v1/agentlocal.pb.go | 1 - api/agentlocal/v1/agentlocal.swagger.json | 295 -- api/alerting/v1/alerting.pb.go | 1 - api/alerting/v1/alerting.swagger.json | 581 --- api/alerting/v1/params.pb.go | 1 - api/alerting/v1/params.swagger.json | 44 - api/backup/v1/artifacts.pb.go | 1 - api/backup/v1/artifacts.swagger.json | 44 - api/backup/v1/backup.pb.go | 1 - api/backup/v1/backup.swagger.json | 1003 ---- api/backup/v1/common.pb.go | 1 - api/backup/v1/common.swagger.json | 44 - api/backup/v1/errors.pb.go | 1 - api/backup/v1/errors.swagger.json | 44 - api/backup/v1/locations.pb.go | 1 - api/backup/v1/locations.swagger.json | 353 -- api/backup/v1/restores.pb.go | 1 - api/backup/v1/restores.swagger.json | 303 -- api/common/common.pb.go | 1 - api/common/common.swagger.json | 44 - api/common/metrics_resolutions.pb.go | 1 - api/common/metrics_resolutions.swagger.json | 44 - api/dump/v1beta1/dump.pb.go | 1 - api/dump/v1beta1/dump.swagger.json | 395 -- api/extensions/v1/redact.pb.go | 1 - api/extensions/v1/redact.swagger.json | 44 - api/ha/v1beta1/ha.pb.go | 1 - api/ha/v1beta1/ha.swagger.json | 148 - api/inventory/v1/agent_status.pb.go | 1 - api/inventory/v1/agent_status.swagger.json | 44 - api/inventory/v1/agents.pb.go | 1 - api/inventory/v1/agents.swagger.json | 4490 ---------------- api/inventory/v1/log_level.pb.go | 1 - api/inventory/v1/log_level.swagger.json | 44 - api/inventory/v1/nodes.pb.go | 1 - api/inventory/v1/nodes.swagger.json | 708 --- api/inventory/v1/services.pb.go | 1 - api/inventory/v1/services.swagger.json | 1189 ----- api/management/v1/agent.pb.go | 1 - api/management/v1/agent.swagger.json | 44 - api/management/v1/annotation.pb.go | 1 - api/management/v1/annotation.swagger.json | 44 - api/management/v1/azure.pb.go | 1 - api/management/v1/azure.swagger.json | 44 - api/management/v1/external.pb.go | 1 - api/management/v1/external.swagger.json | 44 - api/management/v1/haproxy.pb.go | 1 - api/management/v1/haproxy.swagger.json | 44 - api/management/v1/metrics.pb.go | 1 - api/management/v1/metrics.swagger.json | 44 - api/management/v1/mongodb.pb.go | 1 - api/management/v1/mongodb.swagger.json | 44 - api/management/v1/mysql.pb.go | 1 - api/management/v1/mysql.swagger.json | 44 - api/management/v1/node.pb.go | 1 - api/management/v1/node.swagger.json | 44 - api/management/v1/postgresql.pb.go | 1 - api/management/v1/postgresql.swagger.json | 44 - api/management/v1/proxysql.pb.go | 1 - api/management/v1/proxysql.swagger.json | 44 - api/management/v1/rds.pb.go | 1 - api/management/v1/rds.swagger.json | 44 - api/management/v1/service.pb.go | 1 - api/management/v1/service.swagger.json | 4547 ----------------- api/management/v1/severity.pb.go | 1 - api/management/v1/severity.swagger.json | 44 - api/management/v1/valkey.pb.go | 1 - api/management/v1/valkey.swagger.json | 44 - api/qan/v1/collector.pb.go | 1 - api/qan/v1/collector.swagger.json | 44 - api/qan/v1/filters.pb.go | 1 - api/qan/v1/filters.swagger.json | 44 - api/qan/v1/object_details.pb.go | 1 - api/qan/v1/object_details.swagger.json | 44 - api/qan/v1/profile.pb.go | 1 - api/qan/v1/profile.swagger.json | 44 - api/qan/v1/qan.pb.go | 1 - api/qan/v1/qan.swagger.json | 44 - api/qan/v1/service.pb.go | 1 - api/qan/v1/service.swagger.json | 1568 ------ api/realtimeanalytics/v1/collector.pb.go | 1 - .../v1/collector.swagger.json | 44 - api/realtimeanalytics/v1/query.pb.go | 1 - api/realtimeanalytics/v1/query.swagger.json | 44 - .../v1/realtimeanalytics.pb.go | 1 - .../v1/realtimeanalytics.swagger.json | 516 -- api/server/v1/httperror.pb.go | 1 - api/server/v1/httperror.swagger.json | 46 - api/server/v1/server.pb.go | 1 - api/server/v1/server.swagger.json | 839 --- api/user/v1/user.pb.go | 1 - api/user/v1/user.swagger.json | 243 - 103 files changed, 20743 deletions(-) delete mode 100644 api/accesscontrol/v1beta1/accesscontrol.swagger.json delete mode 100644 api/actions/v1/actions.swagger.json delete mode 100644 api/advisors/v1/advisors.swagger.json delete mode 100644 api/agent/pb/agent.swagger.json delete mode 100644 api/agent/v1/agent.swagger.json delete mode 100644 api/agent/v1/collector.swagger.json delete mode 100644 api/agentlocal/v1/agentlocal.swagger.json delete mode 100644 api/alerting/v1/alerting.swagger.json delete mode 100644 api/alerting/v1/params.swagger.json delete mode 100644 api/backup/v1/artifacts.swagger.json delete mode 100644 api/backup/v1/backup.swagger.json delete mode 100644 api/backup/v1/common.swagger.json delete mode 100644 api/backup/v1/errors.swagger.json delete mode 100644 api/backup/v1/locations.swagger.json delete mode 100644 api/backup/v1/restores.swagger.json delete mode 100644 api/common/common.swagger.json delete mode 100644 api/common/metrics_resolutions.swagger.json delete mode 100644 api/dump/v1beta1/dump.swagger.json delete mode 100644 api/extensions/v1/redact.swagger.json delete mode 100644 api/ha/v1beta1/ha.swagger.json delete mode 100644 api/inventory/v1/agent_status.swagger.json delete mode 100644 api/inventory/v1/agents.swagger.json delete mode 100644 api/inventory/v1/log_level.swagger.json delete mode 100644 api/inventory/v1/nodes.swagger.json delete mode 100644 api/inventory/v1/services.swagger.json delete mode 100644 api/management/v1/agent.swagger.json delete mode 100644 api/management/v1/annotation.swagger.json delete mode 100644 api/management/v1/azure.swagger.json delete mode 100644 api/management/v1/external.swagger.json delete mode 100644 api/management/v1/haproxy.swagger.json delete mode 100644 api/management/v1/metrics.swagger.json delete mode 100644 api/management/v1/mongodb.swagger.json delete mode 100644 api/management/v1/mysql.swagger.json delete mode 100644 api/management/v1/node.swagger.json delete mode 100644 api/management/v1/postgresql.swagger.json delete mode 100644 api/management/v1/proxysql.swagger.json delete mode 100644 api/management/v1/rds.swagger.json delete mode 100644 api/management/v1/service.swagger.json delete mode 100644 api/management/v1/severity.swagger.json delete mode 100644 api/management/v1/valkey.swagger.json delete mode 100644 api/qan/v1/collector.swagger.json delete mode 100644 api/qan/v1/filters.swagger.json delete mode 100644 api/qan/v1/object_details.swagger.json delete mode 100644 api/qan/v1/profile.swagger.json delete mode 100644 api/qan/v1/qan.swagger.json delete mode 100644 api/qan/v1/service.swagger.json delete mode 100644 api/realtimeanalytics/v1/collector.swagger.json delete mode 100644 api/realtimeanalytics/v1/query.swagger.json delete mode 100644 api/realtimeanalytics/v1/realtimeanalytics.swagger.json delete mode 100644 api/server/v1/httperror.swagger.json delete mode 100644 api/server/v1/server.swagger.json delete mode 100644 api/user/v1/user.swagger.json diff --git a/api/accesscontrol/v1beta1/accesscontrol.pb.go b/api/accesscontrol/v1beta1/accesscontrol.pb.go index f5e8ea4b004..ebec3bf05b7 100644 --- a/api/accesscontrol/v1beta1/accesscontrol.pb.go +++ b/api/accesscontrol/v1beta1/accesscontrol.pb.go @@ -844,7 +844,6 @@ var ( (*ListRolesResponse_RoleData)(nil), // 14: accesscontrol.v1beta1.ListRolesResponse.RoleData } ) - var file_accesscontrol_v1beta1_accesscontrol_proto_depIdxs = []int32{ 14, // 0: accesscontrol.v1beta1.ListRolesResponse.roles:type_name -> accesscontrol.v1beta1.ListRolesResponse.RoleData 0, // 1: accesscontrol.v1beta1.AccessControlService.CreateRole:input_type -> accesscontrol.v1beta1.CreateRoleRequest diff --git a/api/accesscontrol/v1beta1/accesscontrol.swagger.json b/api/accesscontrol/v1beta1/accesscontrol.swagger.json deleted file mode 100644 index d9435ab700b..00000000000 --- a/api/accesscontrol/v1beta1/accesscontrol.swagger.json +++ /dev/null @@ -1,410 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "accesscontrol/v1beta1/accesscontrol.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "AccessControlService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/accesscontrol/roles": { - "get": { - "summary": "List Roles", - "description": "Lists all roles.", - "operationId": "ListRoles", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1ListRolesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "AccessControlService" - ] - }, - "post": { - "summary": "Create a Role", - "description": "Creates a new role.", - "operationId": "CreateRole", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1CreateRoleResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1beta1CreateRoleRequest" - } - } - ], - "tags": [ - "AccessControlService" - ] - } - }, - "/v1/accesscontrol/roles/{role_id}": { - "get": { - "summary": "Get a Role", - "description": "Retrieves a role by ID.", - "operationId": "GetRole", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1GetRoleResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "role_id", - "in": "path", - "required": true, - "type": "integer", - "format": "int64" - } - ], - "tags": [ - "AccessControlService" - ] - }, - "delete": { - "summary": "Delete a Role", - "description": "Deletes a role.", - "operationId": "DeleteRole", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1DeleteRoleResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "role_id", - "in": "path", - "required": true, - "type": "integer", - "format": "int64" - }, - { - "name": "replacement_role_id", - "description": "Role ID to be used as a replacement for the role. Additional logic applies.", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - } - ], - "tags": [ - "AccessControlService" - ] - }, - "put": { - "summary": "Update a Role", - "description": "Updates an existing role.", - "operationId": "UpdateRole", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1UpdateRoleResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "role_id", - "in": "path", - "required": true, - "type": "integer", - "format": "int64" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/AccessControlServiceUpdateRoleBody" - } - } - ], - "tags": [ - "AccessControlService" - ] - } - }, - "/v1/accesscontrol/roles:assign": { - "post": { - "summary": "Assign Roles to a User", - "description": "Replaces all existing roles for a user.", - "operationId": "AssignRoles", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1AssignRolesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1beta1AssignRolesRequest" - } - } - ], - "tags": [ - "AccessControlService" - ] - } - }, - "/v1/accesscontrol/roles:setDefault": { - "post": { - "summary": "Set a Default Role", - "description": "Configures a default role assigned to users.", - "operationId": "SetDefaultRole", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1SetDefaultRoleResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1beta1SetDefaultRoleRequest" - } - } - ], - "tags": [ - "AccessControlService" - ] - } - } - }, - "definitions": { - "AccessControlServiceUpdateRoleBody": { - "type": "object", - "properties": { - "title": { - "type": "string", - "x-nullable": true - }, - "filter": { - "type": "string", - "x-nullable": true - }, - "description": { - "type": "string", - "x-nullable": true - } - } - }, - "ListRolesResponseRoleData": { - "type": "object", - "properties": { - "role_id": { - "type": "integer", - "format": "int64" - }, - "title": { - "type": "string" - }, - "filter": { - "type": "string" - }, - "description": { - "type": "string" - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1beta1AssignRolesRequest": { - "type": "object", - "properties": { - "role_ids": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - }, - "user_id": { - "type": "integer", - "format": "int64" - } - } - }, - "v1beta1AssignRolesResponse": { - "type": "object" - }, - "v1beta1CreateRoleRequest": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "filter": { - "type": "string" - }, - "description": { - "type": "string" - } - } - }, - "v1beta1CreateRoleResponse": { - "type": "object", - "properties": { - "role_id": { - "type": "integer", - "format": "int64" - } - } - }, - "v1beta1DeleteRoleResponse": { - "type": "object" - }, - "v1beta1GetRoleResponse": { - "type": "object", - "properties": { - "role_id": { - "type": "integer", - "format": "int64" - }, - "title": { - "type": "string" - }, - "filter": { - "type": "string" - }, - "description": { - "type": "string" - } - } - }, - "v1beta1ListRolesResponse": { - "type": "object", - "properties": { - "roles": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/ListRolesResponseRoleData" - } - } - } - }, - "v1beta1SetDefaultRoleRequest": { - "type": "object", - "properties": { - "role_id": { - "type": "integer", - "format": "int64" - } - } - }, - "v1beta1SetDefaultRoleResponse": { - "type": "object" - }, - "v1beta1UpdateRoleResponse": { - "type": "object" - } - } -} diff --git a/api/actions/v1/actions.pb.go b/api/actions/v1/actions.pb.go index f1cfdec8cfa..35461ae3739 100644 --- a/api/actions/v1/actions.pb.go +++ b/api/actions/v1/actions.pb.go @@ -2649,7 +2649,6 @@ var ( (*StartServiceActionResponse)(nil), // 32: actions.v1.StartServiceActionResponse } ) - var file_actions_v1_actions_proto_depIdxs = []int32{ 3, // 0: actions.v1.StartServiceActionRequest.mysql_explain:type_name -> actions.v1.StartMySQLExplainActionParams 5, // 1: actions.v1.StartServiceActionRequest.mysql_explain_json:type_name -> actions.v1.StartMySQLExplainJSONActionParams diff --git a/api/actions/v1/actions.swagger.json b/api/actions/v1/actions.swagger.json deleted file mode 100644 index 04404da66a7..00000000000 --- a/api/actions/v1/actions.swagger.json +++ /dev/null @@ -1,737 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "actions/v1/actions.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "ActionsService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/actions/{action_id}": { - "get": { - "summary": "Get Action", - "description": "Gets the result of a given Action.", - "operationId": "GetAction", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetActionResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "action_id", - "description": "Unique Action ID.", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ActionsService" - ] - } - }, - "/v1/actions:cancelAction": { - "post": { - "summary": "Cancel an Action", - "description": "Stops an Action.", - "operationId": "CancelAction", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1CancelActionResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1CancelActionRequest" - } - } - ], - "tags": [ - "ActionsService" - ] - } - }, - "/v1/actions:startNodeAction": { - "post": { - "summary": "Start 'PT Summary' Action", - "description": "Starts 'Percona Toolkit Summary' Action.", - "operationId": "StartPTSummaryAction", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StartPTSummaryActionResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StartPTSummaryActionRequest" - } - } - ], - "tags": [ - "ActionsService" - ] - } - }, - "/v1/actions:startServiceAction": { - "post": { - "summary": "Start a Service Action", - "description": "Starts a Service Action.", - "operationId": "StartServiceAction", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StartServiceActionResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StartServiceActionRequest" - } - } - ], - "tags": [ - "ActionsService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1CancelActionRequest": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID. Required." - } - } - }, - "v1CancelActionResponse": { - "type": "object" - }, - "v1GetActionResponse": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where this Action is running / was run." - }, - "output": { - "type": "string", - "description": "Current Action output; may be partial if Action is still running." - }, - "done": { - "type": "boolean", - "description": "True if Action is finished." - }, - "error": { - "type": "string", - "description": "Error message if Action failed." - } - } - }, - "v1StartMongoDBExplainActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "query": { - "type": "string", - "description": "Query. Required." - } - } - }, - "v1StartMongoDBExplainActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartMySQLExplainActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "query_id": { - "type": "string", - "description": "Query ID of query." - }, - "placeholders": { - "type": "array", - "items": { - "type": "string" - }, - "title": "Array of placeholder values" - }, - "database": { - "type": "string", - "description": "Database name. Required if it can't be deduced from the query ID." - } - } - }, - "v1StartMySQLExplainActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartMySQLExplainJSONActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "query_id": { - "type": "string", - "description": "Query ID of query." - }, - "placeholders": { - "type": "array", - "items": { - "type": "string" - }, - "title": "Array of placeholder values" - }, - "database": { - "type": "string", - "description": "Database name. Required if it can't be deduced from the query ID." - } - } - }, - "v1StartMySQLExplainJSONActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartMySQLExplainTraditionalJSONActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "query_id": { - "type": "string", - "description": "Query ID of query." - }, - "placeholders": { - "type": "array", - "items": { - "type": "string" - }, - "title": "Array of placeholder values" - }, - "database": { - "type": "string", - "description": "Database name. Required if it can't be deduced from the query ID." - } - } - }, - "v1StartMySQLExplainTraditionalJSONActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartMySQLShowCreateTableActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "table_name": { - "type": "string", - "description": "Table name. Required. May additionally contain a database name." - }, - "database": { - "type": "string", - "description": "Database name. Required if not given in the table_name field." - } - } - }, - "v1StartMySQLShowCreateTableActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartMySQLShowIndexActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "table_name": { - "type": "string", - "description": "Table name. Required. May additionally contain a database name." - }, - "database": { - "type": "string", - "description": "Database name. Required if not given in the table_name field." - } - } - }, - "v1StartMySQLShowIndexActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartMySQLShowTableStatusActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "table_name": { - "type": "string", - "description": "Table name. Required. May additionally contain a database name." - }, - "database": { - "type": "string", - "description": "Database name. Required if not given in the table_name field." - } - } - }, - "v1StartMySQLShowTableStatusActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartPTMongoDBSummaryActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action." - } - }, - "title": "Message to prepare pt-mongodb-summary data" - }, - "v1StartPTMongoDBSummaryActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - }, - "title": "Message to retrieve the prepared pt-mongodb-summary data" - }, - "v1StartPTMySQLSummaryActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action." - } - }, - "title": "Message to prepare pt-mysql-summary data" - }, - "v1StartPTMySQLSummaryActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - }, - "title": "Message to retrieve the prepared pt-mysql-summary data" - }, - "v1StartPTPgSummaryActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action." - } - }, - "title": "Message to prepare pt-pg-summary data" - }, - "v1StartPTPgSummaryActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - }, - "title": "Message to retrieve the prepared pt-pg-summary data" - }, - "v1StartPTSummaryActionRequest": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "node_id": { - "type": "string", - "description": "Node ID for this Action." - } - } - }, - "v1StartPTSummaryActionResponse": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartPostgreSQLShowCreateTableActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "table_name": { - "type": "string", - "description": "Table name. Required. May additionally contain a database name." - }, - "database": { - "type": "string", - "description": "Database name. Required if not given in the table_name field." - } - } - }, - "v1StartPostgreSQLShowCreateTableActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartPostgreSQLShowIndexActionParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to run this Action." - }, - "service_id": { - "type": "string", - "description": "Service ID for this Action. Required." - }, - "table_name": { - "type": "string", - "description": "Table name. Required. May additionally contain a database name." - }, - "database": { - "type": "string", - "description": "Database name. Required if not given in the table_name field." - } - } - }, - "v1StartPostgreSQLShowIndexActionResult": { - "type": "object", - "properties": { - "action_id": { - "type": "string", - "description": "Unique Action ID." - }, - "pmm_agent_id": { - "type": "string", - "description": "pmm-agent ID where to this Action was started." - } - } - }, - "v1StartServiceActionRequest": { - "type": "object", - "properties": { - "mysql_explain": { - "$ref": "#/definitions/v1StartMySQLExplainActionParams" - }, - "mysql_explain_json": { - "$ref": "#/definitions/v1StartMySQLExplainJSONActionParams" - }, - "mysql_explain_traditional_json": { - "$ref": "#/definitions/v1StartMySQLExplainTraditionalJSONActionParams" - }, - "mysql_show_index": { - "$ref": "#/definitions/v1StartMySQLShowIndexActionParams" - }, - "mysql_show_create_table": { - "$ref": "#/definitions/v1StartMySQLShowCreateTableActionParams" - }, - "mysql_show_table_status": { - "$ref": "#/definitions/v1StartMySQLShowTableStatusActionParams" - }, - "postgres_show_create_table": { - "$ref": "#/definitions/v1StartPostgreSQLShowCreateTableActionParams" - }, - "postgres_show_index": { - "$ref": "#/definitions/v1StartPostgreSQLShowIndexActionParams" - }, - "mongodb_explain": { - "$ref": "#/definitions/v1StartMongoDBExplainActionParams" - }, - "pt_mongodb_summary": { - "$ref": "#/definitions/v1StartPTMongoDBSummaryActionParams" - }, - "pt_mysql_summary": { - "$ref": "#/definitions/v1StartPTMySQLSummaryActionParams" - }, - "pt_postgres_summary": { - "$ref": "#/definitions/v1StartPTPgSummaryActionParams" - } - } - }, - "v1StartServiceActionResponse": { - "type": "object", - "properties": { - "mysql_explain": { - "$ref": "#/definitions/v1StartMySQLExplainActionResult" - }, - "mysql_explain_json": { - "$ref": "#/definitions/v1StartMySQLExplainJSONActionResult" - }, - "mysql_explain_traditional_json": { - "$ref": "#/definitions/v1StartMySQLExplainTraditionalJSONActionResult" - }, - "mysql_show_index": { - "$ref": "#/definitions/v1StartMySQLShowIndexActionResult" - }, - "mysql_show_create_table": { - "$ref": "#/definitions/v1StartMySQLShowCreateTableActionResult" - }, - "mysql_show_table_status": { - "$ref": "#/definitions/v1StartMySQLShowTableStatusActionResult" - }, - "postgresql_show_create_table": { - "$ref": "#/definitions/v1StartPostgreSQLShowCreateTableActionResult" - }, - "postgresql_show_index": { - "$ref": "#/definitions/v1StartPostgreSQLShowIndexActionResult" - }, - "mongodb_explain": { - "$ref": "#/definitions/v1StartMongoDBExplainActionResult" - }, - "pt_mongodb_summary": { - "$ref": "#/definitions/v1StartPTMongoDBSummaryActionResult" - }, - "pt_mysql_summary": { - "$ref": "#/definitions/v1StartPTMySQLSummaryActionResult" - }, - "pt_postgres_summary": { - "$ref": "#/definitions/v1StartPTPgSummaryActionResult" - } - } - } - } -} diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index a179ff24f0e..329c6538645 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -2014,7 +2014,6 @@ var ( (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp } ) - var file_advisors_v1_advisors_proto_depIdxs = []int32{ 29, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity 26, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry diff --git a/api/advisors/v1/advisors.swagger.json b/api/advisors/v1/advisors.swagger.json deleted file mode 100644 index 82c8d7b202b..00000000000 --- a/api/advisors/v1/advisors.swagger.json +++ /dev/null @@ -1,841 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "advisors/v1/advisors.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "AdvisorService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/advisors": { - "get": { - "summary": "List Advisors", - "description": "List advisors available to the user.", - "operationId": "ListAdvisors", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListAdvisorsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "AdvisorService" - ] - } - }, - "/v1/advisors/checks": { - "get": { - "summary": "List Advisor Checks", - "description": "List advisor checks available to the user.", - "operationId": "ListAdvisorChecks", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListAdvisorChecksResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "AdvisorService" - ] - } - }, - "/v1/advisors/checks/failed": { - "get": { - "summary": "Get Failed Advisor Checks", - "description": "Returns the latest check results for a given service.", - "operationId": "GetFailedChecks", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetFailedChecksResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "page_size", - "description": "Maximum number of results per page.", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "page_index", - "description": "Index of the requested page, starts from 0.", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "service_id", - "description": "Service ID.", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "AdvisorService" - ] - } - }, - "/v1/advisors/checks/history": { - "get": { - "summary": "List Advisor Check Results History", - "description": "Returns the history of Advisor check runs, including their outcomes.", - "operationId": "ListCheckResultsHistory", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListCheckResultsHistoryResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "page_size", - "description": "Maximum number of results per page.", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "page_index", - "description": "Index of the requested page, starts from 0.", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "service_id", - "description": "Filter by service ID.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "status", - "description": "Filter by outcome.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", - "ADVISOR_CHECK_RESULT_STATUS_OK", - "ADVISOR_CHECK_RESULT_STATUS_FAILED", - "ADVISOR_CHECK_RESULT_STATUS_ERROR" - ], - "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED" - }, - { - "name": "is_read", - "description": "Filter by read state.", - "in": "query", - "required": false, - "type": "boolean" - }, - { - "name": "from", - "description": "Return only results recorded at or after this time.", - "in": "query", - "required": false, - "type": "string", - "format": "date-time" - }, - { - "name": "to", - "description": "Return only results recorded at or before this time.", - "in": "query", - "required": false, - "type": "string", - "format": "date-time" - }, - { - "name": "service_name", - "description": "Filter by service name (partial, case-insensitive match).", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "node_name", - "description": "Filter by node name (partial, case-insensitive match).", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "category", - "description": "Filter by advisor category.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "check_name", - "description": "Filter by check name.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "severity", - "description": "Filter by severity.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "SEVERITY_UNSPECIFIED", - "SEVERITY_EMERGENCY", - "SEVERITY_ALERT", - "SEVERITY_CRITICAL", - "SEVERITY_ERROR", - "SEVERITY_WARNING", - "SEVERITY_NOTICE", - "SEVERITY_INFO", - "SEVERITY_DEBUG" - ], - "default": "SEVERITY_UNSPECIFIED" - } - ], - "tags": [ - "AdvisorService" - ] - } - }, - "/v1/advisors/checks/history:markRead": { - "post": { - "summary": "Mark Advisor Check Results Read", - "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", - "operationId": "MarkCheckResultsRead", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1MarkCheckResultsReadResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1MarkCheckResultsReadRequest" - } - } - ], - "tags": [ - "AdvisorService" - ] - } - }, - "/v1/advisors/checks:batchChange": { - "post": { - "summary": "Change Advisor Checks", - "description": "Enables/disables advisor checks or changes their exec interval.", - "operationId": "ChangeAdvisorChecks", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ChangeAdvisorChecksResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1ChangeAdvisorChecksRequest" - } - } - ], - "tags": [ - "AdvisorService" - ] - } - }, - "/v1/advisors/checks:start": { - "post": { - "summary": "Start Advisor Checks", - "description": "Executes Advisor checks and returns when all checks are executed. All available checks will be started if check names aren't specified.", - "operationId": "StartAdvisorChecks", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StartAdvisorChecksResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StartAdvisorChecksRequest" - } - } - ], - "tags": [ - "AdvisorService" - ] - } - }, - "/v1/advisors/failedServices": { - "get": { - "summary": "List Failed Services", - "description": "Returns a list of services with failed checks and a summary of check results.", - "operationId": "ListFailedServices", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListFailedServicesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "AdvisorService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1Advisor": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Machine-readable name (ID) that is used in expression." - }, - "description": { - "type": "string", - "description": "Long human-readable description." - }, - "summary": { - "type": "string", - "description": "Short human-readable summary." - }, - "comment": { - "type": "string", - "description": "Comment." - }, - "category": { - "type": "string", - "description": "Category." - }, - "checks": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1AdvisorCheck" - }, - "description": "Advisor checks." - } - } - }, - "v1AdvisorCheck": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Machine-readable name (ID) that is used in expression." - }, - "enabled": { - "type": "boolean", - "description": "True if that check is enabled." - }, - "description": { - "type": "string", - "description": "Long human-readable description." - }, - "summary": { - "type": "string", - "description": "Short human-readable summary." - }, - "interval": { - "$ref": "#/definitions/v1AdvisorCheckInterval", - "description": "Check execution interval." - }, - "family": { - "$ref": "#/definitions/v1AdvisorCheckFamily", - "description": "DB family." - } - }, - "description": "AdvisorCheck contains check name and status." - }, - "v1AdvisorCheckFamily": { - "type": "string", - "enum": [ - "ADVISOR_CHECK_FAMILY_UNSPECIFIED", - "ADVISOR_CHECK_FAMILY_MYSQL", - "ADVISOR_CHECK_FAMILY_POSTGRESQL", - "ADVISOR_CHECK_FAMILY_MONGODB" - ], - "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED" - }, - "v1AdvisorCheckInterval": { - "type": "string", - "enum": [ - "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", - "ADVISOR_CHECK_INTERVAL_STANDARD", - "ADVISOR_CHECK_INTERVAL_FREQUENT", - "ADVISOR_CHECK_INTERVAL_RARE" - ], - "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", - "description": "AdvisorCheckInterval represents possible execution interval values for checks." - }, - "v1AdvisorCheckResultStatus": { - "type": "string", - "enum": [ - "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", - "ADVISOR_CHECK_RESULT_STATUS_OK", - "ADVISOR_CHECK_RESULT_STATUS_FAILED", - "ADVISOR_CHECK_RESULT_STATUS_ERROR" - ], - "default": "ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED", - "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed." - }, - "v1ChangeAdvisorCheckParams": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name of the check to change." - }, - "enable": { - "type": "boolean", - "x-nullable": true - }, - "interval": { - "$ref": "#/definitions/v1AdvisorCheckInterval", - "description": "check execution interval." - } - }, - "description": "ChangeAdvisorCheckParams specifies a single check parameters." - }, - "v1ChangeAdvisorChecksRequest": { - "type": "object", - "properties": { - "params": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ChangeAdvisorCheckParams" - } - } - } - }, - "v1ChangeAdvisorChecksResponse": { - "type": "object" - }, - "v1CheckResult": { - "type": "object", - "properties": { - "summary": { - "type": "string" - }, - "description": { - "type": "string" - }, - "severity": { - "$ref": "#/definitions/v1Severity" - }, - "labels": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "read_more_url": { - "type": "string", - "description": "URL containing information on how to resolve an issue detected by an Advisor check." - }, - "service_name": { - "type": "string", - "description": "Name of the monitored service on which the check ran." - }, - "service_id": { - "type": "string", - "description": "ID of the monitored service on which the check ran." - }, - "check_name": { - "type": "string", - "title": "Name of the check that failed" - }, - "silenced": { - "type": "boolean", - "title": "Silence status of the check result" - } - }, - "description": "CheckResult represents the check results for a given service." - }, - "v1CheckResultHistoryItem": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier of the history record." - }, - "check_name": { - "type": "string", - "description": "Name of the check that ran." - }, - "advisor_name": { - "type": "string", - "description": "Name of the advisor the check belongs to." - }, - "category": { - "type": "string", - "description": "Category of the advisor the check belongs to." - }, - "interval": { - "$ref": "#/definitions/v1AdvisorCheckInterval", - "description": "Check execution interval." - }, - "service_id": { - "type": "string", - "description": "ID of the monitored service on which the check ran." - }, - "service_name": { - "type": "string", - "description": "Name of the monitored service on which the check ran." - }, - "service_type": { - "type": "string", - "description": "Type of the monitored service on which the check ran." - }, - "node_id": { - "type": "string", - "description": "ID of the node the service runs on." - }, - "node_name": { - "type": "string", - "description": "Name of the node the service runs on." - }, - "status": { - "$ref": "#/definitions/v1AdvisorCheckResultStatus", - "description": "Outcome of the check run." - }, - "summary": { - "type": "string", - "description": "Short human-readable summary of the result." - }, - "description": { - "type": "string", - "description": "Long human-readable description of the result." - }, - "read_more_url": { - "type": "string", - "description": "URL containing information on how to resolve a detected issue." - }, - "severity": { - "$ref": "#/definitions/v1Severity", - "description": "Severity of the result." - }, - "labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Result labels." - }, - "checked_at": { - "type": "string", - "format": "date-time", - "description": "Time when the check ran." - }, - "is_read": { - "type": "boolean", - "description": "Whether the result has been marked as read." - } - }, - "description": "CheckResultHistoryItem represents a single persisted Advisor check run against a service." - }, - "v1CheckResultSummary": { - "type": "object", - "properties": { - "service_name": { - "type": "string" - }, - "service_id": { - "type": "string" - }, - "emergency_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"EMERGENCY\"." - }, - "alert_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"ALERT\"." - }, - "critical_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"CRITICAL\"." - }, - "error_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"ERROR\"." - }, - "warning_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"WARNING\"." - }, - "notice_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"NOTICE\"." - }, - "info_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"INFO\"." - }, - "debug_count": { - "type": "integer", - "format": "int64", - "description": "Number of failed checks for this service with severity level \"DEBUG\"." - } - }, - "description": "CheckResultSummary is a summary of check results." - }, - "v1GetFailedChecksResponse": { - "type": "object", - "properties": { - "total_items": { - "type": "integer", - "format": "int32", - "description": "Total number of results." - }, - "total_pages": { - "type": "integer", - "format": "int32", - "description": "Total number of pages." - }, - "results": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1CheckResult" - }, - "title": "Check results" - } - } - }, - "v1ListAdvisorChecksResponse": { - "type": "object", - "properties": { - "checks": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1AdvisorCheck" - } - } - } - }, - "v1ListAdvisorsResponse": { - "type": "object", - "properties": { - "advisors": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Advisor" - } - } - } - }, - "v1ListCheckResultsHistoryResponse": { - "type": "object", - "properties": { - "total_items": { - "type": "integer", - "format": "int32", - "description": "Total number of results." - }, - "total_pages": { - "type": "integer", - "format": "int32", - "description": "Total number of pages." - }, - "results": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1CheckResultHistoryItem" - }, - "description": "History records." - } - } - }, - "v1ListFailedServicesResponse": { - "type": "object", - "properties": { - "result": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1CheckResultSummary" - } - } - } - }, - "v1MarkCheckResultsReadRequest": { - "type": "object", - "properties": { - "ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "IDs of the history records to update." - }, - "is_read": { - "type": "boolean", - "description": "Read state to set on the records." - } - } - }, - "v1MarkCheckResultsReadResponse": { - "type": "object" - }, - "v1Severity": { - "type": "string", - "enum": [ - "SEVERITY_UNSPECIFIED", - "SEVERITY_EMERGENCY", - "SEVERITY_ALERT", - "SEVERITY_CRITICAL", - "SEVERITY_ERROR", - "SEVERITY_WARNING", - "SEVERITY_NOTICE", - "SEVERITY_INFO", - "SEVERITY_DEBUG" - ], - "default": "SEVERITY_UNSPECIFIED", - "description": "Severity represents severity level of the check result or alert." - }, - "v1StartAdvisorChecksRequest": { - "type": "object", - "properties": { - "names": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Names of the checks that should be started." - } - } - }, - "v1StartAdvisorChecksResponse": { - "type": "object" - } - } -} diff --git a/api/agent/pb/agent.swagger.json b/api/agent/pb/agent.swagger.json deleted file mode 100644 index 5c75bc6dbe5..00000000000 --- a/api/agent/pb/agent.swagger.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "agent/pb/agent.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "Agent" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string", - "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." - } - }, - "additionalProperties": {}, - "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32", - "description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]." - }, - "message": { - "type": "string", - "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client." - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - }, - "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." - } - }, - "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." - } - } -} diff --git a/api/agent/v1/agent.pb.go b/api/agent/v1/agent.pb.go index c2f2a8b6a9e..7f5d935624b 100644 --- a/api/agent/v1/agent.pb.go +++ b/api/agent/v1/agent.pb.go @@ -7221,7 +7221,6 @@ var ( (*v11.Metadata)(nil), // 104: backup.v1.Metadata } ) - var file_agent_v1_agent_proto_depIdxs = []int32{ 44, // 0: agent.v1.TextFiles.files:type_name -> agent.v1.TextFiles.FilesEntry 94, // 1: agent.v1.Pong.current_time:type_name -> google.protobuf.Timestamp diff --git a/api/agent/v1/agent.swagger.json b/api/agent/v1/agent.swagger.json deleted file mode 100644 index 9be2eb39da2..00000000000 --- a/api/agent/v1/agent.swagger.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "agent/v1/agent.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "AgentService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string", - "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." - } - }, - "additionalProperties": {}, - "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32", - "description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]." - }, - "message": { - "type": "string", - "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client." - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - }, - "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." - } - }, - "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." - } - } -} diff --git a/api/agent/v1/collector.pb.go b/api/agent/v1/collector.pb.go index 65633c05d17..da17db39c64 100644 --- a/api/agent/v1/collector.pb.go +++ b/api/agent/v1/collector.pb.go @@ -2827,7 +2827,6 @@ var ( v1.AgentType(0), // 9: inventory.v1.AgentType } ) - var file_agent_v1_collector_proto_depIdxs = []int32{ 3, // 0: agent.v1.MetricsBucket.common:type_name -> agent.v1.MetricsBucket.Common 4, // 1: agent.v1.MetricsBucket.mysql:type_name -> agent.v1.MetricsBucket.MySQL diff --git a/api/agent/v1/collector.swagger.json b/api/agent/v1/collector.swagger.json deleted file mode 100644 index 461533c2478..00000000000 --- a/api/agent/v1/collector.swagger.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "agent/v1/collector.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string", - "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." - } - }, - "additionalProperties": {}, - "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32", - "description": "The status code, which should be an enum value of\n[google.rpc.Code][google.rpc.Code]." - }, - "message": { - "type": "string", - "description": "A developer-facing error message, which should be in English. Any\nuser-facing error message should be localized and sent in the\n[google.rpc.Status.details][google.rpc.Status.details] field, or localized\nby the client." - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - }, - "description": "A list of messages that carry the error details. There is a common set of\nmessage types for APIs to use." - } - }, - "description": "The `Status` type defines a logical error model that is suitable for\ndifferent programming environments, including REST APIs and RPC APIs. It is\nused by [gRPC](https://github.com/grpc). Each `Status` message contains\nthree pieces of data: error code, error message, and error details.\n\nYou can find out more about this error model and how to work with it in the\n[API Design Guide](https://cloud.google.com/apis/design/errors)." - } - } -} diff --git a/api/agentlocal/v1/agentlocal.pb.go b/api/agentlocal/v1/agentlocal.pb.go index 7bb13a7cb58..12053d57921 100644 --- a/api/agentlocal/v1/agentlocal.pb.go +++ b/api/agentlocal/v1/agentlocal.pb.go @@ -485,7 +485,6 @@ var ( v1.AgentStatus(0), // 8: inventory.v1.AgentStatus } ) - var file_agentlocal_v1_agentlocal_proto_depIdxs = []int32{ 6, // 0: agentlocal.v1.ServerInfo.latency:type_name -> google.protobuf.Duration 6, // 1: agentlocal.v1.ServerInfo.clock_drift:type_name -> google.protobuf.Duration diff --git a/api/agentlocal/v1/agentlocal.swagger.json b/api/agentlocal/v1/agentlocal.swagger.json deleted file mode 100644 index 4f22ad35a7c..00000000000 --- a/api/agentlocal/v1/agentlocal.swagger.json +++ /dev/null @@ -1,295 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "agentlocal/v1/agentlocal.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "AgentLocalService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/local/Reload": { - "post": { - "summary": "Reload reloads pmm-agent configuration.", - "operationId": "Reload", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ReloadResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1ReloadRequest" - } - } - ], - "tags": [ - "AgentLocalService" - ] - } - }, - "/local/Status": { - "get": { - "summary": "Status returns current pmm-agent status.", - "operationId": "Status2", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StatusResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "get_network_info", - "description": "Returns network info (latency and clock_drift) if true.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "AgentLocalService" - ] - }, - "post": { - "summary": "Status returns current pmm-agent status.", - "operationId": "Status", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StatusResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StatusRequest" - } - } - ], - "tags": [ - "AgentLocalService" - ] - } - } - }, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "v1AgentInfo": { - "type": "object", - "properties": { - "agent_id": { - "type": "string" - }, - "agent_type": { - "$ref": "#/definitions/v1AgentType" - }, - "status": { - "$ref": "#/definitions/v1AgentStatus" - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "The current listen port of this Agent (exporter or vmagent).\nZero for other Agent types, or if unknown or not yet supported." - }, - "process_exec_path": { - "type": "string" - } - }, - "description": "AgentInfo contains information about Agent managed by pmm-agent." - }, - "v1AgentStatus": { - "type": "string", - "enum": [ - "AGENT_STATUS_UNSPECIFIED", - "AGENT_STATUS_STARTING", - "AGENT_STATUS_INITIALIZATION_ERROR", - "AGENT_STATUS_RUNNING", - "AGENT_STATUS_WAITING", - "AGENT_STATUS_STOPPING", - "AGENT_STATUS_DONE", - "AGENT_STATUS_UNKNOWN" - ], - "default": "AGENT_STATUS_UNSPECIFIED", - "description": "AgentStatus represents actual Agent status.\n\n - AGENT_STATUS_STARTING: Agent is starting.\n - AGENT_STATUS_INITIALIZATION_ERROR: Agent encountered error when starting.\n - AGENT_STATUS_RUNNING: Agent is running.\n - AGENT_STATUS_WAITING: Agent encountered error and will be restarted automatically soon.\n - AGENT_STATUS_STOPPING: Agent is stopping.\n - AGENT_STATUS_DONE: Agent has been stopped or disabled.\n - AGENT_STATUS_UNKNOWN: Agent is not connected, we don't know anything about it's state." - }, - "v1AgentType": { - "type": "string", - "enum": [ - "AGENT_TYPE_UNSPECIFIED", - "AGENT_TYPE_PMM_AGENT", - "AGENT_TYPE_VM_AGENT", - "AGENT_TYPE_NODE_EXPORTER", - "AGENT_TYPE_MYSQLD_EXPORTER", - "AGENT_TYPE_MONGODB_EXPORTER", - "AGENT_TYPE_POSTGRES_EXPORTER", - "AGENT_TYPE_PROXYSQL_EXPORTER", - "AGENT_TYPE_VALKEY_EXPORTER", - "AGENT_TYPE_QAN_MYSQL_PERFSCHEMA_AGENT", - "AGENT_TYPE_QAN_MYSQL_SLOWLOG_AGENT", - "AGENT_TYPE_QAN_MONGODB_PROFILER_AGENT", - "AGENT_TYPE_QAN_MONGODB_MONGOLOG_AGENT", - "AGENT_TYPE_QAN_POSTGRESQL_PGSTATEMENTS_AGENT", - "AGENT_TYPE_QAN_POSTGRESQL_PGSTATMONITOR_AGENT", - "AGENT_TYPE_EXTERNAL_EXPORTER", - "AGENT_TYPE_RDS_EXPORTER", - "AGENT_TYPE_AZURE_DATABASE_EXPORTER", - "AGENT_TYPE_NOMAD_AGENT", - "AGENT_TYPE_RTA_MONGODB_AGENT" - ], - "default": "AGENT_TYPE_UNSPECIFIED", - "description": "AgentType describes supported Agent types." - }, - "v1ReloadRequest": { - "type": "object" - }, - "v1ReloadResponse": { - "type": "object", - "description": "ReloadRequest may not be received by the client due to pmm-agent restart." - }, - "v1ServerInfo": { - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "PMM Server URL in a form https://HOST:PORT/." - }, - "insecure_tls": { - "type": "boolean", - "description": "PMM Server's TLS certificate validation should be skipped if true." - }, - "connected": { - "type": "boolean", - "description": "True if pmm-agent is currently connected to the server." - }, - "version": { - "type": "string", - "description": "PMM Server version (if agent is connected)." - }, - "latency": { - "type": "string", - "description": "Ping time from pmm-agent to pmm-managed (if agent is connected)." - }, - "clock_drift": { - "type": "string", - "description": "Clock drift from PMM Server (if agent is connected)." - } - }, - "description": "ServerInfo contains information about the PMM Server." - }, - "v1StatusRequest": { - "type": "object", - "properties": { - "get_network_info": { - "type": "boolean", - "description": "Returns network info (latency and clock_drift) if true." - } - } - }, - "v1StatusResponse": { - "type": "object", - "properties": { - "agent_id": { - "type": "string" - }, - "runs_on_node_id": { - "type": "string", - "title": "TODO: rename to node_id" - }, - "node_name": { - "type": "string" - }, - "server_info": { - "$ref": "#/definitions/v1ServerInfo" - }, - "agents_info": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1AgentInfo" - } - }, - "config_filepath": { - "type": "string", - "description": "Config file path if pmm-agent was started with one." - }, - "agent_version": { - "type": "string", - "description": "PMM Agent version." - }, - "connection_uptime": { - "type": "number", - "format": "float", - "title": "Shows connection uptime in percentage between agent and server" - } - } - } - } -} diff --git a/api/alerting/v1/alerting.pb.go b/api/alerting/v1/alerting.pb.go index 3b2c47d73ec..bccb6659d24 100644 --- a/api/alerting/v1/alerting.pb.go +++ b/api/alerting/v1/alerting.pb.go @@ -1459,7 +1459,6 @@ var ( (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp } ) - var file_alerting_v1_alerting_proto_depIdxs = []int32{ 22, // 0: alerting.v1.ParamDefinition.unit:type_name -> alerting.v1.ParamUnit 23, // 1: alerting.v1.ParamDefinition.type:type_name -> alerting.v1.ParamType diff --git a/api/alerting/v1/alerting.swagger.json b/api/alerting/v1/alerting.swagger.json deleted file mode 100644 index 726625709d5..00000000000 --- a/api/alerting/v1/alerting.swagger.json +++ /dev/null @@ -1,581 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "alerting/v1/alerting.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "AlertingService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/alerting/rules": { - "post": { - "summary": "CreateRule creates alerting rule from the given template.", - "operationId": "CreateRule", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1CreateRuleResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1CreateRuleRequest" - } - } - ], - "tags": [ - "AlertingService" - ] - } - }, - "/v1/alerting/templates": { - "get": { - "summary": "ListTemplates returns a list of all collected alert rule templates.", - "operationId": "ListTemplates", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListTemplatesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "page_size", - "description": "Maximum number of results per page.", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "page_index", - "description": "Index of the requested page, starts from 0.", - "in": "query", - "required": false, - "type": "integer", - "format": "int32" - }, - { - "name": "reload", - "description": "If true, template files will be re-read from disk.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "AlertingService" - ] - }, - "post": { - "summary": "CreateTemplate creates a new template.", - "operationId": "CreateTemplate", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1CreateTemplateResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1CreateTemplateRequest" - } - } - ], - "tags": [ - "AlertingService" - ] - } - }, - "/v1/alerting/templates/{name}": { - "delete": { - "summary": "DeleteTemplate deletes existing, previously created via API.", - "operationId": "DeleteTemplate", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1DeleteTemplateResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "name", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "AlertingService" - ] - }, - "put": { - "summary": "UpdateTemplate updates existing template, previously created via API.", - "operationId": "UpdateTemplate", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1UpdateTemplateResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "name", - "description": "Machine-readable name (ID).", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/AlertingServiceUpdateTemplateBody" - } - } - ], - "tags": [ - "AlertingService" - ] - } - } - }, - "definitions": { - "AlertingServiceUpdateTemplateBody": { - "type": "object", - "properties": { - "yaml": { - "type": "string", - "description": "YAML template file content." - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1BoolParamDefinition": { - "type": "object", - "properties": { - "default": { - "type": "boolean", - "x-nullable": true - } - }, - "description": "BoolParamDefinition represents boolean parameter's default value." - }, - "v1CreateRuleRequest": { - "type": "object", - "properties": { - "template_name": { - "type": "string", - "description": "Template name." - }, - "name": { - "type": "string", - "description": "Rule name." - }, - "group": { - "type": "string", - "description": "Rule group name." - }, - "folder_uid": { - "type": "string", - "description": "Folder UID." - }, - "params": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ParamValue" - }, - "description": "Rule parameters. All template parameters should be set." - }, - "for": { - "type": "string", - "description": "Rule duration. Should be set." - }, - "severity": { - "$ref": "#/definitions/v1Severity", - "description": "Rule severity. Should be set." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "All custom labels to add or remove (with empty values) to default labels from template." - }, - "filters": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Filter" - }, - "description": "Filters." - }, - "interval": { - "type": "string", - "title": "Evaluation Interval" - } - } - }, - "v1CreateRuleResponse": { - "type": "object" - }, - "v1CreateTemplateRequest": { - "type": "object", - "properties": { - "yaml": { - "type": "string", - "description": "YAML template file content." - } - } - }, - "v1CreateTemplateResponse": { - "type": "object" - }, - "v1DeleteTemplateResponse": { - "type": "object" - }, - "v1Filter": { - "type": "object", - "properties": { - "type": { - "$ref": "#/definitions/v1FilterType" - }, - "label": { - "type": "string" - }, - "regexp": { - "type": "string" - } - }, - "description": "Filter represents a single filter condition." - }, - "v1FilterType": { - "type": "string", - "enum": [ - "FILTER_TYPE_UNSPECIFIED", - "FILTER_TYPE_MATCH", - "FILTER_TYPE_MISMATCH" - ], - "default": "FILTER_TYPE_UNSPECIFIED", - "description": "FilterType represents filter matching type." - }, - "v1FloatParamDefinition": { - "type": "object", - "properties": { - "default": { - "type": "number", - "format": "double", - "x-nullable": true, - "description": "Default value." - }, - "min": { - "type": "number", - "format": "double", - "x-nullable": true, - "description": "Minimum valid value (inclusive)." - }, - "max": { - "type": "number", - "format": "double", - "x-nullable": true, - "description": "Maximum valid value (inclusive)." - } - }, - "description": "FloatParamDefinition represents float parameter's default value and valid range." - }, - "v1ListTemplatesResponse": { - "type": "object", - "properties": { - "total_items": { - "type": "integer", - "format": "int32", - "description": "Total number of results." - }, - "total_pages": { - "type": "integer", - "format": "int32", - "description": "Total number of pages." - }, - "templates": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Template" - }, - "description": "Alerting templates." - } - } - }, - "v1ParamDefinition": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Machine-readable name (ID) that is used in expression." - }, - "summary": { - "type": "string", - "description": "Short human-readable parameter summary." - }, - "unit": { - "$ref": "#/definitions/v1ParamUnit", - "description": "Parameter unit. TODO: remove this parameter." - }, - "type": { - "$ref": "#/definitions/v1ParamType", - "description": "Parameter type." - }, - "bool": { - "$ref": "#/definitions/v1BoolParamDefinition", - "description": "Bool value." - }, - "float": { - "$ref": "#/definitions/v1FloatParamDefinition", - "description": "Float value." - }, - "string": { - "$ref": "#/definitions/v1StringParamDefinition", - "description": "String value." - } - }, - "description": "ParamDefinition represents a single query parameter." - }, - "v1ParamType": { - "type": "string", - "enum": [ - "PARAM_TYPE_UNSPECIFIED", - "PARAM_TYPE_BOOL", - "PARAM_TYPE_FLOAT", - "PARAM_TYPE_STRING" - ], - "default": "PARAM_TYPE_UNSPECIFIED", - "description": "ParamType represents template parameter type." - }, - "v1ParamUnit": { - "type": "string", - "enum": [ - "PARAM_UNIT_UNSPECIFIED", - "PARAM_UNIT_PERCENTAGE", - "PARAM_UNIT_SECONDS" - ], - "default": "PARAM_UNIT_UNSPECIFIED", - "description": "ParamUnit represents template parameter unit.\n\n - PARAM_UNIT_UNSPECIFIED: Invalid, unknown or absent.\n - PARAM_UNIT_PERCENTAGE: %\n - PARAM_UNIT_SECONDS: s" - }, - "v1ParamValue": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Machine-readable name (ID) that is used in expression." - }, - "type": { - "$ref": "#/definitions/v1ParamType", - "description": "Parameter type." - }, - "bool": { - "type": "boolean", - "description": "Bool value." - }, - "float": { - "type": "number", - "format": "double", - "description": "Float value." - }, - "string": { - "type": "string", - "description": "String value." - } - }, - "description": "ParamValue represents a single rule parameter value." - }, - "v1Severity": { - "type": "string", - "enum": [ - "SEVERITY_UNSPECIFIED", - "SEVERITY_EMERGENCY", - "SEVERITY_ALERT", - "SEVERITY_CRITICAL", - "SEVERITY_ERROR", - "SEVERITY_WARNING", - "SEVERITY_NOTICE", - "SEVERITY_INFO", - "SEVERITY_DEBUG" - ], - "default": "SEVERITY_UNSPECIFIED", - "description": "Severity represents severity level of the check result or alert." - }, - "v1StringParamDefinition": { - "type": "object", - "properties": { - "default": { - "type": "string", - "x-nullable": true, - "description": "Default value." - } - }, - "description": "StringParamDefinition represents string parameter's default value." - }, - "v1Template": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Machine-readable name (ID)." - }, - "summary": { - "type": "string", - "description": "Short human-readable summary." - }, - "expr": { - "type": "string", - "description": "PromQL query expression with templating parameters." - }, - "params": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ParamDefinition" - }, - "description": "Query parameters definitions." - }, - "for": { - "type": "string", - "description": "Default duration value." - }, - "severity": { - "$ref": "#/definitions/v1Severity", - "description": "Severity." - }, - "labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Labels." - }, - "annotations": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Annotations." - }, - "source": { - "$ref": "#/definitions/v1TemplateSource", - "description": "Template source. Only templates created via API can be updated or deleted via API." - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "Template creation time. Empty for built-in and SaaS templates." - }, - "yaml": { - "type": "string", - "description": "YAML template file content. Empty for built-in and SaaS templates." - } - }, - "description": "Template represents Alert Template that is used to create Alert Rule." - }, - "v1TemplateSource": { - "type": "string", - "enum": [ - "TEMPLATE_SOURCE_UNSPECIFIED", - "TEMPLATE_SOURCE_BUILT_IN", - "TEMPLATE_SOURCE_SAAS", - "TEMPLATE_SOURCE_USER_FILE", - "TEMPLATE_SOURCE_USER_API" - ], - "default": "TEMPLATE_SOURCE_UNSPECIFIED", - "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API." - }, - "v1UpdateTemplateResponse": { - "type": "object" - } - } -} diff --git a/api/alerting/v1/params.pb.go b/api/alerting/v1/params.pb.go index 69d88497102..eb001a606db 100644 --- a/api/alerting/v1/params.pb.go +++ b/api/alerting/v1/params.pb.go @@ -163,7 +163,6 @@ var ( ParamType(0), // 1: alerting.v1.ParamType } ) - var file_alerting_v1_params_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/alerting/v1/params.swagger.json b/api/alerting/v1/params.swagger.json deleted file mode 100644 index d56f9a7c05a..00000000000 --- a/api/alerting/v1/params.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "alerting/v1/params.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/backup/v1/artifacts.pb.go b/api/backup/v1/artifacts.pb.go index dde03ceefef..e2352f61cd1 100644 --- a/api/backup/v1/artifacts.pb.go +++ b/api/backup/v1/artifacts.pb.go @@ -656,7 +656,6 @@ var ( (*Metadata)(nil), // 12: backup.v1.Metadata } ) - var file_backup_v1_artifacts_proto_depIdxs = []int32{ 9, // 0: backup.v1.Artifact.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.Artifact.status:type_name -> backup.v1.BackupStatus diff --git a/api/backup/v1/artifacts.swagger.json b/api/backup/v1/artifacts.swagger.json deleted file mode 100644 index c160f10d3e5..00000000000 --- a/api/backup/v1/artifacts.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "backup/v1/artifacts.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/backup/v1/backup.pb.go b/api/backup/v1/backup.pb.go index 4d587217600..19241fc6afd 100644 --- a/api/backup/v1/backup.pb.go +++ b/api/backup/v1/backup.pb.go @@ -1276,7 +1276,6 @@ var ( (*ListPitrTimerangesResponse)(nil), // 27: backup.v1.ListPitrTimerangesResponse } ) - var file_backup_v1_backup_proto_depIdxs = []int32{ 15, // 0: backup.v1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration 16, // 1: backup.v1.StartBackupRequest.data_model:type_name -> backup.v1.DataModel diff --git a/api/backup/v1/backup.swagger.json b/api/backup/v1/backup.swagger.json deleted file mode 100644 index 084b996bce7..00000000000 --- a/api/backup/v1/backup.swagger.json +++ /dev/null @@ -1,1003 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "backup/v1/backup.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "BackupService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/backups/artifacts": { - "get": { - "summary": "List artifacts", - "description": "Return a list of backup artifacts.", - "operationId": "ListArtifacts", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListArtifactsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups/artifacts/{artifact_id}": { - "delete": { - "summary": "Delete Artifact", - "description": "Deletes an artifact.", - "operationId": "DeleteArtifact", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1DeleteArtifactResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "artifact_id", - "description": "Machine-readable artifact ID.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "remove_files", - "description": "Removes all the backup files associated with artifact if flag is set.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups/artifacts/{artifact_id}/pitr-timeranges": { - "get": { - "summary": "List PITR Timeranges", - "description": "Return a list of available MongoDB point-in-time-recovery timeranges.", - "operationId": "ListPitrTimeranges", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListPitrTimerangesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "artifact_id", - "description": "Artifact ID represents artifact whose location has PITR timeranges to be retrieved.", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups/scheduled": { - "get": { - "summary": "List Scheduled Backups", - "description": "List all scheduled backups.", - "operationId": "ListScheduledBackups", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListScheduledBackupsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups/{artifact_id}/compatible-services": { - "get": { - "summary": "List Compatible Services", - "description": "List services that are compatible with the backup artifact.", - "operationId": "ListArtifactCompatibleServices", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListArtifactCompatibleServicesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "artifact_id", - "description": "Artifact id used to determine restore compatibility.", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups/{artifact_id}/logs": { - "get": { - "summary": "Get Logs", - "description": "Get logs from the underlying tools for a backup/restore job.", - "operationId": "GetLogs", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetLogsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "artifact_id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "offset", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - }, - { - "name": "limit", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - } - ], - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups/{scheduled_backup_id}": { - "delete": { - "summary": "Remove a Scheduled Backup", - "description": "Remove a scheduled backup.", - "operationId": "RemoveScheduledBackup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RemoveScheduledBackupResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "scheduled_backup_id", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups:changeScheduled": { - "put": { - "summary": "Change a Scheduled Backup", - "description": "Change a scheduled backup.", - "operationId": "ChangeScheduledBackup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ChangeScheduledBackupResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1ChangeScheduledBackupRequest" - } - } - ], - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups:schedule": { - "post": { - "summary": "Schedule a Backup", - "description": "Schedule a backup to run at a specified time.", - "operationId": "ScheduleBackup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ScheduleBackupResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1ScheduleBackupRequest" - } - } - ], - "tags": [ - "BackupService" - ] - } - }, - "/v1/backups:start": { - "post": { - "summary": "Start a Backup", - "description": "Could return the Error message in the details containing specific ErrorCode indicating failure reason:\nERROR_CODE_XTRABACKUP_NOT_INSTALLED - xtrabackup is not installed on the service\nERROR_CODE_INVALID_XTRABACKUP - different versions of xtrabackup and xbcloud\nERROR_CODE_INCOMPATIBLE_XTRABACKUP - xtrabackup is not compatible with MySQL for taking a backup", - "operationId": "StartBackup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StartBackupResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StartBackupRequest" - } - } - ], - "tags": [ - "BackupService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1Artifact": { - "type": "object", - "properties": { - "artifact_id": { - "type": "string", - "description": "Machine-readable artifact ID." - }, - "name": { - "type": "string", - "title": "Artifact name" - }, - "vendor": { - "type": "string", - "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL." - }, - "location_id": { - "type": "string", - "description": "Machine-readable location ID." - }, - "location_name": { - "type": "string", - "description": "Location name." - }, - "service_id": { - "type": "string", - "description": "Machine-readable service ID." - }, - "service_name": { - "type": "string", - "description": "Service name." - }, - "data_model": { - "$ref": "#/definitions/v1DataModel", - "description": "Backup data model." - }, - "status": { - "$ref": "#/definitions/v1BackupStatus", - "description": "Backup status." - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "Artifact creation time." - }, - "mode": { - "$ref": "#/definitions/v1BackupMode", - "description": "Backup mode." - }, - "is_sharded_cluster": { - "type": "boolean", - "description": "Source database setup type." - }, - "folder": { - "type": "string", - "description": "Folder to store artifact on a storage." - }, - "metadata_list": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Metadata" - }, - "description": "List of artifact metadata." - } - }, - "description": "Artifact represents single backup artifact." - }, - "v1BackupMode": { - "type": "string", - "enum": [ - "BACKUP_MODE_UNSPECIFIED", - "BACKUP_MODE_SNAPSHOT", - "BACKUP_MODE_INCREMENTAL", - "BACKUP_MODE_PITR" - ], - "default": "BACKUP_MODE_UNSPECIFIED", - "description": "BackupMode specifies backup mode." - }, - "v1BackupStatus": { - "type": "string", - "enum": [ - "BACKUP_STATUS_UNSPECIFIED", - "BACKUP_STATUS_PENDING", - "BACKUP_STATUS_IN_PROGRESS", - "BACKUP_STATUS_PAUSED", - "BACKUP_STATUS_SUCCESS", - "BACKUP_STATUS_ERROR", - "BACKUP_STATUS_DELETING", - "BACKUP_STATUS_FAILED_TO_DELETE", - "BACKUP_STATUS_CLEANUP_IN_PROGRESS" - ], - "default": "BACKUP_STATUS_UNSPECIFIED", - "description": "BackupStatus shows the current status of execution of backup." - }, - "v1ChangeScheduledBackupRequest": { - "type": "object", - "properties": { - "scheduled_backup_id": { - "type": "string" - }, - "enabled": { - "type": "boolean", - "x-nullable": true - }, - "cron_expression": { - "type": "string", - "x-nullable": true, - "description": "How often backup should be run in cron format." - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "First backup wouldn't happen before this time." - }, - "name": { - "type": "string", - "x-nullable": true, - "description": "Name of backup." - }, - "description": { - "type": "string", - "x-nullable": true, - "description": "Human-readable description." - }, - "retries": { - "type": "integer", - "format": "int64", - "x-nullable": true, - "description": "How many times to retry a failed backup before giving up." - }, - "retry_interval": { - "type": "string", - "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h." - }, - "retention": { - "type": "integer", - "format": "int64", - "x-nullable": true, - "description": "How many artifacts keep. 0 - unlimited." - } - } - }, - "v1ChangeScheduledBackupResponse": { - "type": "object" - }, - "v1DataModel": { - "type": "string", - "enum": [ - "DATA_MODEL_UNSPECIFIED", - "DATA_MODEL_PHYSICAL", - "DATA_MODEL_LOGICAL" - ], - "default": "DATA_MODEL_UNSPECIFIED", - "description": "DataModel is a model used for performing a backup." - }, - "v1DeleteArtifactResponse": { - "type": "object" - }, - "v1File": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "is_directory": { - "type": "boolean" - } - }, - "description": "File represents file or folder on a storage." - }, - "v1GetLogsResponse": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1LogChunk" - } - }, - "end": { - "type": "boolean" - } - } - }, - "v1ListArtifactCompatibleServicesResponse": { - "type": "object", - "properties": { - "mysql": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MySQLService" - } - }, - "mongodb": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MongoDBService" - } - } - } - }, - "v1ListArtifactsResponse": { - "type": "object", - "properties": { - "artifacts": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Artifact" - } - } - } - }, - "v1ListPitrTimerangesResponse": { - "type": "object", - "properties": { - "timeranges": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1PitrTimerange" - } - } - } - }, - "v1ListScheduledBackupsResponse": { - "type": "object", - "properties": { - "scheduled_backups": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ScheduledBackup" - } - } - } - }, - "v1LogChunk": { - "type": "object", - "properties": { - "chunk_id": { - "type": "integer", - "format": "int64" - }, - "data": { - "type": "string" - } - }, - "description": "LogChunk represent one chunk of logs." - }, - "v1Metadata": { - "type": "object", - "properties": { - "file_list": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1File" - }, - "description": "List of files backup consists of." - }, - "restore_to": { - "type": "string", - "format": "date-time", - "description": "Exact time DB can be restored to." - }, - "pbm_metadata": { - "$ref": "#/definitions/v1PbmMetadata" - } - }, - "description": "Metadata contains extra artifact data like files it consists of, tool specific data, etc." - }, - "v1MongoDBService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "MongoDB version." - } - }, - "description": "MongoDBService represents a generic MongoDB instance." - }, - "v1MySQLService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "MySQL version." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra parameters to be added to the DSN." - } - }, - "description": "MySQLService represents a generic MySQL instance." - }, - "v1PbmMetadata": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of backup in backup tool representation." - } - }, - "description": "PbmMetadata contains additional data for pbm cli tools." - }, - "v1PitrTimerange": { - "type": "object", - "properties": { - "start_timestamp": { - "type": "string", - "format": "date-time", - "description": "start_timestamp is the time of the first event in the PITR chunk." - }, - "end_timestamp": { - "type": "string", - "format": "date-time", - "description": "end_timestamp is the time of the last event in the PITR chunk." - } - } - }, - "v1RemoveScheduledBackupResponse": { - "type": "object" - }, - "v1ScheduleBackupRequest": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Service identifier where backup should be performed." - }, - "location_id": { - "type": "string", - "description": "Machine-readable location ID." - }, - "folder": { - "type": "string", - "description": "How often backup should be run in cron format.\nFolder on storage for artifact." - }, - "cron_expression": { - "type": "string" - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "First backup wouldn't happen before this time." - }, - "name": { - "type": "string", - "description": "Name of backup." - }, - "description": { - "type": "string", - "description": "Human-readable description." - }, - "enabled": { - "type": "boolean", - "description": "If scheduling is enabled." - }, - "retries": { - "type": "integer", - "format": "int64", - "description": "How many times to retry a failed backup before giving up." - }, - "retry_interval": { - "type": "string", - "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h." - }, - "mode": { - "$ref": "#/definitions/v1BackupMode", - "description": "Backup mode." - }, - "data_model": { - "$ref": "#/definitions/v1DataModel", - "description": "Backup data model (physical or logical)." - }, - "retention": { - "type": "integer", - "format": "int64", - "description": "How many artifacts keep. 0 - unlimited." - } - } - }, - "v1ScheduleBackupResponse": { - "type": "object", - "properties": { - "scheduled_backup_id": { - "type": "string" - } - } - }, - "v1ScheduledBackup": { - "type": "object", - "properties": { - "scheduled_backup_id": { - "type": "string", - "description": "Machine-readable ID." - }, - "service_id": { - "type": "string", - "description": "Machine-readable service ID." - }, - "service_name": { - "type": "string", - "description": "Service name." - }, - "location_id": { - "type": "string", - "description": "Machine-readable location ID." - }, - "location_name": { - "type": "string", - "description": "Location name." - }, - "folder": { - "type": "string", - "description": "Folder on storage for artifact." - }, - "cron_expression": { - "type": "string", - "description": "How often backup will be run in cron format." - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "First backup wouldn't happen before this time." - }, - "name": { - "type": "string", - "description": "Artifact name." - }, - "description": { - "type": "string", - "description": "Description." - }, - "enabled": { - "type": "boolean", - "description": "If scheduling is enabled." - }, - "retries": { - "type": "integer", - "format": "int64", - "description": "How many times to retry a failed backup before giving up." - }, - "retry_interval": { - "type": "string", - "description": "Delay between each retry. Should have a suffix in JSON: 2s, 1m, 1h." - }, - "data_model": { - "$ref": "#/definitions/v1DataModel", - "description": "Backup data model (physical or logical)." - }, - "mode": { - "$ref": "#/definitions/v1BackupMode", - "description": "Backup mode." - }, - "vendor": { - "type": "string", - "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL." - }, - "last_run": { - "type": "string", - "format": "date-time", - "description": "Last run." - }, - "next_run": { - "type": "string", - "format": "date-time", - "description": "Next run." - }, - "retention": { - "type": "integer", - "format": "int64", - "description": "How many artifacts keep. 0 - unlimited." - } - }, - "description": "ScheduledBackup represents scheduled task for backup." - }, - "v1StartBackupRequest": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "location_id": { - "type": "string", - "description": "Machine-readable location ID." - }, - "name": { - "type": "string", - "description": "If empty then name is auto-generated." - }, - "description": { - "type": "string", - "description": "Human-readable description." - }, - "retry_interval": { - "type": "string", - "description": "Delay between each retry. Should have a suffix in JSON: 1s, 1m, 1h." - }, - "retries": { - "type": "integer", - "format": "int64", - "description": "How many times to retry a failed backup before giving up." - }, - "data_model": { - "$ref": "#/definitions/v1DataModel", - "description": "DataModel represents the data model used for the backup." - }, - "folder": { - "type": "string", - "description": "Folder on storage for artifact." - } - } - }, - "v1StartBackupResponse": { - "type": "object", - "properties": { - "artifact_id": { - "type": "string", - "description": "Unique identifier." - } - } - } - } -} diff --git a/api/backup/v1/common.pb.go b/api/backup/v1/common.pb.go index c8274024e38..f84ca11de32 100644 --- a/api/backup/v1/common.pb.go +++ b/api/backup/v1/common.pb.go @@ -423,7 +423,6 @@ var ( (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp } ) - var file_backup_v1_common_proto_depIdxs = []int32{ 2, // 0: backup.v1.Metadata.file_list:type_name -> backup.v1.File 6, // 1: backup.v1.Metadata.restore_to:type_name -> google.protobuf.Timestamp diff --git a/api/backup/v1/common.swagger.json b/api/backup/v1/common.swagger.json deleted file mode 100644 index 4e41fc07567..00000000000 --- a/api/backup/v1/common.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "backup/v1/common.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/backup/v1/errors.pb.go b/api/backup/v1/errors.pb.go index 902adc277c1..5709e5ac243 100644 --- a/api/backup/v1/errors.pb.go +++ b/api/backup/v1/errors.pb.go @@ -169,7 +169,6 @@ var ( (*Error)(nil), // 1: backup.v1.Error } ) - var file_backup_v1_errors_proto_depIdxs = []int32{ 0, // 0: backup.v1.Error.code:type_name -> backup.v1.ErrorCode 1, // [1:1] is the sub-list for method output_type diff --git a/api/backup/v1/errors.swagger.json b/api/backup/v1/errors.swagger.json deleted file mode 100644 index 59e7b363676..00000000000 --- a/api/backup/v1/errors.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "backup/v1/errors.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/backup/v1/locations.pb.go b/api/backup/v1/locations.pb.go index 396b552ee80..72c13dece43 100644 --- a/api/backup/v1/locations.pb.go +++ b/api/backup/v1/locations.pb.go @@ -833,7 +833,6 @@ var ( (*TestLocationConfigResponse)(nil), // 12: backup.v1.TestLocationConfigResponse } ) - var file_backup_v1_locations_proto_depIdxs = []int32{ 0, // 0: backup.v1.Location.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig 1, // 1: backup.v1.Location.s3_config:type_name -> backup.v1.S3LocationConfig diff --git a/api/backup/v1/locations.swagger.json b/api/backup/v1/locations.swagger.json deleted file mode 100644 index 26f36fcb836..00000000000 --- a/api/backup/v1/locations.swagger.json +++ /dev/null @@ -1,353 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "backup/v1/locations.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "LocationsService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/backups/locations": { - "get": { - "summary": "List Backup Locations", - "description": "List backup locations.", - "operationId": "ListLocations", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListLocationsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "LocationsService" - ] - }, - "post": { - "summary": "Add a Backup Location", - "description": "Add a backup location.", - "operationId": "AddLocation", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1AddLocationResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1AddLocationRequest" - } - } - ], - "tags": [ - "LocationsService" - ] - } - }, - "/v1/backups/locations/{location_id}": { - "delete": { - "summary": "Remove a Scheduled Backup", - "description": "Remove a backup location.", - "operationId": "RemoveLocation", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RemoveLocationResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "location_id", - "description": "Machine-readable ID.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "force", - "description": "Force mode", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "LocationsService" - ] - }, - "put": { - "summary": "Change a Backup Location", - "description": "Change a backup location.", - "operationId": "ChangeLocation", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ChangeLocationResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "location_id", - "description": "Machine-readable ID.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/LocationsServiceChangeLocationBody" - } - } - ], - "tags": [ - "LocationsService" - ] - } - }, - "/v1/backups/locations:testConfig": { - "post": { - "summary": "Test a Backup Location and Credentials", - "description": "Test a backup location and credentials.", - "operationId": "TestLocationConfig", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1TestLocationConfigResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1TestLocationConfigRequest" - } - } - ], - "tags": [ - "LocationsService" - ] - } - } - }, - "definitions": { - "LocationsServiceChangeLocationBody": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Location name" - }, - "description": { - "type": "string" - }, - "filesystem_config": { - "$ref": "#/definitions/v1FilesystemLocationConfig", - "description": "Filesystem location configuration. Exactly one config should be set." - }, - "s3_config": { - "$ref": "#/definitions/v1S3LocationConfig", - "description": "S3 Bucket configuration. Exactly one config should be set." - } - } - }, - "backupV1Location": { - "type": "object", - "properties": { - "location_id": { - "type": "string", - "description": "Machine-readable ID." - }, - "name": { - "type": "string", - "title": "Location name" - }, - "description": { - "type": "string", - "title": "Short description" - }, - "filesystem_config": { - "$ref": "#/definitions/v1FilesystemLocationConfig" - }, - "s3_config": { - "$ref": "#/definitions/v1S3LocationConfig" - } - }, - "description": "Location represents single Backup Location." - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1AddLocationRequest": { - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Location name" - }, - "description": { - "type": "string" - }, - "filesystem_config": { - "$ref": "#/definitions/v1FilesystemLocationConfig", - "description": "Filesystem location configuration. Exactly one config should be set." - }, - "s3_config": { - "$ref": "#/definitions/v1S3LocationConfig", - "description": "S3 Bucket configuration. Exactly one config should be set." - } - } - }, - "v1AddLocationResponse": { - "type": "object", - "properties": { - "location_id": { - "type": "string", - "description": "Machine-readable ID." - } - } - }, - "v1ChangeLocationResponse": { - "type": "object" - }, - "v1FilesystemLocationConfig": { - "type": "object", - "properties": { - "path": { - "type": "string" - } - }, - "description": "FilesystemLocationConfig represents file system location config." - }, - "v1ListLocationsResponse": { - "type": "object", - "properties": { - "locations": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/backupV1Location" - } - } - } - }, - "v1RemoveLocationResponse": { - "type": "object" - }, - "v1S3LocationConfig": { - "type": "object", - "properties": { - "endpoint": { - "type": "string" - }, - "access_key": { - "type": "string" - }, - "secret_key": { - "type": "string" - }, - "bucket_name": { - "type": "string" - } - }, - "description": "S3LocationConfig represents S3 bucket configuration." - }, - "v1TestLocationConfigRequest": { - "type": "object", - "properties": { - "filesystem_config": { - "$ref": "#/definitions/v1FilesystemLocationConfig", - "description": "Filesystem location configuration. Exactly one config should be set." - }, - "s3_config": { - "$ref": "#/definitions/v1S3LocationConfig", - "description": "S3 Bucket configuration. Exactly one config should be set." - } - } - }, - "v1TestLocationConfigResponse": { - "type": "object" - } - } -} diff --git a/api/backup/v1/restores.pb.go b/api/backup/v1/restores.pb.go index ee12d6b9285..580c158b119 100644 --- a/api/backup/v1/restores.pb.go +++ b/api/backup/v1/restores.pb.go @@ -625,7 +625,6 @@ var ( (*LogChunk)(nil), // 10: backup.v1.LogChunk } ) - var file_backup_v1_restores_proto_depIdxs = []int32{ 8, // 0: backup.v1.RestoreHistoryItem.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.RestoreHistoryItem.status:type_name -> backup.v1.RestoreStatus diff --git a/api/backup/v1/restores.swagger.json b/api/backup/v1/restores.swagger.json deleted file mode 100644 index e7089206289..00000000000 --- a/api/backup/v1/restores.swagger.json +++ /dev/null @@ -1,303 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "backup/v1/restores.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "RestoreService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/backups/restores": { - "get": { - "summary": "List Restore History", - "description": "List all backup restore history items", - "operationId": "ListRestores", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListRestoresResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "RestoreService" - ] - } - }, - "/v1/backups/restores/{restore_id}/logs": { - "get": { - "summary": "Get Logs", - "description": "Get logs from the underlying tools for a restore job", - "operationId": "GetLogs", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RestoreServiceGetLogsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "restore_id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "offset", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - }, - { - "name": "limit", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - } - ], - "tags": [ - "RestoreService" - ] - } - }, - "/v1/backups/restores:start": { - "post": { - "summary": "Restore from a Backup", - "description": "Could return the Error message in the details containing specific ErrorCode indicating failure reason:\nERROR_CODE_XTRABACKUP_NOT_INSTALLED - xtrabackup is not installed on the service\nERROR_CODE_INVALID_XTRABACKUP - different versions of xtrabackup and xbcloud\nERROR_CODE_INCOMPATIBLE_XTRABACKUP - xtrabackup is not compatible with MySQL for taking a backup\nERROR_CODE_INCOMPATIBLE_TARGET_MYSQL - target MySQL version is not compatible with the artifact for performing a restore of the backup", - "operationId": "RestoreBackup", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RestoreBackupResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1RestoreBackupRequest" - } - } - ], - "tags": [ - "RestoreService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1DataModel": { - "type": "string", - "enum": [ - "DATA_MODEL_UNSPECIFIED", - "DATA_MODEL_PHYSICAL", - "DATA_MODEL_LOGICAL" - ], - "default": "DATA_MODEL_UNSPECIFIED", - "description": "DataModel is a model used for performing a backup." - }, - "v1ListRestoresResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1RestoreHistoryItem" - } - } - } - }, - "v1LogChunk": { - "type": "object", - "properties": { - "chunk_id": { - "type": "integer", - "format": "int64" - }, - "data": { - "type": "string" - } - }, - "description": "LogChunk represent one chunk of logs." - }, - "v1RestoreBackupRequest": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Service identifier where backup should be restored." - }, - "artifact_id": { - "type": "string", - "description": "Artifact id to restore." - }, - "pitr_timestamp": { - "type": "string", - "format": "date-time", - "title": "Timestamp of PITR to restore to" - } - } - }, - "v1RestoreBackupResponse": { - "type": "object", - "properties": { - "restore_id": { - "type": "string", - "description": "Unique restore identifier." - } - } - }, - "v1RestoreHistoryItem": { - "type": "object", - "properties": { - "restore_id": { - "type": "string", - "description": "Machine-readable restore id." - }, - "artifact_id": { - "type": "string", - "description": "ID of the artifact used for restore." - }, - "name": { - "type": "string", - "description": "Artifact name used for restore." - }, - "vendor": { - "type": "string", - "description": "Database vendor e.g. PostgreSQL, MongoDB, MySQL." - }, - "location_id": { - "type": "string", - "description": "Machine-readable location ID." - }, - "location_name": { - "type": "string", - "description": "Location name." - }, - "service_id": { - "type": "string", - "description": "Machine-readable service ID." - }, - "service_name": { - "type": "string", - "description": "Service name." - }, - "data_model": { - "$ref": "#/definitions/v1DataModel", - "description": "Backup data model." - }, - "status": { - "$ref": "#/definitions/v1RestoreStatus", - "description": "Restore status." - }, - "started_at": { - "type": "string", - "format": "date-time", - "description": "Restore start time." - }, - "finished_at": { - "type": "string", - "format": "date-time", - "description": "Restore finish time." - }, - "pitr_timestamp": { - "type": "string", - "format": "date-time", - "description": "PITR timestamp is filled for PITR restores, empty otherwise." - } - }, - "description": "RestoreHistoryItem represents single backup restore item." - }, - "v1RestoreServiceGetLogsResponse": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1LogChunk" - } - }, - "end": { - "type": "boolean" - } - } - }, - "v1RestoreStatus": { - "type": "string", - "enum": [ - "RESTORE_STATUS_UNSPECIFIED", - "RESTORE_STATUS_IN_PROGRESS", - "RESTORE_STATUS_SUCCESS", - "RESTORE_STATUS_ERROR" - ], - "default": "RESTORE_STATUS_UNSPECIFIED", - "description": "RestoreStatus shows the current status of execution of restore." - } - } -} diff --git a/api/common/common.pb.go b/api/common/common.pb.go index 0d05883daa1..2303ccd29ab 100644 --- a/api/common/common.pb.go +++ b/api/common/common.pb.go @@ -147,7 +147,6 @@ var ( nil, // 2: common.StringMap.ValuesEntry } ) - var file_common_common_proto_depIdxs = []int32{ 2, // 0: common.StringMap.values:type_name -> common.StringMap.ValuesEntry 1, // [1:1] is the sub-list for method output_type diff --git a/api/common/common.swagger.json b/api/common/common.swagger.json deleted file mode 100644 index 613dea17f41..00000000000 --- a/api/common/common.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "common/common.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/common/metrics_resolutions.pb.go b/api/common/metrics_resolutions.pb.go index 75e587ba9a5..389e4572992 100644 --- a/api/common/metrics_resolutions.pb.go +++ b/api/common/metrics_resolutions.pb.go @@ -118,7 +118,6 @@ var ( (*durationpb.Duration)(nil), // 1: google.protobuf.Duration } ) - var file_common_metrics_resolutions_proto_depIdxs = []int32{ 1, // 0: common.MetricsResolutions.hr:type_name -> google.protobuf.Duration 1, // 1: common.MetricsResolutions.mr:type_name -> google.protobuf.Duration diff --git a/api/common/metrics_resolutions.swagger.json b/api/common/metrics_resolutions.swagger.json deleted file mode 100644 index 995cc971e4a..00000000000 --- a/api/common/metrics_resolutions.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "common/metrics_resolutions.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/dump/v1beta1/dump.pb.go b/api/dump/v1beta1/dump.pb.go index d031bce6b8f..76f0e473adf 100644 --- a/api/dump/v1beta1/dump.pb.go +++ b/api/dump/v1beta1/dump.pb.go @@ -897,7 +897,6 @@ var ( (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp } ) - var file_dump_v1beta1_dump_proto_depIdxs = []int32{ 0, // 0: dump.v1beta1.Dump.status:type_name -> dump.v1beta1.DumpStatus 14, // 1: dump.v1beta1.Dump.start_time:type_name -> google.protobuf.Timestamp diff --git a/api/dump/v1beta1/dump.swagger.json b/api/dump/v1beta1/dump.swagger.json deleted file mode 100644 index 25bbd5672a3..00000000000 --- a/api/dump/v1beta1/dump.swagger.json +++ /dev/null @@ -1,395 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "dump/v1beta1/dump.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "DumpService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/dumps": { - "get": { - "summary": "List All Dumps", - "description": "List all dumps", - "operationId": "ListDumps", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1ListDumpsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "DumpService" - ] - } - }, - "/v1/dumps/{dump_id}/logs": { - "get": { - "summary": "Get Dump Logs", - "description": "Get logs of a selected dump.", - "operationId": "GetDumpLogs", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1GetDumpLogsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "dump_id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "offset", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - }, - { - "name": "limit", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - } - ], - "tags": [ - "DumpService" - ] - } - }, - "/v1/dumps:batchDelete": { - "post": { - "summary": "Delete Dumps", - "description": "Delete selected dumps.", - "operationId": "DeleteDump", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1DeleteDumpResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1beta1DeleteDumpRequest" - } - } - ], - "tags": [ - "DumpService" - ] - } - }, - "/v1/dumps:start": { - "post": { - "summary": "Start a New Dump", - "description": "Start a new dump.", - "operationId": "StartDump", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1StartDumpResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1beta1StartDumpRequest" - } - } - ], - "tags": [ - "DumpService" - ] - } - }, - "/v1/dumps:upload": { - "post": { - "summary": "Upload Dumps", - "description": "Upload selected dumps to a remote server.", - "operationId": "UploadDump", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1UploadDumpResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1beta1UploadDumpRequest" - } - } - ], - "tags": [ - "DumpService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1beta1DeleteDumpRequest": { - "type": "object", - "properties": { - "dump_ids": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "v1beta1DeleteDumpResponse": { - "type": "object" - }, - "v1beta1Dump": { - "type": "object", - "properties": { - "dump_id": { - "type": "string" - }, - "status": { - "$ref": "#/definitions/v1beta1DumpStatus" - }, - "service_names": { - "type": "array", - "items": { - "type": "string" - } - }, - "start_time": { - "type": "string", - "format": "date-time" - }, - "end_time": { - "type": "string", - "format": "date-time" - }, - "created_at": { - "type": "string", - "format": "date-time" - }, - "encrypted": { - "type": "boolean", - "description": "This field is set to true if the dump was created with encryption enabled, and false otherwise." - } - } - }, - "v1beta1DumpStatus": { - "type": "string", - "enum": [ - "DUMP_STATUS_UNSPECIFIED", - "DUMP_STATUS_IN_PROGRESS", - "DUMP_STATUS_SUCCESS", - "DUMP_STATUS_ERROR" - ], - "default": "DUMP_STATUS_UNSPECIFIED" - }, - "v1beta1GetDumpLogsResponse": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1beta1LogChunk" - } - }, - "end": { - "type": "boolean" - } - } - }, - "v1beta1ListDumpsResponse": { - "type": "object", - "properties": { - "dumps": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1beta1Dump" - } - } - } - }, - "v1beta1LogChunk": { - "type": "object", - "properties": { - "chunk_id": { - "type": "integer", - "format": "int64" - }, - "data": { - "type": "string" - } - }, - "description": "LogChunk represent one chunk of logs." - }, - "v1beta1SFTPParameters": { - "type": "object", - "properties": { - "address": { - "type": "string" - }, - "user": { - "type": "string" - }, - "password": { - "type": "string" - }, - "directory": { - "type": "string" - } - } - }, - "v1beta1StartDumpRequest": { - "type": "object", - "properties": { - "service_names": { - "type": "array", - "items": { - "type": "string" - } - }, - "start_time": { - "type": "string", - "format": "date-time" - }, - "end_time": { - "type": "string", - "format": "date-time" - }, - "export_qan": { - "type": "boolean" - }, - "ignore_load": { - "type": "boolean" - }, - "enable_encryption": { - "type": "boolean", - "description": "If true, the dump will be encrypted. Note that enabling encryption may increase the time required to create the dump." - }, - "encryption_password": { - "type": "string", - "description": "The password used for encryption. It must be at least 8 characters long. This field is required if enable_encryption is true." - } - } - }, - "v1beta1StartDumpResponse": { - "type": "object", - "properties": { - "dump_id": { - "type": "string" - } - } - }, - "v1beta1UploadDumpRequest": { - "type": "object", - "properties": { - "dump_ids": { - "type": "array", - "items": { - "type": "string" - } - }, - "sftp_parameters": { - "$ref": "#/definitions/v1beta1SFTPParameters", - "description": "SFTP upload parameters." - } - } - }, - "v1beta1UploadDumpResponse": { - "type": "object" - } - } -} diff --git a/api/extensions/v1/redact.pb.go b/api/extensions/v1/redact.pb.go index 738ce213118..c850a90df3c 100644 --- a/api/extensions/v1/redact.pb.go +++ b/api/extensions/v1/redact.pb.go @@ -135,7 +135,6 @@ var ( (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions } ) - var file_extensions_v1_redact_proto_depIdxs = []int32{ 1, // 0: extensions.v1.sensitive:extendee -> google.protobuf.FieldOptions 0, // 1: extensions.v1.sensitive:type_name -> extensions.v1.RedactType diff --git a/api/extensions/v1/redact.swagger.json b/api/extensions/v1/redact.swagger.json deleted file mode 100644 index 833d6404187..00000000000 --- a/api/extensions/v1/redact.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "extensions/v1/redact.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index f798cccbcc0..655996ccdbc 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -351,7 +351,6 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) - var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/ha/v1beta1/ha.swagger.json b/api/ha/v1beta1/ha.swagger.json deleted file mode 100644 index eab5d5f5d2f..00000000000 --- a/api/ha/v1beta1/ha.swagger.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "ha/v1beta1/ha.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "HAService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/ha/nodes": { - "get": { - "summary": "List HA Nodes", - "description": "Returns a list of all nodes in the High Availability cluster with their current status and roles.", - "operationId": "ListNodes", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1ListNodesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "tags": [ - "HAService" - ] - } - }, - "/v1/ha/status": { - "get": { - "summary": "HA Status", - "description": "Returns whether High Availability mode is enabled or disabled.", - "operationId": "Status", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1beta1StatusResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "tags": [ - "HAService" - ] - } - } - }, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "v1beta1HANode": { - "type": "object", - "properties": { - "node_name": { - "type": "string", - "description": "Human-readable name of the node." - }, - "role": { - "$ref": "#/definitions/v1beta1NodeRole", - "description": "Role of the node in the cluster." - }, - "status": { - "type": "string", - "description": "Current status of the node from MemberList." - } - }, - "description": "HANode represents a single node in the HA cluster." - }, - "v1beta1ListNodesResponse": { - "type": "object", - "properties": { - "nodes": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1beta1HANode" - }, - "description": "List of nodes in the HA cluster." - } - } - }, - "v1beta1NodeRole": { - "type": "string", - "enum": [ - "NODE_ROLE_UNSPECIFIED", - "NODE_ROLE_LEADER", - "NODE_ROLE_FOLLOWER" - ], - "default": "NODE_ROLE_UNSPECIFIED", - "description": "NodeRole represents the role of a node in the HA cluster." - }, - "v1beta1StatusResponse": { - "type": "object", - "properties": { - "status": { - "type": "string", - "description": "Status of HA mode: \"Enabled\" or \"Disabled\"." - } - } - } - } -} diff --git a/api/inventory/v1/agent_status.pb.go b/api/inventory/v1/agent_status.pb.go index 1e23074d2fc..ace1432a5e8 100644 --- a/api/inventory/v1/agent_status.pb.go +++ b/api/inventory/v1/agent_status.pb.go @@ -128,7 +128,6 @@ var ( AgentStatus(0), // 0: inventory.v1.AgentStatus } ) - var file_inventory_v1_agent_status_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/agent_status.swagger.json b/api/inventory/v1/agent_status.swagger.json deleted file mode 100644 index 2e9902fb83f..00000000000 --- a/api/inventory/v1/agent_status.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "inventory/v1/agent_status.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/inventory/v1/agents.pb.go b/api/inventory/v1/agents.pb.go index 3784fc8b7fc..f5d83515360 100644 --- a/api/inventory/v1/agents.pb.go +++ b/api/inventory/v1/agents.pb.go @@ -12513,7 +12513,6 @@ var ( (*common.StringMap)(nil), // 112: common.StringMap } ) - var file_inventory_v1_agents_proto_depIdxs = []int32{ 68, // 0: inventory.v1.PMMAgent.custom_labels:type_name -> inventory.v1.PMMAgent.CustomLabelsEntry 108, // 1: inventory.v1.VMAgent.status:type_name -> inventory.v1.AgentStatus diff --git a/api/inventory/v1/agents.swagger.json b/api/inventory/v1/agents.swagger.json deleted file mode 100644 index 971cac4cec1..00000000000 --- a/api/inventory/v1/agents.swagger.json +++ /dev/null @@ -1,4490 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "inventory/v1/agents.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "AgentsService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/inventory/agents": { - "get": { - "summary": "List Agents", - "description": "Returns a list of all Agents.", - "operationId": "ListAgents", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListAgentsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "pmm_agent_id", - "description": "Return only Agents started by this pmm-agent.\nExactly one of these parameters should be present: pmm_agent_id, node_id, service_id.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "node_id", - "description": "Return only Agents that provide insights for that Node.\nExactly one of these parameters should be present: pmm_agent_id, node_id, service_id.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "service_id", - "description": "Return only Agents that provide insights for that Service.\nExactly one of these parameters should be present: pmm_agent_id, node_id, service_id.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "agent_type", - "description": "Return only agents of a particular type.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "AGENT_TYPE_UNSPECIFIED", - "AGENT_TYPE_PMM_AGENT", - "AGENT_TYPE_VM_AGENT", - "AGENT_TYPE_NODE_EXPORTER", - "AGENT_TYPE_MYSQLD_EXPORTER", - "AGENT_TYPE_MONGODB_EXPORTER", - "AGENT_TYPE_POSTGRES_EXPORTER", - "AGENT_TYPE_PROXYSQL_EXPORTER", - "AGENT_TYPE_VALKEY_EXPORTER", - "AGENT_TYPE_QAN_MYSQL_PERFSCHEMA_AGENT", - "AGENT_TYPE_QAN_MYSQL_SLOWLOG_AGENT", - "AGENT_TYPE_QAN_MONGODB_PROFILER_AGENT", - "AGENT_TYPE_QAN_MONGODB_MONGOLOG_AGENT", - "AGENT_TYPE_QAN_POSTGRESQL_PGSTATEMENTS_AGENT", - "AGENT_TYPE_QAN_POSTGRESQL_PGSTATMONITOR_AGENT", - "AGENT_TYPE_EXTERNAL_EXPORTER", - "AGENT_TYPE_RDS_EXPORTER", - "AGENT_TYPE_AZURE_DATABASE_EXPORTER", - "AGENT_TYPE_NOMAD_AGENT", - "AGENT_TYPE_RTA_MONGODB_AGENT" - ], - "default": "AGENT_TYPE_UNSPECIFIED" - } - ], - "tags": [ - "AgentsService" - ] - }, - "post": { - "summary": "Add an Agent to Inventory", - "description": "Adds an Agent to Inventory. Only one agent at a time can be passed.", - "operationId": "AddAgent", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1AddAgentResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1AddAgentRequest" - } - } - ], - "tags": [ - "AgentsService" - ] - } - }, - "/v1/inventory/agents/{agent_id}": { - "get": { - "summary": "Get Agent", - "description": "Returns a single Agent by ID.", - "operationId": "GetAgent", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetAgentResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "agent_id", - "description": "Unique randomly generated instance identifier.", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "AgentsService" - ] - }, - "delete": { - "summary": "Remove an Agent from Inventory", - "description": "Removes an Agent from Inventory.", - "operationId": "RemoveAgent", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RemoveAgentResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "agent_id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "force", - "description": "Remove agent with all dependencies.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "AgentsService" - ] - }, - "put": { - "summary": "Update an Agent in Inventory", - "description": "Updates an Agent in Inventory. Only one agent at a time can be passed.", - "operationId": "ChangeAgent", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ChangeAgentResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "agent_id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/AgentsServiceChangeAgentBody" - } - } - ], - "tags": [ - "AgentsService" - ] - } - }, - "/v1/inventory/agents/{agent_id}/logs": { - "get": { - "summary": "Get Agent logs", - "description": "Returns Agent logs by ID.", - "operationId": "GetAgentLogs", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetAgentLogsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "agent_id", - "description": "Unique randomly generated instance identifier.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "limit", - "description": "Limit the number of log lines to this value. Pass 0 for no limit.", - "in": "query", - "required": false, - "type": "integer", - "format": "int64" - } - ], - "tags": [ - "AgentsService" - ] - } - } - }, - "definitions": { - "AgentsServiceChangeAgentBody": { - "type": "object", - "properties": { - "node_exporter": { - "$ref": "#/definitions/v1ChangeNodeExporterParams" - }, - "mysqld_exporter": { - "$ref": "#/definitions/v1ChangeMySQLdExporterParams" - }, - "mongodb_exporter": { - "$ref": "#/definitions/v1ChangeMongoDBExporterParams" - }, - "postgres_exporter": { - "$ref": "#/definitions/v1ChangePostgresExporterParams" - }, - "proxysql_exporter": { - "$ref": "#/definitions/v1ChangeProxySQLExporterParams" - }, - "external_exporter": { - "$ref": "#/definitions/v1ChangeExternalExporterParams" - }, - "rds_exporter": { - "$ref": "#/definitions/v1ChangeRDSExporterParams" - }, - "azure_database_exporter": { - "$ref": "#/definitions/v1ChangeAzureDatabaseExporterParams" - }, - "qan_mysql_perfschema_agent": { - "$ref": "#/definitions/v1ChangeQANMySQLPerfSchemaAgentParams" - }, - "qan_mysql_slowlog_agent": { - "$ref": "#/definitions/v1ChangeQANMySQLSlowlogAgentParams" - }, - "qan_mongodb_profiler_agent": { - "$ref": "#/definitions/v1ChangeQANMongoDBProfilerAgentParams" - }, - "qan_mongodb_mongolog_agent": { - "$ref": "#/definitions/v1ChangeQANMongoDBMongologAgentParams" - }, - "qan_postgresql_pgstatements_agent": { - "$ref": "#/definitions/v1ChangeQANPostgreSQLPgStatementsAgentParams" - }, - "qan_postgresql_pgstatmonitor_agent": { - "$ref": "#/definitions/v1ChangeQANPostgreSQLPgStatMonitorAgentParams" - }, - "nomad_agent": { - "$ref": "#/definitions/v1ChangeNomadAgentParams" - }, - "valkey_exporter": { - "$ref": "#/definitions/v1ChangeValkeyExporterParams" - }, - "rta_mongodb_agent": { - "$ref": "#/definitions/v1ChangeRTAMongoDBAgentParams" - } - } - }, - "commonMetricsResolutions": { - "type": "object", - "properties": { - "hr": { - "type": "string", - "description": "High resolution. In JSON should be represented as a string with number of seconds with `s` suffix." - }, - "mr": { - "type": "string", - "description": "Medium resolution. In JSON should be represented as a string with number of seconds with `s` suffix." - }, - "lr": { - "type": "string", - "description": "Low resolution. In JSON should be represented as a string with number of seconds with `s` suffix." - } - }, - "description": "MetricsResolutions represents Prometheus exporters metrics resolutions." - }, - "commonStringMap": { - "type": "object", - "properties": { - "values": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "description": "A wrapper for map[string]string. This type allows to distinguish between an empty map and a null value." - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1AddAgentRequest": { - "type": "object", - "properties": { - "pmm_agent": { - "$ref": "#/definitions/v1AddPMMAgentParams" - }, - "node_exporter": { - "$ref": "#/definitions/v1AddNodeExporterParams" - }, - "mysqld_exporter": { - "$ref": "#/definitions/v1AddMySQLdExporterParams" - }, - "mongodb_exporter": { - "$ref": "#/definitions/v1AddMongoDBExporterParams" - }, - "postgres_exporter": { - "$ref": "#/definitions/v1AddPostgresExporterParams" - }, - "proxysql_exporter": { - "$ref": "#/definitions/v1AddProxySQLExporterParams" - }, - "external_exporter": { - "$ref": "#/definitions/v1AddExternalExporterParams" - }, - "rds_exporter": { - "$ref": "#/definitions/v1AddRDSExporterParams" - }, - "azure_database_exporter": { - "$ref": "#/definitions/v1AddAzureDatabaseExporterParams" - }, - "qan_mysql_perfschema_agent": { - "$ref": "#/definitions/v1AddQANMySQLPerfSchemaAgentParams" - }, - "qan_mysql_slowlog_agent": { - "$ref": "#/definitions/v1AddQANMySQLSlowlogAgentParams" - }, - "qan_mongodb_profiler_agent": { - "$ref": "#/definitions/v1AddQANMongoDBProfilerAgentParams" - }, - "qan_mongodb_mongolog_agent": { - "$ref": "#/definitions/v1AddQANMongoDBMongologAgentParams" - }, - "qan_postgresql_pgstatements_agent": { - "$ref": "#/definitions/v1AddQANPostgreSQLPgStatementsAgentParams" - }, - "qan_postgresql_pgstatmonitor_agent": { - "$ref": "#/definitions/v1AddQANPostgreSQLPgStatMonitorAgentParams" - }, - "valkey_exporter": { - "$ref": "#/definitions/v1AddValkeyExporterParams" - }, - "rta_mongodb_agent": { - "$ref": "#/definitions/v1AddRTAMongoDBAgentParams" - } - } - }, - "v1AddAgentResponse": { - "type": "object", - "properties": { - "pmm_agent": { - "$ref": "#/definitions/v1PMMAgent" - }, - "node_exporter": { - "$ref": "#/definitions/v1NodeExporter" - }, - "mysqld_exporter": { - "$ref": "#/definitions/v1MySQLdExporter" - }, - "mongodb_exporter": { - "$ref": "#/definitions/v1MongoDBExporter" - }, - "postgres_exporter": { - "$ref": "#/definitions/v1PostgresExporter" - }, - "proxysql_exporter": { - "$ref": "#/definitions/v1ProxySQLExporter" - }, - "external_exporter": { - "$ref": "#/definitions/v1ExternalExporter" - }, - "rds_exporter": { - "$ref": "#/definitions/v1RDSExporter" - }, - "azure_database_exporter": { - "$ref": "#/definitions/v1AzureDatabaseExporter" - }, - "qan_mysql_perfschema_agent": { - "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" - }, - "qan_mysql_slowlog_agent": { - "$ref": "#/definitions/v1QANMySQLSlowlogAgent" - }, - "qan_mongodb_profiler_agent": { - "$ref": "#/definitions/v1QANMongoDBProfilerAgent" - }, - "qan_mongodb_mongolog_agent": { - "$ref": "#/definitions/v1QANMongoDBMongologAgent" - }, - "qan_postgresql_pgstatements_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" - }, - "qan_postgresql_pgstatmonitor_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" - }, - "valkey_exporter": { - "$ref": "#/definitions/v1ValkeyExporter" - }, - "rta_mongodb_agent": { - "$ref": "#/definitions/v1RTAMongoDBAgent" - } - } - }, - "v1AddAzureDatabaseExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "node_id": { - "type": "string", - "description": "Node identifier." - }, - "azure_client_id": { - "type": "string", - "title": "Azure client ID" - }, - "azure_client_secret": { - "type": "string", - "title": "Azure client secret" - }, - "azure_tenant_id": { - "type": "string", - "title": "Azure tanant ID" - }, - "azure_subscription_id": { - "type": "string", - "title": "Azure subscription ID" - }, - "azure_resource_group": { - "type": "string", - "description": "Azure resource group." - }, - "azure_database_resource_type": { - "type": "string", - "title": "Azure resource type (mysql, maria, postgres)" - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - } - }, - "v1AddExternalExporterParams": { - "type": "object", - "properties": { - "runs_on_node_id": { - "type": "string", - "description": "The node identifier where this instance is run." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "HTTP basic auth username for collecting metrics." - }, - "password": { - "type": "string", - "description": "HTTP basic auth password for collecting metrics." - }, - "scheme": { - "type": "string", - "description": "Scheme to generate URI to exporter metrics endpoints(default: http)." - }, - "metrics_path": { - "type": "string", - "description": "Path under which metrics are exposed, used to generate URI(default: /metrics)." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname verification." - } - } - }, - "v1AddMongoDBExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for scraping metrics." - }, - "password": { - "type": "string", - "description": "MongoDB password for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "authentication_mechanism": { - "type": "string", - "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." - }, - "authentication_database": { - "type": "string", - "description": "Authentication database." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "stats_collections": { - "type": "array", - "items": { - "type": "string" - }, - "title": "List of colletions to get stats from. Can use *" - }, - "collections_limit": { - "type": "integer", - "format": "int32", - "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "environment_variable_names": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Environment variable names to pass to the exporter.\nValues will be resolved from pmm-agent's environment when starting the exporter." - }, - "enable_all_collectors": { - "type": "boolean", - "description": "Enable all collectors." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddMySQLdExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for scraping metrics." - }, - "password": { - "type": "string", - "description": "MySQL password for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "tablestats_group_table_limit": { - "type": "integer", - "format": "int32", - "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddNodeExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Expose the node_exporter process on all public interfaces" - } - } - }, - "v1AddPMMAgentParams": { - "type": "object", - "properties": { - "runs_on_node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddPostgresExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for scraping metrics." - }, - "password": { - "type": "string", - "description": "PostgreSQL password for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "tls_ca": { - "type": "string", - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "description": "TLS Certifcate." - }, - "tls_key": { - "type": "string", - "description": "TLS Certificate Key." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "max_exporter_connections": { - "type": "integer", - "format": "int32", - "description": "Maximum number of connections that exporter can open to the database instance." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddProxySQLExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "ProxySQL username for scraping metrics." - }, - "password": { - "type": "string", - "description": "ProxySQL password for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddQANMongoDBMongologAgentParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profile data." - }, - "password": { - "type": "string", - "description": "MongoDB password for getting profile data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "authentication_mechanism": { - "type": "string", - "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." - }, - "authentication_database": { - "type": "string", - "description": "Authentication database." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for agent." - } - } - }, - "v1AddQANMongoDBProfilerAgentParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profile data." - }, - "password": { - "type": "string", - "description": "MongoDB password for getting profile data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "authentication_mechanism": { - "type": "string", - "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." - }, - "authentication_database": { - "type": "string", - "description": "Authentication database." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for agent." - } - } - }, - "v1AddQANMySQLPerfSchemaAgentParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for getting performance data." - }, - "password": { - "type": "string", - "description": "MySQL password for getting performance data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "description": "Disable query examples." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - } - } - }, - "v1AddQANMySQLSlowlogAgentParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for getting slowlog data." - }, - "password": { - "type": "string", - "description": "MySQL password for getting slowlog data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "description": "Disable query examples." - }, - "max_slowlog_file_size": { - "type": "string", - "format": "int64", - "description": "Rotate slowlog file at this size if \u003e 0.\nUse zero or negative value to disable rotation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - } - } - }, - "v1AddQANPostgreSQLPgStatMonitorAgentParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for getting pg stat monitor data." - }, - "password": { - "type": "string", - "description": "PostgreSQL password for getting pg stat monitor data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "description": "Disable query examples." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "tls_ca": { - "type": "string", - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "description": "TLS Certifcate." - }, - "tls_key": { - "type": "string", - "description": "TLS Certificate Key." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - } - }, - "v1AddQANPostgreSQLPgStatementsAgentParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for getting pg stat statements data." - }, - "password": { - "type": "string", - "description": "PostgreSQL password for getting pg stat statements data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "tls_ca": { - "type": "string", - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "description": "TLS Certifcate." - }, - "tls_key": { - "type": "string", - "description": "TLS Certificate Key." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - } - }, - "v1AddRDSExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "node_id": { - "type": "string", - "description": "Node identifier." - }, - "aws_access_key": { - "type": "string", - "description": "AWS Access Key." - }, - "aws_secret_key": { - "type": "string", - "description": "AWS Secret Key." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "disable_basic_metrics": { - "type": "boolean", - "description": "Disable basic metrics." - }, - "disable_enhanced_metrics": { - "type": "boolean", - "description": "Disable enhanced metrics." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - } - }, - "v1AddRTAMongoDBAgentParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting queries data." - }, - "password": { - "type": "string", - "description": "MongoDB password for getting queries data." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for agent." - }, - "tls": { - "type": "boolean", - "description": "MongoDB specific options.\nUse TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "authentication_mechanism": { - "type": "string", - "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." - }, - "rta_options": { - "$ref": "#/definitions/v1RTAOptions", - "description": "Real-Time Analytics options." - } - } - }, - "v1AddValkeyExporterParams": { - "type": "object", - "properties": { - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "Valkey username for scraping metrics." - }, - "password": { - "type": "string", - "description": "Valkey password for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "push_metrics": { - "type": "boolean", - "description": "Enables push metrics mode for exporter." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "tls_ca": { - "type": "string", - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "description": "TLS Certifcate." - }, - "tls_key": { - "type": "string", - "description": "TLS Certificate Key." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AgentStatus": { - "type": "string", - "enum": [ - "AGENT_STATUS_UNSPECIFIED", - "AGENT_STATUS_STARTING", - "AGENT_STATUS_INITIALIZATION_ERROR", - "AGENT_STATUS_RUNNING", - "AGENT_STATUS_WAITING", - "AGENT_STATUS_STOPPING", - "AGENT_STATUS_DONE", - "AGENT_STATUS_UNKNOWN" - ], - "default": "AGENT_STATUS_UNSPECIFIED", - "description": "AgentStatus represents actual Agent status.\n\n - AGENT_STATUS_STARTING: Agent is starting.\n - AGENT_STATUS_INITIALIZATION_ERROR: Agent encountered error when starting.\n - AGENT_STATUS_RUNNING: Agent is running.\n - AGENT_STATUS_WAITING: Agent encountered error and will be restarted automatically soon.\n - AGENT_STATUS_STOPPING: Agent is stopping.\n - AGENT_STATUS_DONE: Agent has been stopped or disabled.\n - AGENT_STATUS_UNKNOWN: Agent is not connected, we don't know anything about it's state." - }, - "v1AgentType": { - "type": "string", - "enum": [ - "AGENT_TYPE_UNSPECIFIED", - "AGENT_TYPE_PMM_AGENT", - "AGENT_TYPE_VM_AGENT", - "AGENT_TYPE_NODE_EXPORTER", - "AGENT_TYPE_MYSQLD_EXPORTER", - "AGENT_TYPE_MONGODB_EXPORTER", - "AGENT_TYPE_POSTGRES_EXPORTER", - "AGENT_TYPE_PROXYSQL_EXPORTER", - "AGENT_TYPE_VALKEY_EXPORTER", - "AGENT_TYPE_QAN_MYSQL_PERFSCHEMA_AGENT", - "AGENT_TYPE_QAN_MYSQL_SLOWLOG_AGENT", - "AGENT_TYPE_QAN_MONGODB_PROFILER_AGENT", - "AGENT_TYPE_QAN_MONGODB_MONGOLOG_AGENT", - "AGENT_TYPE_QAN_POSTGRESQL_PGSTATEMENTS_AGENT", - "AGENT_TYPE_QAN_POSTGRESQL_PGSTATMONITOR_AGENT", - "AGENT_TYPE_EXTERNAL_EXPORTER", - "AGENT_TYPE_RDS_EXPORTER", - "AGENT_TYPE_AZURE_DATABASE_EXPORTER", - "AGENT_TYPE_NOMAD_AGENT", - "AGENT_TYPE_RTA_MONGODB_AGENT" - ], - "default": "AGENT_TYPE_UNSPECIFIED", - "description": "AgentType describes supported Agent types." - }, - "v1AzureDatabaseExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "node_id": { - "type": "string", - "description": "Node identifier." - }, - "azure_database_subscription_id": { - "type": "string", - "description": "Azure database subscription ID." - }, - "azure_database_resource_type": { - "type": "string", - "title": "Azure database resource type (mysql, maria, postgres)" - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status (the same for several configurations)." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics (the same for several configurations)." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if the exporter operates in push metrics mode." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - } - }, - "description": "AzureDatabaseExporter runs on Generic or Container Node and exposes RemoteAzure Node metrics." - }, - "v1ChangeAgentResponse": { - "type": "object", - "properties": { - "node_exporter": { - "$ref": "#/definitions/v1NodeExporter" - }, - "mysqld_exporter": { - "$ref": "#/definitions/v1MySQLdExporter" - }, - "mongodb_exporter": { - "$ref": "#/definitions/v1MongoDBExporter" - }, - "postgres_exporter": { - "$ref": "#/definitions/v1PostgresExporter" - }, - "proxysql_exporter": { - "$ref": "#/definitions/v1ProxySQLExporter" - }, - "external_exporter": { - "$ref": "#/definitions/v1ExternalExporter" - }, - "rds_exporter": { - "$ref": "#/definitions/v1RDSExporter" - }, - "azure_database_exporter": { - "$ref": "#/definitions/v1AzureDatabaseExporter" - }, - "qan_mysql_perfschema_agent": { - "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" - }, - "qan_mysql_slowlog_agent": { - "$ref": "#/definitions/v1QANMySQLSlowlogAgent" - }, - "qan_mongodb_profiler_agent": { - "$ref": "#/definitions/v1QANMongoDBProfilerAgent" - }, - "qan_mongodb_mongolog_agent": { - "$ref": "#/definitions/v1QANMongoDBMongologAgent" - }, - "qan_postgresql_pgstatements_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" - }, - "qan_postgresql_pgstatmonitor_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" - }, - "nomad_agent": { - "$ref": "#/definitions/v1NomadAgent" - }, - "valkey_exporter": { - "$ref": "#/definitions/v1ValkeyExporter" - }, - "rta_mongodb_agent": { - "$ref": "#/definitions/v1RTAMongoDBAgent" - } - } - }, - "v1ChangeAzureDatabaseExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "azure_client_id": { - "type": "string", - "x-nullable": true, - "title": "Azure client ID" - }, - "azure_client_secret": { - "type": "string", - "x-nullable": true, - "title": "Azure client secret" - }, - "azure_tenant_id": { - "type": "string", - "x-nullable": true, - "title": "Azure tenant ID" - }, - "azure_subscription_id": { - "type": "string", - "x-nullable": true, - "title": "Azure subscription ID" - }, - "azure_resource_group": { - "type": "string", - "x-nullable": true, - "description": "Azure resource group." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeExternalExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "HTTP basic auth username for collecting metrics." - }, - "scheme": { - "type": "string", - "x-nullable": true, - "description": "Scheme to generate URI to exporter metrics endpoints." - }, - "metrics_path": { - "type": "string", - "x-nullable": true, - "description": "Path under which metrics are exposed, used to generate URI." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "x-nullable": true, - "description": "Listen port for scraping metrics." - } - } - }, - "v1ChangeMongoDBExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "MongoDB username for scraping metrics." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "MongoDB password for scraping metrics." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "x-nullable": true, - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "x-nullable": true, - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "Certificate Authority certificate chain." - }, - "skip_connection_check": { - "type": "boolean", - "x-nullable": true, - "description": "Skip connection check." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "authentication_mechanism": { - "type": "string", - "x-nullable": true, - "description": "Authentication mechanism." - }, - "authentication_database": { - "type": "string", - "x-nullable": true, - "description": "Authentication database." - }, - "agent_password": { - "type": "string", - "x-nullable": true, - "description": "Custom password for exporter endpoint /metrics." - }, - "stats_collections": { - "type": "array", - "items": { - "type": "string" - }, - "title": "List of collections to get stats from. Can use *" - }, - "collections_limit": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server is less than this value. 0: no limit" - }, - "enable_all_collectors": { - "type": "boolean", - "x-nullable": true, - "description": "Enable all collectors." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "x-nullable": true, - "description": "Optionally expose the exporter process on all public interfaces." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1ChangeMySQLdExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "MySQL username for scraping metrics." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "MySQL password for scraping metrics." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "x-nullable": true, - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "x-nullable": true, - "description": "Password for decrypting tls_cert." - }, - "tablestats_group_table_limit": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Tablestats group collectors will be disabled if there are more than that number of tables." - }, - "skip_connection_check": { - "type": "boolean", - "x-nullable": true, - "description": "Skip connection check." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "agent_password": { - "type": "string", - "x-nullable": true, - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "x-nullable": true, - "description": "Optionally expose the exporter process on all public interfaces." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1ChangeNodeExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "x-nullable": true, - "description": "Expose the node_exporter process on all public interfaces." - } - } - }, - "v1ChangeNomadAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - } - } - }, - "v1ChangePostgresExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "PostgreSQL username for scraping metrics." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "PostgreSQL password for scraping metrics." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "skip_connection_check": { - "type": "boolean", - "x-nullable": true, - "description": "Skip connection check." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "x-nullable": true, - "description": "TLS Certificate." - }, - "tls_key": { - "type": "string", - "x-nullable": true, - "description": "TLS Certificate Key." - }, - "agent_password": { - "type": "string", - "x-nullable": true, - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Limit of databases for auto-discovery." - }, - "expose_exporter": { - "type": "boolean", - "x-nullable": true, - "description": "Optionally expose the exporter process on all public interfaces." - }, - "max_exporter_connections": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Maximum number of connections that exporter can open to the database instance." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1ChangeProxySQLExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "ProxySQL username for scraping metrics." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "ProxySQL password for scraping metrics." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "agent_password": { - "type": "string", - "x-nullable": true, - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "x-nullable": true, - "description": "Optionally expose the exporter process on all public interfaces." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1ChangeQANMongoDBMongologAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "MongoDB username for getting mongolog data." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "MongoDB password for getting mongolog data." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "x-nullable": true, - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "x-nullable": true, - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "Certificate Authority certificate chain." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "authentication_mechanism": { - "type": "string", - "x-nullable": true, - "description": "Authentication mechanism." - }, - "authentication_database": { - "type": "string", - "x-nullable": true, - "description": "Authentication database." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeQANMongoDBProfilerAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "MongoDB username for getting profile data." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "MongoDB password for getting profile data." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "x-nullable": true, - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "x-nullable": true, - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "Certificate Authority certificate chain." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "authentication_mechanism": { - "type": "string", - "x-nullable": true, - "description": "Authentication mechanism." - }, - "authentication_database": { - "type": "string", - "x-nullable": true, - "description": "Authentication database." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeQANMySQLPerfSchemaAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "MySQL username for getting performance data." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "MySQL password for getting performance data." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "x-nullable": true, - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "x-nullable": true, - "description": "Password for decrypting tls_cert." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "x-nullable": true, - "description": "Disable query examples." - }, - "skip_connection_check": { - "type": "boolean", - "x-nullable": true, - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "x-nullable": true, - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeQANMySQLSlowlogAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "MySQL username for getting slowlog data." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "MySQL password for getting slowlog data." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "x-nullable": true, - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "x-nullable": true, - "description": "Password for decrypting tls_cert." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "x-nullable": true, - "description": "Disable query examples." - }, - "max_slowlog_file_size": { - "type": "string", - "format": "int64", - "x-nullable": true, - "description": "Rotate slowlog file at this size if \u003e 0." - }, - "skip_connection_check": { - "type": "boolean", - "x-nullable": true, - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "x-nullable": true, - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeQANPostgreSQLPgStatMonitorAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "PostgreSQL username for getting pg stat monitor data." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "PostgreSQL password for getting pg stat monitor data." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "x-nullable": true, - "description": "Disable query examples." - }, - "disable_comments_parsing": { - "type": "boolean", - "x-nullable": true, - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "x-nullable": true, - "description": "TLS Certificate." - }, - "tls_key": { - "type": "string", - "x-nullable": true, - "description": "TLS Certificate Key." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeQANPostgreSQLPgStatementsAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "PostgreSQL username for getting pg stat statements data." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "PostgreSQL password for getting pg stat statements data." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "disable_comments_parsing": { - "type": "boolean", - "x-nullable": true, - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "x-nullable": true, - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "x-nullable": true, - "description": "TLS Certificate." - }, - "tls_key": { - "type": "string", - "x-nullable": true, - "description": "TLS Certificate Key." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeRDSExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "aws_access_key": { - "type": "string", - "x-nullable": true, - "description": "AWS Access Key." - }, - "aws_secret_key": { - "type": "string", - "x-nullable": true, - "description": "AWS Secret Key." - }, - "disable_basic_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Disable basic metrics." - }, - "disable_enhanced_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Disable enhanced metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - } - } - }, - "v1ChangeRTAMongoDBAgentParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "MongoDB username for getting profile data." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "MongoDB password for getting profile data." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "x-nullable": true, - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "x-nullable": true, - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "Certificate Authority certificate chain." - }, - "authentication_mechanism": { - "type": "string", - "x-nullable": true, - "description": "Authentication mechanism." - }, - "rta_options": { - "$ref": "#/definitions/v1RTAOptions", - "x-nullable": true, - "description": "Real-Time Analytics options." - } - } - }, - "v1ChangeValkeyExporterParams": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "x-nullable": true, - "description": "Enable this Agent. Agents are enabled by default when they get added." - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - }, - "enable_push_metrics": { - "type": "boolean", - "x-nullable": true, - "description": "Enables push metrics with vmagent." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "username": { - "type": "string", - "x-nullable": true, - "description": "Valkey username for scraping metrics." - }, - "password": { - "type": "string", - "x-nullable": true, - "description": "Valkey password for scraping metrics." - }, - "tls": { - "type": "boolean", - "x-nullable": true, - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "x-nullable": true, - "description": "Skip TLS certificate and hostname validation." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "tls_ca": { - "type": "string", - "x-nullable": true, - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "x-nullable": true, - "description": "TLS Certifcate." - }, - "tls_key": { - "type": "string", - "x-nullable": true, - "description": "TLS Certificate Key." - }, - "agent_password": { - "type": "string", - "x-nullable": true, - "description": "Custom password for exporter endpoint /metrics." - }, - "expose_exporter": { - "type": "boolean", - "x-nullable": true, - "title": "Optionally expose the exporter process on all public interfaces" - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "x-nullable": true, - "description": "Log level for exporter." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1ExternalExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "runs_on_node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "disabled": { - "type": "boolean", - "description": "If disabled, metrics from this exporter will not be collected." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "HTTP basic auth username for collecting metrics." - }, - "scheme": { - "type": "string", - "description": "Scheme to generate URI to exporter metrics endpoints." - }, - "metrics_path": { - "type": "string", - "description": "Path under which metrics are exposed, used to generate URI." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname verification." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - } - }, - "description": "ExternalExporter runs on any Node type, including Remote Node." - }, - "v1GetAgentLogsResponse": { - "type": "object", - "properties": { - "logs": { - "type": "array", - "items": { - "type": "string" - } - }, - "agent_config_log_lines_count": { - "type": "integer", - "format": "int64" - } - } - }, - "v1GetAgentResponse": { - "type": "object", - "properties": { - "pmm_agent": { - "$ref": "#/definitions/v1PMMAgent" - }, - "vmagent": { - "$ref": "#/definitions/v1VMAgent" - }, - "node_exporter": { - "$ref": "#/definitions/v1NodeExporter" - }, - "mysqld_exporter": { - "$ref": "#/definitions/v1MySQLdExporter" - }, - "mongodb_exporter": { - "$ref": "#/definitions/v1MongoDBExporter" - }, - "postgres_exporter": { - "$ref": "#/definitions/v1PostgresExporter" - }, - "proxysql_exporter": { - "$ref": "#/definitions/v1ProxySQLExporter" - }, - "qan_mysql_perfschema_agent": { - "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" - }, - "qan_mysql_slowlog_agent": { - "$ref": "#/definitions/v1QANMySQLSlowlogAgent" - }, - "qan_mongodb_profiler_agent": { - "$ref": "#/definitions/v1QANMongoDBProfilerAgent" - }, - "qan_mongodb_mongolog_agent": { - "$ref": "#/definitions/v1QANMongoDBMongologAgent" - }, - "qan_postgresql_pgstatements_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" - }, - "qan_postgresql_pgstatmonitor_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" - }, - "external_exporter": { - "$ref": "#/definitions/v1ExternalExporter" - }, - "rds_exporter": { - "$ref": "#/definitions/v1RDSExporter" - }, - "azure_database_exporter": { - "$ref": "#/definitions/v1AzureDatabaseExporter" - }, - "nomad_agent": { - "$ref": "#/definitions/v1NomadAgent" - }, - "valkey_exporter": { - "$ref": "#/definitions/v1ValkeyExporter" - }, - "rta_mongodb_agent": { - "$ref": "#/definitions/v1RTAMongoDBAgent" - } - } - }, - "v1ListAgentsResponse": { - "type": "object", - "properties": { - "pmm_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1PMMAgent" - } - }, - "vm_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1VMAgent" - } - }, - "node_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1NodeExporter" - } - }, - "mysqld_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MySQLdExporter" - } - }, - "mongodb_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MongoDBExporter" - } - }, - "postgres_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1PostgresExporter" - } - }, - "proxysql_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ProxySQLExporter" - } - }, - "qan_mysql_perfschema_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" - } - }, - "qan_mysql_slowlog_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QANMySQLSlowlogAgent" - } - }, - "qan_mongodb_profiler_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QANMongoDBProfilerAgent" - } - }, - "qan_mongodb_mongolog_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QANMongoDBMongologAgent" - } - }, - "qan_postgresql_pgstatements_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" - } - }, - "qan_postgresql_pgstatmonitor_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" - } - }, - "external_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ExternalExporter" - } - }, - "rds_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1RDSExporter" - } - }, - "azure_database_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1AzureDatabaseExporter" - } - }, - "nomad_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1NomadAgent" - } - }, - "valkey_exporter": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ValkeyExporter" - } - }, - "rta_mongodb_agent": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1RTAMongoDBAgent" - } - } - } - }, - "v1LogLevel": { - "type": "string", - "enum": [ - "LOG_LEVEL_UNSPECIFIED", - "LOG_LEVEL_FATAL", - "LOG_LEVEL_ERROR", - "LOG_LEVEL_WARN", - "LOG_LEVEL_INFO", - "LOG_LEVEL_DEBUG" - ], - "default": "LOG_LEVEL_UNSPECIFIED", - "description": "- LOG_LEVEL_UNSPECIFIED: Auto", - "title": "Log level for exporters" - }, - "v1MongoDBExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "stats_collections": { - "type": "array", - "items": { - "type": "string" - }, - "title": "List of colletions to get stats from. Can use *" - }, - "collections_limit": { - "type": "integer", - "format": "int32", - "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" - }, - "enable_all_collectors": { - "type": "boolean", - "description": "Enable all collectors." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "environment_variable_names": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Environment variable names passed to the exporter." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "MongoDBExporter runs on Generic or Container Node and exposes MongoDB Service metrics." - }, - "v1MySQLdExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "tablestats_group_table_limit": { - "type": "integer", - "format": "int32", - "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "table_count": { - "type": "integer", - "format": "int32", - "description": "Actual table count at the moment of adding." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "tablestats_group_disabled": { - "type": "boolean", - "description": "True if tablestats group collectors are currently disabled." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "MySQLdExporter runs on Generic or Container Node and exposes MySQL Service metrics." - }, - "v1NodeExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - } - }, - "description": "NodeExporter runs on Generic or Container Node and exposes its metrics." - }, - "v1NomadAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - } - } - }, - "v1PMMAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "runs_on_node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "connected": { - "type": "boolean", - "description": "True if Agent is running and connected to pmm-managed." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - } - }, - "description": "PMMAgent runs on Generic or Container Node." - }, - "v1PostgresExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "max_exporter_connections": { - "type": "integer", - "format": "int32", - "description": "Maximum number of connections that exporter can open to the database instance." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "PostgresExporter runs on Generic or Container Node and exposes PostgreSQL Service metrics." - }, - "v1ProxySQLExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "ProxySQL username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "ProxySQLExporter runs on Generic or Container Node and exposes ProxySQL Service metrics." - }, - "v1QANMongoDBMongologAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profiler data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANMongoDBMongologAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." - }, - "v1QANMongoDBProfilerAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profiler data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANMongoDBProfilerAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." - }, - "v1QANMySQLPerfSchemaAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for getting performance data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "query_examples_disabled": { - "type": "boolean", - "description": "True if query examples are disabled." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - } - }, - "description": "QANMySQLPerfSchemaAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." - }, - "v1QANMySQLSlowlogAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for getting performance data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "title": "Limit query length in QAN (default: server-defined; -1: no limit)" - }, - "query_examples_disabled": { - "type": "boolean", - "description": "True if query examples are disabled." - }, - "max_slowlog_file_size": { - "type": "string", - "format": "int64", - "description": "Slowlog file is rotated at this size if \u003e 0." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "title": "mod tidy" - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - } - }, - "description": "QANMySQLSlowlogAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." - }, - "v1QANPostgreSQLPgStatMonitorAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for getting pg stat monitor data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "query_examples_disabled": { - "type": "boolean", - "description": "True if query examples are disabled." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANPostgreSQLPgStatMonitorAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." - }, - "v1QANPostgreSQLPgStatementsAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for getting pg stat statements data." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANPostgreSQLPgStatementsAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." - }, - "v1RDSExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "node_id": { - "type": "string", - "description": "Node identifier." - }, - "aws_access_key": { - "type": "string", - "description": "AWS Access Key." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status (the same for several configurations)." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics (the same for several configurations)." - }, - "basic_metrics_disabled": { - "type": "boolean", - "description": "Basic metrics are disabled." - }, - "enhanced_metrics_disabled": { - "type": "boolean", - "description": "Enhanced metrics are disabled." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - } - }, - "description": "RDSExporter runs on Generic or Container Node and exposes RemoteRDS Node metrics." - }, - "v1RTAMongoDBAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique agent identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profiler data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "rta_options": { - "$ref": "#/definitions/v1RTAOptions", - "description": "Real-Time Analytics options." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "RTAMongoDBAgent runs within pmm-agent and sends MongoDB Real-Time Query Analytics data to the PMM Server." - }, - "v1RTAOptions": { - "type": "object", - "properties": { - "collect_interval": { - "type": "string", - "description": "Query collect interval (default 2s is set by server)." - } - }, - "description": "RTAOptions holds Real-Time Query Analytics agent options." - }, - "v1RemoveAgentResponse": { - "type": "object" - }, - "v1VMAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - } - }, - "description": "VMAgent runs on Generic or Container Node alongside pmm-agent.\nIt scrapes other exporter Agents that are configured with push_metrics_enabled\nand uses Prometheus remote write protocol to push metrics to PMM Server." - }, - "v1ValkeyExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "Valkey username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname verification." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "ValkeyExporter runs on Generic or Container Node and exposes Valkey Service metrics." - } - } -} diff --git a/api/inventory/v1/log_level.pb.go b/api/inventory/v1/log_level.pb.go index ff4d79ca3f2..47f0373d578 100644 --- a/api/inventory/v1/log_level.pb.go +++ b/api/inventory/v1/log_level.pb.go @@ -114,7 +114,6 @@ var ( LogLevel(0), // 0: inventory.v1.LogLevel } ) - var file_inventory_v1_log_level_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/log_level.swagger.json b/api/inventory/v1/log_level.swagger.json deleted file mode 100644 index 0e16c21a9e1..00000000000 --- a/api/inventory/v1/log_level.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "inventory/v1/log_level.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/inventory/v1/nodes.pb.go b/api/inventory/v1/nodes.pb.go index 447663477a9..e0186c91815 100644 --- a/api/inventory/v1/nodes.pb.go +++ b/api/inventory/v1/nodes.pb.go @@ -2043,7 +2043,6 @@ var ( nil, // 28: inventory.v1.AddRemoteAzureNodeParams.CustomLabelsEntry } ) - var file_inventory_v1_nodes_proto_depIdxs = []int32{ 19, // 0: inventory.v1.GenericNode.custom_labels:type_name -> inventory.v1.GenericNode.CustomLabelsEntry 20, // 1: inventory.v1.ContainerNode.custom_labels:type_name -> inventory.v1.ContainerNode.CustomLabelsEntry diff --git a/api/inventory/v1/nodes.swagger.json b/api/inventory/v1/nodes.swagger.json deleted file mode 100644 index 32958ba155f..00000000000 --- a/api/inventory/v1/nodes.swagger.json +++ /dev/null @@ -1,708 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "inventory/v1/nodes.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "NodesService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/inventory/nodes": { - "get": { - "summary": "List Nodes", - "description": "Returns a list of all Nodes.", - "operationId": "ListNodes", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListNodesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_type", - "description": "Return only Nodes with matching Node type.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "NODE_TYPE_UNSPECIFIED", - "NODE_TYPE_GENERIC_NODE", - "NODE_TYPE_CONTAINER_NODE", - "NODE_TYPE_REMOTE_NODE", - "NODE_TYPE_REMOTE_RDS_NODE", - "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" - ], - "default": "NODE_TYPE_UNSPECIFIED" - } - ], - "tags": [ - "NodesService" - ] - }, - "post": { - "summary": "Add a Node", - "description": "Adds a Node.", - "operationId": "AddNode", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1AddNodeResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1AddNodeRequest" - } - } - ], - "tags": [ - "NodesService" - ] - } - }, - "/v1/inventory/nodes/{node_id}": { - "get": { - "summary": "Get a Node", - "description": "Returns a single Node by ID.", - "operationId": "GetNode", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetNodeResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_id", - "description": "Unique randomly generated instance identifier.", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "NodesService" - ] - }, - "delete": { - "summary": "Remove a Node", - "description": "Removes a Node.", - "operationId": "RemoveNode", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RemoveNodeResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_id", - "description": "Unique randomly generated instance identifier.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "force", - "description": "Remove node with all dependencies.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "NodesService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1AddContainerNodeParams": { - "type": "object", - "properties": { - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id of the Generic Node where this Container Node runs." - }, - "container_id": { - "type": "string", - "description": "Container identifier. If specified, must be a unique Docker container identifier." - }, - "container_name": { - "type": "string", - "description": "Container name." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddGenericNodeParams": { - "type": "object", - "properties": { - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id." - }, - "distro": { - "type": "string", - "description": "Linux distribution name and version." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddNodeRequest": { - "type": "object", - "properties": { - "generic": { - "$ref": "#/definitions/v1AddGenericNodeParams" - }, - "container": { - "$ref": "#/definitions/v1AddContainerNodeParams" - }, - "remote": { - "$ref": "#/definitions/v1AddRemoteNodeParams" - }, - "remote_rds": { - "$ref": "#/definitions/v1AddRemoteRDSNodeParams" - }, - "remote_azure": { - "$ref": "#/definitions/v1AddRemoteAzureNodeParams" - } - } - }, - "v1AddNodeResponse": { - "type": "object", - "properties": { - "generic": { - "$ref": "#/definitions/v1GenericNode" - }, - "container": { - "$ref": "#/definitions/v1ContainerNode" - }, - "remote": { - "$ref": "#/definitions/v1RemoteNode" - }, - "remote_rds": { - "$ref": "#/definitions/v1RemoteRDSNode" - }, - "remote_azure_database": { - "$ref": "#/definitions/v1RemoteAzureDatabaseNode" - } - } - }, - "v1AddRemoteAzureNodeParams": { - "type": "object", - "properties": { - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "DB instance identifier." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddRemoteNodeParams": { - "type": "object", - "properties": { - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddRemoteRDSNodeParams": { - "type": "object", - "properties": { - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "DB instance identifier." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1ContainerNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id of the Generic Node where this Container Node runs." - }, - "container_id": { - "type": "string", - "description": "Container identifier. If specified, must be a unique Docker container identifier." - }, - "container_name": { - "type": "string", - "description": "Container name." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "is_pmm_server_node": { - "type": "boolean", - "description": "True if this node is a PMM Server node (HA mode)." - } - }, - "description": "ContainerNode represents a Docker container." - }, - "v1GenericNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id." - }, - "distro": { - "type": "string", - "description": "Linux distribution name and version." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "is_pmm_server_node": { - "type": "boolean", - "description": "True if this node is a PMM Server node (HA mode)." - } - }, - "description": "GenericNode represents a bare metal server or virtual machine." - }, - "v1GetNodeResponse": { - "type": "object", - "properties": { - "generic": { - "$ref": "#/definitions/v1GenericNode" - }, - "container": { - "$ref": "#/definitions/v1ContainerNode" - }, - "remote": { - "$ref": "#/definitions/v1RemoteNode" - }, - "remote_rds": { - "$ref": "#/definitions/v1RemoteRDSNode" - }, - "remote_azure_database": { - "$ref": "#/definitions/v1RemoteAzureDatabaseNode" - } - } - }, - "v1ListNodesResponse": { - "type": "object", - "properties": { - "generic": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1GenericNode" - } - }, - "container": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ContainerNode" - } - }, - "remote": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1RemoteNode" - } - }, - "remote_rds": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1RemoteRDSNode" - } - }, - "remote_azure_database": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1RemoteAzureDatabaseNode" - } - } - } - }, - "v1NodeType": { - "type": "string", - "enum": [ - "NODE_TYPE_UNSPECIFIED", - "NODE_TYPE_GENERIC_NODE", - "NODE_TYPE_CONTAINER_NODE", - "NODE_TYPE_REMOTE_NODE", - "NODE_TYPE_REMOTE_RDS_NODE", - "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" - ], - "default": "NODE_TYPE_UNSPECIFIED", - "description": "NodeType describes supported Node types." - }, - "v1RemoteAzureDatabaseNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "DB instance identifier." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - }, - "description": "RemoteAzureDatabaseNode represents remote AzureDatabase Node. Agents can't run on Remote AzureDatabase Nodes." - }, - "v1RemoteNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - }, - "description": "RemoteNode represents generic remote Node. It's a node where we don't run pmm-agents. Only external exporters can run on Remote Nodes." - }, - "v1RemoteRDSNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "DB instance identifier." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "instance_id": { - "type": "string", - "description": "AWS instance ID." - } - }, - "description": "RemoteRDSNode represents remote RDS Node. Agents can't run on Remote RDS Nodes." - }, - "v1RemoveNodeResponse": { - "type": "object" - } - } -} diff --git a/api/inventory/v1/services.pb.go b/api/inventory/v1/services.pb.go index a8d1519b61f..23eeeb28b81 100644 --- a/api/inventory/v1/services.pb.go +++ b/api/inventory/v1/services.pb.go @@ -3334,7 +3334,6 @@ var ( (*common.StringMap)(nil), // 43: common.StringMap } ) - var file_inventory_v1_services_proto_depIdxs = []int32{ 27, // 0: inventory.v1.MySQLService.custom_labels:type_name -> inventory.v1.MySQLService.CustomLabelsEntry 28, // 1: inventory.v1.MySQLService.extra_dsn_params:type_name -> inventory.v1.MySQLService.ExtraDsnParamsEntry diff --git a/api/inventory/v1/services.swagger.json b/api/inventory/v1/services.swagger.json deleted file mode 100644 index ab118f837ff..00000000000 --- a/api/inventory/v1/services.swagger.json +++ /dev/null @@ -1,1189 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "inventory/v1/services.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "ServicesService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/inventory/services": { - "get": { - "summary": "List Services", - "description": "Returns a list of Services filtered by type.", - "operationId": "ListServices", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListServicesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_id", - "description": "Return only Services running on that Node.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "service_type", - "description": "Return only services filtered by service type.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "SERVICE_TYPE_UNSPECIFIED", - "SERVICE_TYPE_MYSQL_SERVICE", - "SERVICE_TYPE_MONGODB_SERVICE", - "SERVICE_TYPE_POSTGRESQL_SERVICE", - "SERVICE_TYPE_VALKEY_SERVICE", - "SERVICE_TYPE_PROXYSQL_SERVICE", - "SERVICE_TYPE_HAPROXY_SERVICE", - "SERVICE_TYPE_EXTERNAL_SERVICE" - ], - "default": "SERVICE_TYPE_UNSPECIFIED" - }, - { - "name": "external_group", - "description": "Return only services in this external group.", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "ServicesService" - ] - }, - "post": { - "summary": "Add a Service", - "description": "Adds a Service.", - "operationId": "AddService", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1AddServiceResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1AddServiceRequest" - } - } - ], - "tags": [ - "ServicesService" - ] - } - }, - "/v1/inventory/services/{service_id}": { - "get": { - "summary": "Get a Service", - "description": "Returns a single Service by ID.", - "operationId": "GetService", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetServiceResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "service_id", - "description": "Unique randomly generated instance identifier.", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ServicesService" - ] - }, - "delete": { - "summary": "Remove Service", - "description": "Removes Service.", - "operationId": "RemoveService", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RemoveServiceResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "service_id", - "description": "Unique randomly generated instance identifier. Required.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "force", - "description": "Remove service with all dependencies.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "ServicesService" - ] - }, - "put": { - "summary": "Change service", - "description": "Changes service configuration. If a new cluster label is specified, it removes all backup/restore tasks scheduled for the related services. Fails if there are running backup/restore tasks.", - "operationId": "ChangeService", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ChangeServiceResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "service_id", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/ServicesServiceChangeServiceBody" - } - } - ], - "tags": [ - "ServicesService" - ] - } - }, - "/v1/inventory/services:getTypes": { - "post": { - "summary": "List Active Service Types", - "description": "Returns a list of active Service types.", - "operationId": "ListActiveServiceTypes", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListActiveServiceTypesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1ListActiveServiceTypesRequest" - } - } - ], - "tags": [ - "ServicesService" - ] - } - } - }, - "definitions": { - "ServicesServiceChangeServiceBody": { - "type": "object", - "properties": { - "environment": { - "type": "string", - "x-nullable": true - }, - "cluster": { - "type": "string", - "x-nullable": true - }, - "replication_set": { - "type": "string", - "x-nullable": true - }, - "external_group": { - "type": "string", - "x-nullable": true - }, - "custom_labels": { - "$ref": "#/definitions/commonStringMap", - "x-nullable": true, - "description": "Replace all custom user-assigned labels." - } - } - }, - "commonStringMap": { - "type": "object", - "properties": { - "values": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "description": "A wrapper for map[string]string. This type allows to distinguish between an empty map and a null value." - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1AddExternalServiceParams": { - "type": "object", - "properties": { - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs. Required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "group": { - "type": "string", - "description": "Group name of external service." - } - } - }, - "v1AddHAProxyServiceParams": { - "type": "object", - "properties": { - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs. Required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddMongoDBServiceParams": { - "type": "object", - "properties": { - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs. Required." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddMySQLServiceParams": { - "type": "object", - "properties": { - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs. Required." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra parameters to be added to the DSN." - } - } - }, - "v1AddPostgreSQLServiceParams": { - "type": "object", - "properties": { - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs. Required." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - } - } - }, - "v1AddProxySQLServiceParams": { - "type": "object", - "properties": { - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs. Required." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1AddServiceRequest": { - "type": "object", - "properties": { - "mysql": { - "$ref": "#/definitions/v1AddMySQLServiceParams" - }, - "mongodb": { - "$ref": "#/definitions/v1AddMongoDBServiceParams" - }, - "postgresql": { - "$ref": "#/definitions/v1AddPostgreSQLServiceParams" - }, - "proxysql": { - "$ref": "#/definitions/v1AddProxySQLServiceParams" - }, - "haproxy": { - "$ref": "#/definitions/v1AddHAProxyServiceParams" - }, - "external": { - "$ref": "#/definitions/v1AddExternalServiceParams" - }, - "valkey": { - "$ref": "#/definitions/v1AddValkeyServiceParams" - } - } - }, - "v1AddServiceResponse": { - "type": "object", - "properties": { - "mysql": { - "$ref": "#/definitions/v1MySQLService" - }, - "mongodb": { - "$ref": "#/definitions/v1MongoDBService" - }, - "postgresql": { - "$ref": "#/definitions/v1PostgreSQLService" - }, - "proxysql": { - "$ref": "#/definitions/v1ProxySQLService" - }, - "haproxy": { - "$ref": "#/definitions/v1HAProxyService" - }, - "external": { - "$ref": "#/definitions/v1ExternalService" - }, - "valkey": { - "$ref": "#/definitions/v1ValkeyService" - } - } - }, - "v1AddValkeyServiceParams": { - "type": "object", - "properties": { - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs. Required." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - } - }, - "v1ChangeServiceResponse": { - "type": "object", - "properties": { - "mysql": { - "$ref": "#/definitions/v1MySQLService" - }, - "mongodb": { - "$ref": "#/definitions/v1MongoDBService" - }, - "postgresql": { - "$ref": "#/definitions/v1PostgreSQLService" - }, - "proxysql": { - "$ref": "#/definitions/v1ProxySQLService" - }, - "haproxy": { - "$ref": "#/definitions/v1HAProxyService" - }, - "external": { - "$ref": "#/definitions/v1ExternalService" - }, - "valkey": { - "$ref": "#/definitions/v1ValkeyService" - } - } - }, - "v1ExternalService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this service instance runs." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "group": { - "type": "string", - "description": "Group name of external service." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP)." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port." - } - }, - "description": "ExternalService represents a generic External service instance." - }, - "v1GetServiceResponse": { - "type": "object", - "properties": { - "mysql": { - "$ref": "#/definitions/v1MySQLService" - }, - "mongodb": { - "$ref": "#/definitions/v1MongoDBService" - }, - "postgresql": { - "$ref": "#/definitions/v1PostgreSQLService" - }, - "proxysql": { - "$ref": "#/definitions/v1ProxySQLService" - }, - "haproxy": { - "$ref": "#/definitions/v1HAProxyService" - }, - "external": { - "$ref": "#/definitions/v1ExternalService" - }, - "valkey": { - "$ref": "#/definitions/v1ValkeyService" - } - } - }, - "v1HAProxyService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this service instance runs." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - }, - "description": "HAProxyService represents a generic HAProxy service instance." - }, - "v1ListActiveServiceTypesRequest": { - "type": "object" - }, - "v1ListActiveServiceTypesResponse": { - "type": "object", - "properties": { - "service_types": { - "type": "array", - "items": { - "$ref": "#/definitions/v1ServiceType" - } - } - } - }, - "v1ListServicesResponse": { - "type": "object", - "properties": { - "mysql": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MySQLService" - } - }, - "mongodb": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MongoDBService" - } - }, - "postgresql": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1PostgreSQLService" - } - }, - "proxysql": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ProxySQLService" - } - }, - "haproxy": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1HAProxyService" - } - }, - "external": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ExternalService" - } - }, - "valkey": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ValkeyService" - } - } - } - }, - "v1MongoDBService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "MongoDB version." - } - }, - "description": "MongoDBService represents a generic MongoDB instance." - }, - "v1MySQLService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "MySQL version." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra parameters to be added to the DSN." - } - }, - "description": "MySQLService represents a generic MySQL instance." - }, - "v1PostgreSQLService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "database_name": { - "type": "string", - "description": "Database name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "PostgreSQL version." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - } - }, - "description": "PostgreSQLService represents a generic PostgreSQL instance." - }, - "v1ProxySQLService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "ProxySQL version." - } - }, - "description": "ProxySQLService represents a generic ProxySQL instance." - }, - "v1RemoveServiceResponse": { - "type": "object" - }, - "v1ServiceType": { - "type": "string", - "enum": [ - "SERVICE_TYPE_UNSPECIFIED", - "SERVICE_TYPE_MYSQL_SERVICE", - "SERVICE_TYPE_MONGODB_SERVICE", - "SERVICE_TYPE_POSTGRESQL_SERVICE", - "SERVICE_TYPE_VALKEY_SERVICE", - "SERVICE_TYPE_PROXYSQL_SERVICE", - "SERVICE_TYPE_HAPROXY_SERVICE", - "SERVICE_TYPE_EXTERNAL_SERVICE" - ], - "default": "SERVICE_TYPE_UNSPECIFIED", - "description": "ServiceType describes supported Service types." - }, - "v1ValkeyService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "Valkey version." - } - }, - "description": "ValkeyService represents a generic Valkey instance." - } - } -} diff --git a/api/management/v1/agent.pb.go b/api/management/v1/agent.pb.go index c76c750f869..8a745a48910 100644 --- a/api/management/v1/agent.pb.go +++ b/api/management/v1/agent.pb.go @@ -1241,7 +1241,6 @@ var ( (*durationpb.Duration)(nil), // 17: google.protobuf.Duration } ) - var file_management_v1_agent_proto_depIdxs = []int32{ 8, // 0: management.v1.UniversalAgent.azure_options:type_name -> management.v1.UniversalAgent.AzureOptions 14, // 1: management.v1.UniversalAgent.created_at:type_name -> google.protobuf.Timestamp diff --git a/api/management/v1/agent.swagger.json b/api/management/v1/agent.swagger.json deleted file mode 100644 index 66ea6d4a070..00000000000 --- a/api/management/v1/agent.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/agent.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/annotation.pb.go b/api/management/v1/annotation.pb.go index ec781561e4c..53bbe233c1b 100644 --- a/api/management/v1/annotation.pb.go +++ b/api/management/v1/annotation.pb.go @@ -164,7 +164,6 @@ var ( (*AddAnnotationResponse)(nil), // 1: management.v1.AddAnnotationResponse } ) - var file_management_v1_annotation_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/annotation.swagger.json b/api/management/v1/annotation.swagger.json deleted file mode 100644 index 3d5937159fb..00000000000 --- a/api/management/v1/annotation.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/annotation.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/azure.pb.go b/api/management/v1/azure.pb.go index 04a05c47ec1..863cff6d5ab 100644 --- a/api/management/v1/azure.pb.go +++ b/api/management/v1/azure.pb.go @@ -726,7 +726,6 @@ var ( (*durationpb.Duration)(nil), // 7: google.protobuf.Duration } ) - var file_management_v1_azure_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverAzureDatabaseInstance.type:type_name -> management.v1.DiscoverAzureDatabaseType 2, // 1: management.v1.DiscoverAzureDatabaseResponse.azure_database_instance:type_name -> management.v1.DiscoverAzureDatabaseInstance diff --git a/api/management/v1/azure.swagger.json b/api/management/v1/azure.swagger.json deleted file mode 100644 index 83b5bc19d33..00000000000 --- a/api/management/v1/azure.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/azure.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/external.pb.go b/api/management/v1/external.pb.go index 3632121e1c2..d990cb53abe 100644 --- a/api/management/v1/external.pb.go +++ b/api/management/v1/external.pb.go @@ -355,7 +355,6 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) - var file_management_v1_external_proto_depIdxs = []int32{ 3, // 0: management.v1.AddExternalServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddExternalServiceParams.custom_labels:type_name -> management.v1.AddExternalServiceParams.CustomLabelsEntry diff --git a/api/management/v1/external.swagger.json b/api/management/v1/external.swagger.json deleted file mode 100644 index ee98890ec3a..00000000000 --- a/api/management/v1/external.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/external.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/haproxy.pb.go b/api/management/v1/haproxy.pb.go index f3de5158762..95cad534323 100644 --- a/api/management/v1/haproxy.pb.go +++ b/api/management/v1/haproxy.pb.go @@ -333,7 +333,6 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) - var file_management_v1_haproxy_proto_depIdxs = []int32{ 3, // 0: management.v1.AddHAProxyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddHAProxyServiceParams.custom_labels:type_name -> management.v1.AddHAProxyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/haproxy.swagger.json b/api/management/v1/haproxy.swagger.json deleted file mode 100644 index 456d36f1f16..00000000000 --- a/api/management/v1/haproxy.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/haproxy.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/metrics.pb.go b/api/management/v1/metrics.pb.go index 748642db7cb..b552c7955fb 100644 --- a/api/management/v1/metrics.pb.go +++ b/api/management/v1/metrics.pb.go @@ -103,7 +103,6 @@ var ( MetricsMode(0), // 0: management.v1.MetricsMode } ) - var file_management_v1_metrics_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/metrics.swagger.json b/api/management/v1/metrics.swagger.json deleted file mode 100644 index 48c8c4ec4ca..00000000000 --- a/api/management/v1/metrics.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/metrics.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/mongodb.pb.go b/api/management/v1/mongodb.pb.go index c25cc4f8282..aad151306df 100644 --- a/api/management/v1/mongodb.pb.go +++ b/api/management/v1/mongodb.pb.go @@ -559,7 +559,6 @@ var ( (*v1.RTAMongoDBAgent)(nil), // 11: inventory.v1.RTAMongoDBAgent } ) - var file_management_v1_mongodb_proto_depIdxs = []int32{ 3, // 0: management.v1.AddMongoDBServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMongoDBServiceParams.custom_labels:type_name -> management.v1.AddMongoDBServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mongodb.swagger.json b/api/management/v1/mongodb.swagger.json deleted file mode 100644 index 2722b769cf7..00000000000 --- a/api/management/v1/mongodb.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/mongodb.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/mysql.pb.go b/api/management/v1/mysql.pb.go index 18f64740d99..70660a14379 100644 --- a/api/management/v1/mysql.pb.go +++ b/api/management/v1/mysql.pb.go @@ -545,7 +545,6 @@ var ( (*v1.QANMySQLSlowlogAgent)(nil), // 11: inventory.v1.QANMySQLSlowlogAgent } ) - var file_management_v1_mysql_proto_depIdxs = []int32{ 4, // 0: management.v1.AddMySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMySQLServiceParams.custom_labels:type_name -> management.v1.AddMySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mysql.swagger.json b/api/management/v1/mysql.swagger.json deleted file mode 100644 index f0be3fa24f2..00000000000 --- a/api/management/v1/mysql.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/mysql.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/node.pb.go b/api/management/v1/node.pb.go index 149fb30ad94..53bb2be68db 100644 --- a/api/management/v1/node.pb.go +++ b/api/management/v1/node.pb.go @@ -1255,7 +1255,6 @@ var ( (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp } ) - var file_management_v1_node_proto_depIdxs = []int32{ 16, // 0: management.v1.AddNodeParams.node_type:type_name -> inventory.v1.NodeType 11, // 1: management.v1.AddNodeParams.custom_labels:type_name -> management.v1.AddNodeParams.CustomLabelsEntry diff --git a/api/management/v1/node.swagger.json b/api/management/v1/node.swagger.json deleted file mode 100644 index 87f7e2581d0..00000000000 --- a/api/management/v1/node.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/node.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/postgresql.pb.go b/api/management/v1/postgresql.pb.go index 0271ba48788..0e6f54ad033 100644 --- a/api/management/v1/postgresql.pb.go +++ b/api/management/v1/postgresql.pb.go @@ -535,7 +535,6 @@ var ( (*v1.QANPostgreSQLPgStatMonitorAgent)(nil), // 10: inventory.v1.QANPostgreSQLPgStatMonitorAgent } ) - var file_management_v1_postgresql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddPostgreSQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddPostgreSQLServiceParams.custom_labels:type_name -> management.v1.AddPostgreSQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/postgresql.swagger.json b/api/management/v1/postgresql.swagger.json deleted file mode 100644 index a4694fd37f7..00000000000 --- a/api/management/v1/postgresql.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/postgresql.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/proxysql.pb.go b/api/management/v1/proxysql.pb.go index e3142ed85df..7d9dbbcfc07 100644 --- a/api/management/v1/proxysql.pb.go +++ b/api/management/v1/proxysql.pb.go @@ -395,7 +395,6 @@ var ( (*v1.ProxySQLExporter)(nil), // 8: inventory.v1.ProxySQLExporter } ) - var file_management_v1_proxysql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddProxySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddProxySQLServiceParams.custom_labels:type_name -> management.v1.AddProxySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/proxysql.swagger.json b/api/management/v1/proxysql.swagger.json deleted file mode 100644 index 64f40cbe45f..00000000000 --- a/api/management/v1/proxysql.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/proxysql.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/rds.pb.go b/api/management/v1/rds.pb.go index d338efd3738..fb882ea8de5 100644 --- a/api/management/v1/rds.pb.go +++ b/api/management/v1/rds.pb.go @@ -854,7 +854,6 @@ var ( (*v1.QANPostgreSQLPgStatementsAgent)(nil), // 16: inventory.v1.QANPostgreSQLPgStatementsAgent } ) - var file_management_v1_rds_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverRDSInstance.engine:type_name -> management.v1.DiscoverRDSEngine 1, // 1: management.v1.DiscoverRDSResponse.rds_instances:type_name -> management.v1.DiscoverRDSInstance diff --git a/api/management/v1/rds.swagger.json b/api/management/v1/rds.swagger.json deleted file mode 100644 index a03802476a3..00000000000 --- a/api/management/v1/rds.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/rds.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index cbad04b7f53..6ea52fbc973 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -1005,7 +1005,6 @@ var ( (*AddAzureDatabaseResponse)(nil), // 47: management.v1.AddAzureDatabaseResponse } ) - var file_management_v1_service_proto_depIdxs = []int32{ 9, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams 10, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams diff --git a/api/management/v1/service.swagger.json b/api/management/v1/service.swagger.json deleted file mode 100644 index 9ac693741d0..00000000000 --- a/api/management/v1/service.swagger.json +++ /dev/null @@ -1,4547 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/service.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "ManagementService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/management/agents": { - "get": { - "summary": "List Agents", - "description": "Lists Agents with filter.", - "operationId": "ListAgents", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListAgentsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "service_id", - "description": "Return only Agents that relate to a specific ServiceID.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "node_id", - "description": "Return only Agents that relate to a specific NodeID.", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/agents/versions": { - "get": { - "summary": "List Agent Versions", - "description": "Lists Agent versions and their update severity.", - "operationId": "ListAgentVersions", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListAgentVersionsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/annotations": { - "post": { - "summary": "Add an Annotation", - "description": "Adds an annotation.", - "operationId": "AddAnnotation", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1AddAnnotationResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "AddAnnotationRequest is a params to add new annotation.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1AddAnnotationRequest" - } - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/nodes": { - "get": { - "summary": "List Nodes", - "description": "Lists Nodes with filter.", - "operationId": "ListNodes", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListNodesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_type", - "description": "Node type to be filtered out.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "NODE_TYPE_UNSPECIFIED", - "NODE_TYPE_GENERIC_NODE", - "NODE_TYPE_CONTAINER_NODE", - "NODE_TYPE_REMOTE_NODE", - "NODE_TYPE_REMOTE_RDS_NODE", - "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" - ], - "default": "NODE_TYPE_UNSPECIFIED" - } - ], - "tags": [ - "ManagementService" - ] - }, - "post": { - "summary": "Register a Node", - "description": "Registers a new Node and a pmm-agent.", - "operationId": "RegisterNode", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RegisterNodeResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1RegisterNodeRequest" - } - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/nodes/{node_id}": { - "get": { - "summary": "Get Node", - "description": "Gets a single Node by ID.", - "operationId": "GetNode", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetNodeResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_id", - "description": "Unique Node identifier.", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "ManagementService" - ] - }, - "delete": { - "summary": "Unregister a Node", - "description": "Unregisters a Node and pmm-agent", - "operationId": "UnregisterNode", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1UnregisterNodeResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_id", - "description": "Node_id to be unregistered.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "force", - "description": "Force delete node, related service account, even if it has more service tokens attached.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/services": { - "get": { - "summary": "List Services", - "description": "Returns a filtered list of Services.", - "operationId": "ListServices", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListServicesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "node_id", - "description": "Return only Services running on that Node.", - "in": "query", - "required": false, - "type": "string" - }, - { - "name": "service_type", - "description": "Return only services filtered by service type.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "SERVICE_TYPE_UNSPECIFIED", - "SERVICE_TYPE_MYSQL_SERVICE", - "SERVICE_TYPE_MONGODB_SERVICE", - "SERVICE_TYPE_POSTGRESQL_SERVICE", - "SERVICE_TYPE_VALKEY_SERVICE", - "SERVICE_TYPE_PROXYSQL_SERVICE", - "SERVICE_TYPE_HAPROXY_SERVICE", - "SERVICE_TYPE_EXTERNAL_SERVICE" - ], - "default": "SERVICE_TYPE_UNSPECIFIED" - }, - { - "name": "external_group", - "description": "Return only services in this external group.", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "ManagementService" - ] - }, - "post": { - "summary": "Add a Service", - "description": "Adds a service and starts several agents.", - "operationId": "AddService", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1AddServiceResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1AddServiceRequest" - } - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/services/azure": { - "post": { - "summary": "Add Azure Database", - "description": "Adds an Azure Database instance.", - "operationId": "AddAzureDatabase", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1AddAzureDatabaseResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1AddAzureDatabaseRequest" - } - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/services/{service_id}": { - "delete": { - "summary": "Remove a Service", - "description": "Removes a Service along with its Agents.", - "operationId": "RemoveService", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1RemoveServiceResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "service_id", - "description": "Either a Service ID or a Service Name.", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "service_type", - "description": "Service type.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "SERVICE_TYPE_UNSPECIFIED", - "SERVICE_TYPE_MYSQL_SERVICE", - "SERVICE_TYPE_MONGODB_SERVICE", - "SERVICE_TYPE_POSTGRESQL_SERVICE", - "SERVICE_TYPE_VALKEY_SERVICE", - "SERVICE_TYPE_PROXYSQL_SERVICE", - "SERVICE_TYPE_HAPROXY_SERVICE", - "SERVICE_TYPE_EXTERNAL_SERVICE" - ], - "default": "SERVICE_TYPE_UNSPECIFIED" - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/services:discoverAzure": { - "post": { - "summary": "Discover Azure Database", - "description": "Discovers Azure Database for MySQL, MariaDB and PostgreSQL Server instances.", - "operationId": "DiscoverAzureDatabase", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1DiscoverAzureDatabaseResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "DiscoverAzureDatabaseRequest discover azure databases request.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1DiscoverAzureDatabaseRequest" - } - } - ], - "tags": [ - "ManagementService" - ] - } - }, - "/v1/management/services:discoverRDS": { - "post": { - "summary": "Discover RDS", - "description": "Discovers RDS instances.", - "operationId": "DiscoverRDS", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1DiscoverRDSResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/googleRpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1DiscoverRDSRequest" - } - } - ], - "tags": [ - "ManagementService" - ] - } - } - }, - "definitions": { - "UniversalAgentAzureOptions": { - "type": "object", - "properties": { - "client_id": { - "type": "string", - "description": "Azure client ID." - }, - "is_client_secret_set": { - "type": "boolean", - "description": "True if Azure client secret is set." - }, - "resource_group": { - "type": "string", - "description": "Azure resource group." - }, - "subscription_id": { - "type": "string", - "description": "Azure subscription ID." - }, - "tenant_id": { - "type": "string", - "description": "Azure tenant ID." - } - } - }, - "UniversalAgentMongoDBOptions": { - "type": "object", - "properties": { - "is_tls_certificate_key_set": { - "type": "boolean", - "description": "True if TLS certificate is set." - }, - "is_tls_certificate_key_file_password_set": { - "type": "boolean", - "description": "True if TLS certificate file password is set." - }, - "authentication_mechanism": { - "type": "string", - "description": "MongoDB auth mechanism." - }, - "authentication_database": { - "type": "string", - "description": "MongoDB auth database." - }, - "stats_collections": { - "type": "array", - "items": { - "type": "string" - }, - "description": "MongoDB stats collections." - }, - "collections_limit": { - "type": "integer", - "format": "int32", - "description": "MongoDB collections limit." - }, - "enable_all_collectors": { - "type": "boolean", - "description": "True if all collectors are enabled." - } - } - }, - "UniversalAgentMySQLOptions": { - "type": "object", - "properties": { - "is_tls_key_set": { - "type": "boolean", - "description": "True if TLS key is set." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - } - } - }, - "UniversalAgentPostgreSQLOptions": { - "type": "object", - "properties": { - "is_ssl_key_set": { - "type": "boolean", - "description": "True if TLS key is set." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - }, - "max_exporter_connections": { - "type": "integer", - "format": "int32", - "description": "Maximum number of connections from exporter to PostgreSQL instance." - } - } - }, - "UniversalAgentValkeyOptions": { - "type": "object" - }, - "UniversalNodeAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique Agent identifier." - }, - "agent_type": { - "type": "string", - "description": "Agent type." - }, - "status": { - "type": "string", - "description": "Actual Agent status." - }, - "is_connected": { - "type": "boolean", - "description": "True if Agent is running and connected to pmm-managed." - } - } - }, - "UniversalNodeService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique Service identifier." - }, - "service_type": { - "type": "string", - "description": "Service type." - }, - "service_name": { - "type": "string", - "description": "Service name." - } - }, - "description": "Service represents a service running on a node." - }, - "commonMetricsResolutions": { - "type": "object", - "properties": { - "hr": { - "type": "string", - "description": "High resolution. In JSON should be represented as a string with number of seconds with `s` suffix." - }, - "mr": { - "type": "string", - "description": "Medium resolution. In JSON should be represented as a string with number of seconds with `s` suffix." - }, - "lr": { - "type": "string", - "description": "Low resolution. In JSON should be represented as a string with number of seconds with `s` suffix." - } - }, - "description": "MetricsResolutions represents Prometheus exporters metrics resolutions." - }, - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "v1AddAnnotationRequest": { - "type": "object", - "properties": { - "text": { - "type": "string", - "description": "An annotation description. Required." - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags are used to filter annotations." - }, - "node_name": { - "type": "string", - "description": "Used for annotating a node." - }, - "service_names": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Used for annotating services." - } - }, - "description": "AddAnnotationRequest is a params to add new annotation." - }, - "v1AddAnnotationResponse": { - "type": "object" - }, - "v1AddAzureDatabaseRequest": { - "type": "object", - "properties": { - "region": { - "type": "string", - "description": "Azure database location." - }, - "az": { - "type": "string", - "description": "Azure database availability zone." - }, - "instance_id": { - "type": "string", - "description": "Azure database instance ID." - }, - "node_model": { - "type": "string", - "description": "Represents a purchasable Stock Keeping Unit (SKU) under a product.\nhttps://docs.microsoft.com/en-us/partner-center/develop/product-resources#sku." - }, - "address": { - "type": "string", - "description": "Address used to connect to it." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name. Defaults to Azure Database instance ID." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Defaults to Azure Database instance ID." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "username": { - "type": "string", - "description": "Username for scraping metrics." - }, - "password": { - "type": "string", - "description": "Password for scraping metrics." - }, - "azure_client_id": { - "type": "string", - "description": "Azure client ID." - }, - "azure_client_secret": { - "type": "string", - "description": "Azure client secret." - }, - "azure_tenant_id": { - "type": "string", - "description": "Azure tanant ID." - }, - "azure_subscription_id": { - "type": "string", - "description": "Azure subscription ID." - }, - "azure_resource_group": { - "type": "string", - "description": "Azure resource group." - }, - "azure_database_exporter": { - "type": "boolean", - "description": "If true, adds azure_database_exporter." - }, - "qan": { - "type": "boolean", - "description": "If true, adds qan-mysql-perfschema-agent or qan-postgresql-pgstatements-agent." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Node and Service." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "disable_query_examples": { - "type": "boolean", - "description": "Disable query examples." - }, - "tablestats_group_table_limit": { - "type": "integer", - "format": "int32", - "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\nIf zero, server's default value is used.\nUse negative value to disable them." - }, - "type": { - "$ref": "#/definitions/v1DiscoverAzureDatabaseType", - "title": "Azure database resource type (mysql, maria, postgres)" - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddAzureDatabaseResponse": { - "type": "object" - }, - "v1AddExternalServiceParams": { - "type": "object", - "properties": { - "runs_on_node_id": { - "type": "string", - "description": "Node identifier on which an external exporter is been running.\nruns_on_node_id should always be passed with node_id.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "node_name": { - "type": "string", - "description": "Node name on which a service and node is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "add_node": { - "$ref": "#/definitions/v1AddNodeParams", - "description": "Create a new Node with those parameters.\nadd_node should always be passed with address.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "address": { - "type": "string", - "description": "Node and Exporter access address (DNS name or IP).\naddress should always be passed with add_node." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "username": { - "type": "string", - "description": "HTTP basic auth username for collecting metrics." - }, - "password": { - "type": "string", - "description": "HTTP basic auth password for collecting metrics." - }, - "scheme": { - "type": "string", - "description": "Scheme to generate URI to exporter metrics endpoints." - }, - "metrics_path": { - "type": "string", - "description": "Path under which metrics are exposed, used to generate URI." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "node_id": { - "type": "string", - "description": "Node identifier on which an external service is been running.\nnode_id should always be passed with runs_on_node_id." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "group": { - "type": "string", - "description": "Group name of external service." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically.\nNode with registered pmm_agent_id must present at pmm-server\nin case of push metrics_mode." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - } - } - }, - "v1AddHAProxyServiceParams": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Node identifier on which an external exporter is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "node_name": { - "type": "string", - "description": "Node name on which a service and node is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "add_node": { - "$ref": "#/definitions/v1AddNodeParams", - "description": "Create a new Node with those parameters.\nadd_node always should be passed with address.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "address": { - "type": "string", - "description": "Node and Exporter access address (DNS name or IP).\naddress always should be passed with add_node." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "username": { - "type": "string", - "description": "HTTP basic auth username for collecting metrics." - }, - "password": { - "type": "string", - "description": "HTTP basic auth password for collecting metrics." - }, - "scheme": { - "type": "string", - "description": "Scheme to generate URI to exporter metrics endpoints." - }, - "metrics_path": { - "type": "string", - "description": "Path under which metrics are exposed, used to generate URI." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically.\nNode with registered pmm_agent_id must present at pmm-server\nin case of push metrics_mode." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - } - } - }, - "v1AddMongoDBServiceParams": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "node_name": { - "type": "string", - "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "add_node": { - "$ref": "#/definitions/v1AddNodeParams", - "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "address": { - "type": "string", - "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Service Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Service Access socket.\nAddress (and port) or socket is required." - }, - "pmm_agent_id": { - "type": "string", - "description": "The \"pmm-agent\" identifier which should run agents. Required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "username": { - "type": "string", - "description": "MongoDB username for exporter and QAN agent access." - }, - "password": { - "type": "string", - "description": "MongoDB password for exporter and QAN agent access." - }, - "qan_mongodb_profiler": { - "type": "boolean", - "description": "If true, adds qan-mongodb-profiler-agent for provided service." - }, - "qan_mongodb_mongolog": { - "type": "boolean", - "description": "If true, adds qan-mongodb-mongolog-agent for provided service." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_certificate_key": { - "type": "string", - "description": "Client certificate and key." - }, - "tls_certificate_key_file_password": { - "type": "string", - "description": "Password for decrypting tls_certificate_key." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "authentication_mechanism": { - "type": "string", - "description": "Authentication mechanism.\nSee https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authMechanism\nfor details." - }, - "authentication_database": { - "type": "string", - "description": "Authentication database." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "stats_collections": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collections to get stats from. Can use * ." - }, - "collections_limit": { - "type": "integer", - "format": "int32", - "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" - }, - "enable_all_collectors": { - "type": "boolean", - "title": "Enable all collectors" - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "title": "Exporter log level" - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "environment_variable_names": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Environment variable names to pass to the exporter.\nValues will be resolved from pmm-agent's environment when starting the exporter." - }, - "rta_mongodb_agent": { - "type": "boolean", - "description": "If true, adds Real-Time Analytics agent for the provided service." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddMySQLServiceParams": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "node_name": { - "type": "string", - "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "add_node": { - "$ref": "#/definitions/v1AddNodeParams", - "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "address": { - "type": "string", - "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Service Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Service Access socket.\nAddress (and port) or socket is required." - }, - "pmm_agent_id": { - "type": "string", - "description": "The \"pmm-agent\" identifier which should run agents. Required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "username": { - "type": "string", - "description": "MySQL username for scraping metrics." - }, - "password": { - "type": "string", - "description": "MySQL password for scraping metrics." - }, - "qan_mysql_perfschema": { - "type": "boolean", - "description": "If true, adds qan-mysql-perfschema-agent for provided service." - }, - "qan_mysql_slowlog": { - "type": "boolean", - "description": "If true, adds qan-mysql-slowlog-agent for provided service." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "description": "Disable query examples." - }, - "max_slowlog_file_size": { - "type": "string", - "format": "int64", - "description": "If qan-mysql-slowlog-agent is added, slowlog file is rotated at this size if \u003e 0.\nIf zero, server's default value is used.\nUse negative value to disable rotation." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "tablestats_group_table_limit": { - "type": "integer", - "format": "int32", - "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\nIf zero, server's default value is used.\nUse negative value to disable them." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "title": "Exporter log level" - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "extra DSN parameters to be used for connecting to MySQL." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddNodeParams": { - "type": "object", - "properties": { - "node_type": { - "$ref": "#/definitions/v1NodeType", - "description": "Node type to be registered." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id." - }, - "distro": { - "type": "string", - "description": "Linux distribution name and version." - }, - "container_id": { - "type": "string", - "description": "Container identifier. If specified, must be a unique Docker container identifier." - }, - "container_name": { - "type": "string", - "description": "Container name." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Node." - } - }, - "description": "AddNodeParams holds node params and is used to add new node to inventory while adding new service." - }, - "v1AddPostgreSQLServiceParams": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "node_name": { - "type": "string", - "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "add_node": { - "$ref": "#/definitions/v1AddNodeParams", - "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "address": { - "type": "string", - "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Service Access port.\nPort is required when the address present." - }, - "database": { - "type": "string", - "description": "Database name." - }, - "socket": { - "type": "string", - "description": "Service Access socket.\nAddress (and port) or socket is required." - }, - "pmm_agent_id": { - "type": "string", - "description": "The \"pmm-agent\" identifier which should run agents. Required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for scraping metrics." - }, - "password": { - "type": "string", - "description": "PostgreSQL password for scraping metrics." - }, - "qan_postgresql_pgstatements_agent": { - "type": "boolean", - "description": "If true, adds qan-postgresql-pgstatements-agent for provided service." - }, - "qan_postgresql_pgstatmonitor_agent": { - "type": "boolean", - "description": "If true, adds qan-postgresql-pgstatmonitor-agent for provided service." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "disable_query_examples": { - "type": "boolean", - "description": "Disable query examples." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "tls_ca": { - "type": "string", - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "description": "TLS Certifcate." - }, - "tls_key": { - "type": "string", - "description": "TLS Certificate Key." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "title": "Exporter log level" - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit for auto discovery." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "max_exporter_connections": { - "type": "integer", - "format": "int32", - "description": "Maximum number of connections that exporter can open to the database instance." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddProxySQLServiceParams": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Node identifier on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "node_name": { - "type": "string", - "description": "Node name on which a service is been running.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "add_node": { - "$ref": "#/definitions/v1AddNodeParams", - "description": "Create a new Node with those parameters.\nExactly one of these parameters should be present: node_id, node_name, add_node." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Required." - }, - "address": { - "type": "string", - "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Service Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Service Access socket.\nAddress (and port) or socket is required." - }, - "pmm_agent_id": { - "type": "string", - "description": "The \"pmm-agent\" identifier which should run agents. Required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "username": { - "type": "string", - "description": "ProxySQL username for scraping metrics." - }, - "password": { - "type": "string", - "description": "ProxySQL password for scraping metrics." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for this exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "title": "Exporter log level" - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddRDSServiceParams": { - "type": "object", - "properties": { - "region": { - "type": "string", - "description": "AWS region." - }, - "az": { - "type": "string", - "description": "AWS availability zone." - }, - "instance_id": { - "type": "string", - "description": "AWS instance ID." - }, - "node_model": { - "type": "string", - "description": "AWS instance class." - }, - "address": { - "type": "string", - "description": "Address used to connect to it." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port." - }, - "engine": { - "$ref": "#/definitions/v1DiscoverRDSEngine", - "description": "Instance engine." - }, - "pmm_agent_id": { - "type": "string", - "description": "PMM Agent ID." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name. Defaults to AWS instance ID." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name. Defaults to AWS instance ID." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "username": { - "type": "string", - "description": "Username for scraping metrics." - }, - "password": { - "type": "string", - "description": "Password for scraping metrics." - }, - "aws_access_key": { - "type": "string", - "description": "AWS Access key." - }, - "aws_secret_key": { - "type": "string", - "description": "AWS Secret key." - }, - "rds_exporter": { - "type": "boolean", - "description": "If true, adds rds_exporter." - }, - "qan_mysql_perfschema": { - "type": "boolean", - "description": "If true, adds qan-mysql-perfschema-agent." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Node and Service." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "disable_query_examples": { - "type": "boolean", - "description": "Disable query examples." - }, - "tablestats_group_table_limit": { - "type": "integer", - "format": "int32", - "description": "Tablestats group collectors will be disabled if there are more than that number of tables.\nIf zero, server's default value is used.\nUse negative value to disable them." - }, - "disable_basic_metrics": { - "type": "boolean", - "description": "Disable basic metrics." - }, - "disable_enhanced_metrics": { - "type": "boolean", - "description": "Disable enhanced metrics." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for this exporter.\nPush metrics mode is not allowed." - }, - "qan_postgresql_pgstatements": { - "type": "boolean", - "title": "If true, add qan-pgstatements" - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "database": { - "type": "string", - "description": "Database name." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_postgresql_exporter_connections": { - "type": "integer", - "format": "int32", - "description": "Maximum number of exporter connections to PostgreSQL instance." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AddServiceRequest": { - "type": "object", - "properties": { - "mysql": { - "$ref": "#/definitions/v1AddMySQLServiceParams" - }, - "mongodb": { - "$ref": "#/definitions/v1AddMongoDBServiceParams" - }, - "postgresql": { - "$ref": "#/definitions/v1AddPostgreSQLServiceParams" - }, - "proxysql": { - "$ref": "#/definitions/v1AddProxySQLServiceParams" - }, - "haproxy": { - "$ref": "#/definitions/v1AddHAProxyServiceParams" - }, - "external": { - "$ref": "#/definitions/v1AddExternalServiceParams" - }, - "rds": { - "$ref": "#/definitions/v1AddRDSServiceParams" - }, - "valkey": { - "$ref": "#/definitions/v1AddValkeyServiceParams" - } - } - }, - "v1AddServiceResponse": { - "type": "object", - "properties": { - "mysql": { - "$ref": "#/definitions/v1MySQLServiceResult" - }, - "mongodb": { - "$ref": "#/definitions/v1MongoDBServiceResult" - }, - "postgresql": { - "$ref": "#/definitions/v1PostgreSQLServiceResult" - }, - "proxysql": { - "$ref": "#/definitions/v1ProxySQLServiceResult" - }, - "haproxy": { - "$ref": "#/definitions/v1HAProxyServiceResult" - }, - "external": { - "$ref": "#/definitions/v1ExternalServiceResult" - }, - "rds": { - "$ref": "#/definitions/v1RDSServiceResult" - }, - "valkey": { - "$ref": "#/definitions/v1ValkeyServiceResult" - } - } - }, - "v1AddValkeyServiceParams": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Node identifier on which the service is running.\nOnly one of these parameters should be present: node_id, node_name, add_node." - }, - "node_name": { - "type": "string", - "description": "Node name on which a service is running.\nOnly one of these parameters should be present: node_id, node_name, add_node." - }, - "add_node": { - "$ref": "#/definitions/v1AddNodeParams", - "description": "Create a new Node with those parameters.\nOnly one of these parameters should be present: node_id, node_name, add_node." - }, - "service_name": { - "type": "string", - "description": "User-defined name, it is required and should be unique across all services." - }, - "address": { - "type": "string", - "description": "Node and Service access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Service access port.\nPort is required when the address is present." - }, - "socket": { - "type": "string", - "description": "Service access socket.\nAddress (and port) or socket is required." - }, - "pmm_agent_id": { - "type": "string", - "description": "The \"pmm-agent\" identifier which should run agents. Required." - }, - "username": { - "type": "string", - "description": "Valkey username for scraping metrics." - }, - "password": { - "type": "string", - "description": "Valkey password for scraping metrics." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "skip_connection_check": { - "type": "boolean", - "description": "Skip connection check." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for connection." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS verification." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for the Valkey exporter.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "title": "Exporter log level" - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "tls_ca": { - "type": "string", - "description": "TLS CA certificate." - }, - "tls_cert": { - "type": "string", - "description": "TLS Certifcate." - }, - "tls_key": { - "type": "string", - "description": "TLS Certificate Key." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1AgentStatus": { - "type": "string", - "enum": [ - "AGENT_STATUS_UNSPECIFIED", - "AGENT_STATUS_STARTING", - "AGENT_STATUS_INITIALIZATION_ERROR", - "AGENT_STATUS_RUNNING", - "AGENT_STATUS_WAITING", - "AGENT_STATUS_STOPPING", - "AGENT_STATUS_DONE", - "AGENT_STATUS_UNKNOWN" - ], - "default": "AGENT_STATUS_UNSPECIFIED", - "description": "AgentStatus represents actual Agent status.\n\n - AGENT_STATUS_STARTING: Agent is starting.\n - AGENT_STATUS_INITIALIZATION_ERROR: Agent encountered error when starting.\n - AGENT_STATUS_RUNNING: Agent is running.\n - AGENT_STATUS_WAITING: Agent encountered error and will be restarted automatically soon.\n - AGENT_STATUS_STOPPING: Agent is stopping.\n - AGENT_STATUS_DONE: Agent has been stopped or disabled.\n - AGENT_STATUS_UNKNOWN: Agent is not connected, we don't know anything about it's state." - }, - "v1AgentVersions": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Agent ID." - }, - "version": { - "type": "string", - "description": "Agent version." - }, - "node_name": { - "type": "string", - "description": "Node name where the agent runs." - }, - "severity": { - "$ref": "#/definitions/v1UpdateSeverity", - "description": "Update severity." - } - } - }, - "v1ContainerNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id of the Generic Node where this Container Node runs." - }, - "container_id": { - "type": "string", - "description": "Container identifier. If specified, must be a unique Docker container identifier." - }, - "container_name": { - "type": "string", - "description": "Container name." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "is_pmm_server_node": { - "type": "boolean", - "description": "True if this node is a PMM Server node (HA mode)." - } - }, - "description": "ContainerNode represents a Docker container." - }, - "v1DiscoverAzureDatabaseInstance": { - "type": "object", - "properties": { - "instance_id": { - "type": "string", - "description": "Azure database instance ID." - }, - "region": { - "type": "string", - "description": "Azure database location." - }, - "service_name": { - "type": "string", - "description": "Azure database server name." - }, - "username": { - "type": "string", - "description": "Database username." - }, - "address": { - "type": "string", - "description": "Address used to connect to it." - }, - "azure_resource_group": { - "type": "string", - "description": "Azure Resource group." - }, - "environment": { - "type": "string", - "description": "Environment tag." - }, - "type": { - "$ref": "#/definitions/v1DiscoverAzureDatabaseType", - "description": "Database type." - }, - "az": { - "type": "string", - "description": "Azure database availability zone." - }, - "node_model": { - "type": "string", - "description": "Represents a purchasable Stock Keeping Unit (SKU) under a product.\nhttps://docs.microsoft.com/en-us/partner-center/develop/product-resources#sku." - } - }, - "description": "DiscoverAzureDatabaseInstance models an unique Azure Database instance for the list of instances returned by Discovery." - }, - "v1DiscoverAzureDatabaseRequest": { - "type": "object", - "properties": { - "azure_client_id": { - "type": "string", - "description": "Azure client ID." - }, - "azure_client_secret": { - "type": "string", - "description": "Azure client secret." - }, - "azure_tenant_id": { - "type": "string", - "description": "Azure tanant ID." - }, - "azure_subscription_id": { - "type": "string", - "description": "Azure subscription ID." - } - }, - "description": "DiscoverAzureDatabaseRequest discover azure databases request." - }, - "v1DiscoverAzureDatabaseResponse": { - "type": "object", - "properties": { - "azure_database_instance": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1DiscoverAzureDatabaseInstance" - } - } - }, - "description": "DiscoverAzureDatabaseResponse discover azure databases response." - }, - "v1DiscoverAzureDatabaseType": { - "type": "string", - "enum": [ - "DISCOVER_AZURE_DATABASE_TYPE_UNSPECIFIED", - "DISCOVER_AZURE_DATABASE_TYPE_MYSQL", - "DISCOVER_AZURE_DATABASE_TYPE_POSTGRESQL" - ], - "default": "DISCOVER_AZURE_DATABASE_TYPE_UNSPECIFIED", - "description": "DiscoverAzureDatabaseType describes supported Azure Database instance engines.\n\n - DISCOVER_AZURE_DATABASE_TYPE_MYSQL: MySQL type: microsoft.dbformysql or MariaDB type: microsoft.dbformariadb\n - DISCOVER_AZURE_DATABASE_TYPE_POSTGRESQL: PostgreSQL type: microsoft.dbformysql" - }, - "v1DiscoverRDSEngine": { - "type": "string", - "enum": [ - "DISCOVER_RDS_ENGINE_UNSPECIFIED", - "DISCOVER_RDS_ENGINE_MYSQL", - "DISCOVER_RDS_ENGINE_POSTGRESQL" - ], - "default": "DISCOVER_RDS_ENGINE_UNSPECIFIED", - "description": "DiscoverRDSEngine describes supported RDS instance engines." - }, - "v1DiscoverRDSInstance": { - "type": "object", - "properties": { - "region": { - "type": "string", - "description": "AWS region." - }, - "az": { - "type": "string", - "description": "AWS availability zone." - }, - "instance_id": { - "type": "string", - "description": "AWS instance ID." - }, - "node_model": { - "type": "string", - "description": "AWS instance class." - }, - "address": { - "type": "string", - "description": "Address used to connect to it." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port." - }, - "engine": { - "$ref": "#/definitions/v1DiscoverRDSEngine", - "description": "Instance engine." - }, - "engine_version": { - "type": "string", - "description": "Engine version." - } - }, - "description": "DiscoverRDSInstance models an unique RDS instance for the list of instances returned by Discovery." - }, - "v1DiscoverRDSRequest": { - "type": "object", - "properties": { - "aws_access_key": { - "type": "string", - "description": "AWS Access key. Optional." - }, - "aws_secret_key": { - "type": "string", - "description": "AWS Secret key. Optional." - } - } - }, - "v1DiscoverRDSResponse": { - "type": "object", - "properties": { - "rds_instances": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1DiscoverRDSInstance" - } - } - } - }, - "v1ExternalExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "runs_on_node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "disabled": { - "type": "boolean", - "description": "If disabled, metrics from this exporter will not be collected." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "HTTP basic auth username for collecting metrics." - }, - "scheme": { - "type": "string", - "description": "Scheme to generate URI to exporter metrics endpoints." - }, - "metrics_path": { - "type": "string", - "description": "Path under which metrics are exposed, used to generate URI." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname verification." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - } - }, - "description": "ExternalExporter runs on any Node type, including Remote Node." - }, - "v1ExternalService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this service instance runs." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "group": { - "type": "string", - "description": "Group name of external service." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP)." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port." - } - }, - "description": "ExternalService represents a generic External service instance." - }, - "v1ExternalServiceResult": { - "type": "object", - "properties": { - "service": { - "$ref": "#/definitions/v1ExternalService" - }, - "external_exporter": { - "$ref": "#/definitions/v1ExternalExporter" - } - } - }, - "v1GenericNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id." - }, - "distro": { - "type": "string", - "description": "Linux distribution name and version." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "is_pmm_server_node": { - "type": "boolean", - "description": "True if this node is a PMM Server node (HA mode)." - } - }, - "description": "GenericNode represents a bare metal server or virtual machine." - }, - "v1GetNodeResponse": { - "type": "object", - "properties": { - "node": { - "$ref": "#/definitions/v1UniversalNode" - } - } - }, - "v1HAProxyService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this service instance runs." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - } - }, - "description": "HAProxyService represents a generic HAProxy service instance." - }, - "v1HAProxyServiceResult": { - "type": "object", - "properties": { - "service": { - "$ref": "#/definitions/v1HAProxyService" - }, - "external_exporter": { - "$ref": "#/definitions/v1ExternalExporter" - } - } - }, - "v1ListAgentVersionsResponse": { - "type": "object", - "properties": { - "agent_versions": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1AgentVersions" - }, - "description": "List of Agent versions." - } - } - }, - "v1ListAgentsResponse": { - "type": "object", - "properties": { - "agents": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1UniversalAgent" - }, - "description": "List of Agents." - } - } - }, - "v1ListNodesResponse": { - "type": "object", - "properties": { - "nodes": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1UniversalNode" - } - } - } - }, - "v1ListServicesResponse": { - "type": "object", - "properties": { - "services": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1UniversalService" - }, - "description": "List of Services." - } - } - }, - "v1LogLevel": { - "type": "string", - "enum": [ - "LOG_LEVEL_UNSPECIFIED", - "LOG_LEVEL_FATAL", - "LOG_LEVEL_ERROR", - "LOG_LEVEL_WARN", - "LOG_LEVEL_INFO", - "LOG_LEVEL_DEBUG" - ], - "default": "LOG_LEVEL_UNSPECIFIED", - "description": "- LOG_LEVEL_UNSPECIFIED: Auto", - "title": "Log level for exporters" - }, - "v1MetricsMode": { - "type": "string", - "enum": [ - "METRICS_MODE_UNSPECIFIED", - "METRICS_MODE_PULL", - "METRICS_MODE_PUSH" - ], - "default": "METRICS_MODE_UNSPECIFIED", - "description": "MetricsMode defines desired metrics mode for agent,\nit can be pull, push or auto mode chosen by server.\n\n - METRICS_MODE_UNSPECIFIED: Auto" - }, - "v1MongoDBExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "stats_collections": { - "type": "array", - "items": { - "type": "string" - }, - "title": "List of colletions to get stats from. Can use *" - }, - "collections_limit": { - "type": "integer", - "format": "int32", - "title": "Collections limit. Only get Databases and collection stats if the total number of collections in the server\nis less than this value. 0: no limit" - }, - "enable_all_collectors": { - "type": "boolean", - "description": "Enable all collectors." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "environment_variable_names": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Environment variable names passed to the exporter." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "MongoDBExporter runs on Generic or Container Node and exposes MongoDB Service metrics." - }, - "v1MongoDBService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "MongoDB version." - } - }, - "description": "MongoDBService represents a generic MongoDB instance." - }, - "v1MongoDBServiceResult": { - "type": "object", - "properties": { - "service": { - "$ref": "#/definitions/v1MongoDBService" - }, - "mongodb_exporter": { - "$ref": "#/definitions/v1MongoDBExporter" - }, - "qan_mongodb_profiler": { - "$ref": "#/definitions/v1QANMongoDBProfilerAgent" - }, - "qan_mongodb_mongolog": { - "$ref": "#/definitions/v1QANMongoDBMongologAgent" - }, - "rta_mongodb_agent": { - "$ref": "#/definitions/v1RTAMongoDBAgent" - } - } - }, - "v1MySQLService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "MySQL version." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra parameters to be added to the DSN." - } - }, - "description": "MySQLService represents a generic MySQL instance." - }, - "v1MySQLServiceResult": { - "type": "object", - "properties": { - "service": { - "$ref": "#/definitions/v1MySQLService" - }, - "mysqld_exporter": { - "$ref": "#/definitions/v1MySQLdExporter" - }, - "qan_mysql_perfschema": { - "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" - }, - "qan_mysql_slowlog": { - "$ref": "#/definitions/v1QANMySQLSlowlogAgent" - }, - "table_count": { - "type": "integer", - "format": "int32", - "description": "Actual table count at the moment of adding." - } - } - }, - "v1MySQLdExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "tablestats_group_table_limit": { - "type": "integer", - "format": "int32", - "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "table_count": { - "type": "integer", - "format": "int32", - "description": "Actual table count at the moment of adding." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "tablestats_group_disabled": { - "type": "boolean", - "description": "True if tablestats group collectors are currently disabled." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "MySQLdExporter runs on Generic or Container Node and exposes MySQL Service metrics." - }, - "v1NodeType": { - "type": "string", - "enum": [ - "NODE_TYPE_UNSPECIFIED", - "NODE_TYPE_GENERIC_NODE", - "NODE_TYPE_CONTAINER_NODE", - "NODE_TYPE_REMOTE_NODE", - "NODE_TYPE_REMOTE_RDS_NODE", - "NODE_TYPE_REMOTE_AZURE_DATABASE_NODE" - ], - "default": "NODE_TYPE_UNSPECIFIED", - "description": "NodeType describes supported Node types." - }, - "v1PMMAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "runs_on_node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "connected": { - "type": "boolean", - "description": "True if Agent is running and connected to pmm-managed." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - } - }, - "description": "PMMAgent runs on Generic or Container Node." - }, - "v1PostgreSQLService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "database_name": { - "type": "string", - "description": "Database name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "PostgreSQL version." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - } - }, - "description": "PostgreSQLService represents a generic PostgreSQL instance." - }, - "v1PostgreSQLServiceResult": { - "type": "object", - "properties": { - "service": { - "$ref": "#/definitions/v1PostgreSQLService" - }, - "postgres_exporter": { - "$ref": "#/definitions/v1PostgresExporter" - }, - "qan_postgresql_pgstatements_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" - }, - "qan_postgresql_pgstatmonitor_agent": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatMonitorAgent" - }, - "warning": { - "type": "string", - "description": "Warning message." - } - } - }, - "v1PostgresExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation. Uses sslmode=required instead of verify-full." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "max_exporter_connections": { - "type": "integer", - "format": "int32", - "description": "Maximum number of connections that exporter can open to the database instance." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "PostgresExporter runs on Generic or Container Node and exposes PostgreSQL Service metrics." - }, - "v1ProxySQLExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "ProxySQL username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "ProxySQLExporter runs on Generic or Container Node and exposes ProxySQL Service metrics." - }, - "v1ProxySQLService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "ProxySQL version." - } - }, - "description": "ProxySQLService represents a generic ProxySQL instance." - }, - "v1ProxySQLServiceResult": { - "type": "object", - "properties": { - "service": { - "$ref": "#/definitions/v1ProxySQLService" - }, - "proxysql_exporter": { - "$ref": "#/definitions/v1ProxySQLExporter" - } - } - }, - "v1QANMongoDBMongologAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profiler data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANMongoDBMongologAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." - }, - "v1QANMongoDBProfilerAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profiler data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANMongoDBProfilerAgent runs within pmm-agent and sends MongoDB Query Analytics data to the PMM Server." - }, - "v1QANMySQLPerfSchemaAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for getting performance data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "query_examples_disabled": { - "type": "boolean", - "description": "True if query examples are disabled." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - } - }, - "description": "QANMySQLPerfSchemaAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." - }, - "v1QANMySQLSlowlogAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MySQL username for getting performance data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "tls_ca": { - "type": "string", - "description": "Certificate Authority certificate chain." - }, - "tls_cert": { - "type": "string", - "description": "Client certificate." - }, - "tls_key": { - "type": "string", - "description": "Password for decrypting tls_cert." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "title": "Limit query length in QAN (default: server-defined; -1: no limit)" - }, - "query_examples_disabled": { - "type": "boolean", - "description": "True if query examples are disabled." - }, - "max_slowlog_file_size": { - "type": "string", - "format": "int64", - "description": "Slowlog file is rotated at this size if \u003e 0." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "title": "mod tidy" - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "extra_dsn_params": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Extra DSN parameters for MySQL connection." - } - }, - "description": "QANMySQLSlowlogAgent runs within pmm-agent and sends MySQL Query Analytics data to the PMM Server." - }, - "v1QANPostgreSQLPgStatMonitorAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for getting pg stat monitor data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "query_examples_disabled": { - "type": "boolean", - "description": "True if query examples are disabled." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANPostgreSQLPgStatMonitorAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." - }, - "v1QANPostgreSQLPgStatementsAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "PostgreSQL username for getting pg stat statements data." - }, - "disable_comments_parsing": { - "type": "boolean", - "description": "Disable parsing comments from queries and showing them in QAN." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN (default: server-defined; -1: no limit)." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "QANPostgreSQLPgStatementsAgent runs within pmm-agent and sends PostgreSQL Query Analytics data to the PMM Server." - }, - "v1RDSExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "node_id": { - "type": "string", - "description": "Node identifier." - }, - "aws_access_key": { - "type": "string", - "description": "AWS Access Key." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status (the same for several configurations)." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics (the same for several configurations)." - }, - "basic_metrics_disabled": { - "type": "boolean", - "description": "Basic metrics are disabled." - }, - "enhanced_metrics_disabled": { - "type": "boolean", - "description": "Enhanced metrics are disabled." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "auto_discovery_limit": { - "type": "integer", - "format": "int32", - "description": "Limit of databases for auto-discovery." - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - } - }, - "description": "RDSExporter runs on Generic or Container Node and exposes RemoteRDS Node metrics." - }, - "v1RDSServiceResult": { - "type": "object", - "properties": { - "node": { - "$ref": "#/definitions/v1RemoteRDSNode" - }, - "rds_exporter": { - "$ref": "#/definitions/v1RDSExporter" - }, - "mysql": { - "$ref": "#/definitions/v1MySQLService" - }, - "mysqld_exporter": { - "$ref": "#/definitions/v1MySQLdExporter" - }, - "qan_mysql_perfschema": { - "$ref": "#/definitions/v1QANMySQLPerfSchemaAgent" - }, - "postgresql": { - "$ref": "#/definitions/v1PostgreSQLService" - }, - "postgresql_exporter": { - "$ref": "#/definitions/v1PostgresExporter" - }, - "qan_postgresql_pgstatements": { - "$ref": "#/definitions/v1QANPostgreSQLPgStatementsAgent" - } - } - }, - "v1RTAMongoDBAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique agent identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "MongoDB username for getting profiler data." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "rta_options": { - "$ref": "#/definitions/v1RTAOptions", - "description": "Real-Time Analytics options." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - } - }, - "description": "RTAMongoDBAgent runs within pmm-agent and sends MongoDB Real-Time Query Analytics data to the PMM Server." - }, - "v1RTAOptions": { - "type": "object", - "properties": { - "collect_interval": { - "type": "string", - "description": "Query collect interval (default 2s is set by server)." - } - }, - "description": "RTAOptions holds Real-Time Query Analytics agent options." - }, - "v1RegisterNodeRequest": { - "type": "object", - "properties": { - "node_type": { - "$ref": "#/definitions/v1NodeType", - "description": "Node type to be registered." - }, - "node_name": { - "type": "string", - "description": "A user-defined name unique across all Nodes." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id." - }, - "distro": { - "type": "string", - "description": "Linux distribution name and version." - }, - "container_id": { - "type": "string", - "description": "Container identifier. If specified, must be a unique Docker container identifier." - }, - "container_name": { - "type": "string", - "description": "Container name." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Node." - }, - "reregister": { - "type": "boolean", - "description": "If true, and Node with that name already exist, it will be removed with all dependent Services and Agents." - }, - "metrics_mode": { - "$ref": "#/definitions/v1MetricsMode", - "description": "Defines metrics flow model for node_exporter being added by this request.\nMetrics could be pushed to the server with vmagent,\npulled by the server, or the server could choose behavior automatically." - }, - "disable_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of collector names to disable in this exporter." - }, - "agent_password": { - "type": "string", - "description": "Custom password for exporter endpoint /metrics." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "instance_id": { - "type": "string", - "description": "AWS instance ID." - } - } - }, - "v1RegisterNodeResponse": { - "type": "object", - "properties": { - "generic_node": { - "$ref": "#/definitions/v1GenericNode" - }, - "container_node": { - "$ref": "#/definitions/v1ContainerNode" - }, - "pmm_agent": { - "$ref": "#/definitions/v1PMMAgent" - }, - "token": { - "type": "string", - "description": "Token represents token for vmagent auth config." - }, - "warning": { - "type": "string", - "description": "Warning message." - } - } - }, - "v1RemoteRDSNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "node_name": { - "type": "string", - "description": "Unique across all Nodes user-defined name." - }, - "address": { - "type": "string", - "description": "DB instance identifier." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "instance_id": { - "type": "string", - "description": "AWS instance ID." - } - }, - "description": "RemoteRDSNode represents remote RDS Node. Agents can't run on Remote RDS Nodes." - }, - "v1RemoveServiceResponse": { - "type": "object" - }, - "v1ServiceType": { - "type": "string", - "enum": [ - "SERVICE_TYPE_UNSPECIFIED", - "SERVICE_TYPE_MYSQL_SERVICE", - "SERVICE_TYPE_MONGODB_SERVICE", - "SERVICE_TYPE_POSTGRESQL_SERVICE", - "SERVICE_TYPE_VALKEY_SERVICE", - "SERVICE_TYPE_PROXYSQL_SERVICE", - "SERVICE_TYPE_HAPROXY_SERVICE", - "SERVICE_TYPE_EXTERNAL_SERVICE" - ], - "default": "SERVICE_TYPE_UNSPECIFIED", - "description": "ServiceType describes supported Service types." - }, - "v1UniversalAgent": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique agent identifier." - }, - "is_agent_password_set": { - "type": "boolean", - "description": "True if the agent password is set." - }, - "agent_type": { - "type": "string", - "description": "Agent type." - }, - "aws_access_key": { - "type": "string", - "description": "AWS Access Key." - }, - "is_aws_secret_key_set": { - "type": "boolean", - "description": "True if AWS Secret Key is set." - }, - "azure_options": { - "$ref": "#/definitions/UniversalAgentAzureOptions", - "description": "Options used for connecting to Azure." - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "Creation timestamp." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "log_level": { - "$ref": "#/definitions/v1LogLevel", - "description": "Log level for exporter." - }, - "max_query_length": { - "type": "integer", - "format": "int32", - "description": "Limit query length in QAN." - }, - "max_query_log_size": { - "type": "string", - "format": "int64", - "description": "Limit query log size in QAN." - }, - "metrics_path": { - "type": "string", - "description": "Path under which metrics are exposed, used to generate URI." - }, - "metrics_scheme": { - "type": "string", - "description": "Scheme to generate URI to exporter metrics endpoints." - }, - "mongo_db_options": { - "$ref": "#/definitions/UniversalAgentMongoDBOptions", - "description": "TLS and other options for connecting to MongoDB." - }, - "mysql_options": { - "$ref": "#/definitions/UniversalAgentMySQLOptions", - "description": "TLS and other options for connecting to MySQL." - }, - "node_id": { - "type": "string", - "description": "A unique node identifier." - }, - "is_password_set": { - "type": "boolean", - "description": "True if password for connecting the agent to the database is set." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier." - }, - "postgresql_options": { - "$ref": "#/definitions/UniversalAgentPostgreSQLOptions", - "description": "TLS options for connecting to PostgreSQL." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "push_metrics": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "query_examples_disabled": { - "type": "boolean", - "description": "True if query examples are disabled." - }, - "comments_parsing_disabled": { - "type": "boolean", - "description": "True if query comments parsing is disabled." - }, - "rds_basic_metrics_disabled": { - "type": "boolean", - "description": "True if RDS basic metrics are disdabled." - }, - "rds_enhanced_metrics_disabled": { - "type": "boolean", - "description": "True if RDS enhanced metrics are disdabled." - }, - "runs_on_node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "status": { - "type": "string", - "description": "Actual Agent status." - }, - "table_count": { - "type": "integer", - "format": "int32", - "description": "Last known table count." - }, - "table_count_tablestats_group_limit": { - "type": "integer", - "format": "int32", - "description": "Tablestats group collectors are disabled if there are more than that number of tables.\n0 means tablestats group collectors are always enabled (no limit).\nNegative value means tablestats group collectors are always disabled." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname validation." - }, - "username": { - "type": "string", - "description": "HTTP basic auth username for collecting metrics." - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp." - }, - "version": { - "type": "string", - "description": "Agent version." - }, - "is_connected": { - "type": "boolean", - "description": "True if Agent is running and connected to pmm-managed." - }, - "expose_exporter": { - "type": "boolean", - "description": "True if an exporter agent is exposed on all host addresses." - }, - "valkey_options": { - "$ref": "#/definitions/UniversalAgentValkeyOptions", - "description": "Options for connecting to Valkey." - }, - "rta_options": { - "$ref": "#/definitions/v1RTAOptions", - "description": "Real-Time Analytics options." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - } - }, - "v1UniversalNode": { - "type": "object", - "properties": { - "node_id": { - "type": "string", - "description": "Unique Node identifier." - }, - "node_type": { - "type": "string", - "description": "Node type." - }, - "node_name": { - "type": "string", - "description": "User-defined node name." - }, - "machine_id": { - "type": "string", - "description": "Linux machine-id." - }, - "distro": { - "type": "string", - "description": "Linux distribution name and version." - }, - "node_model": { - "type": "string", - "description": "Node model." - }, - "container_id": { - "type": "string", - "description": "A node's unique docker container identifier." - }, - "container_name": { - "type": "string", - "description": "Container name." - }, - "address": { - "type": "string", - "description": "Node address (DNS name or IP)." - }, - "region": { - "type": "string", - "description": "Node region." - }, - "az": { - "type": "string", - "description": "Node availability zone." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Node." - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "Creation timestamp." - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp." - }, - "status": { - "$ref": "#/definitions/v1UniversalNodeStatus", - "description": "The health status of the node." - }, - "agents": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/UniversalNodeAgent" - }, - "description": "List of agents related to this node." - }, - "services": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/UniversalNodeService" - }, - "description": "List of services running on this node." - }, - "instance_id": { - "type": "string", - "description": "Instance ID for cloud providers (e.g. AWS RDS)." - }, - "is_pmm_server_node": { - "type": "boolean", - "description": "True if this node is a PMM Server node (HA mode)." - } - } - }, - "v1UniversalNodeStatus": { - "type": "string", - "enum": [ - "STATUS_UNSPECIFIED", - "STATUS_UP", - "STATUS_DOWN", - "STATUS_UNKNOWN" - ], - "default": "STATUS_UNSPECIFIED", - "description": "Node status.\n\n - STATUS_UNSPECIFIED: Invalid status.\n - STATUS_UP: The node is up.\n - STATUS_DOWN: The node is down.\n - STATUS_UNKNOWN: The node's status cannot be known (e.g. there are no metrics yet)." - }, - "v1UniversalService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique service identifier." - }, - "service_type": { - "type": "string", - "description": "Service type." - }, - "service_name": { - "type": "string", - "description": "User-defined name unique across all Services." - }, - "database_name": { - "type": "string", - "description": "Database name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "node_name": { - "type": "string", - "description": "Node name where this instance runs." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels for Service." - }, - "external_group": { - "type": "string", - "description": "External group name." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "Creation timestamp." - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp." - }, - "agents": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1UniversalAgent" - }, - "description": "List of agents related to this service." - }, - "status": { - "$ref": "#/definitions/v1UniversalServiceStatus", - "description": "The health status of the service." - }, - "version": { - "type": "string", - "description": "The service/database version." - } - } - }, - "v1UniversalServiceStatus": { - "type": "string", - "enum": [ - "STATUS_UNSPECIFIED", - "STATUS_UP", - "STATUS_DOWN", - "STATUS_UNKNOWN" - ], - "default": "STATUS_UNSPECIFIED", - "description": "Service status.\n\n - STATUS_UNSPECIFIED: In case we don't support the db vendor yet.\n - STATUS_UP: The service is up.\n - STATUS_DOWN: The service is down.\n - STATUS_UNKNOWN: The service's status cannot be known (e.g. there are no metrics yet)." - }, - "v1UnregisterNodeResponse": { - "type": "object", - "properties": { - "warning": { - "type": "string", - "description": "Warning message if there are more service tokens attached to service account." - } - } - }, - "v1UpdateSeverity": { - "type": "string", - "enum": [ - "UPDATE_SEVERITY_UNSPECIFIED", - "UPDATE_SEVERITY_UNSUPPORTED", - "UPDATE_SEVERITY_UP_TO_DATE", - "UPDATE_SEVERITY_REQUIRED", - "UPDATE_SEVERITY_CRITICAL" - ], - "default": "UPDATE_SEVERITY_UNSPECIFIED", - "description": " - UPDATE_SEVERITY_UNSUPPORTED: The client version is newer than the server version.\n - UPDATE_SEVERITY_UP_TO_DATE: The client version matches the server version.\n - UPDATE_SEVERITY_REQUIRED: The client's minor or patch version is older.\n - UPDATE_SEVERITY_CRITICAL: The client's major version is older." - }, - "v1ValkeyExporter": { - "type": "object", - "properties": { - "agent_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "pmm_agent_id": { - "type": "string", - "description": "The pmm-agent identifier which runs this instance." - }, - "disabled": { - "type": "boolean", - "description": "Desired Agent status: enabled (false) or disabled (true)." - }, - "service_id": { - "type": "string", - "description": "Service identifier." - }, - "username": { - "type": "string", - "description": "Valkey username for scraping metrics." - }, - "tls": { - "type": "boolean", - "description": "Use TLS for database connections." - }, - "tls_skip_verify": { - "type": "boolean", - "description": "Skip TLS certificate and hostname verification." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "push_metrics_enabled": { - "type": "boolean", - "description": "True if exporter uses push metrics mode." - }, - "disabled_collectors": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of disabled collector names." - }, - "status": { - "$ref": "#/definitions/v1AgentStatus", - "description": "Actual Agent status." - }, - "listen_port": { - "type": "integer", - "format": "int64", - "description": "Listen port for scraping metrics." - }, - "process_exec_path": { - "type": "string", - "description": "Path to exec process." - }, - "expose_exporter": { - "type": "boolean", - "title": "Optionally expose the exporter process on all public interfaces" - }, - "metrics_resolutions": { - "$ref": "#/definitions/commonMetricsResolutions", - "description": "Metrics resolution for this agent." - }, - "connection_timeout": { - "type": "string", - "description": "Connection timeout for exporter (if set)." - } - }, - "description": "ValkeyExporter runs on Generic or Container Node and exposes Valkey Service metrics." - }, - "v1ValkeyService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "Valkey version." - } - }, - "description": "ValkeyService represents a generic Valkey instance." - }, - "v1ValkeyServiceResult": { - "type": "object", - "properties": { - "service": { - "$ref": "#/definitions/v1ValkeyService" - }, - "valkey_exporter": { - "$ref": "#/definitions/v1ValkeyExporter" - } - } - } - } -} diff --git a/api/management/v1/severity.pb.go b/api/management/v1/severity.pb.go index 6a14d366aa6..51c04a93a0e 100644 --- a/api/management/v1/severity.pb.go +++ b/api/management/v1/severity.pb.go @@ -125,7 +125,6 @@ var ( Severity(0), // 0: management.v1.Severity } ) - var file_management_v1_severity_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/severity.swagger.json b/api/management/v1/severity.swagger.json deleted file mode 100644 index 251bda17116..00000000000 --- a/api/management/v1/severity.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/severity.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/management/v1/valkey.pb.go b/api/management/v1/valkey.pb.go index a0fc2f73fe2..26cc4db7f99 100644 --- a/api/management/v1/valkey.pb.go +++ b/api/management/v1/valkey.pb.go @@ -417,7 +417,6 @@ var ( (*v1.ValkeyExporter)(nil), // 8: inventory.v1.ValkeyExporter } ) - var file_management_v1_valkey_proto_depIdxs = []int32{ 3, // 0: management.v1.AddValkeyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddValkeyServiceParams.custom_labels:type_name -> management.v1.AddValkeyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/valkey.swagger.json b/api/management/v1/valkey.swagger.json deleted file mode 100644 index a0170f19df2..00000000000 --- a/api/management/v1/valkey.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "management/v1/valkey.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "googleRpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - } - } -} diff --git a/api/qan/v1/collector.pb.go b/api/qan/v1/collector.pb.go index b680bbd8f77..3716a3a24d1 100644 --- a/api/qan/v1/collector.pb.go +++ b/api/qan/v1/collector.pb.go @@ -2757,7 +2757,6 @@ var ( ExampleType(0), // 7: qan.v1.ExampleType } ) - var file_qan_v1_collector_proto_depIdxs = []int32{ 1, // 0: qan.v1.CollectRequest.metrics_bucket:type_name -> qan.v1.MetricsBucket 6, // 1: qan.v1.MetricsBucket.agent_type:type_name -> inventory.v1.AgentType diff --git a/api/qan/v1/collector.swagger.json b/api/qan/v1/collector.swagger.json deleted file mode 100644 index 5313874d3b2..00000000000 --- a/api/qan/v1/collector.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "qan/v1/collector.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/qan/v1/filters.pb.go b/api/qan/v1/filters.pb.go index fcbf5e7aead..390a687dbc4 100644 --- a/api/qan/v1/filters.pb.go +++ b/api/qan/v1/filters.pb.go @@ -293,7 +293,6 @@ var ( (*MapFieldEntry)(nil), // 6: qan.v1.MapFieldEntry } ) - var file_qan_v1_filters_proto_depIdxs = []int32{ 5, // 0: qan.v1.GetFilteredMetricsNamesRequest.period_start_from:type_name -> google.protobuf.Timestamp 5, // 1: qan.v1.GetFilteredMetricsNamesRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/filters.swagger.json b/api/qan/v1/filters.swagger.json deleted file mode 100644 index bd5c3eb7ba0..00000000000 --- a/api/qan/v1/filters.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "qan/v1/filters.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/qan/v1/object_details.pb.go b/api/qan/v1/object_details.pb.go index f004bc0ec60..53e6c06150b 100644 --- a/api/qan/v1/object_details.pb.go +++ b/api/qan/v1/object_details.pb.go @@ -1645,7 +1645,6 @@ var ( ExampleType(0), // 29: qan.v1.ExampleType } ) - var file_qan_v1_object_details_proto_depIdxs = []int32{ 26, // 0: qan.v1.GetMetricsRequest.period_start_from:type_name -> google.protobuf.Timestamp 26, // 1: qan.v1.GetMetricsRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/object_details.swagger.json b/api/qan/v1/object_details.swagger.json deleted file mode 100644 index e5465adaa29..00000000000 --- a/api/qan/v1/object_details.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "qan/v1/object_details.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/qan/v1/profile.pb.go b/api/qan/v1/profile.pb.go index 03ab97e871a..7700b76dcd3 100644 --- a/api/qan/v1/profile.pb.go +++ b/api/qan/v1/profile.pb.go @@ -598,7 +598,6 @@ var ( (*Point)(nil), // 8: qan.v1.Point } ) - var file_qan_v1_profile_proto_depIdxs = []int32{ 7, // 0: qan.v1.GetReportRequest.period_start_from:type_name -> google.protobuf.Timestamp 7, // 1: qan.v1.GetReportRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/profile.swagger.json b/api/qan/v1/profile.swagger.json deleted file mode 100644 index d893a4c50f0..00000000000 --- a/api/qan/v1/profile.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "qan/v1/profile.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/qan/v1/qan.pb.go b/api/qan/v1/qan.pb.go index c1d3bc6bb2e..2d37431a7c0 100644 --- a/api/qan/v1/qan.pb.go +++ b/api/qan/v1/qan.pb.go @@ -1000,7 +1000,6 @@ var ( (*MapFieldEntry)(nil), // 2: qan.v1.MapFieldEntry } ) - var file_qan_v1_qan_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/qan/v1/qan.swagger.json b/api/qan/v1/qan.swagger.json deleted file mode 100644 index eef59052f3e..00000000000 --- a/api/qan/v1/qan.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "qan/v1/qan.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/qan/v1/service.pb.go b/api/qan/v1/service.pb.go index 0e52423aa51..c5c688d9000 100644 --- a/api/qan/v1/service.pb.go +++ b/api/qan/v1/service.pb.go @@ -258,7 +258,6 @@ var ( (*GetQueryExampleResponse)(nil), // 24: qan.v1.GetQueryExampleResponse } ) - var file_qan_v1_service_proto_depIdxs = []int32{ 4, // 0: qan.v1.GetMetricsNamesResponse.data:type_name -> qan.v1.GetMetricsNamesResponse.DataEntry 5, // 1: qan.v1.QANService.GetReport:input_type -> qan.v1.GetReportRequest diff --git a/api/qan/v1/service.swagger.json b/api/qan/v1/service.swagger.json deleted file mode 100644 index d3b007a1e21..00000000000 --- a/api/qan/v1/service.swagger.json +++ /dev/null @@ -1,1568 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "qan/v1/service.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "QANService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/qan/health": { - "get": { - "summary": "Health Check", - "description": "Returns readiness of QAN API2 service.", - "operationId": "HealthCheck", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1HealthCheckResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "QANService" - ] - } - }, - "/v1/qan/metrics:getFilters": { - "post": { - "summary": "Get Filters", - "description": "Provides a filtered map of metrics names.", - "operationId": "GetFilteredMetricsNames", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetFilteredMetricsNamesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "GetFilteredMetricsNamesRequest contains period for which we need filters.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1GetFilteredMetricsNamesRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan/metrics:getNames": { - "post": { - "summary": "Get Metrics Names", - "description": "Provides a map of all metrics names.", - "operationId": "GetMetricsNames", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetMetricsNamesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "MetricsNamesRequest is empty.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1GetMetricsNamesRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan/metrics:getReport": { - "post": { - "summary": "Get Report", - "description": "Returns a list of metrics grouped by queryid or other dimensions.", - "operationId": "GetReport", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetReportResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "ReportRequest defines filtering of metrics report for db server or other dimentions.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1GetReportRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan/query/{queryid}/plan": { - "get": { - "summary": "Get Query Plan", - "description": "Provides a query plan and plan id for specific filtering.", - "operationId": "GetQueryPlan", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetQueryPlanResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "queryid", - "in": "path", - "required": true, - "type": "string" - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan/query:exists": { - "post": { - "summary": "Check Query Existence", - "description": "Checks if query exists in clickhouse.", - "operationId": "QueryExists", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1QueryExistsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "QueryExistsRequest check if provided query exists or not.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1QueryExistsRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan/query:getExample": { - "post": { - "summary": "Get Query Example", - "description": "Provides a list of query examples.", - "operationId": "GetQueryExample", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetQueryExampleResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "GetQueryExampleRequest defines filtering of query examples for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1GetQueryExampleRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan/query:getSchema": { - "post": { - "summary": "Get Schema", - "description": "Provides the schema for a given queryID and serviceID.", - "operationId": "SchemaByQueryID", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1SchemaByQueryIDResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "SchemaByQueryIDRequest returns schema for given query ID and service ID.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1SchemaByQueryIDRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan:explainFingerprint": { - "post": { - "summary": "Get Explain Fingerprint", - "description": "Provides an explain fingerprint for given query ID.", - "operationId": "ExplainFingerprintByQueryID", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ExplainFingerprintByQueryIDResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "ExplainFingerprintByQueryIDRequest get explain fingerprint for given query ID.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1ExplainFingerprintByQueryIDRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan:getHistogram": { - "post": { - "summary": "Get Histogram", - "description": "Provides histogram items for specific filtering.", - "operationId": "GetHistogram", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetHistogramResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "GetHistogramRequest defines filtering by time range, labels and queryid.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1GetHistogramRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan:getLabels": { - "post": { - "summary": "Get Labels", - "description": "Provides a list of labels for object details.", - "operationId": "GetLabels", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetLabelsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "GetLabelsRequest defines filtering of object detail's labels for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1GetLabelsRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - }, - "/v1/qan:getMetrics": { - "post": { - "summary": "Get Metrics", - "description": "Provides a map of metrics for specific filtering.", - "operationId": "GetMetrics", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetMetricsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "GetMetricsRequest defines filtering of metrics for specific value of dimension (ex.: host=hostname1 or queryid=1D410B4BE5060972.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1GetMetricsRequest" - } - } - ], - "tags": [ - "QANService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1ExampleType": { - "type": "string", - "enum": [ - "EXAMPLE_TYPE_UNSPECIFIED", - "EXAMPLE_TYPE_RANDOM", - "EXAMPLE_TYPE_SLOWEST", - "EXAMPLE_TYPE_FASTEST", - "EXAMPLE_TYPE_WITH_ERROR" - ], - "default": "EXAMPLE_TYPE_UNSPECIFIED", - "description": "ExampleType is a type of query example selected for this query class in given period of time." - }, - "v1ExplainFingerprintByQueryIDRequest": { - "type": "object", - "properties": { - "serviceid": { - "type": "string" - }, - "query_id": { - "type": "string" - } - }, - "description": "ExplainFingerprintByQueryIDRequest get explain fingerprint for given query ID." - }, - "v1ExplainFingerprintByQueryIDResponse": { - "type": "object", - "properties": { - "explain_fingerprint": { - "type": "string" - }, - "placeholders_count": { - "type": "integer", - "format": "int64" - } - }, - "description": "ExplainFingerprintByQueryIDResponse is explain fingerprint and placeholders count for given query ID." - }, - "v1GetFilteredMetricsNamesRequest": { - "type": "object", - "properties": { - "period_start_from": { - "type": "string", - "format": "date-time" - }, - "period_start_to": { - "type": "string", - "format": "date-time" - }, - "main_metric_name": { - "type": "string" - }, - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MapFieldEntry" - } - } - }, - "description": "GetFilteredMetricsNamesRequest contains period for which we need filters." - }, - "v1GetFilteredMetricsNamesResponse": { - "type": "object", - "properties": { - "labels": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/v1ListLabels" - } - } - }, - "description": "GetFilteredMetricsNamesResponse is map of labels for given period by key.\nKey is label's name and value is label's value and how many times it occur." - }, - "v1GetHistogramRequest": { - "type": "object", - "properties": { - "period_start_from": { - "type": "string", - "format": "date-time" - }, - "period_start_to": { - "type": "string", - "format": "date-time" - }, - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MapFieldEntry" - } - }, - "queryid": { - "type": "string" - } - }, - "description": "GetHistogramRequest defines filtering by time range, labels and queryid." - }, - "v1GetHistogramResponse": { - "type": "object", - "properties": { - "histogram_items": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1HistogramItem" - } - } - }, - "description": "GetHistogramResponse is histogram items as a list." - }, - "v1GetLabelsRequest": { - "type": "object", - "properties": { - "period_start_from": { - "type": "string", - "format": "date-time" - }, - "period_start_to": { - "type": "string", - "format": "date-time" - }, - "filter_by": { - "type": "string", - "description": "dimension value: ex: queryid - 1D410B4BE5060972." - }, - "group_by": { - "type": "string", - "description": "one of dimension: queryid | host ..." - } - }, - "description": "GetLabelsRequest defines filtering of object detail's labels for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." - }, - "v1GetLabelsResponse": { - "type": "object", - "properties": { - "labels": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/v1ListLabelValues" - } - } - }, - "description": "GetLabelsResponse is a map of labels names as keys and labels values as a list." - }, - "v1GetMetricsNamesRequest": { - "type": "object", - "description": "MetricsNamesRequest is empty." - }, - "v1GetMetricsNamesResponse": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "description": "MetricsNamesReply is map of stored metrics:\nkey is root of metric name in db (Ex:. [m_]query_time[_sum]);\nvalue - Human readable name of metrics." - }, - "v1GetMetricsRequest": { - "type": "object", - "properties": { - "period_start_from": { - "type": "string", - "format": "date-time" - }, - "period_start_to": { - "type": "string", - "format": "date-time" - }, - "filter_by": { - "type": "string", - "description": "dimension value: ex: queryid - 1D410B4BE5060972." - }, - "group_by": { - "type": "string", - "description": "one of dimension: queryid | host ..." - }, - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MapFieldEntry" - } - }, - "include_only_fields": { - "type": "array", - "items": { - "type": "string" - } - }, - "totals": { - "type": "boolean", - "title": "retrieve only values for totals, excluding N/A values" - } - }, - "description": "GetMetricsRequest defines filtering of metrics for specific value of dimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." - }, - "v1GetMetricsResponse": { - "type": "object", - "properties": { - "metrics": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/v1MetricValues" - } - }, - "text_metrics": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "sparkline": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Point" - } - }, - "totals": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/v1MetricValues" - } - }, - "fingerprint": { - "type": "string" - }, - "metadata": { - "$ref": "#/definitions/v1GetSelectedQueryMetadataResponse" - } - }, - "description": "GetMetricsResponse defines metrics for specific value of dimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." - }, - "v1GetQueryExampleRequest": { - "type": "object", - "properties": { - "period_start_from": { - "type": "string", - "format": "date-time" - }, - "period_start_to": { - "type": "string", - "format": "date-time" - }, - "filter_by": { - "type": "string", - "description": "dimension value: ex: queryid - 1D410B4BE5060972." - }, - "group_by": { - "type": "string", - "description": "one of dimension: queryid | host ..." - }, - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MapFieldEntry" - } - }, - "limit": { - "type": "integer", - "format": "int64" - } - }, - "description": "GetQueryExampleRequest defines filtering of query examples for specific value of\ndimension (ex.: host=hostname1 or queryid=1D410B4BE5060972." - }, - "v1GetQueryExampleResponse": { - "type": "object", - "properties": { - "query_examples": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QueryExample" - } - } - }, - "description": "GetQueryExampleResponse list of query examples." - }, - "v1GetQueryPlanResponse": { - "type": "object", - "properties": { - "planid": { - "type": "string" - }, - "query_plan": { - "type": "string" - } - }, - "description": "GetQueryPlanResponse contains planid and query_plan." - }, - "v1GetReportRequest": { - "type": "object", - "properties": { - "period_start_from": { - "type": "string", - "format": "date-time" - }, - "period_start_to": { - "type": "string", - "format": "date-time" - }, - "group_by": { - "type": "string" - }, - "labels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ReportMapFieldEntry" - } - }, - "columns": { - "type": "array", - "items": { - "type": "string" - } - }, - "order_by": { - "type": "string" - }, - "offset": { - "type": "integer", - "format": "int64" - }, - "limit": { - "type": "integer", - "format": "int64" - }, - "main_metric": { - "type": "string" - }, - "search": { - "type": "string" - } - }, - "description": "ReportRequest defines filtering of metrics report for db server or other dimentions." - }, - "v1GetReportResponse": { - "type": "object", - "properties": { - "total_rows": { - "type": "integer", - "format": "int64" - }, - "offset": { - "type": "integer", - "format": "int64" - }, - "limit": { - "type": "integer", - "format": "int64" - }, - "rows": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Row" - } - } - }, - "description": "ReportReply is list of reports per quieryids, hosts etc." - }, - "v1GetSelectedQueryMetadataResponse": { - "type": "object", - "properties": { - "service_name": { - "type": "string" - }, - "database": { - "type": "string" - }, - "schema": { - "type": "string" - }, - "username": { - "type": "string" - }, - "replication_set": { - "type": "string" - }, - "cluster": { - "type": "string" - }, - "service_type": { - "type": "string" - }, - "service_id": { - "type": "string" - }, - "environment": { - "type": "string" - }, - "node_id": { - "type": "string" - }, - "node_name": { - "type": "string" - }, - "node_type": { - "type": "string" - } - }, - "description": "GetSlecetedQueryMetadataResponse consists selected query metadata to show in details for given query ID." - }, - "v1HealthCheckResponse": { - "type": "object", - "description": "HealthCheckResponse is empty, based on returned error qan-api2 is ready or not." - }, - "v1HistogramItem": { - "type": "object", - "properties": { - "range": { - "type": "string" - }, - "frequency": { - "type": "integer", - "format": "int64" - } - }, - "description": "HistogramItem represents one item in histogram." - }, - "v1ListLabelValues": { - "type": "object", - "properties": { - "values": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "description": "ListLabelValues is list of label's values." - }, - "v1ListLabels": { - "type": "object", - "properties": { - "name": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Values" - } - } - }, - "description": "ListLabels is list of label's values: duplicates are impossible." - }, - "v1MapFieldEntry": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "value": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "description": "MapFieldEntry allows to pass labels/dimensions in form like {\"server\": [\"db1\", \"db2\"...]}." - }, - "v1Metric": { - "type": "object", - "properties": { - "stats": { - "$ref": "#/definitions/v1Stat" - } - }, - "description": "Metric cell." - }, - "v1MetricValues": { - "type": "object", - "properties": { - "rate": { - "type": "number", - "format": "float" - }, - "cnt": { - "type": "number", - "format": "float" - }, - "sum": { - "type": "number", - "format": "float" - }, - "min": { - "type": "number", - "format": "float" - }, - "max": { - "type": "number", - "format": "float" - }, - "avg": { - "type": "number", - "format": "float" - }, - "p99": { - "type": "number", - "format": "float" - }, - "percent_of_total": { - "type": "number", - "format": "float" - } - }, - "description": "MetricValues is statistics of specific metric." - }, - "v1Point": { - "type": "object", - "properties": { - "point": { - "type": "integer", - "format": "int64", - "description": "The serial number of the chart point from the largest time in the time interval to the lowest time in the time range." - }, - "time_frame": { - "type": "integer", - "format": "int64", - "description": "Duration beetween two points." - }, - "timestamp": { - "type": "string", - "description": "Time of point in format RFC3339." - }, - "load": { - "type": "number", - "format": "float", - "description": "load is query_time / time_range." - }, - "num_queries_per_sec": { - "type": "number", - "format": "float", - "description": "number of queries in bucket." - }, - "num_queries_with_errors_per_sec": { - "type": "number", - "format": "float", - "description": "number of queries with errors." - }, - "num_queries_with_warnings_per_sec": { - "type": "number", - "format": "float", - "description": "number of queries with warnings." - }, - "m_query_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The statement execution time in seconds." - }, - "m_lock_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The time to acquire locks in seconds." - }, - "m_rows_sent_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of rows sent to the client." - }, - "m_rows_examined_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of rows scanned - SELECT." - }, - "m_rows_affected_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of rows changed - UPDATE, DELETE, INSERT." - }, - "m_rows_read_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of rows read from tables." - }, - "m_merge_passes_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of merge passes that the sort algorithm has had to do." - }, - "m_innodb_io_r_ops_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Counts the number of page read operations scheduled." - }, - "m_innodb_io_r_bytes_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Similar to innodb_IO_r_ops, but the unit is bytes." - }, - "m_innodb_io_r_wait_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Shows how long (in seconds) it took InnoDB to actually read the data from storage." - }, - "m_innodb_rec_lock_wait_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Shows how long (in seconds) the query waited for row locks." - }, - "m_innodb_queue_wait_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Shows how long (in seconds) the query spent either waiting to enter the InnoDB queue or inside that queue waiting for execution." - }, - "m_innodb_pages_distinct_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Counts approximately the number of unique pages the query accessed." - }, - "m_query_length_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Shows how long the query is." - }, - "m_bytes_sent_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of bytes sent to all clients." - }, - "m_tmp_tables_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of temporary tables created on memory for the query." - }, - "m_tmp_disk_tables_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of temporary tables created on disk for the query." - }, - "m_tmp_table_sizes_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total Size in bytes for all temporary tables used in the query." - }, - "m_qc_hit_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Query Cache hits." - }, - "m_full_scan_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The query performed a full table scan." - }, - "m_full_join_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The query performed a full join (a join without indexes)." - }, - "m_tmp_table_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The query created an implicit internal temporary table." - }, - "m_tmp_table_on_disk_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The querys temporary table was stored on disk." - }, - "m_filesort_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The query used a filesort." - }, - "m_filesort_on_disk_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The filesort was performed on disk." - }, - "m_select_full_range_join_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of joins that used a range search on a reference table." - }, - "m_select_range_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of joins that used ranges on the first table." - }, - "m_select_range_check_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of joins without keys that check for key usage after each row." - }, - "m_sort_range_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of sorts that were done using ranges." - }, - "m_sort_rows_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of sorted rows." - }, - "m_sort_scan_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of sorts that were done by scanning the table." - }, - "m_no_index_used_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of queries without index." - }, - "m_no_good_index_used_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of queries without good index." - }, - "m_docs_returned_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of returned documents." - }, - "m_response_length_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The response length of the query result in bytes." - }, - "m_docs_scanned_sum_per_sec": { - "type": "number", - "format": "float", - "description": "The number of scanned documents." - }, - "m_docs_examined_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of documents scanned during query execution." - }, - "m_keys_examined_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of index keys scanned during query execution." - }, - "m_locks_global_acquire_count_read_shared_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of times a global read lock was acquired during query execution." - }, - "m_locks_global_acquire_count_write_shared_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of times a global write lock was acquired during query execution." - }, - "m_locks_database_acquire_count_read_shared_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of times a read lock was acquired at the database level during query execution." - }, - "m_locks_database_acquire_wait_count_read_shared_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of times a read lock at the database level was requested but had to wait before being granted." - }, - "m_locks_database_time_acquiring_micros_read_shared_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Indicates the time, spent acquiring a read lock at the database level during an operation." - }, - "m_locks_collection_acquire_count_read_shared_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Number of times a read lock was acquired on a specific collection during operations." - }, - "m_storage_bytes_read_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of bytes read from storage during a specific operation." - }, - "m_storage_time_reading_micros_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Indicates the time, spent reading data from storage during an operation." - }, - "m_shared_blks_hit_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of shared block cache hits by the statement." - }, - "m_shared_blks_read_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of shared blocks read by the statement." - }, - "m_shared_blks_dirtied_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of shared blocks dirtied by the statement." - }, - "m_shared_blks_written_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of shared blocks written by the statement." - }, - "m_shared_blk_read_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time the statement spent reading shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." - }, - "m_shared_blk_write_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time the statement spent writing shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." - }, - "m_local_blk_read_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time the statement spent reading shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." - }, - "m_local_blk_write_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time the statement spent writing shared blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." - }, - "m_local_blks_hit_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of local block cache hits by the statement." - }, - "m_local_blks_read_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of local blocks read by the statement." - }, - "m_local_blks_dirtied_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of local blocks dirtied by the statement." - }, - "m_local_blks_written_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of local blocks written by the statement." - }, - "m_temp_blks_read_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of temp blocks read by the statement." - }, - "m_temp_blks_written_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of temp blocks written by the statement." - }, - "m_blk_read_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time the statement spent reading blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." - }, - "m_blk_write_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time the statement spent writing blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)." - }, - "m_cpu_user_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time user spent in query." - }, - "m_cpu_sys_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total time system spent in query." - }, - "m_plans_calls_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of planned calls." - }, - "m_wal_records_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of WAL (Write-ahead logging) records." - }, - "m_wal_fpi_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of FPI (full page images) in WAL (Write-ahead logging) records." - }, - "m_wal_bytes_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total bytes of WAL (Write-ahead logging) records." - }, - "m_wal_buffers_full_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of times WAL buffers become full." - }, - "m_parallel_workers_to_launch_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of parallel workers to launch." - }, - "m_parallel_workers_launched_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Total number of parallel workers launched." - }, - "m_plan_time_sum_per_sec": { - "type": "number", - "format": "float", - "description": "Plan time in per seconds." - } - }, - "description": "Point contains values that represents abscissa (time) and ordinate (volume etc.)\nof every point in a coordinate system of Sparklines." - }, - "v1QueryExample": { - "type": "object", - "properties": { - "example": { - "type": "string" - }, - "example_type": { - "$ref": "#/definitions/v1ExampleType" - }, - "is_truncated": { - "type": "integer", - "format": "int64" - }, - "placeholders_count": { - "type": "integer", - "format": "int64" - }, - "explain_fingerprint": { - "type": "string" - }, - "query_id": { - "type": "string" - }, - "example_metrics": { - "type": "string" - }, - "service_id": { - "type": "string" - }, - "service_type": { - "type": "string" - }, - "schema": { - "type": "string" - }, - "tables": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "description": "QueryExample shows query examples and their metrics." - }, - "v1QueryExistsRequest": { - "type": "object", - "properties": { - "serviceid": { - "type": "string" - }, - "query": { - "type": "string" - } - }, - "description": "QueryExistsRequest check if provided query exists or not." - }, - "v1QueryExistsResponse": { - "type": "object", - "properties": { - "exists": { - "type": "boolean" - } - }, - "description": "QueryExistsResponse returns true if query exists." - }, - "v1ReportMapFieldEntry": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "value": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "description": "ReportMapFieldEntry allows to pass labels/dimentions in form like {\"server\": [\"db1\", \"db2\"...]}." - }, - "v1Row": { - "type": "object", - "properties": { - "rank": { - "type": "integer", - "format": "int64" - }, - "dimension": { - "type": "string" - }, - "database": { - "type": "string" - }, - "metrics": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/v1Metric" - } - }, - "sparkline": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Point" - } - }, - "fingerprint": { - "type": "string" - }, - "num_queries": { - "type": "integer", - "format": "int64" - }, - "qps": { - "type": "number", - "format": "float" - }, - "load": { - "type": "number", - "format": "float" - } - }, - "description": "Row define metrics for selected dimention." - }, - "v1SchemaByQueryIDRequest": { - "type": "object", - "properties": { - "service_id": { - "type": "string" - }, - "query_id": { - "type": "string" - } - }, - "description": "SchemaByQueryIDRequest returns schema for given query ID and service ID." - }, - "v1SchemaByQueryIDResponse": { - "type": "object", - "properties": { - "schema": { - "type": "string" - } - }, - "description": "SchemaByQueryIDResponse is schema for given query ID and service ID." - }, - "v1Stat": { - "type": "object", - "properties": { - "rate": { - "type": "number", - "format": "float" - }, - "cnt": { - "type": "number", - "format": "float" - }, - "sum": { - "type": "number", - "format": "float" - }, - "min": { - "type": "number", - "format": "float" - }, - "max": { - "type": "number", - "format": "float" - }, - "p99": { - "type": "number", - "format": "float" - }, - "avg": { - "type": "number", - "format": "float" - }, - "sum_per_sec": { - "type": "number", - "format": "float" - } - }, - "description": "Stat is statistics of specific metric." - }, - "v1Values": { - "type": "object", - "properties": { - "value": { - "type": "string" - }, - "main_metric_percent": { - "type": "number", - "format": "float" - }, - "main_metric_per_sec": { - "type": "number", - "format": "float" - } - }, - "description": "Values is label values and main metric percent and per second." - } - } -} diff --git a/api/realtimeanalytics/v1/collector.pb.go b/api/realtimeanalytics/v1/collector.pb.go index f149de0a6cf..b9b81466e7c 100644 --- a/api/realtimeanalytics/v1/collector.pb.go +++ b/api/realtimeanalytics/v1/collector.pb.go @@ -140,7 +140,6 @@ var ( (*QueryData)(nil), // 2: realtimeanalytics.v1.QueryData } ) - var file_realtimeanalytics_v1_collector_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.CollectRequest.queries:type_name -> realtimeanalytics.v1.QueryData 0, // 1: realtimeanalytics.v1.CollectorService.Collect:input_type -> realtimeanalytics.v1.CollectRequest diff --git a/api/realtimeanalytics/v1/collector.swagger.json b/api/realtimeanalytics/v1/collector.swagger.json deleted file mode 100644 index 0216a29e22a..00000000000 --- a/api/realtimeanalytics/v1/collector.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "realtimeanalytics/v1/collector.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/realtimeanalytics/v1/query.pb.go b/api/realtimeanalytics/v1/query.pb.go index 43c4a1bdd5c..b9ab1809d9a 100644 --- a/api/realtimeanalytics/v1/query.pb.go +++ b/api/realtimeanalytics/v1/query.pb.go @@ -331,7 +331,6 @@ var ( (*durationpb.Duration)(nil), // 3: google.protobuf.Duration } ) - var file_realtimeanalytics_v1_query_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.QueryMongoDBData.operation_start_time:type_name -> google.protobuf.Timestamp 3, // 1: realtimeanalytics.v1.QueryData.query_execution_duration:type_name -> google.protobuf.Duration diff --git a/api/realtimeanalytics/v1/query.swagger.json b/api/realtimeanalytics/v1/query.swagger.json deleted file mode 100644 index 6a628f444b1..00000000000 --- a/api/realtimeanalytics/v1/query.swagger.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "realtimeanalytics/v1/query.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/realtimeanalytics/v1/realtimeanalytics.pb.go b/api/realtimeanalytics/v1/realtimeanalytics.pb.go index 8dbdbf8ccff..bd339f4bad9 100644 --- a/api/realtimeanalytics/v1/realtimeanalytics.pb.go +++ b/api/realtimeanalytics/v1/realtimeanalytics.pb.go @@ -718,7 +718,6 @@ var ( (*QueryData)(nil), // 16: realtimeanalytics.v1.QueryData } ) - var file_realtimeanalytics_v1_realtimeanalytics_proto_depIdxs = []int32{ 12, // 0: realtimeanalytics.v1.ListServicesRequest.service_type:type_name -> inventory.v1.ServiceType 13, // 1: realtimeanalytics.v1.ListServicesResponse.mongodb:type_name -> inventory.v1.MongoDBService diff --git a/api/realtimeanalytics/v1/realtimeanalytics.swagger.json b/api/realtimeanalytics/v1/realtimeanalytics.swagger.json deleted file mode 100644 index 59d45b36d7a..00000000000 --- a/api/realtimeanalytics/v1/realtimeanalytics.swagger.json +++ /dev/null @@ -1,516 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "realtimeanalytics/v1/realtimeanalytics.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "RealtimeAnalyticsService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/realtimeanalytics/queries:search": { - "post": { - "summary": "List Running Database Queries in a particular services", - "description": "Returns list of currently running Database queries in a particular services", - "operationId": "SearchQueries", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1SearchQueriesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "SearchQueriesRequest contains optional filters for listing active Real-Time Analytics session Queries.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1SearchQueriesRequest" - } - } - ], - "tags": [ - "RealtimeAnalyticsService" - ] - } - }, - "/v1/realtimeanalytics/services": { - "get": { - "summary": "List Services that support Real-Time Analytics", - "description": "Returns a list of Services that support Real-Time Analytics filtered by type.", - "operationId": "ListServices", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListServicesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "service_type", - "description": "Return only services filtered by service type.", - "in": "query", - "required": false, - "type": "string", - "enum": [ - "SERVICE_TYPE_UNSPECIFIED", - "SERVICE_TYPE_MYSQL_SERVICE", - "SERVICE_TYPE_MONGODB_SERVICE", - "SERVICE_TYPE_POSTGRESQL_SERVICE", - "SERVICE_TYPE_VALKEY_SERVICE", - "SERVICE_TYPE_PROXYSQL_SERVICE", - "SERVICE_TYPE_HAPROXY_SERVICE", - "SERVICE_TYPE_EXTERNAL_SERVICE" - ], - "default": "SERVICE_TYPE_UNSPECIFIED" - } - ], - "tags": [ - "RealtimeAnalyticsService" - ] - } - }, - "/v1/realtimeanalytics/sessions": { - "get": { - "summary": "List Running Real-Time Analytics Sessions", - "description": "Returns the list of all currently running Real-Time Analytics sessions with their details including service, cluster and status information.", - "operationId": "ListSessions", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListSessionsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "cluster_name", - "description": "Optional filter by cluster name.", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "RealtimeAnalyticsService" - ] - } - }, - "/v1/realtimeanalytics/sessions:start": { - "post": { - "summary": "Start Real-Time Analytics session", - "description": "Start Real-Time Analytics session for a specified service.", - "operationId": "StartSession", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StartSessionResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "StartSessionRequest contains parameters for starting Real-Time Analytics session.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StartSessionRequest" - } - } - ], - "tags": [ - "RealtimeAnalyticsService" - ] - } - }, - "/v1/realtimeanalytics/sessions:stop": { - "post": { - "summary": "Stop Real-Time Analytics session", - "description": "Stop Real-Time Analytics session for a specified service.", - "operationId": "StopSession", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StopSessionResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "description": "StopSessionRequest contains parameters for stopping Real-Time Analytics session.", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StopSessionRequest" - } - } - ], - "tags": [ - "RealtimeAnalyticsService" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1ListServicesResponse": { - "type": "object", - "properties": { - "mongodb": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1MongoDBService" - } - } - } - }, - "v1ListSessionsResponse": { - "type": "object", - "properties": { - "sessions": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1Session" - }, - "description": "List of active Real-Time Analytics Sessions." - } - }, - "description": "ListSessionsResponse returns the list of currently active Real-Time Analytics Sessions." - }, - "v1MongoDBService": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Unique randomly generated instance identifier." - }, - "service_name": { - "type": "string", - "description": "Unique across all Services user-defined name." - }, - "node_id": { - "type": "string", - "description": "Node identifier where this instance runs." - }, - "address": { - "type": "string", - "description": "Access address (DNS name or IP).\nAddress (and port) or socket is required." - }, - "port": { - "type": "integer", - "format": "int64", - "description": "Access port.\nPort is required when the address present." - }, - "socket": { - "type": "string", - "description": "Access unix socket.\nAddress (and port) or socket is required." - }, - "environment": { - "type": "string", - "description": "Environment name." - }, - "cluster": { - "type": "string", - "description": "Cluster name." - }, - "replication_set": { - "type": "string", - "description": "Replication set name." - }, - "custom_labels": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Custom user-assigned labels." - }, - "version": { - "type": "string", - "description": "MongoDB version." - } - }, - "description": "MongoDBService represents a generic MongoDB instance." - }, - "v1QueryData": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "PMM Service identifier that reported the query." - }, - "service_name": { - "type": "string", - "description": "PMM Service name that reported the query." - }, - "query_id": { - "type": "string", - "description": "Unique identifier for the query." - }, - "query_text": { - "type": "string", - "description": "The text of the query." - }, - "query_raw_json": { - "type": "string", - "description": "Raw JSON representation of the query." - }, - "query_execution_duration": { - "type": "string", - "description": "Current query current execution time." - }, - "query_collect_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the query data was collected by Real-Time Analytics agent." - }, - "client_address": { - "type": "string", - "description": "Client address (host:port)." - }, - "mongo_db_payload": { - "$ref": "#/definitions/v1QueryMongoDBData", - "description": "MongoDB-specific query data." - } - }, - "description": "QueryData represents a single Real-Time Analytics query data point.\nIt includes general query information and a payload for database-specific details." - }, - "v1QueryMongoDBData": { - "type": "object", - "properties": { - "db_instance_address": { - "type": "string", - "description": "MongoDB instance address(host:port) that processing the query." - }, - "client_app_name": { - "type": "string", - "description": "Client application name from the MongoDB query." - }, - "database_name": { - "type": "string", - "description": "Database name." - }, - "collection": { - "type": "string", - "description": "Collection name." - }, - "operation": { - "type": "string", - "description": "Query operation (\"find\", \"aggregate\", \"update\", etc)." - }, - "operation_start_time": { - "type": "string", - "format": "date-time", - "description": "The start time of the operation." - }, - "username": { - "type": "string", - "description": "MongoDB user name associated with the query." - }, - "plan_summary": { - "type": "string", - "description": "Indicates if an index (COLLSCAN vs IXSCAN) was utilized in the query." - } - }, - "description": "QueryMongoDBData holds MongoDB-specific Real-Time Analytics query information." - }, - "v1SearchQueriesRequest": { - "type": "object", - "properties": { - "service_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional filter by Service identifiers." - }, - "limit": { - "type": "string", - "format": "int64", - "description": "Optional limit the number of queries in response." - } - }, - "description": "SearchQueriesRequest contains optional filters for listing active Real-Time Analytics session Queries." - }, - "v1SearchQueriesResponse": { - "type": "object", - "properties": { - "queries": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1QueryData" - }, - "description": "List of active Real-Time Analytics session Queries." - } - }, - "description": "SearchQueriesResponse returns the list of currently active Real-Time Analytics session Queries." - }, - "v1ServiceType": { - "type": "string", - "enum": [ - "SERVICE_TYPE_UNSPECIFIED", - "SERVICE_TYPE_MYSQL_SERVICE", - "SERVICE_TYPE_MONGODB_SERVICE", - "SERVICE_TYPE_POSTGRESQL_SERVICE", - "SERVICE_TYPE_VALKEY_SERVICE", - "SERVICE_TYPE_PROXYSQL_SERVICE", - "SERVICE_TYPE_HAPROXY_SERVICE", - "SERVICE_TYPE_EXTERNAL_SERVICE" - ], - "default": "SERVICE_TYPE_UNSPECIFIED", - "description": "ServiceType describes supported Service types." - }, - "v1Session": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Service identifier that has enabled Real-Time Analytics session." - }, - "service_name": { - "type": "string", - "description": "Service name." - }, - "cluster_name": { - "type": "string", - "description": "Cluster name the service belongs to." - }, - "start_time": { - "type": "string", - "format": "date-time", - "description": "Timestamp when the Real-Time Analytics session started." - }, - "collect_interval": { - "type": "string", - "description": "Query collect interval." - }, - "status": { - "$ref": "#/definitions/v1SessionStatus", - "description": "Current status of the Real-Time Analytics session." - } - }, - "description": "Session represents an active Real-Time Analytics session." - }, - "v1SessionStatus": { - "type": "string", - "enum": [ - "SESSION_STATUS_UNSPECIFIED", - "SESSION_STATUS_ERROR", - "SESSION_STATUS_RUNNING", - "SESSION_STATUS_DOWN" - ], - "default": "SESSION_STATUS_UNSPECIFIED", - "description": "Status represents actual Real-Time Analytics session status.\n\n - SESSION_STATUS_ERROR: Session encountered an error.\n - SESSION_STATUS_RUNNING: Session is running.\n - SESSION_STATUS_DOWN: Session has been stopped or disabled." - }, - "v1StartSessionRequest": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Required service identifier the Real-Time Analytics session shall be started for." - } - }, - "description": "StartSessionRequest contains parameters for starting Real-Time Analytics session." - }, - "v1StartSessionResponse": { - "type": "object", - "properties": { - "session": { - "$ref": "#/definitions/v1Session" - } - }, - "description": "StartSessionResponse is the response for starting Real-Time Analytics session." - }, - "v1StopSessionRequest": { - "type": "object", - "properties": { - "service_id": { - "type": "string", - "description": "Required service identifier the Real-Time Analytics session shall be stopped for." - } - }, - "description": "StopSessionRequest contains parameters for stopping Real-Time Analytics session." - }, - "v1StopSessionResponse": { - "type": "object", - "description": "StopSessionResponse is the response for stopping Real-Time Analytics session.\n\nEmpty response for now." - } - } -} diff --git a/api/server/v1/httperror.pb.go b/api/server/v1/httperror.pb.go index 8778ad26272..ef269ba2292 100644 --- a/api/server/v1/httperror.pb.go +++ b/api/server/v1/httperror.pb.go @@ -127,7 +127,6 @@ var ( (*anypb.Any)(nil), // 1: google.protobuf.Any } ) - var file_server_v1_httperror_proto_depIdxs = []int32{ 1, // 0: server.v1.HttpError.details:type_name -> google.protobuf.Any 1, // [1:1] is the sub-list for method output_type diff --git a/api/server/v1/httperror.swagger.json b/api/server/v1/httperror.swagger.json deleted file mode 100644 index 7462173f0ff..00000000000 --- a/api/server/v1/httperror.swagger.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "server/v1/httperror.proto", - "version": "version not set" - }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": {}, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string", - "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." - } - }, - "additionalProperties": {}, - "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - } - } -} diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index ab1ab9b07ae..0bbc3212e77 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -2015,7 +2015,6 @@ var ( (*common.StringArray)(nil), // 30: common.StringArray } ) - var file_server_v1_server_proto_depIdxs = []int32{ 27, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo diff --git a/api/server/v1/server.swagger.json b/api/server/v1/server.swagger.json deleted file mode 100644 index 3de137856a3..00000000000 --- a/api/server/v1/server.swagger.json +++ /dev/null @@ -1,839 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "server/v1/server.proto", - "version": "version not set" - }, - "tags": [ - { - "name": "ServerService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/server/leaderHealthCheck": { - "get": { - "summary": "Check Leadership", - "description": "Checks if the instance is the leader in a cluster. Returns an error if the instance isn't the leader.", - "operationId": "LeaderHealthCheck", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1LeaderHealthCheckResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/readyz": { - "get": { - "summary": "Check server readiness", - "description": "Returns an error when Server components being restarted are not ready yet. Use this API for checking the health of Docker containers and for probing Kubernetes readiness.", - "operationId": "Readiness", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ReadinessResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/settings": { - "get": { - "summary": "Get settings", - "description": "Returns current PMM Server settings.", - "operationId": "GetSettings", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetSettingsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "ServerService" - ] - }, - "put": { - "summary": "Change settings", - "description": "Changes PMM Server settings.", - "operationId": "ChangeSettings", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ChangeSettingsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1ChangeSettingsRequest" - } - } - ], - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/settings/readonly": { - "get": { - "summary": "Get read-only settings", - "description": "Returns a stripped version of PMM Server settings.", - "operationId": "GetReadOnlySettings", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetReadOnlySettingsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/updates": { - "get": { - "summary": "Check updates", - "description": "Checks for available PMM Server updates.", - "operationId": "CheckUpdates", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1CheckUpdatesResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "force", - "description": "If false, cached information may be returned.", - "in": "query", - "required": false, - "type": "boolean" - }, - { - "name": "only_installed_version", - "description": "If true, only installed version will be in response.", - "in": "query", - "required": false, - "type": "boolean" - } - ], - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/updates/changelogs": { - "get": { - "summary": "Get the changelog", - "description": "Display a changelog comparing the installed version to the latest available version.", - "operationId": "ListChangeLogs", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListChangeLogsResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/updates:getStatus": { - "post": { - "summary": "Update status", - "description": "Returns PMM Server update status.", - "operationId": "UpdateStatus", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1UpdateStatusResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1UpdateStatusRequest" - } - } - ], - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/updates:start": { - "post": { - "summary": "Start update", - "description": "Starts PMM Server update.", - "operationId": "StartUpdate", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1StartUpdateResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1StartUpdateRequest" - } - } - ], - "tags": [ - "ServerService" - ] - } - }, - "/v1/server/version": { - "get": { - "summary": "Version", - "description": "Returns PMM Server versions.", - "operationId": "Version", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1VersionResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "dummy", - "description": "Dummy parameter for internal testing. Do not use.", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "ServerService" - ] - } - } - }, - "definitions": { - "commonStringArray": { - "type": "object", - "properties": { - "values": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "description": "A wrapper for a string array. This type allows to distinguish between an empty array and a null value." - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string", - "description": "A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n URL, or have them precompiled into a binary to avoid any\n lookup. Therefore, binary compatibility needs to be preserved\n on changes to types. (Use versioned type names to manage\n breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics." - } - }, - "additionalProperties": {}, - "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n // or ...\n if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n foo = any.unpack(Foo.getDefaultInstance());\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1AdvisorRunIntervals": { - "type": "object", - "properties": { - "standard_interval": { - "type": "string", - "description": "Standard check interval." - }, - "rare_interval": { - "type": "string", - "description": "Interval for rare check runs." - }, - "frequent_interval": { - "type": "string", - "description": "Interval for frequent check runs." - } - }, - "description": "AdvisorRunIntervals represents intervals between each run of Advisor checks." - }, - "v1ChangeSettingsRequest": { - "type": "object", - "properties": { - "enable_updates": { - "type": "boolean", - "x-nullable": true - }, - "enable_telemetry": { - "type": "boolean", - "x-nullable": true - }, - "metrics_resolutions": { - "$ref": "#/definitions/v1MetricsResolutions" - }, - "data_retention": { - "type": "string", - "description": "A number of full days for Prometheus and QAN data retention. Should have a suffix in JSON: 2592000s, 43200m, 720h." - }, - "advisor_history_retention": { - "type": "string", - "description": "A number of full days for Advisor check results history retention, i.e. a multiple of 24h: 2592000s, 43200m, 720h." - }, - "enable_advisor_notifications": { - "type": "boolean", - "x-nullable": true, - "description": "Enable Advisor email notifications." - }, - "advisor_notification_severity_threshold": { - "$ref": "#/definitions/v1Severity", - "description": "Least-severe level that triggers an Advisor notification." - }, - "ssh_key": { - "type": "string", - "x-nullable": true - }, - "aws_partitions": { - "$ref": "#/definitions/commonStringArray", - "x-nullable": true - }, - "enable_advisor": { - "type": "boolean", - "x-nullable": true, - "description": "Enable Advisor." - }, - "enable_alerting": { - "type": "boolean", - "x-nullable": true, - "description": "Enable Alerting." - }, - "pmm_public_address": { - "type": "string", - "x-nullable": true, - "description": "PMM Server public address." - }, - "advisor_run_intervals": { - "$ref": "#/definitions/v1AdvisorRunIntervals", - "description": "Intervals between Advisor runs." - }, - "enable_azurediscover": { - "type": "boolean", - "x-nullable": true, - "description": "Enable Azure Discover." - }, - "enable_backup_management": { - "type": "boolean", - "x-nullable": true, - "description": "Enable Backup Management." - }, - "enable_access_control": { - "type": "boolean", - "x-nullable": true, - "title": "Enable Access Control" - }, - "enable_internal_pg_qan": { - "type": "boolean", - "x-nullable": true, - "description": "Enable Query Analytics for PMM's internal PG database." - }, - "update_snooze_duration": { - "type": "string", - "description": "A number of full days for which an update is snoozed, i.e. a multiple of 24h: 2592000s, 43200m, 720h." - } - } - }, - "v1ChangeSettingsResponse": { - "type": "object", - "properties": { - "settings": { - "$ref": "#/definitions/v1Settings" - } - } - }, - "v1CheckUpdatesResponse": { - "type": "object", - "properties": { - "installed": { - "$ref": "#/definitions/v1VersionInfo", - "description": "Currently installed PMM Server version." - }, - "latest": { - "$ref": "#/definitions/v1DockerVersionInfo", - "description": "Latest available PMM Server version." - }, - "update_available": { - "type": "boolean", - "description": "True if there is a PMM Server update available." - }, - "latest_news_url": { - "type": "string", - "description": "Latest available PMM Server release announcement URL." - }, - "last_check": { - "type": "string", - "format": "date-time", - "description": "Last check time." - } - } - }, - "v1DistributionMethod": { - "type": "string", - "enum": [ - "DISTRIBUTION_METHOD_UNSPECIFIED", - "DISTRIBUTION_METHOD_DOCKER", - "DISTRIBUTION_METHOD_OVF", - "DISTRIBUTION_METHOD_AMI", - "DISTRIBUTION_METHOD_AZURE", - "DISTRIBUTION_METHOD_DO" - ], - "default": "DISTRIBUTION_METHOD_UNSPECIFIED", - "description": "DistributionMethod defines PMM Server distribution method: Docker image, OVF/OVA, or AMI." - }, - "v1DockerVersionInfo": { - "type": "object", - "properties": { - "version": { - "type": "string", - "description": "PMM Version." - }, - "tag": { - "type": "string", - "description": "Docker image tag." - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Release date." - }, - "release_notes_url": { - "type": "string", - "description": "Release notes URL for the version (if available)." - }, - "release_notes_text": { - "type": "string", - "description": "Release notes text for the version (if available)." - } - } - }, - "v1GetReadOnlySettingsResponse": { - "type": "object", - "properties": { - "settings": { - "$ref": "#/definitions/v1ReadOnlySettings" - } - } - }, - "v1GetSettingsResponse": { - "type": "object", - "properties": { - "settings": { - "$ref": "#/definitions/v1Settings" - } - } - }, - "v1LeaderHealthCheckResponse": { - "type": "object", - "description": "This probe is available without authentication, so it should not contain any data." - }, - "v1ListChangeLogsResponse": { - "type": "object", - "properties": { - "updates": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1DockerVersionInfo" - }, - "description": "List of available updates." - }, - "last_check": { - "type": "string", - "format": "date-time", - "description": "Last check time." - } - } - }, - "v1MetricsResolutions": { - "type": "object", - "properties": { - "hr": { - "type": "string", - "description": "High resolution. Should have a suffix in JSON: 1s, 1m, 1h." - }, - "mr": { - "type": "string", - "description": "Medium resolution. Should have a suffix in JSON: 1s, 1m, 1h." - }, - "lr": { - "type": "string", - "description": "Low resolution. Should have a suffix in JSON: 1s, 1m, 1h." - } - }, - "description": "MetricsResolutions represents Prometheus exporters metrics resolutions." - }, - "v1ReadOnlySettings": { - "type": "object", - "properties": { - "updates_enabled": { - "type": "boolean", - "description": "True if updates are enabled." - }, - "telemetry_enabled": { - "type": "boolean", - "description": "True if telemetry is enabled." - }, - "advisor_enabled": { - "type": "boolean", - "description": "True if Advisor is enabled." - }, - "alerting_enabled": { - "type": "boolean", - "description": "True if Alerting is enabled." - }, - "pmm_public_address": { - "type": "string", - "description": "PMM Server public address." - }, - "backup_management_enabled": { - "type": "boolean", - "description": "True if Backup Management is enabled." - }, - "azurediscover_enabled": { - "type": "boolean", - "description": "True if Azure Discover is enabled." - }, - "enable_access_control": { - "type": "boolean", - "description": "True if Access Control is enabled." - } - }, - "description": "ReadOnlySettings represents a stripped-down version of PMM Server settings that can be accessed by users of all roles." - }, - "v1ReadinessResponse": { - "type": "object", - "description": "This probe is available without authentication, so it should not contain any data." - }, - "v1Settings": { - "type": "object", - "properties": { - "updates_enabled": { - "type": "boolean", - "description": "True if updates are enabled." - }, - "telemetry_enabled": { - "type": "boolean", - "description": "True if telemetry is enabled." - }, - "metrics_resolutions": { - "$ref": "#/definitions/v1MetricsResolutions" - }, - "data_retention": { - "type": "string" - }, - "advisor_history_retention": { - "type": "string", - "description": "Advisor check results history retention." - }, - "advisor_notifications_enabled": { - "type": "boolean", - "description": "True if Advisor email notifications are enabled." - }, - "advisor_notification_severity_threshold": { - "$ref": "#/definitions/v1Severity", - "description": "Least-severe level that triggers an Advisor notification." - }, - "ssh_key": { - "type": "string" - }, - "aws_partitions": { - "type": "array", - "items": { - "type": "string" - } - }, - "advisor_enabled": { - "type": "boolean", - "description": "True if Advisor is enabled." - }, - "platform_email": { - "type": "string" - }, - "alerting_enabled": { - "type": "boolean", - "description": "True if Alerting is enabled." - }, - "pmm_public_address": { - "type": "string", - "description": "PMM Server public address." - }, - "advisor_run_intervals": { - "$ref": "#/definitions/v1AdvisorRunIntervals", - "description": "Intervals between Advisor runs." - }, - "backup_management_enabled": { - "type": "boolean", - "description": "True if Backup Management is enabled." - }, - "azurediscover_enabled": { - "type": "boolean", - "description": "True if Azure Discover is enabled." - }, - "connected_to_platform": { - "type": "boolean", - "title": "True if the PMM instance is connected to Platform" - }, - "telemetry_summaries": { - "type": "array", - "items": { - "type": "string" - }, - "title": "Includes list of collected telemetry" - }, - "enable_access_control": { - "type": "boolean", - "description": "True if Access Control is enabled." - }, - "default_role_id": { - "type": "integer", - "format": "int64", - "description": "Default Access Control role ID for new users." - }, - "enable_internal_pg_qan": { - "type": "boolean", - "description": "True if Query Analytics for PMM's internal PG database is enabled." - }, - "update_snooze_duration": { - "type": "string", - "title": "Duration for which an update is snoozed" - } - }, - "description": "Settings represents PMM Server settings." - }, - "v1Severity": { - "type": "string", - "enum": [ - "SEVERITY_UNSPECIFIED", - "SEVERITY_EMERGENCY", - "SEVERITY_ALERT", - "SEVERITY_CRITICAL", - "SEVERITY_ERROR", - "SEVERITY_WARNING", - "SEVERITY_NOTICE", - "SEVERITY_INFO", - "SEVERITY_DEBUG" - ], - "default": "SEVERITY_UNSPECIFIED", - "description": "Severity represents severity level of the check result or alert." - }, - "v1StartUpdateRequest": { - "type": "object", - "properties": { - "new_image": { - "type": "string" - } - } - }, - "v1StartUpdateResponse": { - "type": "object", - "properties": { - "auth_token": { - "type": "string", - "description": "Authentication token for getting update statuses." - }, - "log_offset": { - "type": "integer", - "format": "int64", - "description": "Progress log offset." - } - } - }, - "v1UpdateStatusRequest": { - "type": "object", - "properties": { - "auth_token": { - "type": "string", - "description": "Authentication token." - }, - "log_offset": { - "type": "integer", - "format": "int64", - "description": "Progress log offset." - } - } - }, - "v1UpdateStatusResponse": { - "type": "object", - "properties": { - "log_lines": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Progress log lines." - }, - "log_offset": { - "type": "integer", - "format": "int64", - "description": "Progress log offset for the next request." - }, - "done": { - "type": "boolean", - "description": "True when update is done." - } - } - }, - "v1VersionInfo": { - "type": "object", - "properties": { - "version": { - "type": "string", - "description": "User-visible version." - }, - "full_version": { - "type": "string", - "description": "Full version for debugging." - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "Build or release date." - } - }, - "description": "VersionInfo describes component version, or PMM Server as a whole." - }, - "v1VersionResponse": { - "type": "object", - "properties": { - "version": { - "type": "string", - "description": "PMM Server version." - }, - "server": { - "$ref": "#/definitions/v1VersionInfo", - "description": "Detailed PMM Server version information." - }, - "managed": { - "$ref": "#/definitions/v1VersionInfo", - "description": "pmm-managed version information for debugging." - }, - "distribution_method": { - "$ref": "#/definitions/v1DistributionMethod", - "description": "PMM Server distribution method.\n\nTODO Versions and statuses of Grafana, Prometheus, PostgreSQL, qan-api2, ClickHouse, pmm-agent, etc." - } - } - } - } -} diff --git a/api/user/v1/user.pb.go b/api/user/v1/user.pb.go index 12a954ca3f4..200364a0741 100644 --- a/api/user/v1/user.pb.go +++ b/api/user/v1/user.pb.go @@ -507,7 +507,6 @@ var ( (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp } ) - var file_user_v1_user_proto_depIdxs = []int32{ 7, // 0: user.v1.GetUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp 7, // 1: user.v1.UpdateUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp diff --git a/api/user/v1/user.swagger.json b/api/user/v1/user.swagger.json deleted file mode 100644 index 736cc43bfc0..00000000000 --- a/api/user/v1/user.swagger.json +++ /dev/null @@ -1,243 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "User API", - "version": "version not set" - }, - "tags": [ - { - "name": "UserService" - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/v1/users": { - "get": { - "summary": "List all users", - "description": "Retrieve user details for all users from PMM server", - "operationId": "ListUsers", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ListUsersResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "UserService" - ] - } - }, - "/v1/users/me": { - "get": { - "summary": "Get user details", - "description": "Retrieve user details from PMM server", - "operationId": "GetUser", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1GetUserResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "tags": [ - "UserService" - ] - }, - "put": { - "summary": "Update a user", - "description": "Update user details in PMM server", - "operationId": "UpdateUser", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1UpdateUserResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/v1UpdateUserRequest" - } - } - ], - "tags": [ - "UserService" - ] - } - } - }, - "definitions": { - "ListUsersResponseUserDetail": { - "type": "object", - "properties": { - "user_id": { - "type": "integer", - "format": "int64" - }, - "role_ids": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "description": "List of role IDs assigned to the user." - } - } - }, - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1GetUserResponse": { - "type": "object", - "properties": { - "user_id": { - "type": "integer", - "format": "int64", - "title": "User ID" - }, - "product_tour_completed": { - "type": "boolean", - "title": "Product Tour" - }, - "alerting_tour_completed": { - "type": "boolean", - "title": "Alerting Tour" - }, - "snoozed_pmm_version": { - "type": "string", - "title": "Snoozed PMM version update" - }, - "snoozed_at": { - "type": "string", - "format": "date-time", - "title": "Timestamp of last snooze" - }, - "snooze_count": { - "type": "integer", - "format": "int64", - "title": "Number of times the update was snoozed" - } - } - }, - "v1ListUsersResponse": { - "type": "object", - "properties": { - "users": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/ListUsersResponseUserDetail" - } - } - } - }, - "v1UpdateUserRequest": { - "type": "object", - "properties": { - "product_tour_completed": { - "type": "boolean", - "x-nullable": true, - "title": "Product Tour" - }, - "alerting_tour_completed": { - "type": "boolean", - "x-nullable": true, - "title": "Alerting Tour" - }, - "snoozed_pmm_version": { - "type": "string", - "x-nullable": true, - "title": "Snooze update alert for a PMM version" - } - } - }, - "v1UpdateUserResponse": { - "type": "object", - "properties": { - "user_id": { - "type": "integer", - "format": "int64", - "title": "User ID" - }, - "product_tour_completed": { - "type": "boolean", - "title": "Product Tour" - }, - "alerting_tour_completed": { - "type": "boolean", - "title": "Alerting Tour" - }, - "snoozed_pmm_version": { - "type": "string", - "title": "Snooze update alert for a PMM version" - }, - "snoozed_at": { - "type": "string", - "format": "date-time", - "title": "Timestamp of last snooze" - }, - "snooze_count": { - "type": "integer", - "format": "int64", - "title": "Number of times the update was snoozed" - } - } - } - } -} From 12dac404dcbfa38f126505c94bd8af6e2cba0b53 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 14:45:11 +0300 Subject: [PATCH 010/120] PMM-12345 Format the code --- api/accesscontrol/v1beta1/accesscontrol.pb.go | 1 + api/actions/v1/actions.pb.go | 1 + api/advisors/v1/advisors.pb.go | 1 + api/agent/v1/agent.pb.go | 1 + api/agent/v1/collector.pb.go | 1 + api/agentlocal/v1/agentlocal.pb.go | 1 + api/alerting/v1/alerting.pb.go | 1 + api/alerting/v1/params.pb.go | 1 + api/backup/v1/artifacts.pb.go | 1 + api/backup/v1/backup.pb.go | 1 + api/backup/v1/common.pb.go | 1 + api/backup/v1/errors.pb.go | 1 + api/backup/v1/locations.pb.go | 1 + api/backup/v1/restores.pb.go | 1 + api/common/common.pb.go | 1 + api/common/metrics_resolutions.pb.go | 1 + api/dump/v1beta1/dump.pb.go | 1 + api/extensions/v1/redact.pb.go | 1 + api/ha/v1beta1/ha.pb.go | 1 + api/inventory/v1/agent_status.pb.go | 1 + api/inventory/v1/agents.pb.go | 1 + api/inventory/v1/log_level.pb.go | 1 + api/inventory/v1/nodes.pb.go | 1 + api/inventory/v1/services.pb.go | 1 + api/management/v1/agent.pb.go | 1 + api/management/v1/annotation.pb.go | 1 + api/management/v1/azure.pb.go | 1 + api/management/v1/external.pb.go | 1 + api/management/v1/haproxy.pb.go | 1 + api/management/v1/metrics.pb.go | 1 + api/management/v1/mongodb.pb.go | 1 + api/management/v1/mysql.pb.go | 1 + api/management/v1/node.pb.go | 1 + api/management/v1/postgresql.pb.go | 1 + api/management/v1/proxysql.pb.go | 1 + api/management/v1/rds.pb.go | 1 + api/management/v1/service.pb.go | 1 + api/management/v1/severity.pb.go | 1 + api/management/v1/valkey.pb.go | 1 + api/qan/v1/collector.pb.go | 1 + api/qan/v1/filters.pb.go | 1 + api/qan/v1/object_details.pb.go | 1 + api/qan/v1/profile.pb.go | 1 + api/qan/v1/qan.pb.go | 1 + api/qan/v1/service.pb.go | 1 + api/realtimeanalytics/v1/collector.pb.go | 1 + api/realtimeanalytics/v1/query.pb.go | 1 + api/realtimeanalytics/v1/realtimeanalytics.pb.go | 1 + api/server/v1/httperror.pb.go | 1 + api/server/v1/server.pb.go | 1 + api/user/v1/user.pb.go | 1 + 51 files changed, 51 insertions(+) diff --git a/api/accesscontrol/v1beta1/accesscontrol.pb.go b/api/accesscontrol/v1beta1/accesscontrol.pb.go index ebec3bf05b7..f5e8ea4b004 100644 --- a/api/accesscontrol/v1beta1/accesscontrol.pb.go +++ b/api/accesscontrol/v1beta1/accesscontrol.pb.go @@ -844,6 +844,7 @@ var ( (*ListRolesResponse_RoleData)(nil), // 14: accesscontrol.v1beta1.ListRolesResponse.RoleData } ) + var file_accesscontrol_v1beta1_accesscontrol_proto_depIdxs = []int32{ 14, // 0: accesscontrol.v1beta1.ListRolesResponse.roles:type_name -> accesscontrol.v1beta1.ListRolesResponse.RoleData 0, // 1: accesscontrol.v1beta1.AccessControlService.CreateRole:input_type -> accesscontrol.v1beta1.CreateRoleRequest diff --git a/api/actions/v1/actions.pb.go b/api/actions/v1/actions.pb.go index 35461ae3739..f1cfdec8cfa 100644 --- a/api/actions/v1/actions.pb.go +++ b/api/actions/v1/actions.pb.go @@ -2649,6 +2649,7 @@ var ( (*StartServiceActionResponse)(nil), // 32: actions.v1.StartServiceActionResponse } ) + var file_actions_v1_actions_proto_depIdxs = []int32{ 3, // 0: actions.v1.StartServiceActionRequest.mysql_explain:type_name -> actions.v1.StartMySQLExplainActionParams 5, // 1: actions.v1.StartServiceActionRequest.mysql_explain_json:type_name -> actions.v1.StartMySQLExplainJSONActionParams diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index 329c6538645..a179ff24f0e 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -2014,6 +2014,7 @@ var ( (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp } ) + var file_advisors_v1_advisors_proto_depIdxs = []int32{ 29, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity 26, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry diff --git a/api/agent/v1/agent.pb.go b/api/agent/v1/agent.pb.go index 7f5d935624b..c2f2a8b6a9e 100644 --- a/api/agent/v1/agent.pb.go +++ b/api/agent/v1/agent.pb.go @@ -7221,6 +7221,7 @@ var ( (*v11.Metadata)(nil), // 104: backup.v1.Metadata } ) + var file_agent_v1_agent_proto_depIdxs = []int32{ 44, // 0: agent.v1.TextFiles.files:type_name -> agent.v1.TextFiles.FilesEntry 94, // 1: agent.v1.Pong.current_time:type_name -> google.protobuf.Timestamp diff --git a/api/agent/v1/collector.pb.go b/api/agent/v1/collector.pb.go index da17db39c64..65633c05d17 100644 --- a/api/agent/v1/collector.pb.go +++ b/api/agent/v1/collector.pb.go @@ -2827,6 +2827,7 @@ var ( v1.AgentType(0), // 9: inventory.v1.AgentType } ) + var file_agent_v1_collector_proto_depIdxs = []int32{ 3, // 0: agent.v1.MetricsBucket.common:type_name -> agent.v1.MetricsBucket.Common 4, // 1: agent.v1.MetricsBucket.mysql:type_name -> agent.v1.MetricsBucket.MySQL diff --git a/api/agentlocal/v1/agentlocal.pb.go b/api/agentlocal/v1/agentlocal.pb.go index 12053d57921..7bb13a7cb58 100644 --- a/api/agentlocal/v1/agentlocal.pb.go +++ b/api/agentlocal/v1/agentlocal.pb.go @@ -485,6 +485,7 @@ var ( v1.AgentStatus(0), // 8: inventory.v1.AgentStatus } ) + var file_agentlocal_v1_agentlocal_proto_depIdxs = []int32{ 6, // 0: agentlocal.v1.ServerInfo.latency:type_name -> google.protobuf.Duration 6, // 1: agentlocal.v1.ServerInfo.clock_drift:type_name -> google.protobuf.Duration diff --git a/api/alerting/v1/alerting.pb.go b/api/alerting/v1/alerting.pb.go index bccb6659d24..3b2c47d73ec 100644 --- a/api/alerting/v1/alerting.pb.go +++ b/api/alerting/v1/alerting.pb.go @@ -1459,6 +1459,7 @@ var ( (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp } ) + var file_alerting_v1_alerting_proto_depIdxs = []int32{ 22, // 0: alerting.v1.ParamDefinition.unit:type_name -> alerting.v1.ParamUnit 23, // 1: alerting.v1.ParamDefinition.type:type_name -> alerting.v1.ParamType diff --git a/api/alerting/v1/params.pb.go b/api/alerting/v1/params.pb.go index eb001a606db..69d88497102 100644 --- a/api/alerting/v1/params.pb.go +++ b/api/alerting/v1/params.pb.go @@ -163,6 +163,7 @@ var ( ParamType(0), // 1: alerting.v1.ParamType } ) + var file_alerting_v1_params_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/backup/v1/artifacts.pb.go b/api/backup/v1/artifacts.pb.go index e2352f61cd1..dde03ceefef 100644 --- a/api/backup/v1/artifacts.pb.go +++ b/api/backup/v1/artifacts.pb.go @@ -656,6 +656,7 @@ var ( (*Metadata)(nil), // 12: backup.v1.Metadata } ) + var file_backup_v1_artifacts_proto_depIdxs = []int32{ 9, // 0: backup.v1.Artifact.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.Artifact.status:type_name -> backup.v1.BackupStatus diff --git a/api/backup/v1/backup.pb.go b/api/backup/v1/backup.pb.go index 19241fc6afd..4d587217600 100644 --- a/api/backup/v1/backup.pb.go +++ b/api/backup/v1/backup.pb.go @@ -1276,6 +1276,7 @@ var ( (*ListPitrTimerangesResponse)(nil), // 27: backup.v1.ListPitrTimerangesResponse } ) + var file_backup_v1_backup_proto_depIdxs = []int32{ 15, // 0: backup.v1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration 16, // 1: backup.v1.StartBackupRequest.data_model:type_name -> backup.v1.DataModel diff --git a/api/backup/v1/common.pb.go b/api/backup/v1/common.pb.go index f84ca11de32..c8274024e38 100644 --- a/api/backup/v1/common.pb.go +++ b/api/backup/v1/common.pb.go @@ -423,6 +423,7 @@ var ( (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp } ) + var file_backup_v1_common_proto_depIdxs = []int32{ 2, // 0: backup.v1.Metadata.file_list:type_name -> backup.v1.File 6, // 1: backup.v1.Metadata.restore_to:type_name -> google.protobuf.Timestamp diff --git a/api/backup/v1/errors.pb.go b/api/backup/v1/errors.pb.go index 5709e5ac243..902adc277c1 100644 --- a/api/backup/v1/errors.pb.go +++ b/api/backup/v1/errors.pb.go @@ -169,6 +169,7 @@ var ( (*Error)(nil), // 1: backup.v1.Error } ) + var file_backup_v1_errors_proto_depIdxs = []int32{ 0, // 0: backup.v1.Error.code:type_name -> backup.v1.ErrorCode 1, // [1:1] is the sub-list for method output_type diff --git a/api/backup/v1/locations.pb.go b/api/backup/v1/locations.pb.go index 72c13dece43..396b552ee80 100644 --- a/api/backup/v1/locations.pb.go +++ b/api/backup/v1/locations.pb.go @@ -833,6 +833,7 @@ var ( (*TestLocationConfigResponse)(nil), // 12: backup.v1.TestLocationConfigResponse } ) + var file_backup_v1_locations_proto_depIdxs = []int32{ 0, // 0: backup.v1.Location.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig 1, // 1: backup.v1.Location.s3_config:type_name -> backup.v1.S3LocationConfig diff --git a/api/backup/v1/restores.pb.go b/api/backup/v1/restores.pb.go index 580c158b119..ee12d6b9285 100644 --- a/api/backup/v1/restores.pb.go +++ b/api/backup/v1/restores.pb.go @@ -625,6 +625,7 @@ var ( (*LogChunk)(nil), // 10: backup.v1.LogChunk } ) + var file_backup_v1_restores_proto_depIdxs = []int32{ 8, // 0: backup.v1.RestoreHistoryItem.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.RestoreHistoryItem.status:type_name -> backup.v1.RestoreStatus diff --git a/api/common/common.pb.go b/api/common/common.pb.go index 2303ccd29ab..0d05883daa1 100644 --- a/api/common/common.pb.go +++ b/api/common/common.pb.go @@ -147,6 +147,7 @@ var ( nil, // 2: common.StringMap.ValuesEntry } ) + var file_common_common_proto_depIdxs = []int32{ 2, // 0: common.StringMap.values:type_name -> common.StringMap.ValuesEntry 1, // [1:1] is the sub-list for method output_type diff --git a/api/common/metrics_resolutions.pb.go b/api/common/metrics_resolutions.pb.go index 389e4572992..75e587ba9a5 100644 --- a/api/common/metrics_resolutions.pb.go +++ b/api/common/metrics_resolutions.pb.go @@ -118,6 +118,7 @@ var ( (*durationpb.Duration)(nil), // 1: google.protobuf.Duration } ) + var file_common_metrics_resolutions_proto_depIdxs = []int32{ 1, // 0: common.MetricsResolutions.hr:type_name -> google.protobuf.Duration 1, // 1: common.MetricsResolutions.mr:type_name -> google.protobuf.Duration diff --git a/api/dump/v1beta1/dump.pb.go b/api/dump/v1beta1/dump.pb.go index 76f0e473adf..d031bce6b8f 100644 --- a/api/dump/v1beta1/dump.pb.go +++ b/api/dump/v1beta1/dump.pb.go @@ -897,6 +897,7 @@ var ( (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp } ) + var file_dump_v1beta1_dump_proto_depIdxs = []int32{ 0, // 0: dump.v1beta1.Dump.status:type_name -> dump.v1beta1.DumpStatus 14, // 1: dump.v1beta1.Dump.start_time:type_name -> google.protobuf.Timestamp diff --git a/api/extensions/v1/redact.pb.go b/api/extensions/v1/redact.pb.go index c850a90df3c..738ce213118 100644 --- a/api/extensions/v1/redact.pb.go +++ b/api/extensions/v1/redact.pb.go @@ -135,6 +135,7 @@ var ( (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions } ) + var file_extensions_v1_redact_proto_depIdxs = []int32{ 1, // 0: extensions.v1.sensitive:extendee -> google.protobuf.FieldOptions 0, // 1: extensions.v1.sensitive:type_name -> extensions.v1.RedactType diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index 655996ccdbc..f798cccbcc0 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -351,6 +351,7 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) + var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/inventory/v1/agent_status.pb.go b/api/inventory/v1/agent_status.pb.go index ace1432a5e8..1e23074d2fc 100644 --- a/api/inventory/v1/agent_status.pb.go +++ b/api/inventory/v1/agent_status.pb.go @@ -128,6 +128,7 @@ var ( AgentStatus(0), // 0: inventory.v1.AgentStatus } ) + var file_inventory_v1_agent_status_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/agents.pb.go b/api/inventory/v1/agents.pb.go index f5d83515360..3784fc8b7fc 100644 --- a/api/inventory/v1/agents.pb.go +++ b/api/inventory/v1/agents.pb.go @@ -12513,6 +12513,7 @@ var ( (*common.StringMap)(nil), // 112: common.StringMap } ) + var file_inventory_v1_agents_proto_depIdxs = []int32{ 68, // 0: inventory.v1.PMMAgent.custom_labels:type_name -> inventory.v1.PMMAgent.CustomLabelsEntry 108, // 1: inventory.v1.VMAgent.status:type_name -> inventory.v1.AgentStatus diff --git a/api/inventory/v1/log_level.pb.go b/api/inventory/v1/log_level.pb.go index 47f0373d578..ff4d79ca3f2 100644 --- a/api/inventory/v1/log_level.pb.go +++ b/api/inventory/v1/log_level.pb.go @@ -114,6 +114,7 @@ var ( LogLevel(0), // 0: inventory.v1.LogLevel } ) + var file_inventory_v1_log_level_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/nodes.pb.go b/api/inventory/v1/nodes.pb.go index e0186c91815..447663477a9 100644 --- a/api/inventory/v1/nodes.pb.go +++ b/api/inventory/v1/nodes.pb.go @@ -2043,6 +2043,7 @@ var ( nil, // 28: inventory.v1.AddRemoteAzureNodeParams.CustomLabelsEntry } ) + var file_inventory_v1_nodes_proto_depIdxs = []int32{ 19, // 0: inventory.v1.GenericNode.custom_labels:type_name -> inventory.v1.GenericNode.CustomLabelsEntry 20, // 1: inventory.v1.ContainerNode.custom_labels:type_name -> inventory.v1.ContainerNode.CustomLabelsEntry diff --git a/api/inventory/v1/services.pb.go b/api/inventory/v1/services.pb.go index 23eeeb28b81..a8d1519b61f 100644 --- a/api/inventory/v1/services.pb.go +++ b/api/inventory/v1/services.pb.go @@ -3334,6 +3334,7 @@ var ( (*common.StringMap)(nil), // 43: common.StringMap } ) + var file_inventory_v1_services_proto_depIdxs = []int32{ 27, // 0: inventory.v1.MySQLService.custom_labels:type_name -> inventory.v1.MySQLService.CustomLabelsEntry 28, // 1: inventory.v1.MySQLService.extra_dsn_params:type_name -> inventory.v1.MySQLService.ExtraDsnParamsEntry diff --git a/api/management/v1/agent.pb.go b/api/management/v1/agent.pb.go index 8a745a48910..c76c750f869 100644 --- a/api/management/v1/agent.pb.go +++ b/api/management/v1/agent.pb.go @@ -1241,6 +1241,7 @@ var ( (*durationpb.Duration)(nil), // 17: google.protobuf.Duration } ) + var file_management_v1_agent_proto_depIdxs = []int32{ 8, // 0: management.v1.UniversalAgent.azure_options:type_name -> management.v1.UniversalAgent.AzureOptions 14, // 1: management.v1.UniversalAgent.created_at:type_name -> google.protobuf.Timestamp diff --git a/api/management/v1/annotation.pb.go b/api/management/v1/annotation.pb.go index 53bbe233c1b..ec781561e4c 100644 --- a/api/management/v1/annotation.pb.go +++ b/api/management/v1/annotation.pb.go @@ -164,6 +164,7 @@ var ( (*AddAnnotationResponse)(nil), // 1: management.v1.AddAnnotationResponse } ) + var file_management_v1_annotation_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/azure.pb.go b/api/management/v1/azure.pb.go index 863cff6d5ab..04a05c47ec1 100644 --- a/api/management/v1/azure.pb.go +++ b/api/management/v1/azure.pb.go @@ -726,6 +726,7 @@ var ( (*durationpb.Duration)(nil), // 7: google.protobuf.Duration } ) + var file_management_v1_azure_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverAzureDatabaseInstance.type:type_name -> management.v1.DiscoverAzureDatabaseType 2, // 1: management.v1.DiscoverAzureDatabaseResponse.azure_database_instance:type_name -> management.v1.DiscoverAzureDatabaseInstance diff --git a/api/management/v1/external.pb.go b/api/management/v1/external.pb.go index d990cb53abe..3632121e1c2 100644 --- a/api/management/v1/external.pb.go +++ b/api/management/v1/external.pb.go @@ -355,6 +355,7 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) + var file_management_v1_external_proto_depIdxs = []int32{ 3, // 0: management.v1.AddExternalServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddExternalServiceParams.custom_labels:type_name -> management.v1.AddExternalServiceParams.CustomLabelsEntry diff --git a/api/management/v1/haproxy.pb.go b/api/management/v1/haproxy.pb.go index 95cad534323..f3de5158762 100644 --- a/api/management/v1/haproxy.pb.go +++ b/api/management/v1/haproxy.pb.go @@ -333,6 +333,7 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) + var file_management_v1_haproxy_proto_depIdxs = []int32{ 3, // 0: management.v1.AddHAProxyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddHAProxyServiceParams.custom_labels:type_name -> management.v1.AddHAProxyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/metrics.pb.go b/api/management/v1/metrics.pb.go index b552c7955fb..748642db7cb 100644 --- a/api/management/v1/metrics.pb.go +++ b/api/management/v1/metrics.pb.go @@ -103,6 +103,7 @@ var ( MetricsMode(0), // 0: management.v1.MetricsMode } ) + var file_management_v1_metrics_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/mongodb.pb.go b/api/management/v1/mongodb.pb.go index aad151306df..c25cc4f8282 100644 --- a/api/management/v1/mongodb.pb.go +++ b/api/management/v1/mongodb.pb.go @@ -559,6 +559,7 @@ var ( (*v1.RTAMongoDBAgent)(nil), // 11: inventory.v1.RTAMongoDBAgent } ) + var file_management_v1_mongodb_proto_depIdxs = []int32{ 3, // 0: management.v1.AddMongoDBServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMongoDBServiceParams.custom_labels:type_name -> management.v1.AddMongoDBServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mysql.pb.go b/api/management/v1/mysql.pb.go index 70660a14379..18f64740d99 100644 --- a/api/management/v1/mysql.pb.go +++ b/api/management/v1/mysql.pb.go @@ -545,6 +545,7 @@ var ( (*v1.QANMySQLSlowlogAgent)(nil), // 11: inventory.v1.QANMySQLSlowlogAgent } ) + var file_management_v1_mysql_proto_depIdxs = []int32{ 4, // 0: management.v1.AddMySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMySQLServiceParams.custom_labels:type_name -> management.v1.AddMySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/node.pb.go b/api/management/v1/node.pb.go index 53bb2be68db..149fb30ad94 100644 --- a/api/management/v1/node.pb.go +++ b/api/management/v1/node.pb.go @@ -1255,6 +1255,7 @@ var ( (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp } ) + var file_management_v1_node_proto_depIdxs = []int32{ 16, // 0: management.v1.AddNodeParams.node_type:type_name -> inventory.v1.NodeType 11, // 1: management.v1.AddNodeParams.custom_labels:type_name -> management.v1.AddNodeParams.CustomLabelsEntry diff --git a/api/management/v1/postgresql.pb.go b/api/management/v1/postgresql.pb.go index 0e6f54ad033..0271ba48788 100644 --- a/api/management/v1/postgresql.pb.go +++ b/api/management/v1/postgresql.pb.go @@ -535,6 +535,7 @@ var ( (*v1.QANPostgreSQLPgStatMonitorAgent)(nil), // 10: inventory.v1.QANPostgreSQLPgStatMonitorAgent } ) + var file_management_v1_postgresql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddPostgreSQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddPostgreSQLServiceParams.custom_labels:type_name -> management.v1.AddPostgreSQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/proxysql.pb.go b/api/management/v1/proxysql.pb.go index 7d9dbbcfc07..e3142ed85df 100644 --- a/api/management/v1/proxysql.pb.go +++ b/api/management/v1/proxysql.pb.go @@ -395,6 +395,7 @@ var ( (*v1.ProxySQLExporter)(nil), // 8: inventory.v1.ProxySQLExporter } ) + var file_management_v1_proxysql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddProxySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddProxySQLServiceParams.custom_labels:type_name -> management.v1.AddProxySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/rds.pb.go b/api/management/v1/rds.pb.go index fb882ea8de5..d338efd3738 100644 --- a/api/management/v1/rds.pb.go +++ b/api/management/v1/rds.pb.go @@ -854,6 +854,7 @@ var ( (*v1.QANPostgreSQLPgStatementsAgent)(nil), // 16: inventory.v1.QANPostgreSQLPgStatementsAgent } ) + var file_management_v1_rds_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverRDSInstance.engine:type_name -> management.v1.DiscoverRDSEngine 1, // 1: management.v1.DiscoverRDSResponse.rds_instances:type_name -> management.v1.DiscoverRDSInstance diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index 6ea52fbc973..cbad04b7f53 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -1005,6 +1005,7 @@ var ( (*AddAzureDatabaseResponse)(nil), // 47: management.v1.AddAzureDatabaseResponse } ) + var file_management_v1_service_proto_depIdxs = []int32{ 9, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams 10, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams diff --git a/api/management/v1/severity.pb.go b/api/management/v1/severity.pb.go index 51c04a93a0e..6a14d366aa6 100644 --- a/api/management/v1/severity.pb.go +++ b/api/management/v1/severity.pb.go @@ -125,6 +125,7 @@ var ( Severity(0), // 0: management.v1.Severity } ) + var file_management_v1_severity_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/valkey.pb.go b/api/management/v1/valkey.pb.go index 26cc4db7f99..a0fc2f73fe2 100644 --- a/api/management/v1/valkey.pb.go +++ b/api/management/v1/valkey.pb.go @@ -417,6 +417,7 @@ var ( (*v1.ValkeyExporter)(nil), // 8: inventory.v1.ValkeyExporter } ) + var file_management_v1_valkey_proto_depIdxs = []int32{ 3, // 0: management.v1.AddValkeyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddValkeyServiceParams.custom_labels:type_name -> management.v1.AddValkeyServiceParams.CustomLabelsEntry diff --git a/api/qan/v1/collector.pb.go b/api/qan/v1/collector.pb.go index 3716a3a24d1..b680bbd8f77 100644 --- a/api/qan/v1/collector.pb.go +++ b/api/qan/v1/collector.pb.go @@ -2757,6 +2757,7 @@ var ( ExampleType(0), // 7: qan.v1.ExampleType } ) + var file_qan_v1_collector_proto_depIdxs = []int32{ 1, // 0: qan.v1.CollectRequest.metrics_bucket:type_name -> qan.v1.MetricsBucket 6, // 1: qan.v1.MetricsBucket.agent_type:type_name -> inventory.v1.AgentType diff --git a/api/qan/v1/filters.pb.go b/api/qan/v1/filters.pb.go index 390a687dbc4..fcbf5e7aead 100644 --- a/api/qan/v1/filters.pb.go +++ b/api/qan/v1/filters.pb.go @@ -293,6 +293,7 @@ var ( (*MapFieldEntry)(nil), // 6: qan.v1.MapFieldEntry } ) + var file_qan_v1_filters_proto_depIdxs = []int32{ 5, // 0: qan.v1.GetFilteredMetricsNamesRequest.period_start_from:type_name -> google.protobuf.Timestamp 5, // 1: qan.v1.GetFilteredMetricsNamesRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/object_details.pb.go b/api/qan/v1/object_details.pb.go index 53e6c06150b..f004bc0ec60 100644 --- a/api/qan/v1/object_details.pb.go +++ b/api/qan/v1/object_details.pb.go @@ -1645,6 +1645,7 @@ var ( ExampleType(0), // 29: qan.v1.ExampleType } ) + var file_qan_v1_object_details_proto_depIdxs = []int32{ 26, // 0: qan.v1.GetMetricsRequest.period_start_from:type_name -> google.protobuf.Timestamp 26, // 1: qan.v1.GetMetricsRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/profile.pb.go b/api/qan/v1/profile.pb.go index 7700b76dcd3..03ab97e871a 100644 --- a/api/qan/v1/profile.pb.go +++ b/api/qan/v1/profile.pb.go @@ -598,6 +598,7 @@ var ( (*Point)(nil), // 8: qan.v1.Point } ) + var file_qan_v1_profile_proto_depIdxs = []int32{ 7, // 0: qan.v1.GetReportRequest.period_start_from:type_name -> google.protobuf.Timestamp 7, // 1: qan.v1.GetReportRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/qan.pb.go b/api/qan/v1/qan.pb.go index 2d37431a7c0..c1d3bc6bb2e 100644 --- a/api/qan/v1/qan.pb.go +++ b/api/qan/v1/qan.pb.go @@ -1000,6 +1000,7 @@ var ( (*MapFieldEntry)(nil), // 2: qan.v1.MapFieldEntry } ) + var file_qan_v1_qan_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/qan/v1/service.pb.go b/api/qan/v1/service.pb.go index c5c688d9000..0e52423aa51 100644 --- a/api/qan/v1/service.pb.go +++ b/api/qan/v1/service.pb.go @@ -258,6 +258,7 @@ var ( (*GetQueryExampleResponse)(nil), // 24: qan.v1.GetQueryExampleResponse } ) + var file_qan_v1_service_proto_depIdxs = []int32{ 4, // 0: qan.v1.GetMetricsNamesResponse.data:type_name -> qan.v1.GetMetricsNamesResponse.DataEntry 5, // 1: qan.v1.QANService.GetReport:input_type -> qan.v1.GetReportRequest diff --git a/api/realtimeanalytics/v1/collector.pb.go b/api/realtimeanalytics/v1/collector.pb.go index b9b81466e7c..f149de0a6cf 100644 --- a/api/realtimeanalytics/v1/collector.pb.go +++ b/api/realtimeanalytics/v1/collector.pb.go @@ -140,6 +140,7 @@ var ( (*QueryData)(nil), // 2: realtimeanalytics.v1.QueryData } ) + var file_realtimeanalytics_v1_collector_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.CollectRequest.queries:type_name -> realtimeanalytics.v1.QueryData 0, // 1: realtimeanalytics.v1.CollectorService.Collect:input_type -> realtimeanalytics.v1.CollectRequest diff --git a/api/realtimeanalytics/v1/query.pb.go b/api/realtimeanalytics/v1/query.pb.go index b9ab1809d9a..43c4a1bdd5c 100644 --- a/api/realtimeanalytics/v1/query.pb.go +++ b/api/realtimeanalytics/v1/query.pb.go @@ -331,6 +331,7 @@ var ( (*durationpb.Duration)(nil), // 3: google.protobuf.Duration } ) + var file_realtimeanalytics_v1_query_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.QueryMongoDBData.operation_start_time:type_name -> google.protobuf.Timestamp 3, // 1: realtimeanalytics.v1.QueryData.query_execution_duration:type_name -> google.protobuf.Duration diff --git a/api/realtimeanalytics/v1/realtimeanalytics.pb.go b/api/realtimeanalytics/v1/realtimeanalytics.pb.go index bd339f4bad9..8dbdbf8ccff 100644 --- a/api/realtimeanalytics/v1/realtimeanalytics.pb.go +++ b/api/realtimeanalytics/v1/realtimeanalytics.pb.go @@ -718,6 +718,7 @@ var ( (*QueryData)(nil), // 16: realtimeanalytics.v1.QueryData } ) + var file_realtimeanalytics_v1_realtimeanalytics_proto_depIdxs = []int32{ 12, // 0: realtimeanalytics.v1.ListServicesRequest.service_type:type_name -> inventory.v1.ServiceType 13, // 1: realtimeanalytics.v1.ListServicesResponse.mongodb:type_name -> inventory.v1.MongoDBService diff --git a/api/server/v1/httperror.pb.go b/api/server/v1/httperror.pb.go index ef269ba2292..8778ad26272 100644 --- a/api/server/v1/httperror.pb.go +++ b/api/server/v1/httperror.pb.go @@ -127,6 +127,7 @@ var ( (*anypb.Any)(nil), // 1: google.protobuf.Any } ) + var file_server_v1_httperror_proto_depIdxs = []int32{ 1, // 0: server.v1.HttpError.details:type_name -> google.protobuf.Any 1, // [1:1] is the sub-list for method output_type diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index 0bbc3212e77..ab1ab9b07ae 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -2015,6 +2015,7 @@ var ( (*common.StringArray)(nil), // 30: common.StringArray } ) + var file_server_v1_server_proto_depIdxs = []int32{ 27, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo diff --git a/api/user/v1/user.pb.go b/api/user/v1/user.pb.go index 200364a0741..12a954ca3f4 100644 --- a/api/user/v1/user.pb.go +++ b/api/user/v1/user.pb.go @@ -507,6 +507,7 @@ var ( (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp } ) + var file_user_v1_user_proto_depIdxs = []int32{ 7, // 0: user.v1.GetUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp 7, // 1: user.v1.UpdateUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp From 27c1faa2e82ede8ba39bde2b8a41187293ea9ea8 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 14:59:23 +0300 Subject: [PATCH 011/120] PMM-14109 Remove nolint directives --- managed/services/management/checks.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index 167d651e4a0..a2f26742cb8 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -260,8 +260,8 @@ func (s *ChecksAPIService) ListCheckResultsHistory( return &advisorsv1.ListCheckResultsHistoryResponse{ Results: items, - TotalItems: int32(totalItems), //nolint:gosec - TotalPages: int32(totalPages), //nolint:gosec + TotalItems: int32(totalItems), + TotalPages: int32(totalPages), }, nil } From 7aae5f357a5f037b9f451f5e9265433c54a3a13d Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 15:00:36 +0300 Subject: [PATCH 012/120] PMM-14109 Refactor error handling in CheckResults --- managed/utils/clean/check_results.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/managed/utils/clean/check_results.go b/managed/utils/clean/check_results.go index e9e53da805c..77b8bac7a66 100644 --- a/managed/utils/clean/check_results.go +++ b/managed/utils/clean/check_results.go @@ -47,7 +47,8 @@ func (c *CheckResults) Run(ctx context.Context, interval time.Duration) { l.Error(err) } else { olderThanTS := models.Now().Add(-1 * settings.AdvisorHistoryRetention) - if err := models.CleanupOldCheckResults(c.db.Querier, olderThanTS); err != nil { + err := models.CleanupOldCheckResults(c.db.Querier, olderThanTS) + if err != nil { l.Error(err) } } From 85aff2e13f13754791396a89af29b9242fd95653 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 15:11:25 +0300 Subject: [PATCH 013/120] PMM-14109 Enhance advisor settings test with history retention and severity threshold --- managed/models/settings_helpers_test.go | 12 ++++++++---- managed/services/management/checks.go | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/managed/models/settings_helpers_test.go b/managed/models/settings_helpers_test.go index 81b6116229b..7c1a2667b03 100644 --- a/managed/models/settings_helpers_test.go +++ b/managed/models/settings_helpers_test.go @@ -43,8 +43,9 @@ func TestSettings(t *testing.T) { MR: 10 * time.Second, LR: time.Minute, }, - DataRetention: 30 * 24 * time.Hour, - AWSPartitions: []string{"aws"}, + DataRetention: 30 * 24 * time.Hour, + AdvisorHistoryRetention: 30 * 24 * time.Hour, + AWSPartitions: []string{"aws"}, SaaS: models.Advisors{ AdvisorRunIntervals: models.AdvisorsRunIntervals{ StandardInterval: 24 * time.Hour, @@ -56,6 +57,7 @@ func TestSettings(t *testing.T) { EncryptedItems: actual.EncryptedItems, } expected.Updates.SnoozeDuration = models.DefaultSnoozeDuration + expected.AdvisorNotifications.SeverityThreshold = models.AdvisorNotificationSeverityDefault assert.Equal(t, expected, actual) }) @@ -69,8 +71,9 @@ func TestSettings(t *testing.T) { MR: 10 * time.Second, LR: time.Minute, }, - DataRetention: 30 * 24 * time.Hour, - AWSPartitions: []string{"aws"}, + DataRetention: 30 * 24 * time.Hour, + AdvisorHistoryRetention: 30 * 24 * time.Hour, + AWSPartitions: []string{"aws"}, SaaS: models.Advisors{ AdvisorRunIntervals: models.AdvisorsRunIntervals{ StandardInterval: 24 * time.Hour, @@ -80,6 +83,7 @@ func TestSettings(t *testing.T) { }, } expected.Updates.SnoozeDuration = models.DefaultSnoozeDuration + expected.AdvisorNotifications.SeverityThreshold = models.AdvisorNotificationSeverityDefault assert.Equal(t, expected, s) }) diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index a2f26742cb8..3f1a48fef1b 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -260,7 +260,7 @@ func (s *ChecksAPIService) ListCheckResultsHistory( return &advisorsv1.ListCheckResultsHistoryResponse{ Results: items, - TotalItems: int32(totalItems), + TotalItems: int32(totalItems), //nolint:gosec TotalPages: int32(totalPages), }, nil } From 2fcebfd49eb3d3bc8790fac156ef33904d741f7b Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 15:42:46 +0300 Subject: [PATCH 014/120] PMM-14109 Add tests for CheckResults, Settings, CheckResultRecord, and Advisor Notifications --- managed/models/check_result_helpers_test.go | 233 ++++++++++++++++++ managed/models/settings_helpers_test.go | 19 ++ .../checks/check_result_record_test.go | 90 +++++++ managed/services/checks/checks_test.go | 3 +- managed/services/checks/registry_test.go | 31 +++ .../server/advisor_notifications_test.go | 70 ++++++ managed/utils/clean/check_results_test.go | 62 +++++ 7 files changed, 507 insertions(+), 1 deletion(-) create mode 100644 managed/models/check_result_helpers_test.go create mode 100644 managed/services/checks/check_result_record_test.go create mode 100644 managed/utils/clean/check_results_test.go diff --git a/managed/models/check_result_helpers_test.go b/managed/models/check_result_helpers_test.go new file mode 100644 index 00000000000..821f7ee323a --- /dev/null +++ b/managed/models/check_result_helpers_test.go @@ -0,0 +1,233 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/dialects/postgresql" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/pi/common" + "github.com/percona/pmm/managed/utils/testdb" +) + +func TestCheckResults(t *testing.T) { + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + t.Cleanup(func() { + require.NoError(t, sqlDB.Close()) + }) + + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + q := db.Querier + + create := func(t *testing.T, cr *models.CheckResult) *models.CheckResult { + t.Helper() + require.NoError(t, models.CreateCheckResult(q, cr)) + return cr + } + + t.Run("create and find", func(t *testing.T) { + svc := "svc-find" + labels := map[string]string{"k": "v"} + cr := &models.CheckResult{ + CheckName: "c1", + AdvisorName: "advisor", + Category: "performance", + Interval: models.Standard, + ServiceID: svc, + ServiceName: "find-me", + ServiceType: models.MySQLServiceType, + NodeID: "node-id", + NodeName: "node-find", + Status: models.CheckResultFailed, + Summary: "summary", + Description: "description", + Severity: int(common.Error), + CheckedAt: models.Now(), + } + require.NoError(t, cr.SetLabels(labels)) + create(t, cr) + require.NotEmpty(t, cr.ID) // generated by CreateCheckResult + + got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, cr.ID, got[0].ID) + assert.Equal(t, models.CheckResultFailed, got[0].Status) + assert.Equal(t, int(common.Error), got[0].Severity) + assert.Equal(t, "node-find", got[0].NodeName) + + gotLabels, err := got[0].GetLabels() + require.NoError(t, err) + assert.Equal(t, labels, gotLabels) + }) + + t.Run("filters", func(t *testing.T) { + svc := "svc-filter" + create(t, &models.CheckResult{ + CheckName: "weak_pwd", Category: "security", ServiceID: svc, ServiceName: "ProdMySQL", + NodeName: "node-A", Status: models.CheckResultFailed, Summary: "s", + Severity: int(common.Critical), CheckedAt: models.Now(), + }) + create(t, &models.CheckResult{ + CheckName: "old_ver", Category: "configuration", ServiceID: svc, ServiceName: "devmysql", + NodeName: "node-B", Status: models.CheckResultOK, Summary: "s", + Severity: int(common.Unknown), CheckedAt: models.Now(), + }) + + // service_name: case-insensitive substring. + got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, ServiceName: "prod"}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, "ProdMySQL", got[0].ServiceName) + + // node_name: case-insensitive substring. + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, NodeName: "node-b"}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, "node-B", got[0].NodeName) + + // category: exact. + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, Category: "security"}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + + // check_name: exact. + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, CheckName: "old_ver"}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + + // severity: exact. + sev := int(common.Critical) + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, Severity: &sev}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, int(common.Critical), got[0].Severity) + + // status. + st := models.CheckResultOK + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, Status: &st}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, models.CheckResultOK, got[0].Status) + + count, err := models.CountCheckResults(q, models.CheckResultFilters{ServiceID: svc}) + require.NoError(t, err) + assert.Equal(t, 2, count) + }) + + t.Run("time range filter", func(t *testing.T) { + svc := "svc-time" + create(t, &models.CheckResult{ + CheckName: "c", ServiceID: svc, ServiceName: "s", NodeName: "n", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now().Add(-48 * time.Hour), + }) + create(t, &models.CheckResult{ + CheckName: "c", ServiceID: svc, ServiceName: "s", NodeName: "n", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), + }) + + from := models.Now().Add(-24 * time.Hour) + got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, From: &from}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + }) + + t.Run("pagination ordered by checked_at desc", func(t *testing.T) { + svc := "svc-page" + base := models.Now() + for i := range 5 { + create(t, &models.CheckResult{ + CheckName: fmt.Sprintf("c%d", i), ServiceID: svc, ServiceName: "s", NodeName: "n", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: base.Add(time.Duration(i) * time.Minute), + }) + } + + // First page, newest first. + got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 0, 2) + require.NoError(t, err) + require.Len(t, got, 2) + assert.Equal(t, "c4", got[0].CheckName) + assert.Equal(t, "c3", got[1].CheckName) + + // Last page holds the single oldest row. + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 2, 2) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, "c0", got[0].CheckName) + + count, err := models.CountCheckResults(q, models.CheckResultFilters{ServiceID: svc}) + require.NoError(t, err) + assert.Equal(t, 5, count) + }) + + t.Run("mark read", func(t *testing.T) { + svc := "svc-mark" + cr1 := create(t, &models.CheckResult{ + CheckName: "c1", ServiceID: svc, ServiceName: "s", NodeName: "n", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), + }) + cr2 := create(t, &models.CheckResult{ + CheckName: "c2", ServiceID: svc, ServiceName: "s", NodeName: "n", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), + }) + + require.NoError(t, models.MarkCheckResultsRead(q, []string{cr1.ID}, true)) + + isRead := true + got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, IsRead: &isRead}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, cr1.ID, got[0].ID) + + notRead := false + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, IsRead: ¬Read}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, cr2.ID, got[0].ID) + + // Unmark. + require.NoError(t, models.MarkCheckResultsRead(q, []string{cr1.ID}, false)) + got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, IsRead: ¬Read}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 2) + }) + + t.Run("cleanup old results", func(t *testing.T) { + svc := "svc-clean" + create(t, &models.CheckResult{ + CheckName: "old", ServiceID: svc, ServiceName: "s", NodeName: "n", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now().Add(-72 * time.Hour), + }) + create(t, &models.CheckResult{ + CheckName: "new", ServiceID: svc, ServiceName: "s", NodeName: "n", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), + }) + + require.NoError(t, models.CleanupOldCheckResults(q, models.Now().Add(-24*time.Hour))) + + got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 0, 0) + require.NoError(t, err) + require.Len(t, got, 1) + assert.Equal(t, "new", got[0].CheckName) + }) +} diff --git a/managed/models/settings_helpers_test.go b/managed/models/settings_helpers_test.go index 7c1a2667b03..2a82c7e0ad4 100644 --- a/managed/models/settings_helpers_test.go +++ b/managed/models/settings_helpers_test.go @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/require" "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/utils/testdb" ) @@ -87,6 +88,24 @@ func TestSettings(t *testing.T) { assert.Equal(t, expected, s) }) + t.Run("AdvisorNotifications", func(t *testing.T) { + settings, err := models.UpdateSettings(sqlDB, &models.ChangeSettingsParams{ + EnableAdvisorNotifications: new(true), + AdvisorNotificationSeverityThreshold: common.Warning, + AdvisorHistoryRetention: 48 * time.Hour, + }) + require.NoError(t, err) + assert.True(t, settings.IsAdvisorNotificationsEnabled()) + assert.Equal(t, common.Warning, settings.AdvisorNotifications.SeverityThreshold) + assert.Equal(t, 48*time.Hour, settings.AdvisorHistoryRetention) + + // An out-of-range severity threshold is rejected. + _, err = models.UpdateSettings(sqlDB, &models.ChangeSettingsParams{ + AdvisorNotificationSeverityThreshold: common.Severity(42), + }) + require.ErrorContains(t, err, "advisor_notification_severity_threshold") + }) + t.Run("Validation", func(t *testing.T) { t.Run("AWSPartitions", func(t *testing.T) { s := &models.ChangeSettingsParams{ diff --git a/managed/services/checks/check_result_record_test.go b/managed/services/checks/check_result_record_test.go new file mode 100644 index 00000000000..73590c35b19 --- /dev/null +++ b/managed/services/checks/check_result_record_test.go @@ -0,0 +1,90 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package checks + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/pi/check" + "github.com/percona/pmm/managed/pi/common" + "github.com/percona/pmm/managed/services" +) + +func TestNewCheckResultRecord(t *testing.T) { + t.Parallel() + + c := check.Check{Name: "chk", Advisor: "adv", Interval: check.Standard} + target := services.Target{ + ServiceID: "sid", + ServiceName: "sname", + ServiceType: models.MySQLServiceType, + NodeID: "nid", + NodeName: "nname", + } + checkedAt := models.Now() + + t.Run("failed finding maps all fields", func(t *testing.T) { + t.Parallel() + + result := check.Result{ + Summary: "sum", + Description: "desc", + ReadMoreURL: "https://example.com", + Severity: common.Error, + Labels: map[string]string{"k": "v"}, + } + + rec := newCheckResultRecord(c, target, "performance", models.CheckResultFailed, result, checkedAt) + + assert.Equal(t, "chk", rec.CheckName) + assert.Equal(t, "adv", rec.AdvisorName) + assert.Equal(t, "performance", rec.Category) + assert.Equal(t, models.Interval(check.Standard), rec.Interval) + assert.Equal(t, "sid", rec.ServiceID) + assert.Equal(t, "sname", rec.ServiceName) + assert.Equal(t, models.MySQLServiceType, rec.ServiceType) + assert.Equal(t, "nid", rec.NodeID) + assert.Equal(t, "nname", rec.NodeName) + assert.Equal(t, models.CheckResultFailed, rec.Status) + assert.Equal(t, "sum", rec.Summary) + assert.Equal(t, "desc", rec.Description) + assert.Equal(t, "https://example.com", rec.ReadMoreURL) + assert.Equal(t, int(common.Error), rec.Severity) + assert.Equal(t, checkedAt, rec.CheckedAt) + + labels, err := rec.GetLabels() + require.NoError(t, err) + assert.Equal(t, map[string]string{"k": "v"}, labels) + }) + + t.Run("ok outcome has empty finding fields", func(t *testing.T) { + t.Parallel() + + rec := newCheckResultRecord(c, target, "performance", models.CheckResultOK, check.Result{}, checkedAt) + + assert.Equal(t, models.CheckResultOK, rec.Status) + assert.Empty(t, rec.Summary) + assert.Zero(t, rec.Severity) + + labels, err := rec.GetLabels() + require.NoError(t, err) + assert.Empty(t, labels) + }) +} diff --git a/managed/services/checks/checks_test.go b/managed/services/checks/checks_test.go index dbcc2ddedea..f80bdac2b7f 100644 --- a/managed/services/checks/checks_test.go +++ b/managed/services/checks/checks_test.go @@ -541,7 +541,8 @@ func TestFindTargets(t *testing.T) { } func TestFindTargetsSkipsOnlyInternalPostgreSQL(t *testing.T) { - t.Parallel() + // NOTE: no t.Parallel() - testdb.Open recreates a single shared database, so concurrent + // testdb tests collide. sqlDB := testdb.Open(t, models.SetupFixtures, nil) t.Cleanup(func() { require.NoError(t, sqlDB.Close()) diff --git a/managed/services/checks/registry_test.go b/managed/services/checks/registry_test.go index 90f842bd470..178687fa086 100644 --- a/managed/services/checks/registry_test.go +++ b/managed/services/checks/registry_test.go @@ -16,11 +16,14 @@ package checks import ( + "strings" "testing" + "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/pi/check" "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/services" @@ -237,3 +240,31 @@ func TestRegistry(t *testing.T) { assert.Empty(t, collectedAlerts) }) } + +func TestRegistryInsightsMetric(t *testing.T) { + r := newRegistry() + r.set([]services.CheckResult{ + { + CheckName: "mysql_version", + AdvisorName: "adv", + Interval: check.Standard, + Target: services.Target{ + ServiceID: "svc-id", + ServiceName: "mysql-prod", + ServiceType: models.MySQLServiceType, + }, + Result: check.Result{ + Summary: "outdated", + Severity: common.Error, + }, + }, + }) + + const expected = ` +# HELP pmm_managed_advisor_check_insights Number of advisor insights per service type, service name, advisor, check name and severity +# TYPE pmm_managed_advisor_check_insights gauge +pmm_managed_advisor_check_insights{advisor="adv",check_name="mysql_version",service_name="mysql-prod",service_type="mysql",severity="error"} 1 +` + err := testutil.CollectAndCompare(r, strings.NewReader(expected), "pmm_managed_advisor_check_insights") + require.NoError(t, err) +} diff --git a/managed/services/server/advisor_notifications_test.go b/managed/services/server/advisor_notifications_test.go index 3a99882ac75..cbb3279c10e 100644 --- a/managed/services/server/advisor_notifications_test.go +++ b/managed/services/server/advisor_notifications_test.go @@ -16,12 +16,17 @@ package server import ( + "errors" "testing" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/pi/common" + "github.com/percona/pmm/managed/services" ) func TestAdvisorNotificationSeverityRegex(t *testing.T) { @@ -46,3 +51,68 @@ func TestBuildAdvisorNotificationRule(t *testing.T) { assert.True(t, rule.GrafanaAlert.Data[0].Model.Instant) assert.Equal(t, "1", rule.Labels[advisorNotificationLabel]) } + +func TestReconcileAdvisorNotifications(t *testing.T) { + t.Parallel() + + newServer := func(t *testing.T) (*Server, *mockGrafanaClient) { + t.Helper() + gc := newMockGrafanaClient(t) + s := &Server{ + grafanaClient: gc, + l: logrus.WithField("test", t.Name()), + } + return s, gc + } + + enabledSettings := func() *models.Settings { + s := &models.Settings{} + s.AdvisorNotifications.Enabled = new(true) + s.AdvisorNotifications.SeverityThreshold = common.Error + return s + } + + t.Run("enabled creates folder and rule", func(t *testing.T) { + t.Parallel() + + s, gc := newServer(t) + gc.On("CreateFolderWithUID", mock.Anything, advisorNotificationsFolderTitle, advisorNotificationsFolderUID).Return(nil) + gc.On("DeleteAlertRuleGroup", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup).Return(nil) + gc.On("GetDatasourceUIDByID", mock.Anything, int64(1)).Return("ds-uid", nil) + gc.On( + "CreateAlertRule", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup, advisorNotificationsRuleInterval, + mock.MatchedBy(func(rule *services.Rule) bool { + return rule.GrafanaAlert.Data[0].Model.Expr == `pmm_managed_advisor_check_insights{severity=~"emergency|alert|critical|error"} > 0` && + rule.Labels[advisorNotificationLabel] == "1" + }), + ).Return(nil) + + err := s.reconcileAdvisorNotifications(t.Context(), enabledSettings()) + require.NoError(t, err) + }) + + t.Run("disabled deletes rule group only", func(t *testing.T) { + t.Parallel() + + s, gc := newServer(t) + gc.On("DeleteAlertRuleGroup", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup).Return(nil) + + err := s.reconcileAdvisorNotifications(t.Context(), &models.Settings{}) + require.NoError(t, err) + gc.AssertNotCalled(t, "CreateFolderWithUID") + gc.AssertNotCalled(t, "CreateAlertRule") + }) + + t.Run("enabled returns error when datasource lookup fails", func(t *testing.T) { + t.Parallel() + + s, gc := newServer(t) + gc.On("CreateFolderWithUID", mock.Anything, mock.Anything, mock.Anything).Return(nil) + gc.On("DeleteAlertRuleGroup", mock.Anything, mock.Anything, mock.Anything).Return(nil) + gc.On("GetDatasourceUIDByID", mock.Anything, int64(1)).Return("", errors.New("boom")) + + err := s.reconcileAdvisorNotifications(t.Context(), enabledSettings()) + require.Error(t, err) + gc.AssertNotCalled(t, "CreateAlertRule") + }) +} diff --git a/managed/utils/clean/check_results_test.go b/managed/utils/clean/check_results_test.go new file mode 100644 index 00000000000..53910b1ee5a --- /dev/null +++ b/managed/utils/clean/check_results_test.go @@ -0,0 +1,62 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package clean + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/dialects/postgresql" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/utils/testdb" +) + +func TestCheckResultsCleaner(t *testing.T) { + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + defer func() { + require.NoError(t, sqlDB.Close()) + }() + + db := reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)) + q := db.Querier + + // Default retention is 30 days, so this row is past it and must be removed. + require.NoError(t, models.CreateCheckResult(q, &models.CheckResult{ + CheckName: "old", ServiceID: "svc", ServiceName: "svc", NodeName: "node", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now().Add(-31 * 24 * time.Hour), + })) + require.NoError(t, models.CreateCheckResult(q, &models.CheckResult{ + CheckName: "new", ServiceID: "svc", ServiceName: "svc", NodeName: "node", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), + })) + + ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second) + defer cancel() + + go NewCheckResults(db).Run(ctx, 5*time.Second) + // Give the cleaner the chance to run one iteration. + time.Sleep(100 * time.Millisecond) + + results, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: "svc"}, 0, 0) + require.NoError(t, err) + require.Len(t, results, 1) + assert.Equal(t, "new", results[0].CheckName) +} From 67310ac86907084be996e88c4d61ad52b53822cb Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 28 Jun 2026 18:47:23 +0300 Subject: [PATCH 015/120] PMM-14109 Enhance Advisor notifications handling in server tests --- managed/services/server/server_test.go | 76 ++++++++++++++++++++------ 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/managed/services/server/server_test.go b/managed/services/server/server_test.go index 9b51698e684..052b17feb20 100644 --- a/managed/services/server/server_test.go +++ b/managed/services/server/server_test.go @@ -16,7 +16,6 @@ package server import ( - "context" "errors" "testing" "time" @@ -30,6 +29,7 @@ import ( "gopkg.in/reform.v1" "gopkg.in/reform.v1/dialects/postgresql" + managementv1 "github.com/percona/pmm/api/management/v1" serverv1 "github.com/percona/pmm/api/server/v1" "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/utils/testdb" @@ -50,8 +50,8 @@ func TestServer(t *testing.T) { mvmdb.On("RequestConfigurationUpdate").Return(nil) mState := &mockAgentsStateUpdater{} mState.Test(t) - mState.On("UpdateAgentsState", context.TODO()).Return(nil) - mState.On("RequestStateUpdate", context.TODO(), mock.Anything).Return(nil) + mState.On("UpdateAgentsState", t.Context()).Return(nil) + mState.On("RequestStateUpdate", t.Context(), mock.Anything).Return(nil) var mvmalert mockPrometheusService mvmalert.Test(t) @@ -59,11 +59,11 @@ func TestServer(t *testing.T) { var mtemplatesService mockTemplatesService mtemplatesService.Test(t) - mtemplatesService.On("CollectTemplates", context.TODO()).Return(nil) + mtemplatesService.On("CollectTemplates", t.Context()).Return(nil) var mchecksService mockChecksService mchecksService.Test(t) - mchecksService.On("UpdateAdvisorsList", context.TODO()).Return(nil) + mchecksService.On("UpdateAdvisorsList", t.Context()).Return(nil) var par mockVmAlertExternalRules par.Test(t) @@ -82,6 +82,16 @@ func TestServer(t *testing.T) { ha.On("IsLeader").Return(true) ha.On("Params").Return(&models.HAParams{Enabled: false}) + // Permissive expectations so the Advisor-notifications reconcile (triggered on a settings + // toggle) succeeds; calls are a no-op for tests that don't change those settings. + var mgrafana mockGrafanaClient + mgrafana.Test(t) + mgrafana.On("IsReady", mock.Anything).Return(nil) + mgrafana.On("CreateFolderWithUID", mock.Anything, mock.Anything, mock.Anything).Return(nil) + mgrafana.On("DeleteAlertRuleGroup", mock.Anything, mock.Anything, mock.Anything).Return(nil) + mgrafana.On("GetDatasourceUIDByID", mock.Anything, mock.Anything).Return("ds-uid", nil) + mgrafana.On("CreateAlertRule", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + s, err := NewServer(&Params{ DB: reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)), VMDB: &mvmdb, @@ -94,6 +104,7 @@ func TestServer(t *testing.T) { TelemetryService: &ts, Nomad: &nomad, HAService: &ha, + GrafanaClient: &mgrafana, }) require.NoError(t, err) return s @@ -102,7 +113,7 @@ func TestServer(t *testing.T) { t.Run("UpdateSettingsFromEnv", func(t *testing.T) { t.Run("Typical", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_ENABLE_UPDATES=true", "PMM_ENABLE_TELEMETRY=1", "PMM_METRICS_RESOLUTION_HR=1s", @@ -125,7 +136,7 @@ func TestServer(t *testing.T) { t.Run("Untypical", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_ENABLE_TELEMETRY=TrUe", "PMM_METRICS_RESOLUTION=3S", "PMM_DATA_RETENTION=360H", @@ -138,7 +149,7 @@ func TestServer(t *testing.T) { t.Run("NoValue", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_ENABLE_TELEMETRY", }) require.Len(t, errs, 1) @@ -148,7 +159,7 @@ func TestServer(t *testing.T) { t.Run("InvalidValue", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_ENABLE_TELEMETRY=", }) require.Len(t, errs, 1) @@ -158,7 +169,7 @@ func TestServer(t *testing.T) { t.Run("MetricsLessThenMin", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_METRICS_RESOLUTION=5ns", }) require.Len(t, errs, 1) @@ -170,7 +181,7 @@ func TestServer(t *testing.T) { t.Run("DataRetentionLessThenMin", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_DATA_RETENTION=12h", }) require.Len(t, errs, 1) @@ -182,7 +193,7 @@ func TestServer(t *testing.T) { t.Run("Data retention is not a natural number of days", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_DATA_RETENTION=30h", }) require.Len(t, errs, 1) @@ -194,7 +205,7 @@ func TestServer(t *testing.T) { t.Run("Data retention without suffix", func(t *testing.T) { s := newServer(t) - errs := s.UpdateSettingsFromEnv(context.TODO(), []string{ + errs := s.UpdateSettingsFromEnv(t.Context(), []string{ "PMM_DATA_RETENTION=30", }) require.Len(t, errs, 1) @@ -206,7 +217,7 @@ func TestServer(t *testing.T) { t.Run("ValidateChangeSettingsRequest", func(t *testing.T) { s := newServer(t) - ctx := context.TODO() + ctx := t.Context() s.envSettings.EnableUpdates = new(true) expected := status.New(codes.FailedPrecondition, "Updates are configured via PMM_ENABLE_UPDATES environment variable.") @@ -250,17 +261,26 @@ func TestServer(t *testing.T) { require.NoError(t, s.validateChangeSettingsRequest(ctx, &serverv1.ChangeSettingsRequest{ EnableAdvisor: new(true), })) + + s.envSettings.EnableAdvisorNotifications = new(true) + expected = status.New(codes.FailedPrecondition, "Advisor notifications are configured via PMM_ENABLE_ADVISOR_NOTIFICATIONS environment variable.") + tests.AssertGRPCError(t, expected, s.validateChangeSettingsRequest(ctx, &serverv1.ChangeSettingsRequest{ + EnableAdvisorNotifications: new(false), + })) + require.NoError(t, s.validateChangeSettingsRequest(ctx, &serverv1.ChangeSettingsRequest{ + EnableAdvisorNotifications: new(true), + })) }) t.Run("ChangeSettings", func(t *testing.T) { server := newServer(t) - server.UpdateSettingsFromEnv(context.TODO(), []string{ + server.UpdateSettingsFromEnv(t.Context(), []string{ "ENABLE_ALERTING=1", "PMM_ENABLE_AZURE_DISCOVER=1", }) - ctx := context.TODO() + ctx := t.Context() s, err := server.ChangeSettings(ctx, &serverv1.ChangeSettingsRequest{ EnableTelemetry: new(true), @@ -277,9 +297,9 @@ func TestServer(t *testing.T) { t.Run("ChangeSettings Alerting", func(t *testing.T) { server := newServer(t) - server.UpdateSettingsFromEnv(context.TODO(), []string{}) + server.UpdateSettingsFromEnv(t.Context(), []string{}) - ctx := context.TODO() + ctx := t.Context() s, err := server.ChangeSettings(ctx, &serverv1.ChangeSettingsRequest{ EnableAlerting: new(false), }) @@ -292,4 +312,24 @@ func TestServer(t *testing.T) { require.NoError(t, err) require.NotNil(t, s) }) + + t.Run("ChangeSettings Advisor notifications", func(t *testing.T) { + server := newServer(t) + server.UpdateSettingsFromEnv(t.Context(), []string{}) + + ctx := t.Context() + s, err := server.ChangeSettings(ctx, &serverv1.ChangeSettingsRequest{ + EnableAdvisorNotifications: new(true), + AdvisorNotificationSeverityThreshold: managementv1.Severity_SEVERITY_WARNING, + AdvisorHistoryRetention: durationpb.New(48 * time.Hour), + }) + require.NoError(t, err) + require.NotNil(t, s) + + settings, err := server.GetSettings(ctx, &serverv1.GetSettingsRequest{}) + require.NoError(t, err) + assert.True(t, settings.Settings.AdvisorNotificationsEnabled) + assert.Equal(t, managementv1.Severity_SEVERITY_WARNING, settings.Settings.AdvisorNotificationSeverityThreshold) + assert.Equal(t, durationpb.New(48*time.Hour), settings.Settings.AdvisorHistoryRetention) + }) } From 85d057e56d5c8608a87d4815d93495d44d920d12 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 10:42:12 +0300 Subject: [PATCH 016/120] PMM-14109 Add advisors UI --- ui/AGENTS.md | 1 + ui/apps/pmm/src/api/advisors.ts | 21 +- .../navigation/navigation.constants.ts | 2 +- .../navigation/navigation.provider.tsx | 7 +- .../contexts/navigation/navigation.utils.tsx | 21 +- ui/apps/pmm/src/hooks/api/useAdvisors.ts | 51 +++- .../pages/advisors/AdvisorsList.constants.tsx | 105 ++++++++ .../pages/advisors/AdvisorsList.messages.ts | 32 +++ .../src/pages/advisors/AdvisorsList.test.tsx | 243 ++++++++++++++++++ .../pmm/src/pages/advisors/AdvisorsList.tsx | 180 +++++++++++++ ui/apps/pmm/src/pages/advisors/index.ts | 1 + .../run-menu-button/RunMenuButton.tsx | 61 +++++ .../pages/advisors/run-menu-button/index.ts | 2 + ui/apps/pmm/src/router.tsx | 10 + ui/apps/pmm/src/types/advisors.types.ts | 25 ++ ui/apps/pmm/src/utils/advisors.utils.ts | 20 +- 16 files changed, 752 insertions(+), 30 deletions(-) create mode 100644 ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts create mode 100644 ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/index.ts create mode 100644 ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts diff --git a/ui/AGENTS.md b/ui/AGENTS.md index 65675ce9b53..f77e4be1aab 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -54,6 +54,7 @@ Routes are defined in `ui/apps/pmm/src/router.tsx` using React Router's `createB | `/rta/selection` | RTA service selection | | `/rta/sessions` | RTA sessions list | | `/rta/overview` | RTA overview | +| `/advisors` | Advisors | | `/graph/*` | Grafana iframe | | `*` | 404 fallback | diff --git a/ui/apps/pmm/src/api/advisors.ts b/ui/apps/pmm/src/api/advisors.ts index 536cafbd7dd..2ecfb582b43 100644 --- a/ui/apps/pmm/src/api/advisors.ts +++ b/ui/apps/pmm/src/api/advisors.ts @@ -1,7 +1,26 @@ -import { Advisor, ListAdvisorsResponse } from 'types/advisors.types'; +import { + Advisor, + ChangeAdvisorCheckParams, + ChangeAdvisorChecksRequest, + ListAdvisorsResponse, + StartAdvisorChecksRequest, +} from 'types/advisors.types'; +import { EmptyResponse } from 'types/util.types'; import { api } from './api'; export const listAdvisors = async (): Promise => { const res = await api.get('/advisors'); return res.data.advisors; }; + +export const startAdvisorChecks = async (names: string[]): Promise => { + const payload: StartAdvisorChecksRequest = { names }; + await api.post('/advisors/checks:start', payload); +}; + +export const changeAdvisorChecks = async ( + params: ChangeAdvisorCheckParams[] +): Promise => { + const payload: ChangeAdvisorChecksRequest = { params }; + await api.post('/advisors/checks:batchChange', payload); +}; diff --git a/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts b/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts index 0399e2b8ca3..adb9f55b267 100644 --- a/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts +++ b/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts @@ -537,7 +537,7 @@ export const NAV_ADVISORS: NavItem = { id: 'advisors', icon: 'intelligence', text: 'Advisors', - url: `${PMM_NEW_NAV_GRAFANA_PATH}/advisors`, + url: `${PMM_NEW_NAV_PATH}/advisors`, }; export const NAV_ADVISORS_INSIGHTS = { diff --git a/ui/apps/pmm/src/contexts/navigation/navigation.provider.tsx b/ui/apps/pmm/src/contexts/navigation/navigation.provider.tsx index d14d7f6c307..45d048bce43 100644 --- a/ui/apps/pmm/src/contexts/navigation/navigation.provider.tsx +++ b/ui/apps/pmm/src/contexts/navigation/navigation.provider.tsx @@ -14,7 +14,6 @@ import { addHomePage, } from './navigation.utils'; import { useUser } from 'contexts/user'; -import { useAdvisors } from 'hooks/api/useAdvisors'; import { useColorMode } from 'hooks/theme'; import { INTERVALS_MS } from 'lib/constants'; import { useSettings } from 'contexts/settings'; @@ -38,9 +37,6 @@ export const NavigationProvider: FC = ({ children }) => { refetchInterval: INTERVALS_MS.SERVICE_TYPES, }); const { settings } = useSettings(); - const { data: advisors } = useAdvisors({ - enabled: !!user?.isEditor, - }); const { data: folders = [] } = useFolders(); const { colorMode, toggleColorMode } = useColorMode(); const { status, versionInfo } = useUpdates(); @@ -79,7 +75,7 @@ export const NavigationProvider: FC = ({ children }) => { } if (user.isEditor && settings.advisorEnabled) { - items.push(addAdvisors(advisors || [])); + items.push(addAdvisors()); } if (user.isPMMAdmin) { @@ -113,7 +109,6 @@ export const NavigationProvider: FC = ({ children }) => { folders, user, settings, - advisors, colorMode, haInfo, toggleColorMode, diff --git a/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx b/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx index 8f715e7a7ce..8bd275bd4dd 100644 --- a/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx +++ b/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx @@ -1,8 +1,6 @@ import { NavItem } from 'types/navigation.types'; import { ServiceType } from 'types/services.types'; import { User, UserPreferences } from 'types/user.types'; -import { Advisor } from 'types/advisors.types'; -import { groupAdvisorsIntoCategories } from 'utils/advisors.utils'; import { PMM_NEW_NAV_GRAFANA_PATH } from 'lib/constants'; import { ColorMode } from '@pmm/shared'; import { @@ -48,7 +46,6 @@ import { NAV_HOME_PAGE, } from './navigation.constants'; import { CombinedSettings } from 'contexts/settings'; -import { capitalize } from 'utils/text.utils'; import { DashboardFolder } from 'types/folders.types'; import { GetUpdatesResponse, UpdateStatus } from 'types/updates.types'; import { HighAvailabilityIcon } from 'components/ha-icon'; @@ -167,20 +164,10 @@ export const addExplore = (exploreMetricsEnabled: boolean): NavItem => { return { ...NAV_EXPLORE, children }; }; -export const addAdvisors = (advisors: Advisor[]): NavItem => { - const children: NavItem[] = [NAV_ADVISORS_INSIGHTS]; - const categories = groupAdvisorsIntoCategories(advisors); - - for (const category of Object.keys(categories)) { - children.push({ - id: `advisors-${category}`, - text: `${capitalize(category)} advisors`, - url: `${PMM_NEW_NAV_GRAFANA_PATH}/advisors/${category}`, - }); - } - - return { ...NAV_ADVISORS, children }; -}; +export const addAdvisors = (): NavItem => ({ + ...NAV_ADVISORS, + children: [NAV_ADVISORS_INSIGHTS], +}); export const addAccount = ( user: User, diff --git a/ui/apps/pmm/src/hooks/api/useAdvisors.ts b/ui/apps/pmm/src/hooks/api/useAdvisors.ts index 2d4f9080b14..5e1e8942b5d 100644 --- a/ui/apps/pmm/src/hooks/api/useAdvisors.ts +++ b/ui/apps/pmm/src/hooks/api/useAdvisors.ts @@ -1,10 +1,53 @@ -import { useQuery, UseQueryOptions } from '@tanstack/react-query'; -import { listAdvisors } from 'api/advisors'; -import { Advisor } from 'types/advisors.types'; +import { + useMutation, + UseMutationOptions, + useQuery, + useQueryClient, + UseQueryOptions, +} from '@tanstack/react-query'; +import { + changeAdvisorChecks, + listAdvisors, + startAdvisorChecks, +} from 'api/advisors'; +import { Advisor, ChangeAdvisorCheckParams } from 'types/advisors.types'; + +const KEYS = { + LIST: 'advisors:list', + START_CHECKS: 'advisors:start-checks', + CHANGE_CHECKS: 'advisors:change-checks', +}; export const useAdvisors = (options?: Partial>) => useQuery({ - queryKey: ['advisors'], + queryKey: [KEYS.LIST], queryFn: () => listAdvisors(), ...options, }); + +export const useStartAdvisorChecks = ( + options?: Partial> +) => + useMutation({ + mutationKey: [KEYS.START_CHECKS], + mutationFn: startAdvisorChecks, + ...options, + }); + +export const useChangeAdvisorChecks = ( + options?: Partial< + UseMutationOptions + > +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: [KEYS.CHANGE_CHECKS], + mutationFn: changeAdvisorChecks, + ...options, + onSuccess: async (data, variables, onMutate, context) => { + await options?.onSuccess?.(data, variables, onMutate, context); + await queryClient.invalidateQueries({ queryKey: [KEYS.LIST] }); + }, + }); +}; diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx new file mode 100644 index 00000000000..d86abcaeaae --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx @@ -0,0 +1,105 @@ +import { type MRT_ColumnDef } from 'material-react-table'; +import Select from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; +import Switch from '@mui/material/Switch'; +import { AdvisorCheckRow, AdvisorInterval } from 'types/advisors.types'; +import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; +import { capitalize } from 'utils/text.utils'; +import { Messages } from './AdvisorsList.messages'; + +export const INTERVAL_OPTIONS = [ + AdvisorInterval.standard, + AdvisorInterval.rare, + AdvisorInterval.frequent, +]; + +interface AdvisorsColumnsProps { + categories: string[]; + technologies: string[]; + onToggleCheck: (check: AdvisorCheckRow) => void; + onChangeInterval: (check: AdvisorCheckRow, interval: AdvisorInterval) => void; +} + +export const getAdvisorsColumns = ({ + categories, + technologies, + onToggleCheck, + onChangeInterval, +}: AdvisorsColumnsProps): MRT_ColumnDef[] => [ + { + header: Messages.columns.check, + accessorKey: 'summary', + filterFn: 'contains', + size: 250, + }, + { + header: Messages.columns.description, + accessorKey: 'description', + filterFn: 'contains', + size: 350, + }, + { + id: 'category', + header: Messages.columns.category, + accessorFn: (row) => capitalize(row.category), + filterVariant: 'select', + filterSelectOptions: categories, + size: 150, + }, + { + id: 'technology', + header: Messages.columns.technology, + accessorFn: (row) => ADVISOR_FAMILY[row.family], + filterVariant: 'select', + filterSelectOptions: technologies, + size: 140, + }, + { + id: 'interval', + header: Messages.columns.interval, + accessorFn: (row) => ADVISOR_INTERVAL[row.interval], + filterVariant: 'select', + filterSelectOptions: INTERVAL_OPTIONS.map( + (interval) => ADVISOR_INTERVAL[interval] + ), + size: 130, + Cell: ({ row }) => ( + + ), + }, + { + id: 'status', + header: Messages.columns.status, + accessorFn: (row) => + row.enabled ? Messages.status.enabled : Messages.status.disabled, + filterVariant: 'select', + filterSelectOptions: [Messages.status.enabled, Messages.status.disabled], + size: 110, + Cell: ({ row }) => ( + onToggleCheck(row.original)} + data-testid={`check-${row.original.checkName}-status-switch`} + /> + ), + }, +]; diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts new file mode 100644 index 00000000000..26054123f1f --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts @@ -0,0 +1,32 @@ +export const Messages = { + title: 'Advisors', + description: + 'Advisors run automated checks against your connected databases to identify potential security threats, performance degradation, data loss and data corruption.', + noData: 'No advisor checks found', + columns: { + check: 'Check', + description: 'Description', + category: 'Category', + technology: 'Technology', + interval: 'Interval', + status: 'Status', + }, + status: { + enabled: 'Enabled', + disabled: 'Disabled', + }, + runAll: 'Run all checks', + runCategory: 'Run category', + runTechnology: 'Run technology', + run: 'Run', + success: { + checksStarted: + 'Advisor checks started. The results will be available shortly.', + checkStarted: (summary: string) => + `Check "${summary}" started. The results will be available shortly.`, + checkEnabled: (summary: string) => `Check "${summary}" enabled`, + checkDisabled: (summary: string) => `Check "${summary}" disabled`, + intervalChanged: (summary: string, interval: string) => + `Check "${summary}" interval changed to "${interval}"`, + }, +}; diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx new file mode 100644 index 00000000000..137b805f85f --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -0,0 +1,243 @@ +import { + fireEvent, + render, + screen, + waitFor, + within, +} from '@testing-library/react'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import AdvisorsList from './AdvisorsList'; +import { Messages } from './AdvisorsList.messages'; +import * as advisorsApi from 'api/advisors'; +import { + wrapWithQueryProvider, + wrapWithRouter, + wrapWithSnackbarProvider, + wrapWithUserProvider, +} from 'utils/testUtils'; +import { + Advisor, + AdvisorFamily, + AdvisorInterval, +} from 'types/advisors.types'; + +vi.mock('api/advisors'); + +const TEST_ADVISORS: Advisor[] = [ + { + name: 'mysql_version', + summary: 'MySQL Version', + description: 'Advisor for MySQL versions', + comment: '', + category: 'version_configuration', + checks: [ + { + name: 'mysql_version_check', + enabled: true, + summary: 'MySQL version check', + description: 'Warns if MySQL version is EOL', + interval: AdvisorInterval.standard, + family: AdvisorFamily.mysql, + }, + ], + }, + { + name: 'postgresql_security', + summary: 'PostgreSQL Security', + description: 'Advisor for PostgreSQL security', + comment: '', + category: 'security', + checks: [ + { + name: 'postgresql_super_role', + enabled: true, + summary: 'PostgreSQL super role', + description: 'Detects users with the SUPER role', + interval: AdvisorInterval.rare, + family: AdvisorFamily.postgresql, + }, + { + name: 'postgresql_disabled_check', + enabled: false, + summary: 'PostgreSQL disabled check', + description: 'A disabled check', + interval: AdvisorInterval.standard, + family: AdvisorFamily.postgresql, + }, + ], + }, +]; + +const renderComponent = () => + render( + wrapWithQueryProvider( + wrapWithSnackbarProvider( + wrapWithUserProvider(wrapWithRouter()) + ) + ) + ); + +const waitForRows = async () => { + await waitFor(() => + expect(screen.getByText('MySQL version check')).toBeInTheDocument() + ); +}; + +describe('AdvisorsList', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(advisorsApi.listAdvisors).mockResolvedValue(TEST_ADVISORS); + vi.mocked(advisorsApi.startAdvisorChecks).mockResolvedValue(); + vi.mocked(advisorsApi.changeAdvisorChecks).mockResolvedValue(); + }); + + it('renders all checks', async () => { + renderComponent(); + + await waitForRows(); + + expect(screen.getByText('PostgreSQL super role')).toBeInTheDocument(); + expect(screen.getByText('PostgreSQL disabled check')).toBeInTheDocument(); + }); + + it('filters checks with global search', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.change(screen.getByPlaceholderText(/search/i), { + target: { value: 'super role' }, + }); + + // the matched text gets split by search-highlight marks, so assert via testids + await waitFor(() => + expect( + screen.queryByTestId('check-mysql_version_check-run') + ).not.toBeInTheDocument() + ); + expect( + screen.getByTestId('check-postgresql_super_role-run') + ).toBeInTheDocument(); + }); + + it('runs all checks', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('run-all-checks')); + + await waitFor(() => + expect(advisorsApi.startAdvisorChecks).toHaveBeenCalledWith( + [], + expect.anything() + ) + ); + expect( + screen.getByText(Messages.success.checksStarted) + ).toBeInTheDocument(); + }); + + it('runs enabled checks of a category', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId(`run-menu-${Messages.runCategory}`)); + + const menu = await screen.findByRole('menu'); + fireEvent.click(within(menu).getByText('Security')); + + await waitFor(() => + expect(advisorsApi.startAdvisorChecks).toHaveBeenCalledWith( + ['postgresql_super_role'], + expect.anything() + ) + ); + }); + + it('runs enabled checks of a technology', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId(`run-menu-${Messages.runTechnology}`)); + + const menu = await screen.findByRole('menu'); + fireEvent.click(within(menu).getByText('MySQL')); + + await waitFor(() => + expect(advisorsApi.startAdvisorChecks).toHaveBeenCalledWith( + ['mysql_version_check'], + expect.anything() + ) + ); + }); + + it('runs an individual check', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('check-mysql_version_check-run')); + + await waitFor(() => + expect(advisorsApi.startAdvisorChecks).toHaveBeenCalledWith( + ['mysql_version_check'], + expect.anything() + ) + ); + }); + + it('disables the run action for disabled checks', async () => { + renderComponent(); + + await waitForRows(); + + expect( + screen.getByTestId('check-postgresql_disabled_check-run') + ).toBeDisabled(); + }); + + it('toggles a check', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click( + within( + screen.getByTestId('check-mysql_version_check-status-switch') + ).getByRole('switch') + ); + + await waitFor(() => + expect(advisorsApi.changeAdvisorChecks).toHaveBeenCalledWith( + [{ name: 'mysql_version_check', enable: false }], + expect.anything() + ) + ); + }); + + it('changes the check interval', async () => { + renderComponent(); + + await waitForRows(); + + const select = within( + screen.getByTestId('check-mysql_version_check-interval-select') + ).getByRole('combobox'); + fireEvent.mouseDown(select); + + // 'hidden' skips the visibility computation, which crashes in jsdom: + // nwsapi expands ':scope' with the listbox's unescaped React useId + const listbox = await screen.findByRole('listbox', { hidden: true }); + fireEvent.click(within(listbox).getByText('Rare')); + + await waitFor(() => + expect(advisorsApi.changeAdvisorChecks).toHaveBeenCalledWith( + [{ name: 'mysql_version_check', interval: AdvisorInterval.rare }], + expect.anything() + ) + ); + }); +}); diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx new file mode 100644 index 00000000000..1b9c5d9a35b --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -0,0 +1,180 @@ +import { FC, useCallback, useMemo } from 'react'; +import Button from '@mui/material/Button'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined'; +import { Table } from '@percona/percona-ui'; +import { enqueueSnackbar } from 'notistack'; +import { Page } from 'components/page'; +import { + useAdvisors, + useChangeAdvisorChecks, + useStartAdvisorChecks, +} from 'hooks/api/useAdvisors'; +import { AdvisorCheckRow, AdvisorInterval } from 'types/advisors.types'; +import { OrgRole } from 'types/user.types'; +import { flattenAdvisorChecks } from 'utils/advisors.utils'; +import { capitalize } from 'utils/text.utils'; +import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; +import { Messages } from './AdvisorsList.messages'; +import { getAdvisorsColumns } from './AdvisorsList.constants'; +import { RunMenuButton, RunMenuOption } from './run-menu-button'; + +const AdvisorsList: FC = () => { + const { data: advisors = [], isLoading } = useAdvisors(); + const { mutate: startChecks, isPending: isStarting } = + useStartAdvisorChecks(); + const { mutate: changeChecks } = useChangeAdvisorChecks(); + + const rows = useMemo(() => flattenAdvisorChecks(advisors), [advisors]); + + const categoryOptions = useMemo( + () => + [...new Set(rows.map((row) => row.category))].sort().map((category) => ({ + label: capitalize(category), + names: rows + .filter((row) => row.category === category && row.enabled) + .map((row) => row.checkName), + })), + [rows] + ); + + const technologyOptions = useMemo( + () => + [...new Set(rows.map((row) => row.family))].sort().map((family) => ({ + label: ADVISOR_FAMILY[family], + names: rows + .filter((row) => row.family === family && row.enabled) + .map((row) => row.checkName), + })), + [rows] + ); + + const runChecks = useCallback( + (names: string[], message: string) => + startChecks(names, { + onSuccess: () => enqueueSnackbar(message, { variant: 'success' }), + }), + [startChecks] + ); + + const handleToggleCheck = useCallback( + (check: AdvisorCheckRow) => + changeChecks([{ name: check.checkName, enable: !check.enabled }], { + onSuccess: () => + enqueueSnackbar( + check.enabled + ? Messages.success.checkDisabled(check.summary) + : Messages.success.checkEnabled(check.summary), + { variant: 'success' } + ), + }), + [changeChecks] + ); + + const handleChangeInterval = useCallback( + (check: AdvisorCheckRow, interval: AdvisorInterval) => + changeChecks([{ name: check.checkName, interval }], { + onSuccess: () => + enqueueSnackbar( + Messages.success.intervalChanged( + check.summary, + ADVISOR_INTERVAL[interval] + ), + { variant: 'success' } + ), + }), + [changeChecks] + ); + + const columns = useMemo( + () => + getAdvisorsColumns({ + categories: categoryOptions.map((option) => option.label), + technologies: technologyOptions.map((option) => option.label), + onToggleCheck: handleToggleCheck, + onChangeInterval: handleChangeInterval, + }), + [categoryOptions, technologyOptions, handleToggleCheck, handleChangeInterval] + ); + + return ( + + + {Messages.description} + ( + + )} + renderTopToolbarCustomActions={() => ( + + + + runChecks(option.names, Messages.success.checksStarted) + } + /> + + runChecks(option.names, Messages.success.checksStarted) + } + /> + + )} + muiTableContainerProps={{ + sx: { + flex: 1, + borderRadius: 2, + border: '1px solid', + borderColor: 'divider', + }, + }} + /> + + + ); +}; + +export default AdvisorsList; diff --git a/ui/apps/pmm/src/pages/advisors/index.ts b/ui/apps/pmm/src/pages/advisors/index.ts new file mode 100644 index 00000000000..037ba6534ca --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/index.ts @@ -0,0 +1 @@ +export { default as AdvisorsList } from './AdvisorsList'; diff --git a/ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx b/ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx new file mode 100644 index 00000000000..25ff29732ab --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx @@ -0,0 +1,61 @@ +import { FC, useState, MouseEvent } from 'react'; +import Button from '@mui/material/Button'; +import Menu from '@mui/material/Menu'; +import MenuItem from '@mui/material/MenuItem'; +import ArrowDropDownOutlinedIcon from '@mui/icons-material/ArrowDropDownOutlined'; + +export interface RunMenuOption { + label: string; + // names of the enabled checks to run; empty disables the option + names: string[]; +} + +interface RunMenuButtonProps { + label: string; + options: RunMenuOption[]; + disabled?: boolean; + onRun: (option: RunMenuOption) => void; +} + +export const RunMenuButton: FC = ({ + label, + options, + disabled, + onRun, +}) => { + const [anchorEl, setAnchorEl] = useState(null); + + const handleOpen = (event: MouseEvent) => + setAnchorEl(event.currentTarget); + + const handleClose = () => setAnchorEl(null); + + const handleRun = (option: RunMenuOption) => { + handleClose(); + onRun(option); + }; + + return ( + <> + + + {options.map((option) => ( + handleRun(option)} + > + {option.label} + + ))} + + + ); +}; diff --git a/ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts b/ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts new file mode 100644 index 00000000000..c7fdb303c51 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts @@ -0,0 +1,2 @@ +export { RunMenuButton } from './RunMenuButton'; +export type { RunMenuOption } from './RunMenuButton'; diff --git a/ui/apps/pmm/src/router.tsx b/ui/apps/pmm/src/router.tsx index 12cdba5d678..c87fad2dba9 100644 --- a/ui/apps/pmm/src/router.tsx +++ b/ui/apps/pmm/src/router.tsx @@ -13,6 +13,7 @@ import { RealtimeSessionsPage } from 'pages/rta/sessions'; import { Redirect, SettingsRedirect } from 'components/redirect'; import RealtimeOverviewPage from 'pages/rta/overview/RealtimeOverview'; import RealtimeTab from 'pages/rta/tab/RealtimeTab'; +import { AdvisorsList } from 'pages/advisors'; const router = createBrowserRouter( [ @@ -65,6 +66,15 @@ const router = createBrowserRouter( }, ], }, + { + path: 'advisors', + children: [ + { + path: '', + element: , + }, + ], + }, // Fallback { path: 'graph/settings/:tab?', diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index f984bc2205a..8e0f669cbd3 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -39,3 +39,28 @@ export interface CategorizedAdvisor { export interface ListAdvisorsResponse { advisors: Advisor[]; } + +export interface StartAdvisorChecksRequest { + names: string[]; +} + +export interface ChangeAdvisorCheckParams { + name: string; + enable?: boolean; + interval?: AdvisorInterval; +} + +export interface ChangeAdvisorChecksRequest { + params: ChangeAdvisorCheckParams[]; +} + +export interface AdvisorCheckRow { + checkName: string; + summary: string; + description: string; + advisorName: string; + category: string; + family: AdvisorFamily; + interval: AdvisorInterval; + enabled: boolean; +} diff --git a/ui/apps/pmm/src/utils/advisors.utils.ts b/ui/apps/pmm/src/utils/advisors.utils.ts index 855b0eea7a3..e1ae390b63b 100644 --- a/ui/apps/pmm/src/utils/advisors.utils.ts +++ b/ui/apps/pmm/src/utils/advisors.utils.ts @@ -1,5 +1,23 @@ import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; -import { Advisor, CategorizedAdvisor } from 'types/advisors.types'; +import { + Advisor, + AdvisorCheckRow, + CategorizedAdvisor, +} from 'types/advisors.types'; + +export const flattenAdvisorChecks = (advisors: Advisor[]): AdvisorCheckRow[] => + advisors.flatMap((advisor) => + advisor.checks.map((check) => ({ + checkName: check.name, + summary: check.summary, + description: check.description, + advisorName: advisor.summary, + category: advisor.category, + family: check.family, + interval: check.interval, + enabled: check.enabled, + })) + ); export const groupAdvisorsIntoCategories = ( advisors: Advisor[] From 4dda30a53a7b541ff56699fdb9529bbecf278265 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 12:31:00 +0300 Subject: [PATCH 017/120] PMM-14109 Improve advisor rendering --- ui/apps/pmm/src/components/page/Page.tsx | 3 +- ui/apps/pmm/src/components/page/Page.types.ts | 2 + .../pages/advisors/AdvisorsList.constants.tsx | 14 +- .../pages/advisors/AdvisorsList.messages.ts | 8 +- .../src/pages/advisors/AdvisorsList.test.tsx | 43 ++++-- .../pmm/src/pages/advisors/AdvisorsList.tsx | 124 +++++++++++------- .../run-menu-button/RunMenuButton.tsx | 61 --------- .../pages/advisors/run-menu-button/index.ts | 2 - 8 files changed, 123 insertions(+), 134 deletions(-) delete mode 100644 ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx delete mode 100644 ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts diff --git a/ui/apps/pmm/src/components/page/Page.tsx b/ui/apps/pmm/src/components/page/Page.tsx index 029e9e3fd6b..840a06f884b 100644 --- a/ui/apps/pmm/src/components/page/Page.tsx +++ b/ui/apps/pmm/src/components/page/Page.tsx @@ -24,6 +24,7 @@ export const Page: FC = ({ footer, children, fullWidth, + wide, surface, roles, }) => { @@ -50,7 +51,7 @@ export const Page: FC = ({ flex: 1, width: '100%', maxWidth: { - lg: 1000, + lg: wide ? 'none' : 1000, }, p: { xs: 2, diff --git a/ui/apps/pmm/src/components/page/Page.types.ts b/ui/apps/pmm/src/components/page/Page.types.ts index 2217df28c68..eefbf12f010 100644 --- a/ui/apps/pmm/src/components/page/Page.types.ts +++ b/ui/apps/pmm/src/components/page/Page.types.ts @@ -6,6 +6,8 @@ export interface PageProps extends PropsWithChildren { footer?: ReactNode; topBar?: ReactNode; fullWidth?: boolean; + // removes the default max-width cap so the page spans the whole viewport + wide?: boolean; surface?: 'default' | 'paper'; roles?: OrgRole[]; } diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx index d86abcaeaae..30e1e96ca73 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx @@ -15,14 +15,14 @@ export const INTERVAL_OPTIONS = [ interface AdvisorsColumnsProps { categories: string[]; - technologies: string[]; + vendors: string[]; onToggleCheck: (check: AdvisorCheckRow) => void; onChangeInterval: (check: AdvisorCheckRow, interval: AdvisorInterval) => void; } export const getAdvisorsColumns = ({ categories, - technologies, + vendors, onToggleCheck, onChangeInterval, }: AdvisorsColumnsProps): MRT_ColumnDef[] => [ @@ -43,15 +43,17 @@ export const getAdvisorsColumns = ({ header: Messages.columns.category, accessorFn: (row) => capitalize(row.category), filterVariant: 'select', + filterFn: 'equals', filterSelectOptions: categories, size: 150, }, { - id: 'technology', - header: Messages.columns.technology, + id: 'vendor', + header: Messages.columns.vendor, accessorFn: (row) => ADVISOR_FAMILY[row.family], filterVariant: 'select', - filterSelectOptions: technologies, + filterFn: 'equals', + filterSelectOptions: vendors, size: 140, }, { @@ -59,6 +61,7 @@ export const getAdvisorsColumns = ({ header: Messages.columns.interval, accessorFn: (row) => ADVISOR_INTERVAL[row.interval], filterVariant: 'select', + filterFn: 'equals', filterSelectOptions: INTERVAL_OPTIONS.map( (interval) => ADVISOR_INTERVAL[interval] ), @@ -91,6 +94,7 @@ export const getAdvisorsColumns = ({ accessorFn: (row) => row.enabled ? Messages.status.enabled : Messages.status.disabled, filterVariant: 'select', + filterFn: 'equals', filterSelectOptions: [Messages.status.enabled, Messages.status.disabled], size: 110, Cell: ({ row }) => ( diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts index 26054123f1f..b47ffba92c5 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts @@ -7,7 +7,7 @@ export const Messages = { check: 'Check', description: 'Description', category: 'Category', - technology: 'Technology', + vendor: 'Vendor', interval: 'Interval', status: 'Status', }, @@ -15,9 +15,9 @@ export const Messages = { enabled: 'Enabled', disabled: 'Disabled', }, - runAll: 'Run all checks', - runCategory: 'Run category', - runTechnology: 'Run technology', + runAll: 'Run all', + runSelected: 'Run selected', + addAdvisor: 'Add advisor', run: 'Run', success: { checksStarted: diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx index 137b805f85f..6c9298a69e3 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -83,6 +83,7 @@ const waitForRows = async () => { ); }; + describe('AdvisorsList', () => { beforeEach(() => { vi.clearAllMocks(); @@ -98,6 +99,15 @@ describe('AdvisorsList', () => { expect(screen.getByText('PostgreSQL super role')).toBeInTheDocument(); expect(screen.getByText('PostgreSQL disabled check')).toBeInTheDocument(); + expect(screen.getByTestId('add-advisor')).toBeInTheDocument(); + }); + + it('disables run selected when nothing is filtered', async () => { + renderComponent(); + + await waitForRows(); + + expect(screen.getByTestId('run-selected-checks')).toBeDisabled(); }); it('filters checks with global search', async () => { @@ -138,15 +148,22 @@ describe('AdvisorsList', () => { ).toBeInTheDocument(); }); - it('runs enabled checks of a category', async () => { + it('runs checks matching the global search', async () => { renderComponent(); await waitForRows(); - fireEvent.click(screen.getByTestId(`run-menu-${Messages.runCategory}`)); + fireEvent.change(screen.getByPlaceholderText(/search/i), { + target: { value: 'super role' }, + }); - const menu = await screen.findByRole('menu'); - fireEvent.click(within(menu).getByText('Security')); + await waitFor(() => + expect( + screen.queryByTestId('check-mysql_version_check-run') + ).not.toBeInTheDocument() + ); + + fireEvent.click(screen.getByTestId('run-selected-checks')); await waitFor(() => expect(advisorsApi.startAdvisorChecks).toHaveBeenCalledWith( @@ -156,22 +173,22 @@ describe('AdvisorsList', () => { ); }); - it('runs enabled checks of a technology', async () => { + it('disables run selected when only disabled checks are visible', async () => { renderComponent(); await waitForRows(); - fireEvent.click(screen.getByTestId(`run-menu-${Messages.runTechnology}`)); - - const menu = await screen.findByRole('menu'); - fireEvent.click(within(menu).getByText('MySQL')); + fireEvent.change(screen.getByPlaceholderText(/search/i), { + target: { value: 'A disabled check' }, + }); await waitFor(() => - expect(advisorsApi.startAdvisorChecks).toHaveBeenCalledWith( - ['mysql_version_check'], - expect.anything() - ) + expect( + screen.queryByTestId('check-mysql_version_check-run') + ).not.toBeInTheDocument() ); + + expect(screen.getByTestId('run-selected-checks')).toBeDisabled(); }); it('runs an individual check', async () => { diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index 1b9c5d9a35b..bd43afb582d 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -1,7 +1,9 @@ import { FC, useCallback, useMemo } from 'react'; import Button from '@mui/material/Button'; +import { boxClasses } from '@mui/material/Box'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; +import AddOutlinedIcon from '@mui/icons-material/AddOutlined'; import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined'; import { Table } from '@percona/percona-ui'; import { enqueueSnackbar } from 'notistack'; @@ -18,7 +20,6 @@ import { capitalize } from 'utils/text.utils'; import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; import { Messages } from './AdvisorsList.messages'; import { getAdvisorsColumns } from './AdvisorsList.constants'; -import { RunMenuButton, RunMenuOption } from './run-menu-button'; const AdvisorsList: FC = () => { const { data: advisors = [], isLoading } = useAdvisors(); @@ -28,25 +29,14 @@ const AdvisorsList: FC = () => { const rows = useMemo(() => flattenAdvisorChecks(advisors), [advisors]); - const categoryOptions = useMemo( + const categories = useMemo( () => - [...new Set(rows.map((row) => row.category))].sort().map((category) => ({ - label: capitalize(category), - names: rows - .filter((row) => row.category === category && row.enabled) - .map((row) => row.checkName), - })), + [...new Set(rows.map((row) => capitalize(row.category)))].sort(), [rows] ); - const technologyOptions = useMemo( - () => - [...new Set(rows.map((row) => row.family))].sort().map((family) => ({ - label: ADVISOR_FAMILY[family], - names: rows - .filter((row) => row.family === family && row.enabled) - .map((row) => row.checkName), - })), + const vendors = useMemo( + () => [...new Set(rows.map((row) => ADVISOR_FAMILY[row.family]))].sort(), [rows] ); @@ -90,16 +80,21 @@ const AdvisorsList: FC = () => { const columns = useMemo( () => getAdvisorsColumns({ - categories: categoryOptions.map((option) => option.label), - technologies: technologyOptions.map((option) => option.label), + categories, + vendors, onToggleCheck: handleToggleCheck, onChangeInterval: handleChangeInterval, }), - [categoryOptions, technologyOptions, handleToggleCheck, handleChangeInterval] + [categories, vendors, handleToggleCheck, handleChangeInterval] ); return ( - + {Messages.description}
{ {Messages.run} )} - renderTopToolbarCustomActions={() => ( - - - - runChecks(option.names, Messages.success.checksStarted) - } - /> - - runChecks(option.names, Messages.success.checksStarted) - } - /> - - )} + renderTopToolbarCustomActions={({ table }) => { + const { globalFilter, columnFilters } = table.getState(); + // no active search/filter means no selection ("all") + const hasSelection = + !!globalFilter || + columnFilters.some( + (filter) => filter.value !== undefined && filter.value !== '' + ); + // enabled checks currently visible after global search + filters + const selectedNames = hasSelection + ? table + .getFilteredRowModel() + .rows.map((row) => row.original) + .filter((row) => row.enabled) + .map((row) => row.checkName) + : []; + + return ( + + + + + + ); + }} + muiSearchTextFieldProps={{ + // inline style: MRT's toolbar overwrites any `sx` passed here + style: { width: 400 }, + }} + muiTopToolbarProps={{ + sx: { + // search on the left, action buttons on the right, + // flush with the table edges + [`& > .${boxClasses.root}`]: { + alignItems: 'center', + flexDirection: 'row-reverse', + px: 0, + }, + }, + }} muiTableContainerProps={{ sx: { flex: 1, diff --git a/ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx b/ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx deleted file mode 100644 index 25ff29732ab..00000000000 --- a/ui/apps/pmm/src/pages/advisors/run-menu-button/RunMenuButton.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { FC, useState, MouseEvent } from 'react'; -import Button from '@mui/material/Button'; -import Menu from '@mui/material/Menu'; -import MenuItem from '@mui/material/MenuItem'; -import ArrowDropDownOutlinedIcon from '@mui/icons-material/ArrowDropDownOutlined'; - -export interface RunMenuOption { - label: string; - // names of the enabled checks to run; empty disables the option - names: string[]; -} - -interface RunMenuButtonProps { - label: string; - options: RunMenuOption[]; - disabled?: boolean; - onRun: (option: RunMenuOption) => void; -} - -export const RunMenuButton: FC = ({ - label, - options, - disabled, - onRun, -}) => { - const [anchorEl, setAnchorEl] = useState(null); - - const handleOpen = (event: MouseEvent) => - setAnchorEl(event.currentTarget); - - const handleClose = () => setAnchorEl(null); - - const handleRun = (option: RunMenuOption) => { - handleClose(); - onRun(option); - }; - - return ( - <> - - - {options.map((option) => ( - handleRun(option)} - > - {option.label} - - ))} - - - ); -}; diff --git a/ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts b/ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts deleted file mode 100644 index c7fdb303c51..00000000000 --- a/ui/apps/pmm/src/pages/advisors/run-menu-button/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { RunMenuButton } from './RunMenuButton'; -export type { RunMenuOption } from './RunMenuButton'; From 282703bef56c546809a57e5590c53fc4a864536e Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 15:43:22 +0300 Subject: [PATCH 018/120] PMM-14109 Add advisor insights page and related functionality --- .../checks/check_result_record_test.go | 21 ++- managed/services/checks/checks.go | 8 + ui/AGENTS.md | 1 + ui/apps/pmm/src/api/advisors.ts | 21 ++- .../navigation/navigation.constants.ts | 10 +- .../contexts/navigation/navigation.utils.tsx | 3 +- ui/apps/pmm/src/hooks/api/useAdvisors.ts | 46 ++++- ui/apps/pmm/src/lib/constants.ts | 27 ++- .../insights/AdvisorInsights.constants.tsx | 125 +++++++++++++ .../insights/AdvisorInsights.messages.ts | 24 +++ .../insights/AdvisorInsights.test.tsx | 176 ++++++++++++++++++ .../advisors/insights/AdvisorInsights.tsx | 147 +++++++++++++++ .../pmm/src/pages/advisors/insights/index.ts | 1 + ui/apps/pmm/src/router.tsx | 5 + ui/apps/pmm/src/types/advisors.types.ts | 50 +++++ ui/apps/pmm/src/types/severity.types.ts | 12 ++ ui/apps/pmm/src/types/util.types.ts | 6 + 17 files changed, 674 insertions(+), 9 deletions(-) create mode 100644 ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts create mode 100644 ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/insights/index.ts create mode 100644 ui/apps/pmm/src/types/severity.types.ts diff --git a/managed/services/checks/check_result_record_test.go b/managed/services/checks/check_result_record_test.go index 73590c35b19..203f4ce23d8 100644 --- a/managed/services/checks/check_result_record_test.go +++ b/managed/services/checks/check_result_record_test.go @@ -30,7 +30,7 @@ import ( func TestNewCheckResultRecord(t *testing.T) { t.Parallel() - c := check.Check{Name: "chk", Advisor: "adv", Interval: check.Standard} + c := check.Check{Name: "chk", Summary: "Check title", Advisor: "adv", Interval: check.Standard} target := services.Target{ ServiceID: "sid", ServiceName: "sname", @@ -74,17 +74,30 @@ func TestNewCheckResultRecord(t *testing.T) { assert.Equal(t, map[string]string{"k": "v"}, labels) }) - t.Run("ok outcome has empty finding fields", func(t *testing.T) { + t.Run("ok outcome falls back to check summary and info severity", func(t *testing.T) { t.Parallel() rec := newCheckResultRecord(c, target, "performance", models.CheckResultOK, check.Result{}, checkedAt) assert.Equal(t, models.CheckResultOK, rec.Status) - assert.Empty(t, rec.Summary) - assert.Zero(t, rec.Severity) + assert.Equal(t, "Check title", rec.Summary) + assert.Equal(t, int(common.Info), rec.Severity) labels, err := rec.GetLabels() require.NoError(t, err) assert.Empty(t, labels) }) + + t.Run("error outcome falls back to check summary", func(t *testing.T) { + t.Parallel() + + result := check.Result{Description: "execution failed"} + + rec := newCheckResultRecord(c, target, "performance", models.CheckResultError, result, checkedAt) + + assert.Equal(t, models.CheckResultError, rec.Status) + assert.Equal(t, "Check title", rec.Summary) + assert.Equal(t, "execution failed", rec.Description) + assert.Zero(t, rec.Severity) + }) } diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index aca46a3071d..b4358118226 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -45,6 +45,7 @@ import ( agentv1 "github.com/percona/pmm/api/agent/v1" "github.com/percona/pmm/managed/models" "github.com/percona/pmm/managed/pi/check" + "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/services" "github.com/percona/pmm/utils/pdeathsig" "github.com/percona/pmm/utils/sqlrows" @@ -773,6 +774,13 @@ func newCheckResultRecord( Severity: int(result.Severity), CheckedAt: checkedAt, } + // OK and error outcomes carry no finding; fall back to the check's own summary + if r.Summary == "" { + r.Summary = c.Summary + } + if status == models.CheckResultOK { + r.Severity = int(common.Info) + } if len(result.Labels) != 0 { _ = r.SetLabels(result.Labels) } diff --git a/ui/AGENTS.md b/ui/AGENTS.md index f77e4be1aab..f9223286df9 100644 --- a/ui/AGENTS.md +++ b/ui/AGENTS.md @@ -55,6 +55,7 @@ Routes are defined in `ui/apps/pmm/src/router.tsx` using React Router's `createB | `/rta/sessions` | RTA sessions list | | `/rta/overview` | RTA overview | | `/advisors` | Advisors | +| `/advisors/insights` | Advisor insights | | `/graph/*` | Grafana iframe | | `*` | 404 fallback | diff --git a/ui/apps/pmm/src/api/advisors.ts b/ui/apps/pmm/src/api/advisors.ts index 2ecfb582b43..deae1f3035a 100644 --- a/ui/apps/pmm/src/api/advisors.ts +++ b/ui/apps/pmm/src/api/advisors.ts @@ -2,10 +2,13 @@ import { Advisor, ChangeAdvisorCheckParams, ChangeAdvisorChecksRequest, + CheckResultHistoryItem, ListAdvisorsResponse, + ListCheckResultsHistoryParams, + MarkCheckResultsReadRequest, StartAdvisorChecksRequest, } from 'types/advisors.types'; -import { EmptyResponse } from 'types/util.types'; +import { EmptyResponse, PaginatedResponse } from 'types/util.types'; import { api } from './api'; export const listAdvisors = async (): Promise => { @@ -24,3 +27,19 @@ export const changeAdvisorChecks = async ( const payload: ChangeAdvisorChecksRequest = { params }; await api.post('/advisors/checks:batchChange', payload); }; + +export const listCheckResultsHistory = async ( + params: ListCheckResultsHistoryParams +): Promise> => { + const res = await api.get>( + '/advisors/checks/history', + { params } + ); + return res.data; +}; + +export const markCheckResultsRead = async ( + payload: MarkCheckResultsReadRequest +): Promise => { + await api.post('/advisors/checks/history:markRead', payload); +}; diff --git a/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts b/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts index adb9f55b267..c14d9c16e99 100644 --- a/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts +++ b/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts @@ -540,10 +540,18 @@ export const NAV_ADVISORS: NavItem = { url: `${PMM_NEW_NAV_PATH}/advisors`, }; +// the sidebar links a parent item to its first child's url, +// so the checks list must be an explicit (and first) child +export const NAV_ADVISORS_CHECKS: NavItem = { + id: 'advisors-checks', + text: 'Advisor checks', + url: `${PMM_NEW_NAV_PATH}/advisors`, +}; + export const NAV_ADVISORS_INSIGHTS = { id: 'advisors-insights', text: 'Advisor insights', - url: `${PMM_NEW_NAV_GRAFANA_PATH}/advisors/insights`, + url: `${PMM_NEW_NAV_PATH}/advisors/insights`, }; // diff --git a/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx b/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx index 8bd275bd4dd..4fab9a79965 100644 --- a/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx +++ b/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx @@ -6,6 +6,7 @@ import { ColorMode } from '@pmm/shared'; import { NAV_ACCOUNT, NAV_ADVISORS, + NAV_ADVISORS_CHECKS, NAV_ADVISORS_INSIGHTS, NAV_ALERTS_RULES, NAV_ALERTS, @@ -166,7 +167,7 @@ export const addExplore = (exploreMetricsEnabled: boolean): NavItem => { export const addAdvisors = (): NavItem => ({ ...NAV_ADVISORS, - children: [NAV_ADVISORS_INSIGHTS], + children: [NAV_ADVISORS_CHECKS, NAV_ADVISORS_INSIGHTS], }); export const addAccount = ( diff --git a/ui/apps/pmm/src/hooks/api/useAdvisors.ts b/ui/apps/pmm/src/hooks/api/useAdvisors.ts index 5e1e8942b5d..739ab7da8b4 100644 --- a/ui/apps/pmm/src/hooks/api/useAdvisors.ts +++ b/ui/apps/pmm/src/hooks/api/useAdvisors.ts @@ -1,4 +1,5 @@ import { + keepPreviousData, useMutation, UseMutationOptions, useQuery, @@ -8,14 +9,25 @@ import { import { changeAdvisorChecks, listAdvisors, + listCheckResultsHistory, + markCheckResultsRead, startAdvisorChecks, } from 'api/advisors'; -import { Advisor, ChangeAdvisorCheckParams } from 'types/advisors.types'; +import { + Advisor, + ChangeAdvisorCheckParams, + CheckResultHistoryItem, + ListCheckResultsHistoryParams, + MarkCheckResultsReadRequest, +} from 'types/advisors.types'; +import { PaginatedResponse } from 'types/util.types'; const KEYS = { LIST: 'advisors:list', START_CHECKS: 'advisors:start-checks', CHANGE_CHECKS: 'advisors:change-checks', + HISTORY: 'advisors:history', + MARK_READ: 'advisors:mark-read', }; export const useAdvisors = (options?: Partial>) => @@ -34,6 +46,38 @@ export const useStartAdvisorChecks = ( ...options, }); +export const useCheckResultsHistory = ( + params: ListCheckResultsHistoryParams, + options?: Partial< + UseQueryOptions> + > +) => + useQuery({ + queryKey: [KEYS.HISTORY, params], + queryFn: () => listCheckResultsHistory(params), + // keep showing the current page while the next one loads + placeholderData: keepPreviousData, + ...options, + }); + +export const useMarkCheckResultsRead = ( + options?: Partial< + UseMutationOptions + > +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: [KEYS.MARK_READ], + mutationFn: markCheckResultsRead, + ...options, + onSuccess: async (data, variables, onMutate, context) => { + await options?.onSuccess?.(data, variables, onMutate, context); + await queryClient.invalidateQueries({ queryKey: [KEYS.HISTORY] }); + }, + }); +}; + export const useChangeAdvisorChecks = ( options?: Partial< UseMutationOptions diff --git a/ui/apps/pmm/src/lib/constants.ts b/ui/apps/pmm/src/lib/constants.ts index cc28370b528..eba07ab5ed1 100644 --- a/ui/apps/pmm/src/lib/constants.ts +++ b/ui/apps/pmm/src/lib/constants.ts @@ -1,4 +1,9 @@ -import { AdvisorFamily, AdvisorInterval } from 'types/advisors.types'; +import { + AdvisorCheckResultStatus, + AdvisorFamily, + AdvisorInterval, +} from 'types/advisors.types'; +import { Severity } from 'types/severity.types'; import { ServiceType } from 'types/services.types'; export const PMM_TITLE = 'Percona Monitoring and Management'; @@ -35,6 +40,26 @@ export const ADVISOR_INTERVAL: Record = { [AdvisorInterval.unspecified]: 'Unspecified', }; +export const ADVISOR_RESULT_STATUS: Record = + { + [AdvisorCheckResultStatus.ok]: 'OK', + [AdvisorCheckResultStatus.failed]: 'Failed', + [AdvisorCheckResultStatus.error]: 'Error', + [AdvisorCheckResultStatus.unspecified]: 'Unspecified', + }; + +export const SEVERITY: Record = { + [Severity.emergency]: 'Emergency', + [Severity.alert]: 'Alert', + [Severity.critical]: 'Critical', + [Severity.error]: 'Error', + [Severity.warning]: 'Warning', + [Severity.notice]: 'Notice', + [Severity.info]: 'Info', + [Severity.debug]: 'Debug', + [Severity.unspecified]: 'Unspecified', +}; + export const ALL_SERVICE_TYPES = [ ServiceType.external, ServiceType.haproxy, diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx new file mode 100644 index 00000000000..e4561517ac8 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx @@ -0,0 +1,125 @@ +import { type MRT_ColumnDef } from 'material-react-table'; +import Chip from '@mui/material/Chip'; +import Link from '@mui/material/Link'; +import { format } from 'date-fns'; +import { + AdvisorCheckResultStatus, + CheckResultHistoryItem, +} from 'types/advisors.types'; +import { Severity } from 'types/severity.types'; +import { + ADVISOR_RESULT_STATUS, + SEVERITY, + TIME_FORMAT, +} from 'lib/constants'; +import { capitalize } from 'utils/text.utils'; +import { Messages } from './AdvisorInsights.messages'; + +const SEVERITY_OPTIONS = [ + Severity.emergency, + Severity.alert, + Severity.critical, + Severity.error, + Severity.warning, + Severity.notice, + Severity.info, + Severity.debug, +].map((severity) => ({ label: SEVERITY[severity], value: severity })); + +const STATUS_OPTIONS = [ + AdvisorCheckResultStatus.ok, + AdvisorCheckResultStatus.failed, + AdvisorCheckResultStatus.error, +].map((status) => ({ label: ADVISOR_RESULT_STATUS[status], value: status })); + +const READ_OPTIONS = [ + { label: Messages.read, value: 'true' }, + { label: Messages.unread, value: 'false' }, +]; + +export const getInsightsColumns = ( + categories: string[] +): MRT_ColumnDef[] => [ + { + header: Messages.columns.summary, + accessorKey: 'summary', + enableColumnFilter: false, + size: 300, + Cell: ({ row }) => ( + + {row.original.summary} + {row.original.readMoreUrl && ( + <> + {' '} + + {Messages.readMore} + + + )} + + ), + }, + { + id: 'serviceName', + header: Messages.columns.service, + accessorKey: 'serviceName', + size: 160, + }, + { + id: 'category', + header: Messages.columns.category, + accessorFn: (row) => capitalize(row.category), + filterVariant: 'select', + filterSelectOptions: categories.map((category) => ({ + label: capitalize(category), + value: category, + })), + size: 140, + }, + { + id: 'severity', + header: Messages.columns.severity, + accessorFn: (row) => SEVERITY[row.severity], + filterVariant: 'select', + filterSelectOptions: SEVERITY_OPTIONS, + size: 130, + }, + { + id: 'status', + header: Messages.columns.status, + accessorFn: (row) => ADVISOR_RESULT_STATUS[row.status], + filterVariant: 'select', + filterSelectOptions: STATUS_OPTIONS, + size: 120, + }, + { + header: Messages.columns.checkedAt, + accessorKey: 'checkedAt', + enableColumnFilter: false, + size: 160, + Cell: ({ row }) => + row.original.checkedAt + ? format(new Date(row.original.checkedAt), TIME_FORMAT) + : null, + }, + { + id: 'isRead', + header: Messages.columns.read, + accessorFn: (row) => (row.isRead ? Messages.read : Messages.unread), + filterVariant: 'select', + filterSelectOptions: READ_OPTIONS, + size: 110, + Cell: ({ row }) => ( + + ), + }, +]; diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts new file mode 100644 index 00000000000..0f665dbd3a7 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -0,0 +1,24 @@ +export const Messages = { + title: 'Advisor insights', + description: + 'Results of the advisor checks that ran against your monitored services.', + noData: 'No advisor insights found', + readMore: 'Read more', + markRead: 'Mark read', + markUnread: 'Mark unread', + read: 'Read', + unread: 'Unread', + columns: { + summary: 'Summary', + service: 'Service', + category: 'Category', + severity: 'Severity', + status: 'Status', + checkedAt: 'Checked at', + read: 'Read', + }, + success: { + markedRead: 'Insight marked as read', + markedUnread: 'Insight marked as unread', + }, +}; diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx new file mode 100644 index 00000000000..fd746032822 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -0,0 +1,176 @@ +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import AdvisorInsights from './AdvisorInsights'; +import { Messages } from './AdvisorInsights.messages'; +import * as advisorsApi from 'api/advisors'; +import { + wrapWithQueryProvider, + wrapWithRouter, + wrapWithSnackbarProvider, + wrapWithUserProvider, +} from 'utils/testUtils'; +import { + AdvisorCheckResultStatus, + AdvisorInterval, + CheckResultHistoryItem, +} from 'types/advisors.types'; +import { Severity } from 'types/severity.types'; + +vi.mock('api/advisors'); + +const TEST_ITEM: CheckResultHistoryItem = { + id: 'result-1', + checkName: 'mysql_version_check', + advisorName: 'MySQL Version', + category: 'version_configuration', + interval: AdvisorInterval.standard, + serviceId: 'service-1', + serviceName: 'mysql-prod', + serviceType: 'mysql', + nodeId: 'node-1', + nodeName: 'node-1', + status: AdvisorCheckResultStatus.failed, + summary: 'MySQL is outdated', + description: 'Newer version of MySQL is available', + readMoreUrl: 'https://percona.com', + severity: Severity.warning, + labels: {}, + checkedAt: '2026-07-05T10:00:00Z', + isRead: true, +}; + +const TEST_ITEM_UNREAD: CheckResultHistoryItem = { + ...TEST_ITEM, + id: 'result-2', + serviceName: 'postgresql-prod', + serviceType: 'postgresql', + summary: 'PostgreSQL super role detected', + description: 'A user has the SUPER role', + severity: Severity.error, + isRead: false, +}; + +const renderComponent = () => + render( + wrapWithQueryProvider( + wrapWithSnackbarProvider( + wrapWithUserProvider(wrapWithRouter()) + ) + ) + ); + +const waitForRows = async () => { + await waitFor(() => + expect(screen.getByText('MySQL is outdated')).toBeInTheDocument() + ); +}; + +describe('AdvisorInsights', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(advisorsApi.listAdvisors).mockResolvedValue([]); + vi.mocked(advisorsApi.listCheckResultsHistory).mockResolvedValue({ + totalItems: 250, + totalPages: 3, + results: [TEST_ITEM, TEST_ITEM_UNREAD], + }); + vi.mocked(advisorsApi.markCheckResultsRead).mockResolvedValue(); + }); + + it('renders history items with read state', async () => { + renderComponent(); + + await waitForRows(); + + expect( + screen.getByText('PostgreSQL super role detected') + ).toBeInTheDocument(); + expect(screen.getByTestId('insight-result-1-read-state')).toHaveTextContent( + Messages.read + ); + expect(screen.getByTestId('insight-result-2-read-state')).toHaveTextContent( + Messages.unread + ); + }); + + it('requests the first page by default', async () => { + renderComponent(); + + await waitForRows(); + + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ pageIndex: 0, pageSize: 100 }) + ); + }); + + it('requests the next page on pagination change', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByRole('button', { name: /go to next page/i })); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ pageIndex: 1 }) + ) + ); + }); + + it('passes the service filter to the API and resets the page', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByRole('button', { name: /go to next page/i })); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ pageIndex: 1 }) + ) + ); + + fireEvent.change(screen.getByPlaceholderText('Filter by Service'), { + target: { value: 'mysql-prod' }, + }); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ serviceName: 'mysql-prod', pageIndex: 0 }) + ) + ); + }); + + it('marks an unread insight as read', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-2-toggle-read')); + + await waitFor(() => + expect(advisorsApi.markCheckResultsRead).toHaveBeenCalledWith( + { ids: ['result-2'], isRead: true }, + expect.anything() + ) + ); + expect( + await screen.findByText(Messages.success.markedRead) + ).toBeInTheDocument(); + }); + + it('marks a read insight as unread', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-1-toggle-read')); + + await waitFor(() => + expect(advisorsApi.markCheckResultsRead).toHaveBeenCalledWith( + { ids: ['result-1'], isRead: false }, + expect.anything() + ) + ); + }); +}); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx new file mode 100644 index 00000000000..9fa2c90b1f3 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -0,0 +1,147 @@ +import { FC, useMemo, useState } from 'react'; +import Button from '@mui/material/Button'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { Table } from '@percona/percona-ui'; +import { + type MRT_ColumnFiltersState, + type MRT_PaginationState, + type MRT_Updater, +} from 'material-react-table'; +import { enqueueSnackbar } from 'notistack'; +import { Page } from 'components/page'; +import { + useAdvisors, + useCheckResultsHistory, + useMarkCheckResultsRead, +} from 'hooks/api/useAdvisors'; +import { + AdvisorCheckResultStatus, + CheckResultHistoryItem, + ListCheckResultsHistoryParams, +} from 'types/advisors.types'; +import { Severity } from 'types/severity.types'; +import { OrgRole } from 'types/user.types'; +import { Messages } from './AdvisorInsights.messages'; +import { getInsightsColumns } from './AdvisorInsights.constants'; + +const AdvisorInsights: FC = () => { + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: 100, + }); + const [columnFilters, setColumnFilters] = useState( + [] + ); + + const params = useMemo(() => { + const filterValue = (id: string) => + (columnFilters.find((filter) => filter.id === id)?.value as string) || + undefined; + const isRead = filterValue('isRead'); + + return { + pageIndex: pagination.pageIndex, + pageSize: pagination.pageSize, + serviceName: filterValue('serviceName'), + category: filterValue('category'), + severity: filterValue('severity') as Severity | undefined, + status: filterValue('status') as AdvisorCheckResultStatus | undefined, + isRead: isRead === undefined ? undefined : isRead === 'true', + }; + }, [pagination, columnFilters]); + + const { data, isLoading, isFetching } = useCheckResultsHistory(params); + const { data: advisors = [] } = useAdvisors(); + const { mutate: markRead, isPending: isMarking } = useMarkCheckResultsRead(); + + const categories = useMemo( + () => [...new Set(advisors.map((advisor) => advisor.category))].sort(), + [advisors] + ); + + const columns = useMemo(() => getInsightsColumns(categories), [categories]); + + const handleColumnFiltersChange = ( + updater: MRT_Updater + ) => { + setColumnFilters(updater); + // filters change the result set, so start from the first page + setPagination((current) => ({ ...current, pageIndex: 0 })); + }; + + const handleToggleRead = (item: CheckResultHistoryItem) => + markRead( + { ids: [item.id], isRead: !item.isRead }, + { + onSuccess: () => + enqueueSnackbar( + item.isRead + ? Messages.success.markedUnread + : Messages.success.markedRead, + { variant: 'success' } + ), + } + ); + + return ( + + + {Messages.description} +
( + + )} + muiTableContainerProps={{ + sx: { + flex: 1, + borderRadius: 2, + border: '1px solid', + borderColor: 'divider', + }, + }} + /> + + + ); +}; + +export default AdvisorInsights; diff --git a/ui/apps/pmm/src/pages/advisors/insights/index.ts b/ui/apps/pmm/src/pages/advisors/insights/index.ts new file mode 100644 index 00000000000..9ca0b28096c --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/index.ts @@ -0,0 +1 @@ +export { default as AdvisorInsights } from './AdvisorInsights'; diff --git a/ui/apps/pmm/src/router.tsx b/ui/apps/pmm/src/router.tsx index c87fad2dba9..908d72c1026 100644 --- a/ui/apps/pmm/src/router.tsx +++ b/ui/apps/pmm/src/router.tsx @@ -14,6 +14,7 @@ import { Redirect, SettingsRedirect } from 'components/redirect'; import RealtimeOverviewPage from 'pages/rta/overview/RealtimeOverview'; import RealtimeTab from 'pages/rta/tab/RealtimeTab'; import { AdvisorsList } from 'pages/advisors'; +import { AdvisorInsights } from 'pages/advisors/insights'; const router = createBrowserRouter( [ @@ -73,6 +74,10 @@ const router = createBrowserRouter( path: '', element: , }, + { + path: 'insights', + element: , + }, ], }, // Fallback diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index 8e0f669cbd3..63a32bd8276 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -1,3 +1,5 @@ +import { Severity } from './severity.types'; + export enum AdvisorInterval { standard = 'ADVISOR_CHECK_INTERVAL_STANDARD', rare = 'ADVISOR_CHECK_INTERVAL_RARE', @@ -54,6 +56,54 @@ export interface ChangeAdvisorChecksRequest { params: ChangeAdvisorCheckParams[]; } +export enum AdvisorCheckResultStatus { + unspecified = 'ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED', + ok = 'ADVISOR_CHECK_RESULT_STATUS_OK', + failed = 'ADVISOR_CHECK_RESULT_STATUS_FAILED', + error = 'ADVISOR_CHECK_RESULT_STATUS_ERROR', +} + +export interface CheckResultHistoryItem { + id: string; + checkName: string; + advisorName: string; + category: string; + interval: AdvisorInterval; + serviceId: string; + serviceName: string; + serviceType: string; + nodeId: string; + nodeName: string; + status: AdvisorCheckResultStatus; + summary: string; + description: string; + readMoreUrl: string; + severity: Severity; + labels: Record; + checkedAt: string; + isRead: boolean; +} + +export interface ListCheckResultsHistoryParams { + pageSize?: number; + pageIndex?: number; + serviceId?: string; + serviceName?: string; + nodeName?: string; + category?: string; + checkName?: string; + status?: AdvisorCheckResultStatus; + severity?: Severity; + isRead?: boolean; + from?: string; + to?: string; +} + +export interface MarkCheckResultsReadRequest { + ids: string[]; + isRead: boolean; +} + export interface AdvisorCheckRow { checkName: string; summary: string; diff --git a/ui/apps/pmm/src/types/severity.types.ts b/ui/apps/pmm/src/types/severity.types.ts new file mode 100644 index 00000000000..1abe61cd221 --- /dev/null +++ b/ui/apps/pmm/src/types/severity.types.ts @@ -0,0 +1,12 @@ +// comes from api/management/v1/severity.proto +export enum Severity { + unspecified = 'SEVERITY_UNSPECIFIED', + emergency = 'SEVERITY_EMERGENCY', + alert = 'SEVERITY_ALERT', + critical = 'SEVERITY_CRITICAL', + error = 'SEVERITY_ERROR', + warning = 'SEVERITY_WARNING', + notice = 'SEVERITY_NOTICE', + info = 'SEVERITY_INFO', + debug = 'SEVERITY_DEBUG', +} diff --git a/ui/apps/pmm/src/types/util.types.ts b/ui/apps/pmm/src/types/util.types.ts index cdbba235f6e..8c69fe18bc8 100644 --- a/ui/apps/pmm/src/types/util.types.ts +++ b/ui/apps/pmm/src/types/util.types.ts @@ -8,4 +8,10 @@ export type SvgIconComponent = typeof SvgIcon; export type EmptyResponse = Record; +export interface PaginatedResponse { + totalItems: number; + totalPages: number; + results: T[]; +} + export type CodeLanguage = 'text' | 'mongodb' | 'json'; From c36e2c69514dbb7e0228ae7c15cb2ce6882a9bf7 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 17:02:10 +0300 Subject: [PATCH 019/120] PMM-12345 Enhance Advisor Check Results with Severity and Triggered By Fields - Introduced CheckSeverity and CheckTriggeredBy types to represent the severity levels and initiators of advisor checks. - Updated CheckResult model to include Severity (CheckSeverity) and TriggeredBy (CheckTriggeredBy) fields. - Modified database schema to accommodate new fields in the check_results table. - Adjusted related services and models to handle the new fields, including changes in the execution flow of advisor checks. - Updated API services to support the new fields in requests and responses. - Enhanced tests to cover new functionality and ensure proper handling of severity and triggered by information. --- api/accesscontrol/v1beta1/accesscontrol.pb.go | 1 - api/actions/v1/actions.pb.go | 1 - api/advisors/v1/advisors.pb.go | 339 ++++++++++++------ api/advisors/v1/advisors.pb.validate.go | 12 + api/advisors/v1/advisors.proto | 56 ++- .../list_check_results_history_parameters.go | 78 +++- .../list_check_results_history_responses.go | 59 +++ .../start_advisor_checks_responses.go | 45 ++- api/advisors/v1/json/v1.json | 77 +++- api/agent/v1/agent.pb.go | 1 - api/agent/v1/collector.pb.go | 1 - api/agentlocal/v1/agentlocal.pb.go | 1 - api/alerting/v1/alerting.pb.go | 1 - api/alerting/v1/params.pb.go | 1 - api/backup/v1/artifacts.pb.go | 1 - api/backup/v1/backup.pb.go | 1 - api/backup/v1/common.pb.go | 1 - api/backup/v1/errors.pb.go | 1 - api/backup/v1/locations.pb.go | 1 - api/backup/v1/restores.pb.go | 1 - api/common/common.pb.go | 1 - api/common/metrics_resolutions.pb.go | 1 - api/descriptor.bin | Bin 826121 -> 828035 bytes api/dump/v1beta1/dump.pb.go | 1 - api/extensions/v1/redact.pb.go | 1 - api/ha/v1beta1/ha.pb.go | 1 - api/inventory/v1/agent_status.pb.go | 1 - api/inventory/v1/agents.pb.go | 1 - api/inventory/v1/log_level.pb.go | 1 - api/inventory/v1/nodes.pb.go | 1 - api/inventory/v1/services.pb.go | 1 - api/management/v1/agent.pb.go | 1 - api/management/v1/annotation.pb.go | 1 - api/management/v1/azure.pb.go | 1 - api/management/v1/external.pb.go | 1 - api/management/v1/haproxy.pb.go | 1 - api/management/v1/metrics.pb.go | 1 - api/management/v1/mongodb.pb.go | 1 - api/management/v1/mysql.pb.go | 1 - api/management/v1/node.pb.go | 1 - api/management/v1/postgresql.pb.go | 1 - api/management/v1/proxysql.pb.go | 1 - api/management/v1/rds.pb.go | 1 - api/management/v1/service.pb.go | 1 - api/management/v1/severity.pb.go | 1 - api/management/v1/valkey.pb.go | 1 - api/qan/v1/collector.pb.go | 1 - api/qan/v1/filters.pb.go | 1 - api/qan/v1/object_details.pb.go | 1 - api/qan/v1/profile.pb.go | 1 - api/qan/v1/qan.pb.go | 1 - api/qan/v1/service.pb.go | 1 - api/realtimeanalytics/v1/collector.pb.go | 1 - api/realtimeanalytics/v1/query.pb.go | 1 - .../v1/realtimeanalytics.pb.go | 1 - api/server/v1/httperror.pb.go | 1 - api/server/v1/server.pb.go | 1 - api/swagger/swagger-dev.json | 77 +++- api/swagger/swagger.json | 77 +++- api/user/v1/user.pb.go | 1 - managed/models/check_result_helpers.go | 26 +- managed/models/check_result_helpers_test.go | 13 +- managed/models/check_result_model.go | 32 +- managed/models/check_result_model_reform.go | 14 +- managed/models/database.go | 5 +- .../checks/check_result_record_test.go | 17 +- managed/services/checks/checks.go | 88 +++-- managed/services/management/checks.go | 95 ++++- managed/services/management/checks_test.go | 10 +- managed/services/management/deps.go | 2 +- .../management/mock_checks_service_test.go | 20 +- managed/services/server/deps.go | 2 +- .../server/mock_checks_service_test.go | 20 +- managed/services/server/server.go | 2 +- ui/apps/pmm/src/api/advisors.ts | 11 +- ui/apps/pmm/src/hooks/api/useAdvisors.ts | 2 +- .../pages/advisors/AdvisorsList.messages.ts | 1 + .../src/pages/advisors/AdvisorsList.test.tsx | 3 +- .../pmm/src/pages/advisors/AdvisorsList.tsx | 24 +- .../insights/AdvisorInsights.test.tsx | 21 +- .../advisors/insights/AdvisorInsights.tsx | 7 +- ui/apps/pmm/src/types/advisors.types.ts | 14 + 82 files changed, 977 insertions(+), 322 deletions(-) diff --git a/api/accesscontrol/v1beta1/accesscontrol.pb.go b/api/accesscontrol/v1beta1/accesscontrol.pb.go index f5e8ea4b004..ebec3bf05b7 100644 --- a/api/accesscontrol/v1beta1/accesscontrol.pb.go +++ b/api/accesscontrol/v1beta1/accesscontrol.pb.go @@ -844,7 +844,6 @@ var ( (*ListRolesResponse_RoleData)(nil), // 14: accesscontrol.v1beta1.ListRolesResponse.RoleData } ) - var file_accesscontrol_v1beta1_accesscontrol_proto_depIdxs = []int32{ 14, // 0: accesscontrol.v1beta1.ListRolesResponse.roles:type_name -> accesscontrol.v1beta1.ListRolesResponse.RoleData 0, // 1: accesscontrol.v1beta1.AccessControlService.CreateRole:input_type -> accesscontrol.v1beta1.CreateRoleRequest diff --git a/api/actions/v1/actions.pb.go b/api/actions/v1/actions.pb.go index f1cfdec8cfa..35461ae3739 100644 --- a/api/actions/v1/actions.pb.go +++ b/api/actions/v1/actions.pb.go @@ -2649,7 +2649,6 @@ var ( (*StartServiceActionResponse)(nil), // 32: actions.v1.StartServiceActionResponse } ) - var file_actions_v1_actions_proto_depIdxs = []int32{ 3, // 0: actions.v1.StartServiceActionRequest.mysql_explain:type_name -> actions.v1.StartMySQLExplainActionParams 5, // 1: actions.v1.StartServiceActionRequest.mysql_explain_json:type_name -> actions.v1.StartMySQLExplainJSONActionParams diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index a179ff24f0e..b55ddf66ec9 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -189,6 +189,58 @@ func (AdvisorCheckResultStatus) EnumDescriptor() ([]byte, []int) { return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{2} } +// AdvisorCheckTriggeredBy represents the actor that initiated an Advisor check run. +type AdvisorCheckTriggeredBy int32 + +const ( + AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED AdvisorCheckTriggeredBy = 0 + // The run was started by a user via the API or UI. + AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_USER AdvisorCheckTriggeredBy = 1 + // The run was started by the built-in scheduler. + AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER AdvisorCheckTriggeredBy = 2 +) + +// Enum value maps for AdvisorCheckTriggeredBy. +var ( + AdvisorCheckTriggeredBy_name = map[int32]string{ + 0: "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + 1: "ADVISOR_CHECK_TRIGGERED_BY_USER", + 2: "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER", + } + AdvisorCheckTriggeredBy_value = map[string]int32{ + "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED": 0, + "ADVISOR_CHECK_TRIGGERED_BY_USER": 1, + "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER": 2, + } +) + +func (x AdvisorCheckTriggeredBy) Enum() *AdvisorCheckTriggeredBy { + p := new(AdvisorCheckTriggeredBy) + *p = x + return p +} + +func (x AdvisorCheckTriggeredBy) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AdvisorCheckTriggeredBy) Descriptor() protoreflect.EnumDescriptor { + return file_advisors_v1_advisors_proto_enumTypes[3].Descriptor() +} + +func (AdvisorCheckTriggeredBy) Type() protoreflect.EnumType { + return &file_advisors_v1_advisors_proto_enumTypes[3] +} + +func (x AdvisorCheckTriggeredBy) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AdvisorCheckTriggeredBy.Descriptor instead. +func (AdvisorCheckTriggeredBy) EnumDescriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{3} +} + // AdvisorCheckResult represents the check result returned from pmm-managed after running the check. type AdvisorCheckResult struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -805,7 +857,9 @@ func (x *StartAdvisorChecksRequest) GetNames() []string { } type StartAdvisorChecksResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` + state protoimpl.MessageState `protogen:"open.v1"` + // ID assigned to this run; all check results produced by it share this run_id. + RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -840,6 +894,13 @@ func (*StartAdvisorChecksResponse) Descriptor() ([]byte, []int) { return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{7} } +func (x *StartAdvisorChecksResponse) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + type ListAdvisorChecksRequest struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -1291,40 +1352,44 @@ type CheckResultHistoryItem struct { state protoimpl.MessageState `protogen:"open.v1"` // Unique identifier of the history record. Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // ID of the run this result belongs to; all results produced by one execution share it. + RunId string `protobuf:"bytes,2,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` // Name of the check that ran. - CheckName string `protobuf:"bytes,2,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` + CheckName string `protobuf:"bytes,3,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` // Name of the advisor the check belongs to. - AdvisorName string `protobuf:"bytes,3,opt,name=advisor_name,json=advisorName,proto3" json:"advisor_name,omitempty"` + AdvisorName string `protobuf:"bytes,4,opt,name=advisor_name,json=advisorName,proto3" json:"advisor_name,omitempty"` // Category of the advisor the check belongs to. - Category string `protobuf:"bytes,4,opt,name=category,proto3" json:"category,omitempty"` + Category string `protobuf:"bytes,5,opt,name=category,proto3" json:"category,omitempty"` // Check execution interval. - Interval AdvisorCheckInterval `protobuf:"varint,5,opt,name=interval,proto3,enum=advisors.v1.AdvisorCheckInterval" json:"interval,omitempty"` + Interval AdvisorCheckInterval `protobuf:"varint,6,opt,name=interval,proto3,enum=advisors.v1.AdvisorCheckInterval" json:"interval,omitempty"` // ID of the monitored service on which the check ran. - ServiceId string `protobuf:"bytes,6,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` + ServiceId string `protobuf:"bytes,7,opt,name=service_id,json=serviceId,proto3" json:"service_id,omitempty"` // Name of the monitored service on which the check ran. - ServiceName string `protobuf:"bytes,7,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + ServiceName string `protobuf:"bytes,8,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // Type of the monitored service on which the check ran. - ServiceType string `protobuf:"bytes,8,opt,name=service_type,json=serviceType,proto3" json:"service_type,omitempty"` + ServiceType string `protobuf:"bytes,9,opt,name=service_type,json=serviceType,proto3" json:"service_type,omitempty"` // ID of the node the service runs on. - NodeId string `protobuf:"bytes,9,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + NodeId string `protobuf:"bytes,10,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` // Name of the node the service runs on. - NodeName string `protobuf:"bytes,10,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + NodeName string `protobuf:"bytes,11,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` // Outcome of the check run. - Status AdvisorCheckResultStatus `protobuf:"varint,11,opt,name=status,proto3,enum=advisors.v1.AdvisorCheckResultStatus" json:"status,omitempty"` + Status AdvisorCheckResultStatus `protobuf:"varint,12,opt,name=status,proto3,enum=advisors.v1.AdvisorCheckResultStatus" json:"status,omitempty"` // Short human-readable summary of the result. - Summary string `protobuf:"bytes,12,opt,name=summary,proto3" json:"summary,omitempty"` + Summary string `protobuf:"bytes,13,opt,name=summary,proto3" json:"summary,omitempty"` // Long human-readable description of the result. - Description string `protobuf:"bytes,13,opt,name=description,proto3" json:"description,omitempty"` + Description string `protobuf:"bytes,14,opt,name=description,proto3" json:"description,omitempty"` // URL containing information on how to resolve a detected issue. - ReadMoreUrl string `protobuf:"bytes,14,opt,name=read_more_url,json=readMoreUrl,proto3" json:"read_more_url,omitempty"` + ReadMoreUrl string `protobuf:"bytes,15,opt,name=read_more_url,json=readMoreUrl,proto3" json:"read_more_url,omitempty"` // Severity of the result. - Severity v1.Severity `protobuf:"varint,15,opt,name=severity,proto3,enum=management.v1.Severity" json:"severity,omitempty"` + Severity v1.Severity `protobuf:"varint,16,opt,name=severity,proto3,enum=management.v1.Severity" json:"severity,omitempty"` // Result labels. - Labels map[string]string `protobuf:"bytes,16,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Labels map[string]string `protobuf:"bytes,17,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Time when the check ran. - CheckedAt *timestamppb.Timestamp `protobuf:"bytes,17,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"` + CheckedAt *timestamppb.Timestamp `protobuf:"bytes,18,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"` // Whether the result has been marked as read. - IsRead bool `protobuf:"varint,18,opt,name=is_read,json=isRead,proto3" json:"is_read,omitempty"` + IsRead bool `protobuf:"varint,19,opt,name=is_read,json=isRead,proto3" json:"is_read,omitempty"` + // The actor that initiated the run. + TriggeredBy AdvisorCheckTriggeredBy `protobuf:"varint,20,opt,name=triggered_by,json=triggeredBy,proto3,enum=advisors.v1.AdvisorCheckTriggeredBy" json:"triggered_by,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1366,6 +1431,13 @@ func (x *CheckResultHistoryItem) GetId() string { return "" } +func (x *CheckResultHistoryItem) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + func (x *CheckResultHistoryItem) GetCheckName() string { if x != nil { return x.CheckName @@ -1485,6 +1557,13 @@ func (x *CheckResultHistoryItem) GetIsRead() bool { return false } +func (x *CheckResultHistoryItem) GetTriggeredBy() AdvisorCheckTriggeredBy { + if x != nil { + return x.TriggeredBy + } + return AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED +} + type ListCheckResultsHistoryRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Maximum number of results per page. @@ -1510,7 +1589,11 @@ type ListCheckResultsHistoryRequest struct { // Filter by check name. CheckName string `protobuf:"bytes,11,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` // Filter by severity. - Severity *v1.Severity `protobuf:"varint,12,opt,name=severity,proto3,enum=management.v1.Severity,oneof" json:"severity,omitempty"` + Severity *v1.Severity `protobuf:"varint,12,opt,name=severity,proto3,enum=management.v1.Severity,oneof" json:"severity,omitempty"` + // Filter by run ID. + RunId string `protobuf:"bytes,13,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // Filter by the actor that initiated the run. + TriggeredBy *AdvisorCheckTriggeredBy `protobuf:"varint,14,opt,name=triggered_by,json=triggeredBy,proto3,enum=advisors.v1.AdvisorCheckTriggeredBy,oneof" json:"triggered_by,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1629,6 +1712,20 @@ func (x *ListCheckResultsHistoryRequest) GetSeverity() v1.Severity { return v1.Severity(0) } +func (x *ListCheckResultsHistoryRequest) GetRunId() string { + if x != nil { + return x.RunId + } + return "" +} + +func (x *ListCheckResultsHistoryRequest) GetTriggeredBy() AdvisorCheckTriggeredBy { + if x != nil && x.TriggeredBy != nil { + return *x.TriggeredBy + } + return AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED +} + type ListCheckResultsHistoryResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // Total number of results. @@ -1850,8 +1947,9 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\binterval\x18\x04 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\bintervalB\t\n" + "\a_enable\"1\n" + "\x19StartAdvisorChecksRequest\x12\x14\n" + - "\x05names\x18\x01 \x03(\tR\x05names\"\x1c\n" + - "\x1aStartAdvisorChecksResponse\"\x1a\n" + + "\x05names\x18\x01 \x03(\tR\x05names\"3\n" + + "\x1aStartAdvisorChecksResponse\x12\x15\n" + + "\x06run_id\x18\x01 \x01(\tR\x05runId\"\x1a\n" + "\x18ListAdvisorChecksRequest\"N\n" + "\x19ListAdvisorChecksResponse\x121\n" + "\x06checks\x18\x01 \x03(\v2\x19.advisors.v1.AdvisorCheckR\x06checks\"\x15\n" + @@ -1878,33 +1976,35 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "totalItems\x12\x1f\n" + "\vtotal_pages\x18\x02 \x01(\x05R\n" + "totalPages\x122\n" + - "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\x8c\x06\n" + + "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\xec\x06\n" + "\x16CheckResultHistoryItem\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x1d\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x15\n" + + "\x06run_id\x18\x02 \x01(\tR\x05runId\x12\x1d\n" + "\n" + - "check_name\x18\x02 \x01(\tR\tcheckName\x12!\n" + - "\fadvisor_name\x18\x03 \x01(\tR\vadvisorName\x12\x1a\n" + - "\bcategory\x18\x04 \x01(\tR\bcategory\x12=\n" + - "\binterval\x18\x05 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\binterval\x12\x1d\n" + + "check_name\x18\x03 \x01(\tR\tcheckName\x12!\n" + + "\fadvisor_name\x18\x04 \x01(\tR\vadvisorName\x12\x1a\n" + + "\bcategory\x18\x05 \x01(\tR\bcategory\x12=\n" + + "\binterval\x18\x06 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\binterval\x12\x1d\n" + "\n" + - "service_id\x18\x06 \x01(\tR\tserviceId\x12!\n" + - "\fservice_name\x18\a \x01(\tR\vserviceName\x12!\n" + - "\fservice_type\x18\b \x01(\tR\vserviceType\x12\x17\n" + - "\anode_id\x18\t \x01(\tR\x06nodeId\x12\x1b\n" + - "\tnode_name\x18\n" + - " \x01(\tR\bnodeName\x12=\n" + - "\x06status\x18\v \x01(\x0e2%.advisors.v1.AdvisorCheckResultStatusR\x06status\x12\x18\n" + - "\asummary\x18\f \x01(\tR\asummary\x12 \n" + - "\vdescription\x18\r \x01(\tR\vdescription\x12\"\n" + - "\rread_more_url\x18\x0e \x01(\tR\vreadMoreUrl\x123\n" + - "\bseverity\x18\x0f \x01(\x0e2\x17.management.v1.SeverityR\bseverity\x12G\n" + - "\x06labels\x18\x10 \x03(\v2/.advisors.v1.CheckResultHistoryItem.LabelsEntryR\x06labels\x129\n" + + "service_id\x18\a \x01(\tR\tserviceId\x12!\n" + + "\fservice_name\x18\b \x01(\tR\vserviceName\x12!\n" + + "\fservice_type\x18\t \x01(\tR\vserviceType\x12\x17\n" + + "\anode_id\x18\n" + + " \x01(\tR\x06nodeId\x12\x1b\n" + + "\tnode_name\x18\v \x01(\tR\bnodeName\x12=\n" + + "\x06status\x18\f \x01(\x0e2%.advisors.v1.AdvisorCheckResultStatusR\x06status\x12\x18\n" + + "\asummary\x18\r \x01(\tR\asummary\x12 \n" + + "\vdescription\x18\x0e \x01(\tR\vdescription\x12\"\n" + + "\rread_more_url\x18\x0f \x01(\tR\vreadMoreUrl\x123\n" + + "\bseverity\x18\x10 \x01(\x0e2\x17.management.v1.SeverityR\bseverity\x12G\n" + + "\x06labels\x18\x11 \x03(\v2/.advisors.v1.CheckResultHistoryItem.LabelsEntryR\x06labels\x129\n" + "\n" + - "checked_at\x18\x11 \x01(\v2\x1a.google.protobuf.TimestampR\tcheckedAt\x12\x17\n" + - "\ais_read\x18\x12 \x01(\bR\x06isRead\x1a9\n" + + "checked_at\x18\x12 \x01(\v2\x1a.google.protobuf.TimestampR\tcheckedAt\x12\x17\n" + + "\ais_read\x18\x13 \x01(\bR\x06isRead\x12G\n" + + "\ftriggered_by\x18\x14 \x01(\x0e2$.advisors.v1.AdvisorCheckTriggeredByR\vtriggeredBy\x1a9\n" + "\vLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xcb\x04\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc1\x05\n" + "\x1eListCheckResultsHistoryRequest\x12)\n" + "\tpage_size\x18\x01 \x01(\x05B\a\xfaB\x04\x1a\x02(\x01H\x00R\bpageSize\x88\x01\x01\x12+\n" + "\n" + @@ -1921,14 +2021,17 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + " \x01(\tR\bcategory\x12\x1d\n" + "\n" + "check_name\x18\v \x01(\tR\tcheckName\x128\n" + - "\bseverity\x18\f \x01(\x0e2\x17.management.v1.SeverityH\x04R\bseverity\x88\x01\x01B\f\n" + + "\bseverity\x18\f \x01(\x0e2\x17.management.v1.SeverityH\x04R\bseverity\x88\x01\x01\x12\x15\n" + + "\x06run_id\x18\r \x01(\tR\x05runId\x12L\n" + + "\ftriggered_by\x18\x0e \x01(\x0e2$.advisors.v1.AdvisorCheckTriggeredByH\x05R\vtriggeredBy\x88\x01\x01B\f\n" + "\n" + "_page_sizeB\r\n" + "\v_page_indexB\t\n" + "\a_statusB\n" + "\n" + "\b_is_readB\v\n" + - "\t_severity\"\xa2\x01\n" + + "\t_severityB\x0f\n" + + "\r_triggered_by\"\xa2\x01\n" + "\x1fListCheckResultsHistoryResponse\x12\x1f\n" + "\vtotal_items\x18\x01 \x01(\x05R\n" + "totalItems\x12\x1f\n" + @@ -1953,7 +2056,11 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "'ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED\x10\x00\x12\"\n" + "\x1eADVISOR_CHECK_RESULT_STATUS_OK\x10\x01\x12&\n" + "\"ADVISOR_CHECK_RESULT_STATUS_FAILED\x10\x02\x12%\n" + - "!ADVISOR_CHECK_RESULT_STATUS_ERROR\x10\x032\xac\x0f\n" + + "!ADVISOR_CHECK_RESULT_STATUS_ERROR\x10\x03*\x94\x01\n" + + "\x17AdvisorCheckTriggeredBy\x12*\n" + + "&ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED\x10\x00\x12#\n" + + "\x1fADVISOR_CHECK_TRIGGERED_BY_USER\x10\x01\x12(\n" + + "$ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER\x10\x022\xac\x0f\n" + "\x0eAdvisorService\x12\xf3\x01\n" + "\x12ListFailedServices\x12&.advisors.v1.ListFailedServicesRequest\x1a'.advisors.v1.ListFailedServicesResponse\"\x8b\x01\x92Ae\x12\x14List Failed Services\x1aMReturns a list of services with failed checks and a summary of check results.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/failedServices\x12\xd5\x01\n" + "\x0fGetFailedChecks\x12#.advisors.v1.GetFailedChecksRequest\x1a$.advisors.v1.GetFailedChecksResponse\"w\x92AR\x12\x19Get Failed Advisor Checks\x1a5Returns the latest check results for a given service.\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/advisors/checks/failed\x12\x87\x02\n" + @@ -1978,88 +2085,90 @@ func file_advisors_v1_advisors_proto_rawDescGZIP() []byte { } var ( - file_advisors_v1_advisors_proto_enumTypes = make([]protoimpl.EnumInfo, 3) + file_advisors_v1_advisors_proto_enumTypes = make([]protoimpl.EnumInfo, 4) file_advisors_v1_advisors_proto_msgTypes = make([]protoimpl.MessageInfo, 26) file_advisors_v1_advisors_proto_goTypes = []any{ AdvisorCheckInterval(0), // 0: advisors.v1.AdvisorCheckInterval AdvisorCheckFamily(0), // 1: advisors.v1.AdvisorCheckFamily AdvisorCheckResultStatus(0), // 2: advisors.v1.AdvisorCheckResultStatus - (*AdvisorCheckResult)(nil), // 3: advisors.v1.AdvisorCheckResult - (*CheckResultSummary)(nil), // 4: advisors.v1.CheckResultSummary - (*CheckResult)(nil), // 5: advisors.v1.CheckResult - (*AdvisorCheck)(nil), // 6: advisors.v1.AdvisorCheck - (*Advisor)(nil), // 7: advisors.v1.Advisor - (*ChangeAdvisorCheckParams)(nil), // 8: advisors.v1.ChangeAdvisorCheckParams - (*StartAdvisorChecksRequest)(nil), // 9: advisors.v1.StartAdvisorChecksRequest - (*StartAdvisorChecksResponse)(nil), // 10: advisors.v1.StartAdvisorChecksResponse - (*ListAdvisorChecksRequest)(nil), // 11: advisors.v1.ListAdvisorChecksRequest - (*ListAdvisorChecksResponse)(nil), // 12: advisors.v1.ListAdvisorChecksResponse - (*ListAdvisorsRequest)(nil), // 13: advisors.v1.ListAdvisorsRequest - (*ListAdvisorsResponse)(nil), // 14: advisors.v1.ListAdvisorsResponse - (*ChangeAdvisorChecksRequest)(nil), // 15: advisors.v1.ChangeAdvisorChecksRequest - (*ChangeAdvisorChecksResponse)(nil), // 16: advisors.v1.ChangeAdvisorChecksResponse - (*ListFailedServicesRequest)(nil), // 17: advisors.v1.ListFailedServicesRequest - (*ListFailedServicesResponse)(nil), // 18: advisors.v1.ListFailedServicesResponse - (*GetFailedChecksRequest)(nil), // 19: advisors.v1.GetFailedChecksRequest - (*GetFailedChecksResponse)(nil), // 20: advisors.v1.GetFailedChecksResponse - (*CheckResultHistoryItem)(nil), // 21: advisors.v1.CheckResultHistoryItem - (*ListCheckResultsHistoryRequest)(nil), // 22: advisors.v1.ListCheckResultsHistoryRequest - (*ListCheckResultsHistoryResponse)(nil), // 23: advisors.v1.ListCheckResultsHistoryResponse - (*MarkCheckResultsReadRequest)(nil), // 24: advisors.v1.MarkCheckResultsReadRequest - (*MarkCheckResultsReadResponse)(nil), // 25: advisors.v1.MarkCheckResultsReadResponse - nil, // 26: advisors.v1.AdvisorCheckResult.LabelsEntry - nil, // 27: advisors.v1.CheckResult.LabelsEntry - nil, // 28: advisors.v1.CheckResultHistoryItem.LabelsEntry - v1.Severity(0), // 29: management.v1.Severity - (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp + AdvisorCheckTriggeredBy(0), // 3: advisors.v1.AdvisorCheckTriggeredBy + (*AdvisorCheckResult)(nil), // 4: advisors.v1.AdvisorCheckResult + (*CheckResultSummary)(nil), // 5: advisors.v1.CheckResultSummary + (*CheckResult)(nil), // 6: advisors.v1.CheckResult + (*AdvisorCheck)(nil), // 7: advisors.v1.AdvisorCheck + (*Advisor)(nil), // 8: advisors.v1.Advisor + (*ChangeAdvisorCheckParams)(nil), // 9: advisors.v1.ChangeAdvisorCheckParams + (*StartAdvisorChecksRequest)(nil), // 10: advisors.v1.StartAdvisorChecksRequest + (*StartAdvisorChecksResponse)(nil), // 11: advisors.v1.StartAdvisorChecksResponse + (*ListAdvisorChecksRequest)(nil), // 12: advisors.v1.ListAdvisorChecksRequest + (*ListAdvisorChecksResponse)(nil), // 13: advisors.v1.ListAdvisorChecksResponse + (*ListAdvisorsRequest)(nil), // 14: advisors.v1.ListAdvisorsRequest + (*ListAdvisorsResponse)(nil), // 15: advisors.v1.ListAdvisorsResponse + (*ChangeAdvisorChecksRequest)(nil), // 16: advisors.v1.ChangeAdvisorChecksRequest + (*ChangeAdvisorChecksResponse)(nil), // 17: advisors.v1.ChangeAdvisorChecksResponse + (*ListFailedServicesRequest)(nil), // 18: advisors.v1.ListFailedServicesRequest + (*ListFailedServicesResponse)(nil), // 19: advisors.v1.ListFailedServicesResponse + (*GetFailedChecksRequest)(nil), // 20: advisors.v1.GetFailedChecksRequest + (*GetFailedChecksResponse)(nil), // 21: advisors.v1.GetFailedChecksResponse + (*CheckResultHistoryItem)(nil), // 22: advisors.v1.CheckResultHistoryItem + (*ListCheckResultsHistoryRequest)(nil), // 23: advisors.v1.ListCheckResultsHistoryRequest + (*ListCheckResultsHistoryResponse)(nil), // 24: advisors.v1.ListCheckResultsHistoryResponse + (*MarkCheckResultsReadRequest)(nil), // 25: advisors.v1.MarkCheckResultsReadRequest + (*MarkCheckResultsReadResponse)(nil), // 26: advisors.v1.MarkCheckResultsReadResponse + nil, // 27: advisors.v1.AdvisorCheckResult.LabelsEntry + nil, // 28: advisors.v1.CheckResult.LabelsEntry + nil, // 29: advisors.v1.CheckResultHistoryItem.LabelsEntry + v1.Severity(0), // 30: management.v1.Severity + (*timestamppb.Timestamp)(nil), // 31: google.protobuf.Timestamp } ) - var file_advisors_v1_advisors_proto_depIdxs = []int32{ - 29, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity - 26, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry - 29, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity - 27, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry + 30, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity + 27, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry + 30, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity + 28, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry 0, // 4: advisors.v1.AdvisorCheck.interval:type_name -> advisors.v1.AdvisorCheckInterval 1, // 5: advisors.v1.AdvisorCheck.family:type_name -> advisors.v1.AdvisorCheckFamily - 6, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck + 7, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck 0, // 7: advisors.v1.ChangeAdvisorCheckParams.interval:type_name -> advisors.v1.AdvisorCheckInterval - 6, // 8: advisors.v1.ListAdvisorChecksResponse.checks:type_name -> advisors.v1.AdvisorCheck - 7, // 9: advisors.v1.ListAdvisorsResponse.advisors:type_name -> advisors.v1.Advisor - 8, // 10: advisors.v1.ChangeAdvisorChecksRequest.params:type_name -> advisors.v1.ChangeAdvisorCheckParams - 4, // 11: advisors.v1.ListFailedServicesResponse.result:type_name -> advisors.v1.CheckResultSummary - 5, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult + 7, // 8: advisors.v1.ListAdvisorChecksResponse.checks:type_name -> advisors.v1.AdvisorCheck + 8, // 9: advisors.v1.ListAdvisorsResponse.advisors:type_name -> advisors.v1.Advisor + 9, // 10: advisors.v1.ChangeAdvisorChecksRequest.params:type_name -> advisors.v1.ChangeAdvisorCheckParams + 5, // 11: advisors.v1.ListFailedServicesResponse.result:type_name -> advisors.v1.CheckResultSummary + 6, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult 0, // 13: advisors.v1.CheckResultHistoryItem.interval:type_name -> advisors.v1.AdvisorCheckInterval 2, // 14: advisors.v1.CheckResultHistoryItem.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 29, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity - 28, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry - 30, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp - 2, // 18: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 30, // 19: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp - 30, // 20: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp - 29, // 21: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity - 21, // 22: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem - 17, // 23: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest - 19, // 24: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest - 22, // 25: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest - 24, // 26: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest - 9, // 27: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest - 11, // 28: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest - 13, // 29: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest - 15, // 30: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest - 18, // 31: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse - 20, // 32: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse - 23, // 33: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse - 25, // 34: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse - 10, // 35: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse - 12, // 36: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse - 14, // 37: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse - 16, // 38: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse - 31, // [31:39] is the sub-list for method output_type - 23, // [23:31] is the sub-list for method input_type - 23, // [23:23] is the sub-list for extension type_name - 23, // [23:23] is the sub-list for extension extendee - 0, // [0:23] is the sub-list for field type_name + 30, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity + 29, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry + 31, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp + 3, // 18: advisors.v1.CheckResultHistoryItem.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy + 2, // 19: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus + 31, // 20: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp + 31, // 21: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp + 30, // 22: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity + 3, // 23: advisors.v1.ListCheckResultsHistoryRequest.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy + 22, // 24: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem + 18, // 25: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest + 20, // 26: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest + 23, // 27: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest + 25, // 28: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest + 10, // 29: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest + 12, // 30: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest + 14, // 31: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest + 16, // 32: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest + 19, // 33: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse + 21, // 34: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse + 24, // 35: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse + 26, // 36: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse + 11, // 37: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse + 13, // 38: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse + 15, // 39: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse + 17, // 40: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse + 33, // [33:41] is the sub-list for method output_type + 25, // [25:33] is the sub-list for method input_type + 25, // [25:25] is the sub-list for extension type_name + 25, // [25:25] is the sub-list for extension extendee + 0, // [0:25] is the sub-list for field type_name } func init() { file_advisors_v1_advisors_proto_init() } @@ -2075,7 +2184,7 @@ func file_advisors_v1_advisors_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_advisors_v1_advisors_proto_rawDesc), len(file_advisors_v1_advisors_proto_rawDesc)), - NumEnums: 3, + NumEnums: 4, NumMessages: 26, NumExtensions: 0, NumServices: 1, diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index d64096525dd..570511b8501 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -886,6 +886,8 @@ func (m *StartAdvisorChecksResponse) validate(all bool) error { var errors []error + // no validation rules for RunId + if len(errors) > 0 { return StartAdvisorChecksResponseMultiError(errors) } @@ -2224,6 +2226,8 @@ func (m *CheckResultHistoryItem) validate(all bool) error { // no validation rules for Id + // no validation rules for RunId + // no validation rules for CheckName // no validation rules for AdvisorName @@ -2285,6 +2289,8 @@ func (m *CheckResultHistoryItem) validate(all bool) error { // no validation rules for IsRead + // no validation rules for TriggeredBy + if len(errors) > 0 { return CheckResultHistoryItemMultiError(errors) } @@ -2456,6 +2462,8 @@ func (m *ListCheckResultsHistoryRequest) validate(all bool) error { // no validation rules for CheckName + // no validation rules for RunId + if m.PageSize != nil { if m.GetPageSize() < 1 { err := ListCheckResultsHistoryRequestValidationError{ @@ -2494,6 +2502,10 @@ func (m *ListCheckResultsHistoryRequest) validate(all bool) error { // no validation rules for Severity } + if m.TriggeredBy != nil { + // no validation rules for TriggeredBy + } + if len(errors) > 0 { return ListCheckResultsHistoryRequestMultiError(errors) } diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index a0c6d9d2999..19ecf4ca367 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -34,6 +34,15 @@ enum AdvisorCheckResultStatus { ADVISOR_CHECK_RESULT_STATUS_ERROR = 3; } +// AdvisorCheckTriggeredBy represents the actor that initiated an Advisor check run. +enum AdvisorCheckTriggeredBy { + ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED = 0; + // The run was started by a user via the API or UI. + ADVISOR_CHECK_TRIGGERED_BY_USER = 1; + // The run was started by the built-in scheduler. + ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER = 2; +} + // AdvisorCheckResult represents the check result returned from pmm-managed after running the check. message AdvisorCheckResult { string summary = 1; @@ -131,7 +140,10 @@ message StartAdvisorChecksRequest { repeated string names = 1; } -message StartAdvisorChecksResponse {} +message StartAdvisorChecksResponse { + // ID assigned to this run; all check results produced by it share this run_id. + string run_id = 1; +} message ListAdvisorChecksRequest {} @@ -179,40 +191,44 @@ message GetFailedChecksResponse { message CheckResultHistoryItem { // Unique identifier of the history record. string id = 1; + // ID of the run this result belongs to; all results produced by one execution share it. + string run_id = 2; // Name of the check that ran. - string check_name = 2; + string check_name = 3; // Name of the advisor the check belongs to. - string advisor_name = 3; + string advisor_name = 4; // Category of the advisor the check belongs to. - string category = 4; + string category = 5; // Check execution interval. - AdvisorCheckInterval interval = 5; + AdvisorCheckInterval interval = 6; // ID of the monitored service on which the check ran. - string service_id = 6; + string service_id = 7; // Name of the monitored service on which the check ran. - string service_name = 7; + string service_name = 8; // Type of the monitored service on which the check ran. - string service_type = 8; + string service_type = 9; // ID of the node the service runs on. - string node_id = 9; + string node_id = 10; // Name of the node the service runs on. - string node_name = 10; + string node_name = 11; // Outcome of the check run. - AdvisorCheckResultStatus status = 11; + AdvisorCheckResultStatus status = 12; // Short human-readable summary of the result. - string summary = 12; + string summary = 13; // Long human-readable description of the result. - string description = 13; + string description = 14; // URL containing information on how to resolve a detected issue. - string read_more_url = 14; + string read_more_url = 15; // Severity of the result. - management.v1.Severity severity = 15; + management.v1.Severity severity = 16; // Result labels. - map labels = 16; + map labels = 17; // Time when the check ran. - google.protobuf.Timestamp checked_at = 17; + google.protobuf.Timestamp checked_at = 18; // Whether the result has been marked as read. - bool is_read = 18; + bool is_read = 19; + // The actor that initiated the run. + AdvisorCheckTriggeredBy triggered_by = 20; } message ListCheckResultsHistoryRequest { @@ -240,6 +256,10 @@ message ListCheckResultsHistoryRequest { string check_name = 11; // Filter by severity. optional management.v1.Severity severity = 12; + // Filter by run ID. + string run_id = 13; + // Filter by the actor that initiated the run. + optional AdvisorCheckTriggeredBy triggered_by = 14; } message ListCheckResultsHistoryResponse { diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go index 1313a1ca74f..55c153ed500 100644 --- a/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go @@ -106,6 +106,12 @@ type ListCheckResultsHistoryParams struct { */ PageSize *int32 + /* RunID. + + Filter by run ID. + */ + RunID *string + /* ServiceID. Filter by service ID. @@ -146,6 +152,17 @@ type ListCheckResultsHistoryParams struct { */ To *strfmt.DateTime + /* TriggeredBy. + + Filter by the actor that initiated the run. + + - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI. + - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler. + + Default: "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED" + */ + TriggeredBy *string + timeout time.Duration Context context.Context HTTPClient *http.Client @@ -167,11 +184,14 @@ func (o *ListCheckResultsHistoryParams) SetDefaults() { severityDefault = string("SEVERITY_UNSPECIFIED") statusDefault = string("ADVISOR_CHECK_RESULT_STATUS_UNSPECIFIED") + + triggeredByDefault = string("ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED") ) val := ListCheckResultsHistoryParams{ - Severity: &severityDefault, - Status: &statusDefault, + Severity: &severityDefault, + Status: &statusDefault, + TriggeredBy: &triggeredByDefault, } val.timeout = o.timeout @@ -290,6 +310,17 @@ func (o *ListCheckResultsHistoryParams) SetPageSize(pageSize *int32) { o.PageSize = pageSize } +// WithRunID adds the runID to the list check results history params +func (o *ListCheckResultsHistoryParams) WithRunID(runID *string) *ListCheckResultsHistoryParams { + o.SetRunID(runID) + return o +} + +// SetRunID adds the runId to the list check results history params +func (o *ListCheckResultsHistoryParams) SetRunID(runID *string) { + o.RunID = runID +} + // WithServiceID adds the serviceID to the list check results history params func (o *ListCheckResultsHistoryParams) WithServiceID(serviceID *string) *ListCheckResultsHistoryParams { o.SetServiceID(serviceID) @@ -345,6 +376,17 @@ func (o *ListCheckResultsHistoryParams) SetTo(to *strfmt.DateTime) { o.To = to } +// WithTriggeredBy adds the triggeredBy to the list check results history params +func (o *ListCheckResultsHistoryParams) WithTriggeredBy(triggeredBy *string) *ListCheckResultsHistoryParams { + o.SetTriggeredBy(triggeredBy) + return o +} + +// SetTriggeredBy adds the triggeredBy to the list check results history params +func (o *ListCheckResultsHistoryParams) SetTriggeredBy(triggeredBy *string) { + o.TriggeredBy = triggeredBy +} + // WriteToRequest writes these params to a swagger request func (o *ListCheckResultsHistoryParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { if err := r.SetTimeout(o.timeout); err != nil { @@ -464,6 +506,22 @@ func (o *ListCheckResultsHistoryParams) WriteToRequest(r runtime.ClientRequest, } } + if o.RunID != nil { + + // query param run_id + var qrRunID string + + if o.RunID != nil { + qrRunID = *o.RunID + } + qRunID := qrRunID + if qRunID != "" { + if err := r.SetQueryParam("run_id", qRunID); err != nil { + return err + } + } + } + if o.ServiceID != nil { // query param service_id @@ -544,6 +602,22 @@ func (o *ListCheckResultsHistoryParams) WriteToRequest(r runtime.ClientRequest, } } + if o.TriggeredBy != nil { + + // query param triggered_by + var qrTriggeredBy string + + if o.TriggeredBy != nil { + qrTriggeredBy = *o.TriggeredBy + } + qTriggeredBy := qrTriggeredBy + if qTriggeredBy != "" { + if err := r.SetQueryParam("triggered_by", qTriggeredBy); err != nil { + return err + } + } + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go index af4221cfe55..b4773bf49cc 100644 --- a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go @@ -538,6 +538,9 @@ type ListCheckResultsHistoryOKBodyResultsItems0 struct { // Unique identifier of the history record. ID string `json:"id,omitempty"` + // ID of the run this result belongs to; all results produced by one execution share it. + RunID string `json:"run_id,omitempty"` + // Name of the check that ran. CheckName string `json:"check_name,omitempty"` @@ -596,6 +599,13 @@ type ListCheckResultsHistoryOKBodyResultsItems0 struct { // Whether the result has been marked as read. IsRead bool `json:"is_read,omitempty"` + + // AdvisorCheckTriggeredBy represents the actor that initiated an Advisor check run. + // + // - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI. + // - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler. + // Enum: ["ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED","ADVISOR_CHECK_TRIGGERED_BY_USER","ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER"] + TriggeredBy *string `json:"triggered_by,omitempty"` } // Validate validates this list check results history OK body results items0 @@ -618,6 +628,10 @@ func (o *ListCheckResultsHistoryOKBodyResultsItems0) Validate(formats strfmt.Reg res = append(res, err) } + if err := o.validateTriggeredBy(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -795,6 +809,51 @@ func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateCheckedAt(formats s return nil } +var listCheckResultsHistoryOkBodyResultsItems0TypeTriggeredByPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED","ADVISOR_CHECK_TRIGGERED_BY_USER","ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + listCheckResultsHistoryOkBodyResultsItems0TypeTriggeredByPropEnum = append(listCheckResultsHistoryOkBodyResultsItems0TypeTriggeredByPropEnum, v) + } +} + +const ( + + // ListCheckResultsHistoryOKBodyResultsItems0TriggeredByADVISORCHECKTRIGGEREDBYUNSPECIFIED captures enum value "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED" + ListCheckResultsHistoryOKBodyResultsItems0TriggeredByADVISORCHECKTRIGGEREDBYUNSPECIFIED string = "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED" + + // ListCheckResultsHistoryOKBodyResultsItems0TriggeredByADVISORCHECKTRIGGEREDBYUSER captures enum value "ADVISOR_CHECK_TRIGGERED_BY_USER" + ListCheckResultsHistoryOKBodyResultsItems0TriggeredByADVISORCHECKTRIGGEREDBYUSER string = "ADVISOR_CHECK_TRIGGERED_BY_USER" + + // ListCheckResultsHistoryOKBodyResultsItems0TriggeredByADVISORCHECKTRIGGEREDBYSCHEDULER captures enum value "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" + ListCheckResultsHistoryOKBodyResultsItems0TriggeredByADVISORCHECKTRIGGEREDBYSCHEDULER string = "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" +) + +// prop value enum +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateTriggeredByEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, listCheckResultsHistoryOkBodyResultsItems0TypeTriggeredByPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *ListCheckResultsHistoryOKBodyResultsItems0) validateTriggeredBy(formats strfmt.Registry) error { + if swag.IsZero(o.TriggeredBy) { // not required + return nil + } + + // value enum + if err := o.validateTriggeredByEnum("triggered_by", "body", *o.TriggeredBy); err != nil { + return err + } + + return nil +} + // ContextValidate validates this list check results history OK body results items0 based on context it is used func (o *ListCheckResultsHistoryOKBodyResultsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { return nil diff --git a/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go b/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go index 8477c9cc6ee..9c3e2635ec6 100644 --- a/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go +++ b/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go @@ -53,7 +53,7 @@ StartAdvisorChecksOK describes a response with status code 200, with default hea A successful response. */ type StartAdvisorChecksOK struct { - Payload any + Payload *StartAdvisorChecksOKBody } // IsSuccess returns true when this start advisor checks Ok response has a 2xx status code @@ -96,13 +96,15 @@ func (o *StartAdvisorChecksOK) String() string { return fmt.Sprintf("[POST /v1/advisors/checks:start][%d] startAdvisorChecksOk %s", 200, payload) } -func (o *StartAdvisorChecksOK) GetPayload() any { +func (o *StartAdvisorChecksOK) GetPayload() *StartAdvisorChecksOKBody { return o.Payload } func (o *StartAdvisorChecksOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(StartAdvisorChecksOKBody) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } @@ -446,3 +448,40 @@ func (o *StartAdvisorChecksDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) e *o = res return nil } + +/* +StartAdvisorChecksOKBody start advisor checks OK body +swagger:model StartAdvisorChecksOKBody +*/ +type StartAdvisorChecksOKBody struct { + // ID assigned to this run; all check results produced by it share this run_id. + RunID string `json:"run_id,omitempty"` +} + +// Validate validates this start advisor checks OK body +func (o *StartAdvisorChecksOKBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this start advisor checks OK body based on context it is used +func (o *StartAdvisorChecksOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *StartAdvisorChecksOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *StartAdvisorChecksOKBody) UnmarshalBinary(b []byte) error { + var res StartAdvisorChecksOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index dba0e99f7fa..38fc50c3621 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -514,6 +514,24 @@ "description": "Filter by severity.", "name": "severity", "in": "query" + }, + { + "type": "string", + "description": "Filter by run ID.", + "name": "run_id", + "in": "query" + }, + { + "enum": [ + "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "ADVISOR_CHECK_TRIGGERED_BY_USER", + "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" + ], + "type": "string", + "default": "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "description": "Filter by the actor that initiated the run.\n\n - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI.\n - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler.", + "name": "triggered_by", + "in": "query" } ], "responses": { @@ -546,20 +564,25 @@ "type": "string", "x-order": 0 }, + "run_id": { + "description": "ID of the run this result belongs to; all results produced by one execution share it.", + "type": "string", + "x-order": 1 + }, "check_name": { "description": "Name of the check that ran.", "type": "string", - "x-order": 1 + "x-order": 2 }, "advisor_name": { "description": "Name of the advisor the check belongs to.", "type": "string", - "x-order": 2 + "x-order": 3 }, "category": { "description": "Category of the advisor the check belongs to.", "type": "string", - "x-order": 3 + "x-order": 4 }, "interval": { "description": "AdvisorCheckInterval represents possible execution interval values for checks.", @@ -571,32 +594,32 @@ "ADVISOR_CHECK_INTERVAL_FREQUENT", "ADVISOR_CHECK_INTERVAL_RARE" ], - "x-order": 4 + "x-order": 5 }, "service_id": { "description": "ID of the monitored service on which the check ran.", "type": "string", - "x-order": 5 + "x-order": 6 }, "service_name": { "description": "Name of the monitored service on which the check ran.", "type": "string", - "x-order": 6 + "x-order": 7 }, "service_type": { "description": "Type of the monitored service on which the check ran.", "type": "string", - "x-order": 7 + "x-order": 8 }, "node_id": { "description": "ID of the node the service runs on.", "type": "string", - "x-order": 8 + "x-order": 9 }, "node_name": { "description": "Name of the node the service runs on.", "type": "string", - "x-order": 9 + "x-order": 10 }, "status": { "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", @@ -608,22 +631,22 @@ "ADVISOR_CHECK_RESULT_STATUS_FAILED", "ADVISOR_CHECK_RESULT_STATUS_ERROR" ], - "x-order": 10 + "x-order": 11 }, "summary": { "description": "Short human-readable summary of the result.", "type": "string", - "x-order": 11 + "x-order": 12 }, "description": { "description": "Long human-readable description of the result.", "type": "string", - "x-order": 12 + "x-order": 13 }, "read_more_url": { "description": "URL containing information on how to resolve a detected issue.", "type": "string", - "x-order": 13 + "x-order": 14 }, "severity": { "description": "Severity represents severity level of the check result or alert.", @@ -640,7 +663,7 @@ "SEVERITY_INFO", "SEVERITY_DEBUG" ], - "x-order": 14 + "x-order": 15 }, "labels": { "description": "Result labels.", @@ -648,18 +671,29 @@ "additionalProperties": { "type": "string" }, - "x-order": 15 + "x-order": 16 }, "checked_at": { "description": "Time when the check ran.", "type": "string", "format": "date-time", - "x-order": 16 + "x-order": 17 }, "is_read": { "description": "Whether the result has been marked as read.", "type": "boolean", - "x-order": 17 + "x-order": 18 + }, + "triggered_by": { + "description": "AdvisorCheckTriggeredBy represents the actor that initiated an Advisor check run.\n\n - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI.\n - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler.", + "type": "string", + "default": "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "ADVISOR_CHECK_TRIGGERED_BY_USER", + "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" + ], + "x-order": 19 } } }, @@ -901,7 +935,14 @@ "200": { "description": "A successful response.", "schema": { - "type": "object" + "type": "object", + "properties": { + "run_id": { + "description": "ID assigned to this run; all check results produced by it share this run_id.", + "type": "string", + "x-order": 0 + } + } } }, "default": { diff --git a/api/agent/v1/agent.pb.go b/api/agent/v1/agent.pb.go index c2f2a8b6a9e..7f5d935624b 100644 --- a/api/agent/v1/agent.pb.go +++ b/api/agent/v1/agent.pb.go @@ -7221,7 +7221,6 @@ var ( (*v11.Metadata)(nil), // 104: backup.v1.Metadata } ) - var file_agent_v1_agent_proto_depIdxs = []int32{ 44, // 0: agent.v1.TextFiles.files:type_name -> agent.v1.TextFiles.FilesEntry 94, // 1: agent.v1.Pong.current_time:type_name -> google.protobuf.Timestamp diff --git a/api/agent/v1/collector.pb.go b/api/agent/v1/collector.pb.go index 65633c05d17..da17db39c64 100644 --- a/api/agent/v1/collector.pb.go +++ b/api/agent/v1/collector.pb.go @@ -2827,7 +2827,6 @@ var ( v1.AgentType(0), // 9: inventory.v1.AgentType } ) - var file_agent_v1_collector_proto_depIdxs = []int32{ 3, // 0: agent.v1.MetricsBucket.common:type_name -> agent.v1.MetricsBucket.Common 4, // 1: agent.v1.MetricsBucket.mysql:type_name -> agent.v1.MetricsBucket.MySQL diff --git a/api/agentlocal/v1/agentlocal.pb.go b/api/agentlocal/v1/agentlocal.pb.go index 7bb13a7cb58..12053d57921 100644 --- a/api/agentlocal/v1/agentlocal.pb.go +++ b/api/agentlocal/v1/agentlocal.pb.go @@ -485,7 +485,6 @@ var ( v1.AgentStatus(0), // 8: inventory.v1.AgentStatus } ) - var file_agentlocal_v1_agentlocal_proto_depIdxs = []int32{ 6, // 0: agentlocal.v1.ServerInfo.latency:type_name -> google.protobuf.Duration 6, // 1: agentlocal.v1.ServerInfo.clock_drift:type_name -> google.protobuf.Duration diff --git a/api/alerting/v1/alerting.pb.go b/api/alerting/v1/alerting.pb.go index 3b2c47d73ec..bccb6659d24 100644 --- a/api/alerting/v1/alerting.pb.go +++ b/api/alerting/v1/alerting.pb.go @@ -1459,7 +1459,6 @@ var ( (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp } ) - var file_alerting_v1_alerting_proto_depIdxs = []int32{ 22, // 0: alerting.v1.ParamDefinition.unit:type_name -> alerting.v1.ParamUnit 23, // 1: alerting.v1.ParamDefinition.type:type_name -> alerting.v1.ParamType diff --git a/api/alerting/v1/params.pb.go b/api/alerting/v1/params.pb.go index 69d88497102..eb001a606db 100644 --- a/api/alerting/v1/params.pb.go +++ b/api/alerting/v1/params.pb.go @@ -163,7 +163,6 @@ var ( ParamType(0), // 1: alerting.v1.ParamType } ) - var file_alerting_v1_params_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/backup/v1/artifacts.pb.go b/api/backup/v1/artifacts.pb.go index dde03ceefef..e2352f61cd1 100644 --- a/api/backup/v1/artifacts.pb.go +++ b/api/backup/v1/artifacts.pb.go @@ -656,7 +656,6 @@ var ( (*Metadata)(nil), // 12: backup.v1.Metadata } ) - var file_backup_v1_artifacts_proto_depIdxs = []int32{ 9, // 0: backup.v1.Artifact.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.Artifact.status:type_name -> backup.v1.BackupStatus diff --git a/api/backup/v1/backup.pb.go b/api/backup/v1/backup.pb.go index 4d587217600..19241fc6afd 100644 --- a/api/backup/v1/backup.pb.go +++ b/api/backup/v1/backup.pb.go @@ -1276,7 +1276,6 @@ var ( (*ListPitrTimerangesResponse)(nil), // 27: backup.v1.ListPitrTimerangesResponse } ) - var file_backup_v1_backup_proto_depIdxs = []int32{ 15, // 0: backup.v1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration 16, // 1: backup.v1.StartBackupRequest.data_model:type_name -> backup.v1.DataModel diff --git a/api/backup/v1/common.pb.go b/api/backup/v1/common.pb.go index c8274024e38..f84ca11de32 100644 --- a/api/backup/v1/common.pb.go +++ b/api/backup/v1/common.pb.go @@ -423,7 +423,6 @@ var ( (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp } ) - var file_backup_v1_common_proto_depIdxs = []int32{ 2, // 0: backup.v1.Metadata.file_list:type_name -> backup.v1.File 6, // 1: backup.v1.Metadata.restore_to:type_name -> google.protobuf.Timestamp diff --git a/api/backup/v1/errors.pb.go b/api/backup/v1/errors.pb.go index 902adc277c1..5709e5ac243 100644 --- a/api/backup/v1/errors.pb.go +++ b/api/backup/v1/errors.pb.go @@ -169,7 +169,6 @@ var ( (*Error)(nil), // 1: backup.v1.Error } ) - var file_backup_v1_errors_proto_depIdxs = []int32{ 0, // 0: backup.v1.Error.code:type_name -> backup.v1.ErrorCode 1, // [1:1] is the sub-list for method output_type diff --git a/api/backup/v1/locations.pb.go b/api/backup/v1/locations.pb.go index 396b552ee80..72c13dece43 100644 --- a/api/backup/v1/locations.pb.go +++ b/api/backup/v1/locations.pb.go @@ -833,7 +833,6 @@ var ( (*TestLocationConfigResponse)(nil), // 12: backup.v1.TestLocationConfigResponse } ) - var file_backup_v1_locations_proto_depIdxs = []int32{ 0, // 0: backup.v1.Location.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig 1, // 1: backup.v1.Location.s3_config:type_name -> backup.v1.S3LocationConfig diff --git a/api/backup/v1/restores.pb.go b/api/backup/v1/restores.pb.go index ee12d6b9285..580c158b119 100644 --- a/api/backup/v1/restores.pb.go +++ b/api/backup/v1/restores.pb.go @@ -625,7 +625,6 @@ var ( (*LogChunk)(nil), // 10: backup.v1.LogChunk } ) - var file_backup_v1_restores_proto_depIdxs = []int32{ 8, // 0: backup.v1.RestoreHistoryItem.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.RestoreHistoryItem.status:type_name -> backup.v1.RestoreStatus diff --git a/api/common/common.pb.go b/api/common/common.pb.go index 0d05883daa1..2303ccd29ab 100644 --- a/api/common/common.pb.go +++ b/api/common/common.pb.go @@ -147,7 +147,6 @@ var ( nil, // 2: common.StringMap.ValuesEntry } ) - var file_common_common_proto_depIdxs = []int32{ 2, // 0: common.StringMap.values:type_name -> common.StringMap.ValuesEntry 1, // [1:1] is the sub-list for method output_type diff --git a/api/common/metrics_resolutions.pb.go b/api/common/metrics_resolutions.pb.go index 75e587ba9a5..389e4572992 100644 --- a/api/common/metrics_resolutions.pb.go +++ b/api/common/metrics_resolutions.pb.go @@ -118,7 +118,6 @@ var ( (*durationpb.Duration)(nil), // 1: google.protobuf.Duration } ) - var file_common_metrics_resolutions_proto_depIdxs = []int32{ 1, // 0: common.MetricsResolutions.hr:type_name -> google.protobuf.Duration 1, // 1: common.MetricsResolutions.mr:type_name -> google.protobuf.Duration diff --git a/api/descriptor.bin b/api/descriptor.bin index 7b4a8888ada22cb99259f8f7dd79f7d72b0f83bd..b04dcf58e84b59a0661ed71b933430eb732976b1 100644 GIT binary patch delta 9989 zcma)C4Rlr2m40WRo12&W0!i)*A-sfmA%Q?3frNkv$WI7=ia&&(B6UaudBD?{KoVrK z9QwcjDu0RyM=L1);9nP_P6cai7j@Ke)V8!z$D(7cwe56Kmcw$|E{E0SeEXbp-=kf1 z&9GM1;ydSjd+)Q)IeYJO?z`(mL;vdyTegX9^c}f;C2e`^xj&RLj2? zt5kbmjZIQJZ<3zKS08l9G3wM!vRDi_xJ3*V1J&m@$x2b62Hz|zM4`HFVRV#Qc{9cq zsnpGKq43p)3(-pTi<@Qfh&XgdTijGnOR}xqpXcTGcBj^^O?D^STUYg!7Nd7yLzQ|Y zDTkCU345CQT4I@DO?_(mH{>+uhdEw_y1PdXKDnqvUJ&Chao2!LJ+Sa^R1CaC#gI!> z%+I-0iJIOi=ae)RcmrB9nqlDZM}>Ep(fV+w^yHM9`-C@mmT}~4cJw6@{TgrNtmb74 z7GKxWI(z<{*;ltNX<0CD-kg>>&8QC`(o(^?lpRP)k> z7)d9e-XNdL_5M5M<@!01$Ztp$y&Nr8;}%6@CvWeQ{W9I^QI7PT5s@(>u{ih&JA>}z z`tD>;va`1*=v|i#+E({=b>n|+y+Nuo)thSTO|}PZogqEY8!EtNtn=_s=1Aeo5jo{v zzL%3DDFQT-MtL#M$w>n;stx-HXv|oP1V)acVcrakl%&DPL_@FyCO~+wsjVmI>22#~ z?W_8NwqRpVvOBmn)uxS{b^U?>RxVutBaC7J;iIZXSj6&bR?tZAN-Z6IH8dtM{;Q<( zyjN{Zb@bMzI)fg}uzh1kvO6Q2m_NG4>+;Bn_)cBqa#gTdcBSj03D)OCD3asLaTMig zGh#3(?1Cxd@(M#Ff#Ss$3DCx8Xc#!2hJ;;=@-hQK8$Yy;xRbzb)?5ba;&wT6c!YAmnv@rM3Hww|DjkB|z~Y=K zk!#eNw49NiVqGk>i>F#&0r_$&86^M^HPwm&f~ctw#S;_6E}oX5Vc;|}ZbTQOym&Ye zv}q-SEh5mSQ#9r+hv9-Zz;rcki(FARJujpa2-C}q%LGXfW%X-Hz8y0Tx+ zP=DGY<8?FbVqz%w+Qk&a-faT$Ynlk}Hc@%vDnq<=t1PK&$_tHhKx|5sSrgf{%^8gv zWHf%U6&jl}8ri$e8I3N+&INIq)`&eZ7wfseXzaUP4yv1L7gLZ6;#|9!f^tEe58_fy z%w>>B%s0e~x69(1`I$w?1#y065uzYo1>#~&i~^`D`sLEPt1{k?V*FJZ@8@Cs!pzk2 z7$ibxUhJ3g@`ahH<$<_x@DT56Y#j2P>m#kIW}Cb^eSOp{Ea{E22*P;R1Nm~1J(~d7 z0gLR}1cInV_H2^gI4v0(2DaF2MFn)zyKhhiJMvNb; z$77@1sD80S*45mY8PEIU#>{x$A1lfA>h*Z+kCm$a4mqKGWp07q>_ogjR{F)>6f84R z+NwyG+H!}S60C}v5Q$U+8ST(H2QqZxX(vB1S-o;Yv`hubXhkE(1CyZI^9E?KKoHwr zSY#2$iZw8!R*Qhw*Qj}S%5gPoatDSZFn&#uZxMTL9aN6f6(3 zb#`w^9V2eCZUOS;P3rVcIchxq4`nymjR?eDb|Xr1;O`D9@kVJaSmF-#{rhB~f<4kf zisk6rG59iT60dW|@JfqvK<%VrZ-}PC+D-}*`9X72u%_*nR7ao5aPSHT8?77B0n$e6MzdizSvLataud6;F1^V*5N#O0$vV){ZtuhR!SDi* zFZ*av!V6}1-Es@69_s^iKz(0E1g}9~Mg#}x+aRJ;i@+M(MkR?@FdN0u+OBTnN40sE zjMm(iXLggLkKAp=Cc!zB1JY*lyb3J=;x?<}yJRqSbIe3{jDY^lr4@SVfS`Z#u;Jb{ zSc4qj-6|q?2=&D-IlDTBmB3hMtB3~P0Bq_UUJ9pQz`pU24#-G-W4EkM+kOo17gz%e zaf12<7QsM)HQpv*TfSyvEKph43DMg`45hHvgwO|ASQ0`=+9nWJOfQ0;vqNC7j@FW} zG=K;9$e_jcgS|swvswuD4xx7|?{fDp5!o#S0=0BpjJ!)khv|_nMPTACHgPHh0|Ke_ zd*qerT_R?tfksev34d@%f$&{IXG?N&eRr>j?6bmiF>Xb&^rY5yq6Y2lLgAU};o5X+(ALpm>fki0=bnunD4o}LceQU^ZHm=YZ_u-@ ztvi`v;1-8%#*>D4D8EPK8HWPG%zK0%*M}|YJNreXQhOkZar=3R^RWZ+eD{EeC~JQn zx(;aPq#-g-d*@)dfPlUORH^j=VNDJS>@rpl2<}0FZDt|V9~9VUeAYeRc|b%ew0aNY z9uQFu3FO3l_dyXkY}Lom^`MBBLqs~qiD~tRLiK>Y17x-)5Y!(MF<asb9XCZd(PW1#OG6_G04F%TU`*~4sCf$u&kB2Qbp3efdrXji&G z8}?La7@+R}jnJ?4Fbj#<6aGcfgaVtbz22xvAMjO-z_ed{&JgbT0!EsS!))OP4={T<^?=C=S zIxd2lR+F%rj*DS4>%Jlk{f>wlJBqY>PN06(ITX-$PN*Xf%c=?ZKSrJqC>GgbK*&77 zG7UsU;Jn1dkua}_4R}d?xlfKtzm%o$oL|aPP=q-zv+ss#3T6aUnJ5VK13?%sOf)Fs zauNM86Hfu5;bk${tP~(bzs#pIg>C5j?hi!dcS0n-9;heom8&a$5N;4(&+rucaWb?5 z`pzj;y`}Wuk$KXl9~d|K*fo#aoFoxqp#U~5jRm!N4a2C zvZJeWE#3*bObq;c!LO?`86^KPxq4%7s;e_-GJ!C~X_j3IwOWyle}FLRRgQnAm-oYK zY}6QS6ukGE+Phzlu4m7@hQ$xZf%aPHbe~ha^9Iwd&@^$vWMv>#{ZiSimSGf&jl&gm=}r}DJ=p96AsBPW^DSsJQrzzhx7Fz07X zH+F7Pe*EA%Cv+7SuPMgGO;jBRQY34Qnw6g+tOaljk_94@* z)ik6Hpz_2_wPCv)r_}wjw4T$)hXR)`%Yc9n#SjxDeJa2#KSGrAs;EKp4q)&w!4NnvXE#`1`wBdO6WX>69kdFnfjYe1@gncY7 z3uPBU*e6`&@vXwAB1UT419C(?ht5w#dFb0B@IDcv$5=5wCjTkk1+1%mAa(Wuc}3a> z?Nfn^l2PY__Ngcek82$2ek*W+<{O?*agD|%D)och-+gi9Cpq)TXavR~|FMq=eaO<0{YH5)%qq3(Q` zH5nRp=fkWS=PSGO8E?T6a3>&;+Vh~SuKg^GA83To&%*c-CkYELu!X}l1)UevuO5_D z(=LQ%6UM--3t`y=$b-0SGIPMfIiIrxqm+@Fbx2mv`aHZI#Q8FcF@@$l146>*T!R}4 z95?^Sn~nouoF@S^A~8{w9hOzeIkSaMW z=hpsNl$(5sMo|9D`O@g)nE3^}X@RC7W`3dWIxMfQ{UQu`apFk%MHuqp#F6qMQ|4+4 zR^p-(56Stp7sH^1F`!%&gUsoU6GzFvFojbVAdtHCAz54dmoR~#5tP4(;*i4O@yqP` zAv}JmPCq28>%PpcABV;-MMiZ@J)K$rv?l!ym&@$!wwbv(0k!p~G(apL&dPc~NrLS8@N6~?%C z08H9WY1qVZH%H`uaOpS%Z>P%8bPmDWsi9FH_hR3@ zlOlK9(_UGOp?6ZWT3c1DE1{iug3^%<(06u{dgNg_x^5@gG7qhgx07sgE!M|#H*>hm z1N5EUbnsp|tP%g$AVcJ%x;sncl3_2eN}!22ht(X_mjQ$q7|I|gzsOL z1L^z8rf~FP2k)oEY+ZpfJRappy`RdOEP+GQ0o0*7G!NprA5beEkrO5#AREom2%!g% zB=kM0#CPteNVUEvm0De`jlpnId-6nm6%yh3kW)V6_kgxnEm3R|H55pq{~*K4DN?;a)kwwnBy zye@r|TG`UytX9tWS-#te3&m!}vY1Urei^pi*nh?VLXR|&hYyPuYpPMEKc{b~F90K<^IWJ_)CvE<5 zioK9EpW8rtj@${>d~SjI=gGZ+UtVCG^xYSUegN|q25L)}ELPVYl}+gv$<;Sm9sv9O42kPaBh3WR82c_vG26y8Vx}j_ZTPD;B#4*DEx1J5 z%jA52er8@$&+BE1eP7RuSB0Bk)Az_7j|~^LNI&Nla&H&j8a*$Vb&BZU)bb}}GJPt0 z0QiH&sq6vZYm7m#- zxPW+<>gR;LF!~HR6Rpv%HTn$28m-Z$2|~_LFu@w_!swrq^M1x?R~!9vioKsTn%h8o zkK77tG`B$gzmt0fU&&z&UM)W$`c&Ga%=5mOdIyiN7;SD(mp2V*OM}{$>F-^ zO}`>{q@4`6z^qU1c>EcOKL>v~_;c}>i@)f}$Dhe-e1ZNj|K!;ly|;*V4?Ouqt9Om- z`IEiUTl#u7bhN6U4s+sTs{)B1zm({v=2TDHs*dFBu8xi*|4O09Z}Nt&@9ODYi-(Ai zF>Hiplx5rhmZpAM=FC1hagFyb<((L3em!yT$)c3EIY-=a^6pNrYhb|1R8l4UgLie$ zdt4v`18X=waX_eGNzUkWGPtI1@uG!6ds}bYspN1(o}jC< zqc7OBF4-9*JJ+W0ID$vy<^_vqU$<;dOKVH>;?_CW&RcNpoYre@fTXcO7Yd{9O)1F2 zD>8=S^|=c_kFnP}n7~Dxee|BnCLsg&3;fu`S`4T63tRF@s=@^DAn$q4nh8{CI5F|C znSe;D3rk|fqyE2ktKY5jD$@VAkyS8qNBA-iD`4Xe;hSO(5H{`*wwS~A!n6Oq_T7%} z4|w)BMK3-Up(xym%QZ?R{&d5&oS?M1*y#^Tz(Y;(tG_G(;)5!C0^f|l#U}&)jR12Y z7)YmWMjDoxno)mWLT`<^9VW`;IK%rJjgS%UlhiW;6?#`;kcU)(WprMwF zP9R<4KrLUe_K1pFYa*wwJz{*lh4=)5&l37;FESPS^87dR%gg^4 DcY~u@ delta 8146 zcmZ8meQ;GpmVbS^-_3pZg?!wXgybcJM+gLh2_ykA0tN^wAL0iLGbpPRgt&r8m=LW| z%X#t@2q1_eEg$Mc#Bm%HbQ#0WI5UjvjI4^oIF?%$MOl{RSgz~3Oifv?GcNl(-F@Gi z-9KJce%*Z@?iSYIMHFAVV=;GQ$dQ^}R;}VPfbv>)PuZNm&M&NDeThVv-hRP&nidx6$!ERZl z|NZ;2Q2*x|StbhiKPX0sVS3b^a&)H1u#>&rD^@M+>Fr+9yEbeK{0-grboZ|AySK7f z?_S`K)4T4JK|x7Ij!U*q)Y+A?Qvd8u*(^%+ODB_~bbPI>7#2d2zsOs?VG&g6@2{29 z=`A&Me60*f*Y?O+L+g9wSUJ?RL7pfG-d-6Lgz;GH52Pn|49cS^0hB0-kOWGVIV3=9$k8C!KvmHcqeM;+ zw1(l8ZjQWAj-$$~Ge?ZZMswhes~Qy{@W$1TaY%wU9*$WrF*TkdK?&OUike7}=SF56 zQt)yDyj*D(rx;YHmt>actGCOglVYU6osg)Aq`{p~6$K^^ZWFk343~jEyIsz#i%}e` zrbHB_I9N@URY31o1?GTBs;P#F2urwxYfl9D3q;ajQ~JZt5XF8Rjp9PnGwVx zZp+ai*hV&tm|~PjMS`HURSb8CK$}8-GFS@71tG*!wAd_fX`YgZ=mf%)Y8x^^5`?L+ z^Bp6Psi{L@NZjlwu?TN@K z1!8-;+PTP~otCp`K+fV@TVQco<&5TF#;e*%=^y*I2}!n1OuGvlbU@mF3MdTrvfD zAkJ{f6jT6W2Z&1yv4BB3J=YS?Zk1(?9l0bFfY^~sf)C;>5EmPw51^C%a!K>7T=ad& z&&owV0r}3{(h>~PQ83T;%T!HgZfOY+JBL>V3$Sr0RM*D7tN+$77i6#XZDPr6oVifO zyB;W%bKThlzz&$}&L$94&2?v!%*L6Qqd{<GX~_G#+zLJAOZQC zT>i*xl*N$0%*bP-EY?3Akj;&YbMm}D7U$%7e=H#{Xfg8GA4{~{A=_$}6cn4yPQ?3T zNmv$Ki8RYl-5k4JFWMomti9Q{B~qF+FN4jip#vzC%P7NCNV=mWB>-w3frnL?e&%F2^~q)BkfwX7t&^ ze!(PZ(!AVl40~E>?`s_|bW`)~@7~?^=3neK8yNfD3j`>g6) zaP^kiR;DNp@jeQITEm5+KD}|b%ry2TZ5@XMEcaE`IzRZR^^K}C6)YaAAH;sB&+e9; z^_&Wp{DE&9aonWhJ{L`(P~NAf?vV{y-VDHyz0c(V2wLxRd5DvMPxr$ou7N-d>@EO+ zhxaFKwt;xA#P)I^D7oKNjkqao54gPu6v_vvK3$#Z(tp|`(>GctSoZ^NM?wbt2h5J- zjqE)rVw;746H<9-@(&7sR4@#_dlbX|+a%!NG&l$dq!&FbXJj{tWN9P=$|eyGk08px zCV_6q+qWQ8TSaV)QC$GJt-`M}6Mm?+iP&f};bUT(FwrEH2)zLj+v(g%U}_+8Ct=*# z!R{cmN&$xoaI~=u^y2cL=1@LHM;pAfN145UPhntk#$hAoq~)IqsyAp|?lG z_B!)POzjbVjZu*_<{xJBg;|&f4i#V~nuYm?MKX*axDSg|bp&DlVS!W4RtiJ!Q4xF0 zSt*3%qZ}A^w9r`DXRN>oV5op5Mw2kIPb9N;&6ovupQvw)reS5DXu?^7m0_XMA~x16 zav0>a@JE}8qEHyaDX~XIPLp3OLrps^C z#~+o!@2M$HKo-_TZRa_ZaH= zu{?zreJoGGl}5eD!5d*HSQ60abaAGWze_W{-5c&++qc0ks+21f=93l99$R=(47aJm zEL6Y9Cv!EnU>JHYi`c&jkzSV3<@;q<)y zI?ZgpnE^85>*n;Smd&l;bbh6{Ndo3pif<0}TAqzU|C;{xfb4ANGXGkhh6^QNj)ohh zdYx%}yhFm#0V+?A!4c3G4k9hw3|<##|JDiIF9Fg2EyM?i`W@4!7%u!+M8^R zD?~_1Aid|1Y;WPd@Mhl0BxrAnRFus^(B5X+Rfbjwr2qSnoPIeM`nLt{RCY0ipuH{d zjb!04(B5I%^@fJ(4OEk!sju58C+dTTW#v^|#orP5cyJ6Tct=#(x)f3oR(TGEC1@}T zQ00Ld(p4xk=2b?YI3z1uxZs}?_}Z~LilF0Me#ynq@h&oAZb=~(1L^iBWK9bi(Xni6UA8+IwRB1gE7GOMV|;vo64; zK>ETHvV9?!w)X|D`qo-0XzzjK_5m2G^R9h- z@g&;E`KYL43dHkK`v8QA^HKW%#Lhe)wGW22eVmWlM~bg*>O#~$02!I~aR>X10j%vp z-W->k3sDcjEX-YqdI%uQU5I)JLu>9r)I(CHAbrTYV+W z0R++?JT04=zKBXZ20{5kltq*PlrQu7Lkap)w;hoU&0ps8$K~fsQBmpEl0>{Oa`Z0?|T@(OA^)+7<>L%lF26-ay@2~SjzAk*j zOUYmCMUpMOhXJy+J8_Crv3_|Hf!kYwNzbitug<=inmR$kyE#%kZJ&3$m z=xw9eAN0j%<%)0{`4#;B=JE5iH$b#UulliElpP??>;oQ0xCW@Il^tOSBLg(!dl5uv zcaWOHp7X3a@#d>_Je2GV;7D!=N_J3Yc2I1UsLVi?xuK95=`{n z7-+l58-t-}1m+(iZ)I?!aax4lULvhmJtuF-?j_H}7hD12UaGjvdC8I4OH;3pAe?@L zlnFNrJEtF^FUh&^)dzREs^piUa$JR~4F5-1a<8}Nw@-~U!cH=gz9wYjh-ttq~ zojsP{)%+@aEWfMy_3#+)YP&ztdAt`8&YZK#Ir{=7Pvo4ngK+jm@*148b_~uQ&pXT7 zULtjJZY~MRB;h4Wo-|2d-+2f=z0AAau7*cs82=~o4hxrrc<2og{ZgMeCYLQ8BG0rv zkmFzuQRO5TdTwMxH0?VPgo~$0O?PKB?sm>8N=|cL+aV}9MVTx0`iBaqjH-7#A#S`- zzaXz8xXFYRPd2|M`mO%w7vzmPzPoUA)>Z}&W=@lu;>>u?%xOwac4q7l%$%l7n+r8q z-fu{~o{NoVV)GkHzMhK>4}tX>d9}_f9>F62g}nBl8?P~lK|$!fL3B2a}fsJ$=fDZ;B1zu0=4 zMQoRAy8HpRS@^c4;}sTnm@T-~qo?s3C^{98y}JT&lMo|pX9q-_wg~(qf}0#(U_sr= z-!PU6Ss+thdD6gawQcU^xfaun_MVM*SaAFKB4xSA2T){|TUo!TiOh1*>(86T|3C0J zMKZf8T*EV2hQGnxc dump.v1beta1.DumpStatus 14, // 1: dump.v1beta1.Dump.start_time:type_name -> google.protobuf.Timestamp diff --git a/api/extensions/v1/redact.pb.go b/api/extensions/v1/redact.pb.go index 738ce213118..c850a90df3c 100644 --- a/api/extensions/v1/redact.pb.go +++ b/api/extensions/v1/redact.pb.go @@ -135,7 +135,6 @@ var ( (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions } ) - var file_extensions_v1_redact_proto_depIdxs = []int32{ 1, // 0: extensions.v1.sensitive:extendee -> google.protobuf.FieldOptions 0, // 1: extensions.v1.sensitive:type_name -> extensions.v1.RedactType diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index f798cccbcc0..655996ccdbc 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -351,7 +351,6 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) - var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/inventory/v1/agent_status.pb.go b/api/inventory/v1/agent_status.pb.go index 1e23074d2fc..ace1432a5e8 100644 --- a/api/inventory/v1/agent_status.pb.go +++ b/api/inventory/v1/agent_status.pb.go @@ -128,7 +128,6 @@ var ( AgentStatus(0), // 0: inventory.v1.AgentStatus } ) - var file_inventory_v1_agent_status_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/agents.pb.go b/api/inventory/v1/agents.pb.go index 3784fc8b7fc..f5d83515360 100644 --- a/api/inventory/v1/agents.pb.go +++ b/api/inventory/v1/agents.pb.go @@ -12513,7 +12513,6 @@ var ( (*common.StringMap)(nil), // 112: common.StringMap } ) - var file_inventory_v1_agents_proto_depIdxs = []int32{ 68, // 0: inventory.v1.PMMAgent.custom_labels:type_name -> inventory.v1.PMMAgent.CustomLabelsEntry 108, // 1: inventory.v1.VMAgent.status:type_name -> inventory.v1.AgentStatus diff --git a/api/inventory/v1/log_level.pb.go b/api/inventory/v1/log_level.pb.go index ff4d79ca3f2..47f0373d578 100644 --- a/api/inventory/v1/log_level.pb.go +++ b/api/inventory/v1/log_level.pb.go @@ -114,7 +114,6 @@ var ( LogLevel(0), // 0: inventory.v1.LogLevel } ) - var file_inventory_v1_log_level_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/nodes.pb.go b/api/inventory/v1/nodes.pb.go index 447663477a9..e0186c91815 100644 --- a/api/inventory/v1/nodes.pb.go +++ b/api/inventory/v1/nodes.pb.go @@ -2043,7 +2043,6 @@ var ( nil, // 28: inventory.v1.AddRemoteAzureNodeParams.CustomLabelsEntry } ) - var file_inventory_v1_nodes_proto_depIdxs = []int32{ 19, // 0: inventory.v1.GenericNode.custom_labels:type_name -> inventory.v1.GenericNode.CustomLabelsEntry 20, // 1: inventory.v1.ContainerNode.custom_labels:type_name -> inventory.v1.ContainerNode.CustomLabelsEntry diff --git a/api/inventory/v1/services.pb.go b/api/inventory/v1/services.pb.go index a8d1519b61f..23eeeb28b81 100644 --- a/api/inventory/v1/services.pb.go +++ b/api/inventory/v1/services.pb.go @@ -3334,7 +3334,6 @@ var ( (*common.StringMap)(nil), // 43: common.StringMap } ) - var file_inventory_v1_services_proto_depIdxs = []int32{ 27, // 0: inventory.v1.MySQLService.custom_labels:type_name -> inventory.v1.MySQLService.CustomLabelsEntry 28, // 1: inventory.v1.MySQLService.extra_dsn_params:type_name -> inventory.v1.MySQLService.ExtraDsnParamsEntry diff --git a/api/management/v1/agent.pb.go b/api/management/v1/agent.pb.go index c76c750f869..8a745a48910 100644 --- a/api/management/v1/agent.pb.go +++ b/api/management/v1/agent.pb.go @@ -1241,7 +1241,6 @@ var ( (*durationpb.Duration)(nil), // 17: google.protobuf.Duration } ) - var file_management_v1_agent_proto_depIdxs = []int32{ 8, // 0: management.v1.UniversalAgent.azure_options:type_name -> management.v1.UniversalAgent.AzureOptions 14, // 1: management.v1.UniversalAgent.created_at:type_name -> google.protobuf.Timestamp diff --git a/api/management/v1/annotation.pb.go b/api/management/v1/annotation.pb.go index ec781561e4c..53bbe233c1b 100644 --- a/api/management/v1/annotation.pb.go +++ b/api/management/v1/annotation.pb.go @@ -164,7 +164,6 @@ var ( (*AddAnnotationResponse)(nil), // 1: management.v1.AddAnnotationResponse } ) - var file_management_v1_annotation_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/azure.pb.go b/api/management/v1/azure.pb.go index 04a05c47ec1..863cff6d5ab 100644 --- a/api/management/v1/azure.pb.go +++ b/api/management/v1/azure.pb.go @@ -726,7 +726,6 @@ var ( (*durationpb.Duration)(nil), // 7: google.protobuf.Duration } ) - var file_management_v1_azure_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverAzureDatabaseInstance.type:type_name -> management.v1.DiscoverAzureDatabaseType 2, // 1: management.v1.DiscoverAzureDatabaseResponse.azure_database_instance:type_name -> management.v1.DiscoverAzureDatabaseInstance diff --git a/api/management/v1/external.pb.go b/api/management/v1/external.pb.go index 3632121e1c2..d990cb53abe 100644 --- a/api/management/v1/external.pb.go +++ b/api/management/v1/external.pb.go @@ -355,7 +355,6 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) - var file_management_v1_external_proto_depIdxs = []int32{ 3, // 0: management.v1.AddExternalServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddExternalServiceParams.custom_labels:type_name -> management.v1.AddExternalServiceParams.CustomLabelsEntry diff --git a/api/management/v1/haproxy.pb.go b/api/management/v1/haproxy.pb.go index f3de5158762..95cad534323 100644 --- a/api/management/v1/haproxy.pb.go +++ b/api/management/v1/haproxy.pb.go @@ -333,7 +333,6 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) - var file_management_v1_haproxy_proto_depIdxs = []int32{ 3, // 0: management.v1.AddHAProxyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddHAProxyServiceParams.custom_labels:type_name -> management.v1.AddHAProxyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/metrics.pb.go b/api/management/v1/metrics.pb.go index 748642db7cb..b552c7955fb 100644 --- a/api/management/v1/metrics.pb.go +++ b/api/management/v1/metrics.pb.go @@ -103,7 +103,6 @@ var ( MetricsMode(0), // 0: management.v1.MetricsMode } ) - var file_management_v1_metrics_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/mongodb.pb.go b/api/management/v1/mongodb.pb.go index c25cc4f8282..aad151306df 100644 --- a/api/management/v1/mongodb.pb.go +++ b/api/management/v1/mongodb.pb.go @@ -559,7 +559,6 @@ var ( (*v1.RTAMongoDBAgent)(nil), // 11: inventory.v1.RTAMongoDBAgent } ) - var file_management_v1_mongodb_proto_depIdxs = []int32{ 3, // 0: management.v1.AddMongoDBServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMongoDBServiceParams.custom_labels:type_name -> management.v1.AddMongoDBServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mysql.pb.go b/api/management/v1/mysql.pb.go index 18f64740d99..70660a14379 100644 --- a/api/management/v1/mysql.pb.go +++ b/api/management/v1/mysql.pb.go @@ -545,7 +545,6 @@ var ( (*v1.QANMySQLSlowlogAgent)(nil), // 11: inventory.v1.QANMySQLSlowlogAgent } ) - var file_management_v1_mysql_proto_depIdxs = []int32{ 4, // 0: management.v1.AddMySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMySQLServiceParams.custom_labels:type_name -> management.v1.AddMySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/node.pb.go b/api/management/v1/node.pb.go index 149fb30ad94..53bb2be68db 100644 --- a/api/management/v1/node.pb.go +++ b/api/management/v1/node.pb.go @@ -1255,7 +1255,6 @@ var ( (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp } ) - var file_management_v1_node_proto_depIdxs = []int32{ 16, // 0: management.v1.AddNodeParams.node_type:type_name -> inventory.v1.NodeType 11, // 1: management.v1.AddNodeParams.custom_labels:type_name -> management.v1.AddNodeParams.CustomLabelsEntry diff --git a/api/management/v1/postgresql.pb.go b/api/management/v1/postgresql.pb.go index 0271ba48788..0e6f54ad033 100644 --- a/api/management/v1/postgresql.pb.go +++ b/api/management/v1/postgresql.pb.go @@ -535,7 +535,6 @@ var ( (*v1.QANPostgreSQLPgStatMonitorAgent)(nil), // 10: inventory.v1.QANPostgreSQLPgStatMonitorAgent } ) - var file_management_v1_postgresql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddPostgreSQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddPostgreSQLServiceParams.custom_labels:type_name -> management.v1.AddPostgreSQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/proxysql.pb.go b/api/management/v1/proxysql.pb.go index e3142ed85df..7d9dbbcfc07 100644 --- a/api/management/v1/proxysql.pb.go +++ b/api/management/v1/proxysql.pb.go @@ -395,7 +395,6 @@ var ( (*v1.ProxySQLExporter)(nil), // 8: inventory.v1.ProxySQLExporter } ) - var file_management_v1_proxysql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddProxySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddProxySQLServiceParams.custom_labels:type_name -> management.v1.AddProxySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/rds.pb.go b/api/management/v1/rds.pb.go index d4821f97cd9..b30d865e5fd 100644 --- a/api/management/v1/rds.pb.go +++ b/api/management/v1/rds.pb.go @@ -876,7 +876,6 @@ var ( (*v1.QANPostgreSQLPgStatementsAgent)(nil), // 16: inventory.v1.QANPostgreSQLPgStatementsAgent } ) - var file_management_v1_rds_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverRDSInstance.engine:type_name -> management.v1.DiscoverRDSEngine 1, // 1: management.v1.DiscoverRDSResponse.rds_instances:type_name -> management.v1.DiscoverRDSInstance diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index cbad04b7f53..6ea52fbc973 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -1005,7 +1005,6 @@ var ( (*AddAzureDatabaseResponse)(nil), // 47: management.v1.AddAzureDatabaseResponse } ) - var file_management_v1_service_proto_depIdxs = []int32{ 9, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams 10, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams diff --git a/api/management/v1/severity.pb.go b/api/management/v1/severity.pb.go index 6a14d366aa6..51c04a93a0e 100644 --- a/api/management/v1/severity.pb.go +++ b/api/management/v1/severity.pb.go @@ -125,7 +125,6 @@ var ( Severity(0), // 0: management.v1.Severity } ) - var file_management_v1_severity_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/valkey.pb.go b/api/management/v1/valkey.pb.go index a0fc2f73fe2..26cc4db7f99 100644 --- a/api/management/v1/valkey.pb.go +++ b/api/management/v1/valkey.pb.go @@ -417,7 +417,6 @@ var ( (*v1.ValkeyExporter)(nil), // 8: inventory.v1.ValkeyExporter } ) - var file_management_v1_valkey_proto_depIdxs = []int32{ 3, // 0: management.v1.AddValkeyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddValkeyServiceParams.custom_labels:type_name -> management.v1.AddValkeyServiceParams.CustomLabelsEntry diff --git a/api/qan/v1/collector.pb.go b/api/qan/v1/collector.pb.go index b680bbd8f77..3716a3a24d1 100644 --- a/api/qan/v1/collector.pb.go +++ b/api/qan/v1/collector.pb.go @@ -2757,7 +2757,6 @@ var ( ExampleType(0), // 7: qan.v1.ExampleType } ) - var file_qan_v1_collector_proto_depIdxs = []int32{ 1, // 0: qan.v1.CollectRequest.metrics_bucket:type_name -> qan.v1.MetricsBucket 6, // 1: qan.v1.MetricsBucket.agent_type:type_name -> inventory.v1.AgentType diff --git a/api/qan/v1/filters.pb.go b/api/qan/v1/filters.pb.go index fcbf5e7aead..390a687dbc4 100644 --- a/api/qan/v1/filters.pb.go +++ b/api/qan/v1/filters.pb.go @@ -293,7 +293,6 @@ var ( (*MapFieldEntry)(nil), // 6: qan.v1.MapFieldEntry } ) - var file_qan_v1_filters_proto_depIdxs = []int32{ 5, // 0: qan.v1.GetFilteredMetricsNamesRequest.period_start_from:type_name -> google.protobuf.Timestamp 5, // 1: qan.v1.GetFilteredMetricsNamesRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/object_details.pb.go b/api/qan/v1/object_details.pb.go index f004bc0ec60..53e6c06150b 100644 --- a/api/qan/v1/object_details.pb.go +++ b/api/qan/v1/object_details.pb.go @@ -1645,7 +1645,6 @@ var ( ExampleType(0), // 29: qan.v1.ExampleType } ) - var file_qan_v1_object_details_proto_depIdxs = []int32{ 26, // 0: qan.v1.GetMetricsRequest.period_start_from:type_name -> google.protobuf.Timestamp 26, // 1: qan.v1.GetMetricsRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/profile.pb.go b/api/qan/v1/profile.pb.go index 03ab97e871a..7700b76dcd3 100644 --- a/api/qan/v1/profile.pb.go +++ b/api/qan/v1/profile.pb.go @@ -598,7 +598,6 @@ var ( (*Point)(nil), // 8: qan.v1.Point } ) - var file_qan_v1_profile_proto_depIdxs = []int32{ 7, // 0: qan.v1.GetReportRequest.period_start_from:type_name -> google.protobuf.Timestamp 7, // 1: qan.v1.GetReportRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/qan.pb.go b/api/qan/v1/qan.pb.go index c1d3bc6bb2e..2d37431a7c0 100644 --- a/api/qan/v1/qan.pb.go +++ b/api/qan/v1/qan.pb.go @@ -1000,7 +1000,6 @@ var ( (*MapFieldEntry)(nil), // 2: qan.v1.MapFieldEntry } ) - var file_qan_v1_qan_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/qan/v1/service.pb.go b/api/qan/v1/service.pb.go index 0e52423aa51..c5c688d9000 100644 --- a/api/qan/v1/service.pb.go +++ b/api/qan/v1/service.pb.go @@ -258,7 +258,6 @@ var ( (*GetQueryExampleResponse)(nil), // 24: qan.v1.GetQueryExampleResponse } ) - var file_qan_v1_service_proto_depIdxs = []int32{ 4, // 0: qan.v1.GetMetricsNamesResponse.data:type_name -> qan.v1.GetMetricsNamesResponse.DataEntry 5, // 1: qan.v1.QANService.GetReport:input_type -> qan.v1.GetReportRequest diff --git a/api/realtimeanalytics/v1/collector.pb.go b/api/realtimeanalytics/v1/collector.pb.go index f149de0a6cf..b9b81466e7c 100644 --- a/api/realtimeanalytics/v1/collector.pb.go +++ b/api/realtimeanalytics/v1/collector.pb.go @@ -140,7 +140,6 @@ var ( (*QueryData)(nil), // 2: realtimeanalytics.v1.QueryData } ) - var file_realtimeanalytics_v1_collector_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.CollectRequest.queries:type_name -> realtimeanalytics.v1.QueryData 0, // 1: realtimeanalytics.v1.CollectorService.Collect:input_type -> realtimeanalytics.v1.CollectRequest diff --git a/api/realtimeanalytics/v1/query.pb.go b/api/realtimeanalytics/v1/query.pb.go index 43c4a1bdd5c..b9ab1809d9a 100644 --- a/api/realtimeanalytics/v1/query.pb.go +++ b/api/realtimeanalytics/v1/query.pb.go @@ -331,7 +331,6 @@ var ( (*durationpb.Duration)(nil), // 3: google.protobuf.Duration } ) - var file_realtimeanalytics_v1_query_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.QueryMongoDBData.operation_start_time:type_name -> google.protobuf.Timestamp 3, // 1: realtimeanalytics.v1.QueryData.query_execution_duration:type_name -> google.protobuf.Duration diff --git a/api/realtimeanalytics/v1/realtimeanalytics.pb.go b/api/realtimeanalytics/v1/realtimeanalytics.pb.go index 8dbdbf8ccff..bd339f4bad9 100644 --- a/api/realtimeanalytics/v1/realtimeanalytics.pb.go +++ b/api/realtimeanalytics/v1/realtimeanalytics.pb.go @@ -718,7 +718,6 @@ var ( (*QueryData)(nil), // 16: realtimeanalytics.v1.QueryData } ) - var file_realtimeanalytics_v1_realtimeanalytics_proto_depIdxs = []int32{ 12, // 0: realtimeanalytics.v1.ListServicesRequest.service_type:type_name -> inventory.v1.ServiceType 13, // 1: realtimeanalytics.v1.ListServicesResponse.mongodb:type_name -> inventory.v1.MongoDBService diff --git a/api/server/v1/httperror.pb.go b/api/server/v1/httperror.pb.go index 8778ad26272..ef269ba2292 100644 --- a/api/server/v1/httperror.pb.go +++ b/api/server/v1/httperror.pb.go @@ -127,7 +127,6 @@ var ( (*anypb.Any)(nil), // 1: google.protobuf.Any } ) - var file_server_v1_httperror_proto_depIdxs = []int32{ 1, // 0: server.v1.HttpError.details:type_name -> google.protobuf.Any 1, // [1:1] is the sub-list for method output_type diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index ab1ab9b07ae..0bbc3212e77 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -2015,7 +2015,6 @@ var ( (*common.StringArray)(nil), // 30: common.StringArray } ) - var file_server_v1_server_proto_depIdxs = []int32{ 27, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index 97538706933..990d5709873 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -1827,6 +1827,24 @@ "description": "Filter by severity.", "name": "severity", "in": "query" + }, + { + "type": "string", + "description": "Filter by run ID.", + "name": "run_id", + "in": "query" + }, + { + "enum": [ + "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "ADVISOR_CHECK_TRIGGERED_BY_USER", + "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" + ], + "type": "string", + "default": "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "description": "Filter by the actor that initiated the run.\n\n - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI.\n - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler.", + "name": "triggered_by", + "in": "query" } ], "responses": { @@ -1859,20 +1877,25 @@ "type": "string", "x-order": 0 }, + "run_id": { + "description": "ID of the run this result belongs to; all results produced by one execution share it.", + "type": "string", + "x-order": 1 + }, "check_name": { "description": "Name of the check that ran.", "type": "string", - "x-order": 1 + "x-order": 2 }, "advisor_name": { "description": "Name of the advisor the check belongs to.", "type": "string", - "x-order": 2 + "x-order": 3 }, "category": { "description": "Category of the advisor the check belongs to.", "type": "string", - "x-order": 3 + "x-order": 4 }, "interval": { "description": "AdvisorCheckInterval represents possible execution interval values for checks.", @@ -1884,32 +1907,32 @@ "ADVISOR_CHECK_INTERVAL_FREQUENT", "ADVISOR_CHECK_INTERVAL_RARE" ], - "x-order": 4 + "x-order": 5 }, "service_id": { "description": "ID of the monitored service on which the check ran.", "type": "string", - "x-order": 5 + "x-order": 6 }, "service_name": { "description": "Name of the monitored service on which the check ran.", "type": "string", - "x-order": 6 + "x-order": 7 }, "service_type": { "description": "Type of the monitored service on which the check ran.", "type": "string", - "x-order": 7 + "x-order": 8 }, "node_id": { "description": "ID of the node the service runs on.", "type": "string", - "x-order": 8 + "x-order": 9 }, "node_name": { "description": "Name of the node the service runs on.", "type": "string", - "x-order": 9 + "x-order": 10 }, "status": { "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", @@ -1921,22 +1944,22 @@ "ADVISOR_CHECK_RESULT_STATUS_FAILED", "ADVISOR_CHECK_RESULT_STATUS_ERROR" ], - "x-order": 10 + "x-order": 11 }, "summary": { "description": "Short human-readable summary of the result.", "type": "string", - "x-order": 11 + "x-order": 12 }, "description": { "description": "Long human-readable description of the result.", "type": "string", - "x-order": 12 + "x-order": 13 }, "read_more_url": { "description": "URL containing information on how to resolve a detected issue.", "type": "string", - "x-order": 13 + "x-order": 14 }, "severity": { "description": "Severity represents severity level of the check result or alert.", @@ -1953,7 +1976,7 @@ "SEVERITY_INFO", "SEVERITY_DEBUG" ], - "x-order": 14 + "x-order": 15 }, "labels": { "description": "Result labels.", @@ -1961,18 +1984,29 @@ "additionalProperties": { "type": "string" }, - "x-order": 15 + "x-order": 16 }, "checked_at": { "description": "Time when the check ran.", "type": "string", "format": "date-time", - "x-order": 16 + "x-order": 17 }, "is_read": { "description": "Whether the result has been marked as read.", "type": "boolean", - "x-order": 17 + "x-order": 18 + }, + "triggered_by": { + "description": "AdvisorCheckTriggeredBy represents the actor that initiated an Advisor check run.\n\n - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI.\n - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler.", + "type": "string", + "default": "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "ADVISOR_CHECK_TRIGGERED_BY_USER", + "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" + ], + "x-order": 19 } } }, @@ -2214,7 +2248,14 @@ "200": { "description": "A successful response.", "schema": { - "type": "object" + "type": "object", + "properties": { + "run_id": { + "description": "ID assigned to this run; all check results produced by it share this run_id.", + "type": "string", + "x-order": 0 + } + } } }, "default": { diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index b00594fa509..758ac74cc5c 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1310,6 +1310,24 @@ "description": "Filter by severity.", "name": "severity", "in": "query" + }, + { + "type": "string", + "description": "Filter by run ID.", + "name": "run_id", + "in": "query" + }, + { + "enum": [ + "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "ADVISOR_CHECK_TRIGGERED_BY_USER", + "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" + ], + "type": "string", + "default": "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "description": "Filter by the actor that initiated the run.\n\n - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI.\n - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler.", + "name": "triggered_by", + "in": "query" } ], "responses": { @@ -1342,20 +1360,25 @@ "type": "string", "x-order": 0 }, + "run_id": { + "description": "ID of the run this result belongs to; all results produced by one execution share it.", + "type": "string", + "x-order": 1 + }, "check_name": { "description": "Name of the check that ran.", "type": "string", - "x-order": 1 + "x-order": 2 }, "advisor_name": { "description": "Name of the advisor the check belongs to.", "type": "string", - "x-order": 2 + "x-order": 3 }, "category": { "description": "Category of the advisor the check belongs to.", "type": "string", - "x-order": 3 + "x-order": 4 }, "interval": { "description": "AdvisorCheckInterval represents possible execution interval values for checks.", @@ -1367,32 +1390,32 @@ "ADVISOR_CHECK_INTERVAL_FREQUENT", "ADVISOR_CHECK_INTERVAL_RARE" ], - "x-order": 4 + "x-order": 5 }, "service_id": { "description": "ID of the monitored service on which the check ran.", "type": "string", - "x-order": 5 + "x-order": 6 }, "service_name": { "description": "Name of the monitored service on which the check ran.", "type": "string", - "x-order": 6 + "x-order": 7 }, "service_type": { "description": "Type of the monitored service on which the check ran.", "type": "string", - "x-order": 7 + "x-order": 8 }, "node_id": { "description": "ID of the node the service runs on.", "type": "string", - "x-order": 8 + "x-order": 9 }, "node_name": { "description": "Name of the node the service runs on.", "type": "string", - "x-order": 9 + "x-order": 10 }, "status": { "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", @@ -1404,22 +1427,22 @@ "ADVISOR_CHECK_RESULT_STATUS_FAILED", "ADVISOR_CHECK_RESULT_STATUS_ERROR" ], - "x-order": 10 + "x-order": 11 }, "summary": { "description": "Short human-readable summary of the result.", "type": "string", - "x-order": 11 + "x-order": 12 }, "description": { "description": "Long human-readable description of the result.", "type": "string", - "x-order": 12 + "x-order": 13 }, "read_more_url": { "description": "URL containing information on how to resolve a detected issue.", "type": "string", - "x-order": 13 + "x-order": 14 }, "severity": { "description": "Severity represents severity level of the check result or alert.", @@ -1436,7 +1459,7 @@ "SEVERITY_INFO", "SEVERITY_DEBUG" ], - "x-order": 14 + "x-order": 15 }, "labels": { "description": "Result labels.", @@ -1444,18 +1467,29 @@ "additionalProperties": { "type": "string" }, - "x-order": 15 + "x-order": 16 }, "checked_at": { "description": "Time when the check ran.", "type": "string", "format": "date-time", - "x-order": 16 + "x-order": 17 }, "is_read": { "description": "Whether the result has been marked as read.", "type": "boolean", - "x-order": 17 + "x-order": 18 + }, + "triggered_by": { + "description": "AdvisorCheckTriggeredBy represents the actor that initiated an Advisor check run.\n\n - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI.\n - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler.", + "type": "string", + "default": "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED", + "ADVISOR_CHECK_TRIGGERED_BY_USER", + "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" + ], + "x-order": 19 } } }, @@ -1697,7 +1731,14 @@ "200": { "description": "A successful response.", "schema": { - "type": "object" + "type": "object", + "properties": { + "run_id": { + "description": "ID assigned to this run; all check results produced by it share this run_id.", + "type": "string", + "x-order": 0 + } + } } }, "default": { diff --git a/api/user/v1/user.pb.go b/api/user/v1/user.pb.go index 12a954ca3f4..200364a0741 100644 --- a/api/user/v1/user.pb.go +++ b/api/user/v1/user.pb.go @@ -507,7 +507,6 @@ var ( (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp } ) - var file_user_v1_user_proto_depIdxs = []int32{ 7, // 0: user.v1.GetUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp 7, // 1: user.v1.UpdateUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp diff --git a/managed/models/check_result_helpers.go b/managed/models/check_result_helpers.go index 1f54db188d4..5b2ec348eb8 100644 --- a/managed/models/check_result_helpers.go +++ b/managed/models/check_result_helpers.go @@ -38,14 +38,16 @@ type CheckResultFilters struct { // ServiceName is matched as a case-insensitive substring. ServiceName string // NodeName is matched as a case-insensitive substring. - NodeName string - Category string - CheckName string - Severity *int - Status *CheckResultStatus - IsRead *bool - From *time.Time - To *time.Time + NodeName string + Category string + CheckName string + RunID string + TriggeredBy *CheckTriggeredBy + Severity *CheckSeverity + Status *CheckResultStatus + IsRead *bool + From *time.Time + To *time.Time } // checkResultConditions builds the WHERE clause and arguments for the given filters. @@ -73,6 +75,14 @@ func checkResultConditions(q *reform.Querier, filters CheckResultFilters) (strin conditions = append(conditions, "check_name = "+q.Placeholder(len(args)+1)) args = append(args, filters.CheckName) } + if filters.RunID != "" { + conditions = append(conditions, "run_id = "+q.Placeholder(len(args)+1)) + args = append(args, filters.RunID) + } + if filters.TriggeredBy != nil { + conditions = append(conditions, "triggered_by = "+q.Placeholder(len(args)+1)) + args = append(args, *filters.TriggeredBy) + } if filters.Severity != nil { conditions = append(conditions, "severity = "+q.Placeholder(len(args)+1)) args = append(args, *filters.Severity) diff --git a/managed/models/check_result_helpers_test.go b/managed/models/check_result_helpers_test.go index 821f7ee323a..8b3547447b7 100644 --- a/managed/models/check_result_helpers_test.go +++ b/managed/models/check_result_helpers_test.go @@ -26,7 +26,6 @@ import ( "gopkg.in/reform.v1/dialects/postgresql" "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/pi/common" "github.com/percona/pmm/managed/utils/testdb" ) @@ -61,7 +60,7 @@ func TestCheckResults(t *testing.T) { Status: models.CheckResultFailed, Summary: "summary", Description: "description", - Severity: int(common.Error), + Severity: models.CheckSeverityError, CheckedAt: models.Now(), } require.NoError(t, cr.SetLabels(labels)) @@ -73,7 +72,7 @@ func TestCheckResults(t *testing.T) { require.Len(t, got, 1) assert.Equal(t, cr.ID, got[0].ID) assert.Equal(t, models.CheckResultFailed, got[0].Status) - assert.Equal(t, int(common.Error), got[0].Severity) + assert.Equal(t, models.CheckSeverityError, got[0].Severity) assert.Equal(t, "node-find", got[0].NodeName) gotLabels, err := got[0].GetLabels() @@ -86,12 +85,12 @@ func TestCheckResults(t *testing.T) { create(t, &models.CheckResult{ CheckName: "weak_pwd", Category: "security", ServiceID: svc, ServiceName: "ProdMySQL", NodeName: "node-A", Status: models.CheckResultFailed, Summary: "s", - Severity: int(common.Critical), CheckedAt: models.Now(), + Severity: models.CheckSeverityCritical, CheckedAt: models.Now(), }) create(t, &models.CheckResult{ CheckName: "old_ver", Category: "configuration", ServiceID: svc, ServiceName: "devmysql", NodeName: "node-B", Status: models.CheckResultOK, Summary: "s", - Severity: int(common.Unknown), CheckedAt: models.Now(), + Severity: models.CheckSeverityUnknown, CheckedAt: models.Now(), }) // service_name: case-insensitive substring. @@ -117,11 +116,11 @@ func TestCheckResults(t *testing.T) { require.Len(t, got, 1) // severity: exact. - sev := int(common.Critical) + sev := models.CheckSeverityCritical got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, Severity: &sev}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) - assert.Equal(t, int(common.Critical), got[0].Severity) + assert.Equal(t, models.CheckSeverityCritical, got[0].Severity) // status. st := models.CheckResultOK diff --git a/managed/models/check_result_model.go b/managed/models/check_result_model.go index edb36057ae5..7d1fd3d7621 100644 --- a/managed/models/check_result_model.go +++ b/managed/models/check_result_model.go @@ -36,6 +36,34 @@ const ( CheckResultError CheckResultStatus = "error" ) +// CheckSeverity represents the severity of an Advisor check result persisted to history. +// The values match the lowercase names of management API severity levels. +type CheckSeverity string + +// Available Advisor check result severities. +const ( + CheckSeverityUnknown CheckSeverity = "unknown" + CheckSeverityEmergency CheckSeverity = "emergency" + CheckSeverityAlert CheckSeverity = "alert" + CheckSeverityCritical CheckSeverity = "critical" + CheckSeverityError CheckSeverity = "error" + CheckSeverityWarning CheckSeverity = "warning" + CheckSeverityNotice CheckSeverity = "notice" + CheckSeverityInfo CheckSeverity = "info" + CheckSeverityDebug CheckSeverity = "debug" +) + +// CheckTriggeredBy represents the actor that initiated an Advisor check run. +type CheckTriggeredBy string + +// Available Advisor check run initiators. +const ( + // CheckTriggeredByUser means the run was started by a user via the API or UI. + CheckTriggeredByUser CheckTriggeredBy = "user" + // CheckTriggeredByScheduler means the run was started by the built-in scheduler. + CheckTriggeredByScheduler CheckTriggeredBy = "scheduler" +) + // CheckResult represents a single Advisor check run against a target persisted to history. // //reform:check_results @@ -54,10 +82,12 @@ type CheckResult struct { Summary string `reform:"summary"` Description string `reform:"description"` ReadMoreURL string `reform:"read_more_url"` - Severity int `reform:"severity"` + Severity CheckSeverity `reform:"severity"` Labels []byte `reform:"labels"` CheckedAt time.Time `reform:"checked_at"` IsRead bool `reform:"is_read"` + RunID string `reform:"run_id"` + TriggeredBy CheckTriggeredBy `reform:"triggered_by"` } // BeforeInsert implements reform.BeforeInserter interface. diff --git a/managed/models/check_result_model_reform.go b/managed/models/check_result_model_reform.go index 137eb43cf0b..bb6202cd5ad 100644 --- a/managed/models/check_result_model_reform.go +++ b/managed/models/check_result_model_reform.go @@ -46,6 +46,8 @@ func (v *checkResultTableType) Columns() []string { "labels", "checked_at", "is_read", + "run_id", + "triggered_by", } } @@ -84,10 +86,12 @@ var CheckResultTable = &checkResultTableType{ {Name: "Summary", Type: "string", Column: "summary"}, {Name: "Description", Type: "string", Column: "description"}, {Name: "ReadMoreURL", Type: "string", Column: "read_more_url"}, - {Name: "Severity", Type: "int", Column: "severity"}, + {Name: "Severity", Type: "CheckSeverity", Column: "severity"}, {Name: "Labels", Type: "[]uint8", Column: "labels"}, {Name: "CheckedAt", Type: "time.Time", Column: "checked_at"}, {Name: "IsRead", Type: "bool", Column: "is_read"}, + {Name: "RunID", Type: "string", Column: "run_id"}, + {Name: "TriggeredBy", Type: "CheckTriggeredBy", Column: "triggered_by"}, }, PKFieldIndex: 0, }, @@ -96,7 +100,7 @@ var CheckResultTable = &checkResultTableType{ // String returns a string representation of this struct or record. func (s CheckResult) String() string { - res := make([]string, 18) + res := make([]string, 20) res[0] = "ID: " + reform.Inspect(s.ID, true) res[1] = "CheckName: " + reform.Inspect(s.CheckName, true) res[2] = "AdvisorName: " + reform.Inspect(s.AdvisorName, true) @@ -115,6 +119,8 @@ func (s CheckResult) String() string { res[15] = "Labels: " + reform.Inspect(s.Labels, true) res[16] = "CheckedAt: " + reform.Inspect(s.CheckedAt, true) res[17] = "IsRead: " + reform.Inspect(s.IsRead, true) + res[18] = "RunID: " + reform.Inspect(s.RunID, true) + res[19] = "TriggeredBy: " + reform.Inspect(s.TriggeredBy, true) return strings.Join(res, ", ") } @@ -140,6 +146,8 @@ func (s *CheckResult) Values() []interface{} { s.Labels, s.CheckedAt, s.IsRead, + s.RunID, + s.TriggeredBy, } } @@ -165,6 +173,8 @@ func (s *CheckResult) Pointers() []interface{} { &s.Labels, &s.CheckedAt, &s.IsRead, + &s.RunID, + &s.TriggeredBy, } } diff --git a/managed/models/database.go b/managed/models/database.go index 7a1368e0aaf..d55d47cd140 100644 --- a/managed/models/database.go +++ b/managed/models/database.go @@ -1188,6 +1188,7 @@ var databaseSchema = [][]string{ 119: { `CREATE TABLE check_results ( id VARCHAR NOT NULL, + run_id VARCHAR NOT NULL, check_name VARCHAR NOT NULL CHECK (check_name <> ''), advisor_name VARCHAR NOT NULL, category VARCHAR NOT NULL, @@ -1201,13 +1202,15 @@ var databaseSchema = [][]string{ summary VARCHAR NOT NULL, description TEXT NOT NULL, read_more_url VARCHAR NOT NULL, - severity INTEGER NOT NULL, + severity VARCHAR NOT NULL, labels TEXT, checked_at TIMESTAMP NOT NULL, is_read BOOLEAN NOT NULL, + triggered_by VARCHAR NOT NULL, PRIMARY KEY (id) )`, + `CREATE INDEX check_results_run_id_idx ON check_results (run_id)`, `CREATE INDEX check_results_service_id_idx ON check_results (service_id)`, `CREATE INDEX check_results_checked_at_idx ON check_results (checked_at)`, }, diff --git a/managed/services/checks/check_result_record_test.go b/managed/services/checks/check_result_record_test.go index 203f4ce23d8..1d465cbee63 100644 --- a/managed/services/checks/check_result_record_test.go +++ b/managed/services/checks/check_result_record_test.go @@ -39,6 +39,7 @@ func TestNewCheckResultRecord(t *testing.T) { NodeName: "nname", } checkedAt := models.Now() + ri := runInfo{runID: "run-1", triggeredBy: models.CheckTriggeredByUser} t.Run("failed finding maps all fields", func(t *testing.T) { t.Parallel() @@ -51,7 +52,7 @@ func TestNewCheckResultRecord(t *testing.T) { Labels: map[string]string{"k": "v"}, } - rec := newCheckResultRecord(c, target, "performance", models.CheckResultFailed, result, checkedAt) + rec := newCheckResultRecord(c, target, "performance", models.CheckResultFailed, result, checkedAt, ri) assert.Equal(t, "chk", rec.CheckName) assert.Equal(t, "adv", rec.AdvisorName) @@ -66,8 +67,10 @@ func TestNewCheckResultRecord(t *testing.T) { assert.Equal(t, "sum", rec.Summary) assert.Equal(t, "desc", rec.Description) assert.Equal(t, "https://example.com", rec.ReadMoreURL) - assert.Equal(t, int(common.Error), rec.Severity) + assert.Equal(t, models.CheckSeverityError, rec.Severity) assert.Equal(t, checkedAt, rec.CheckedAt) + assert.Equal(t, "run-1", rec.RunID) + assert.Equal(t, models.CheckTriggeredByUser, rec.TriggeredBy) labels, err := rec.GetLabels() require.NoError(t, err) @@ -77,27 +80,27 @@ func TestNewCheckResultRecord(t *testing.T) { t.Run("ok outcome falls back to check summary and info severity", func(t *testing.T) { t.Parallel() - rec := newCheckResultRecord(c, target, "performance", models.CheckResultOK, check.Result{}, checkedAt) + rec := newCheckResultRecord(c, target, "performance", models.CheckResultOK, check.Result{}, checkedAt, ri) assert.Equal(t, models.CheckResultOK, rec.Status) assert.Equal(t, "Check title", rec.Summary) - assert.Equal(t, int(common.Info), rec.Severity) + assert.Equal(t, models.CheckSeverityInfo, rec.Severity) labels, err := rec.GetLabels() require.NoError(t, err) assert.Empty(t, labels) }) - t.Run("error outcome falls back to check summary", func(t *testing.T) { + t.Run("error outcome falls back to check summary and debug severity", func(t *testing.T) { t.Parallel() result := check.Result{Description: "execution failed"} - rec := newCheckResultRecord(c, target, "performance", models.CheckResultError, result, checkedAt) + rec := newCheckResultRecord(c, target, "performance", models.CheckResultError, result, checkedAt, ri) assert.Equal(t, models.CheckResultError, rec.Status) assert.Equal(t, "Check title", rec.Summary) assert.Equal(t, "execution failed", rec.Description) - assert.Zero(t, rec.Severity) + assert.Equal(t, models.CheckSeverityDebug, rec.Severity) }) } diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index b4358118226..82fd0828f9b 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -35,6 +35,7 @@ import ( "text/template" "time" + "github.com/google/uuid" v1 "github.com/prometheus/client_golang/api/prometheus/v1" prom "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/common/model" @@ -282,40 +283,49 @@ func (s *Service) runChecksGroup(ctx context.Context, intervalGroup check.Interv } s.UpdateAdvisorsList(ctx) - return s.run(ctx, intervalGroup, nil) + ri := runInfo{runID: uuid.NewString(), triggeredBy: models.CheckTriggeredByScheduler} + return s.run(ctx, intervalGroup, nil, ri) } -// StartChecks downloads and executes advisor checks in asynchronous way. +// StartChecks downloads and executes advisor checks in asynchronous way and returns the run ID. // If checkNames specified then only matched checks will be executed. -func (s *Service) StartChecks(checkNames []string) error { +func (s *Service) StartChecks(checkNames []string) (string, error) { settings, err := models.GetSettings(s.db) if err != nil { - return err + return "", err } if !settings.IsAdvisorsEnabled() { - return services.ErrAdvisorsDisabled + return "", services.ErrAdvisorsDisabled } + ri := runInfo{runID: uuid.NewString(), triggeredBy: models.CheckTriggeredByUser} + go func() { ctx := context.Background() s.UpdateAdvisorsList(ctx) - err := s.run(ctx, "", checkNames) + err := s.run(ctx, "", checkNames, ri) if err != nil { s.l.Errorf("Failed to execute advisor checks: %+v.", err) } }() - return nil + return ri.runID, nil } -func (s *Service) run(ctx context.Context, intervalGroup check.Interval, checkNames []string) error { +// runInfo identifies a single Advisor checks execution batch. +type runInfo struct { + runID string + triggeredBy models.CheckTriggeredBy +} + +func (s *Service) run(ctx context.Context, intervalGroup check.Interval, checkNames []string, ri runInfo) error { err := intervalGroup.Validate() if err != nil { return err } - res, err := s.executeChecks(ctx, intervalGroup, checkNames) + res, err := s.executeChecks(ctx, intervalGroup, checkNames, ri) if err != nil { return err } @@ -638,7 +648,7 @@ func (s *Service) getActiveUserServiceTypes() (map[models.ServiceType]struct{}, // executeChecks runs checks for all reachable services. If intervalGroup specified only checks from that group will be // executed. If checkNames specified then only matched checks will be executed. -func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interval, checkNames []string) ([]services.CheckResult, error) { +func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interval, checkNames []string, ri runInfo) ([]services.CheckResult, error) { disabledChecks, err := s.GetDisabledChecks() if err != nil { return nil, err @@ -659,7 +669,7 @@ func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interva // Execute MySQL checks only if MySQL services exist if _, hasMySQL := activeServiceTypes[models.MySQLServiceType]; hasMySQL { mySQLChecks = s.filterChecks(mySQLChecks, intervalGroup, disabledChecks, checkNames) - mySQLCheckResults := s.executeChecksForTargetType(ctx, models.MySQLServiceType, mySQLChecks) + mySQLCheckResults := s.executeChecksForTargetType(ctx, models.MySQLServiceType, mySQLChecks, ri) res = append(res, mySQLCheckResults...) } else { s.l.Info("Skipping MySQL advisor checks: no MySQL services in inventory") @@ -668,7 +678,7 @@ func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interva // Execute PostgreSQL checks only if PostgreSQL services exist if _, hasPostgreSQL := activeServiceTypes[models.PostgreSQLServiceType]; hasPostgreSQL { postgreSQLChecks = s.filterChecks(postgreSQLChecks, intervalGroup, disabledChecks, checkNames) - postgreSQLCheckResults := s.executeChecksForTargetType(ctx, models.PostgreSQLServiceType, postgreSQLChecks) + postgreSQLCheckResults := s.executeChecksForTargetType(ctx, models.PostgreSQLServiceType, postgreSQLChecks, ri) res = append(res, postgreSQLCheckResults...) } else { s.l.Info("Skipping PostgreSQL advisor checks: no PostgreSQL services in inventory") @@ -677,7 +687,7 @@ func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interva // Execute MongoDB checks only if MongoDB services exist if _, hasMongoDB := activeServiceTypes[models.MongoDBServiceType]; hasMongoDB { mongoDBChecks = s.filterChecks(mongoDBChecks, intervalGroup, disabledChecks, checkNames) - mongoDBCheckResults := s.executeChecksForTargetType(ctx, models.MongoDBServiceType, mongoDBChecks) + mongoDBCheckResults := s.executeChecksForTargetType(ctx, models.MongoDBServiceType, mongoDBChecks, ri) res = append(res, mongoDBCheckResults...) } else { s.l.Info("Skipping MongoDB advisor checks: no MongoDB services in inventory") @@ -686,11 +696,10 @@ func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interva return res, nil } -func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType models.ServiceType, checks map[string]check.Check) []services.CheckResult { +func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType models.ServiceType, checks map[string]check.Check, ri runInfo) []services.CheckResult { var res []services.CheckResult var history []*models.CheckResult categories := s.advisorCategories() - checkedAt := models.Now() for _, c := range checks { s.l.Infof("Executing check: %s with interval: %s", c.Name, c.Interval) @@ -706,10 +715,12 @@ func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType mo for _, target := range targets { results, err := s.executeCheck(ctx, target, c) + // stamp each (check, target) outcome with its actual completion time + checkedAt := models.Now() if err != nil { s.l.Warnf("Failed to execute check %s of type %s on target %s: %+v", c.Name, c.Type, target.AgentID, err) s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name, "error").Inc() - history = append(history, newCheckResultRecord(c, target, category, models.CheckResultError, check.Result{Description: err.Error()}, checkedAt)) + history = append(history, newCheckResultRecord(c, target, category, models.CheckResultError, check.Result{Description: err.Error()}, checkedAt, ri)) continue } @@ -718,12 +729,12 @@ func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType mo s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name, "ok").Inc() if len(results) == 0 { - history = append(history, newCheckResultRecord(c, target, category, models.CheckResultOK, check.Result{}, checkedAt)) + history = append(history, newCheckResultRecord(c, target, category, models.CheckResultOK, check.Result{}, checkedAt, ri)) continue } for _, finding := range results { - history = append(history, newCheckResultRecord(c, target, category, models.CheckResultFailed, finding.Result, checkedAt)) + history = append(history, newCheckResultRecord(c, target, category, models.CheckResultFailed, finding.Result, checkedAt, ri)) } } } @@ -756,6 +767,7 @@ func newCheckResultRecord( status models.CheckResultStatus, result check.Result, checkedAt time.Time, + ri runInfo, ) *models.CheckResult { r := &models.CheckResult{ CheckName: c.Name, @@ -771,15 +783,23 @@ func newCheckResultRecord( Summary: result.Summary, Description: result.Description, ReadMoreURL: result.ReadMoreURL, - Severity: int(result.Severity), + Severity: convertCommonSeverity(result.Severity), CheckedAt: checkedAt, + RunID: ri.runID, + TriggeredBy: ri.triggeredBy, } // OK and error outcomes carry no finding; fall back to the check's own summary if r.Summary == "" { r.Summary = c.Summary } - if status == models.CheckResultOK { - r.Severity = int(common.Info) + switch status { + case models.CheckResultOK: + r.Severity = models.CheckSeverityInfo + case models.CheckResultError: + // the check could not be executed, which is a diagnostic concern, not a database issue + r.Severity = models.CheckSeverityDebug + case models.CheckResultFailed: + // keep the severity reported by the finding } if len(result.Labels) != 0 { _ = r.SetLabels(result.Labels) @@ -787,6 +807,32 @@ func newCheckResultRecord( return r } +// convertCommonSeverity converts common.Severity to models.CheckSeverity. +func convertCommonSeverity(severity common.Severity) models.CheckSeverity { + switch severity { + case common.Emergency: + return models.CheckSeverityEmergency + case common.Alert: + return models.CheckSeverityAlert + case common.Critical: + return models.CheckSeverityCritical + case common.Error: + return models.CheckSeverityError + case common.Warning: + return models.CheckSeverityWarning + case common.Notice: + return models.CheckSeverityNotice + case common.Info: + return models.CheckSeverityInfo + case common.Debug: + return models.CheckSeverityDebug + case common.Unknown: + return models.CheckSeverityUnknown + default: + return models.CheckSeverityUnknown + } +} + // saveCheckResultsHistory persists Advisor check results history in a single transaction. func (s *Service) saveCheckResultsHistory(ctx context.Context, history []*models.CheckResult) error { if len(history) == 0 { diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index d65bfb262c1..11d4d66da33 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -196,6 +196,7 @@ func (s *ChecksAPIService) ListCheckResultsHistory( NodeName: req.NodeName, Category: req.Category, CheckName: req.CheckName, + RunID: req.RunId, IsRead: req.IsRead, } if req.Status != nil { @@ -203,8 +204,13 @@ func (s *ChecksAPIService) ListCheckResultsHistory( filters.Status = &st } } + if req.TriggeredBy != nil { + if tb := convertAPITriggeredBy(*req.TriggeredBy); tb != "" { + filters.TriggeredBy = &tb + } + } if req.Severity != nil { - severity := int(*req.Severity) + severity := convertAPISeverity(*req.Severity) filters.Severity = &severity } if req.From != nil { @@ -243,10 +249,12 @@ func (s *ChecksAPIService) ListCheckResultsHistory( Summary: r.Summary, Description: r.Description, ReadMoreUrl: r.ReadMoreURL, - Severity: managementv1.Severity(r.Severity), //nolint:gosec + Severity: convertModelSeverity(r.Severity), Labels: labels, CheckedAt: timestamppb.New(r.CheckedAt), IsRead: r.IsRead, + RunId: r.RunID, + TriggeredBy: convertModelTriggeredBy(r.TriggeredBy), }) } @@ -278,10 +286,10 @@ func (s *ChecksAPIService) MarkCheckResultsRead( return &advisorsv1.MarkCheckResultsReadResponse{}, nil } -// StartAdvisorChecks executes advisor checks and returns when all checks are executed. +// StartAdvisorChecks executes advisor checks and returns the ID assigned to this run. func (s *ChecksAPIService) StartAdvisorChecks(_ context.Context, req *advisorsv1.StartAdvisorChecksRequest) (*advisorsv1.StartAdvisorChecksResponse, error) { // Start only specified checks from any group. - err := s.checksService.StartChecks(req.Names) + runID, err := s.checksService.StartChecks(req.Names) if err != nil { if errors.Is(err, services.ErrAdvisorsDisabled) { return nil, status.Errorf(codes.FailedPrecondition, "%v.", err) @@ -290,7 +298,7 @@ func (s *ChecksAPIService) StartAdvisorChecks(_ context.Context, req *advisorsv1 return nil, fmt.Errorf("failed to start advisor checks: %w", err) } - return &advisorsv1.StartAdvisorChecksResponse{}, nil + return &advisorsv1.StartAdvisorChecksResponse{RunId: runID}, nil } // ListAdvisorChecks returns a list of available advisor checks and their statuses. @@ -501,6 +509,83 @@ func convertAPIResultStatus(status advisorsv1.AdvisorCheckResultStatus) models.C } } +// convertModelSeverity converts models.CheckSeverity to managementv1.Severity. +func convertModelSeverity(severity models.CheckSeverity) managementv1.Severity { + switch severity { + case models.CheckSeverityEmergency: + return managementv1.Severity_SEVERITY_EMERGENCY + case models.CheckSeverityAlert: + return managementv1.Severity_SEVERITY_ALERT + case models.CheckSeverityCritical: + return managementv1.Severity_SEVERITY_CRITICAL + case models.CheckSeverityError: + return managementv1.Severity_SEVERITY_ERROR + case models.CheckSeverityWarning: + return managementv1.Severity_SEVERITY_WARNING + case models.CheckSeverityNotice: + return managementv1.Severity_SEVERITY_NOTICE + case models.CheckSeverityInfo: + return managementv1.Severity_SEVERITY_INFO + case models.CheckSeverityDebug: + return managementv1.Severity_SEVERITY_DEBUG + case models.CheckSeverityUnknown: + return managementv1.Severity_SEVERITY_UNSPECIFIED + default: + return managementv1.Severity_SEVERITY_UNSPECIFIED + } +} + +// convertAPISeverity converts managementv1.Severity to models.CheckSeverity. +func convertAPISeverity(severity managementv1.Severity) models.CheckSeverity { + switch severity { + case managementv1.Severity_SEVERITY_EMERGENCY: + return models.CheckSeverityEmergency + case managementv1.Severity_SEVERITY_ALERT: + return models.CheckSeverityAlert + case managementv1.Severity_SEVERITY_CRITICAL: + return models.CheckSeverityCritical + case managementv1.Severity_SEVERITY_ERROR: + return models.CheckSeverityError + case managementv1.Severity_SEVERITY_WARNING: + return models.CheckSeverityWarning + case managementv1.Severity_SEVERITY_NOTICE: + return models.CheckSeverityNotice + case managementv1.Severity_SEVERITY_INFO: + return models.CheckSeverityInfo + case managementv1.Severity_SEVERITY_DEBUG: + return models.CheckSeverityDebug + case managementv1.Severity_SEVERITY_UNSPECIFIED: + return models.CheckSeverityUnknown + default: + return models.CheckSeverityUnknown + } +} + +// convertModelTriggeredBy converts models.CheckTriggeredBy to advisorsv1.AdvisorCheckTriggeredBy. +func convertModelTriggeredBy(triggeredBy models.CheckTriggeredBy) advisorsv1.AdvisorCheckTriggeredBy { + switch triggeredBy { + case models.CheckTriggeredByUser: + return advisorsv1.AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_USER + case models.CheckTriggeredByScheduler: + return advisorsv1.AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER + default: + return advisorsv1.AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED + } +} + +// convertAPITriggeredBy converts advisorsv1.AdvisorCheckTriggeredBy to models.CheckTriggeredBy. +// An empty string is returned for unknown values. +func convertAPITriggeredBy(triggeredBy advisorsv1.AdvisorCheckTriggeredBy) models.CheckTriggeredBy { + switch triggeredBy { + case advisorsv1.AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_USER: + return models.CheckTriggeredByUser + case advisorsv1.AdvisorCheckTriggeredBy_ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: + return models.CheckTriggeredByScheduler + default: + return "" + } +} + // convertFamily converts check.Family type to advisorsv1.AdvisorCheckFamily. func convertFamily(family check.Family) advisorsv1.AdvisorCheckFamily { switch family { diff --git a/managed/services/management/checks_test.go b/managed/services/management/checks_test.go index 1f92cb90092..64165a37cf3 100644 --- a/managed/services/management/checks_test.go +++ b/managed/services/management/checks_test.go @@ -40,7 +40,7 @@ import ( func TestStartAdvisorChecks(t *testing.T) { t.Run("internal error", func(t *testing.T) { var checksService mockChecksService - checksService.On("StartChecks", []string(nil)).Return(errors.New("random error")) + checksService.On("StartChecks", []string(nil)).Return("", errors.New("random error")) s := NewChecksAPIService(&checksService) @@ -51,7 +51,7 @@ func TestStartAdvisorChecks(t *testing.T) { t.Run("Advisors disabled error", func(t *testing.T) { var checksService mockChecksService - checksService.On("StartChecks", []string(nil)).Return(services.ErrAdvisorsDisabled) + checksService.On("StartChecks", []string(nil)).Return("", services.ErrAdvisorsDisabled) s := NewChecksAPIService(&checksService) @@ -117,7 +117,7 @@ func TestGetFailedChecks(t *testing.T) { Summary: "Check summary", Description: "Check Description", ReadMoreUrl: "https://www.example.com", - Severity: managementv1.Severity(common.Emergency), + Severity: managementv1.Severity_SEVERITY_EMERGENCY, Labels: map[string]string{"label_key": "label_value"}, ServiceName: "svc", ServiceId: "test_svc", @@ -244,7 +244,7 @@ func TestListCheckResultsHistory(t *testing.T) { Summary: "Check summary", Description: "Check Description", ReadMoreURL: "https://www.example.com", - Severity: int(common.Emergency), + Severity: models.CheckSeverityEmergency, CheckedAt: checkedAt, } require.NoError(t, record.SetLabels(map[string]string{"label_key": "label_value"})) @@ -279,7 +279,7 @@ func TestListCheckResultsHistory(t *testing.T) { Summary: "Check summary", Description: "Check Description", ReadMoreUrl: "https://www.example.com", - Severity: managementv1.Severity(common.Emergency), + Severity: managementv1.Severity_SEVERITY_EMERGENCY, Labels: map[string]string{"label_key": "label_value"}, CheckedAt: timestamppb.New(checkedAt), }, diff --git a/managed/services/management/deps.go b/managed/services/management/deps.go index a649bcb8235..b0c98f9074d 100644 --- a/managed/services/management/deps.go +++ b/managed/services/management/deps.go @@ -55,7 +55,7 @@ type prometheusService interface { // checksService is a subset of methods of checks.Service used by this package. // We use it instead of real type for testing and to avoid dependency cycle. type checksService interface { - StartChecks(checkNames []string) error + StartChecks(checkNames []string) (string, error) GetChecks() (map[string]check.Check, error) GetAdvisors() ([]check.Advisor, error) GetChecksResults(ctx context.Context, serviceID string) ([]services.CheckResult, error) diff --git a/managed/services/management/mock_checks_service_test.go b/managed/services/management/mock_checks_service_test.go index 6364dc1ce90..ac20fc75a9a 100644 --- a/managed/services/management/mock_checks_service_test.go +++ b/managed/services/management/mock_checks_service_test.go @@ -247,21 +247,31 @@ func (_m *mockChecksService) MarkCheckResultsRead(ctx context.Context, ids []str } // StartChecks provides a mock function with given fields: checkNames -func (_m *mockChecksService) StartChecks(checkNames []string) error { +func (_m *mockChecksService) StartChecks(checkNames []string) (string, error) { ret := _m.Called(checkNames) if len(ret) == 0 { panic("no return value specified for StartChecks") } - var r0 error - if rf, ok := ret.Get(0).(func([]string) error); ok { + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func([]string) (string, error)); ok { + return rf(checkNames) + } + if rf, ok := ret.Get(0).(func([]string) string); ok { r0 = rf(checkNames) } else { - r0 = ret.Error(0) + r0 = ret.Get(0).(string) } - return r0 + if rf, ok := ret.Get(1).(func([]string) error); ok { + r1 = rf(checkNames) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } // newMockChecksService creates a new instance of mockChecksService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. diff --git a/managed/services/server/deps.go b/managed/services/server/deps.go index 33f9d9408b4..2a05d27db2f 100644 --- a/managed/services/server/deps.go +++ b/managed/services/server/deps.go @@ -56,7 +56,7 @@ type prometheusService interface { //nolint:iface // checksService is a subset of methods of checks.Service used by this package. // We use it instead of real type for testing and to avoid dependency cycle. type checksService interface { - StartChecks(checkNames []string) error + StartChecks(checkNames []string) (string, error) UpdateAdvisorsList(ctx context.Context) CleanupAlerts() UpdateIntervals(rare, standard, frequent time.Duration) diff --git a/managed/services/server/mock_checks_service_test.go b/managed/services/server/mock_checks_service_test.go index bcb24a68ebc..26e61518f55 100644 --- a/managed/services/server/mock_checks_service_test.go +++ b/managed/services/server/mock_checks_service_test.go @@ -20,21 +20,31 @@ func (_m *mockChecksService) CleanupAlerts() { } // StartChecks provides a mock function with given fields: checkNames -func (_m *mockChecksService) StartChecks(checkNames []string) error { +func (_m *mockChecksService) StartChecks(checkNames []string) (string, error) { ret := _m.Called(checkNames) if len(ret) == 0 { panic("no return value specified for StartChecks") } - var r0 error - if rf, ok := ret.Get(0).(func([]string) error); ok { + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func([]string) (string, error)); ok { + return rf(checkNames) + } + if rf, ok := ret.Get(0).(func([]string) string); ok { r0 = rf(checkNames) } else { - r0 = ret.Error(0) + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func([]string) error); ok { + r1 = rf(checkNames) + } else { + r1 = ret.Error(1) } - return r0 + return r0, r1 } // UpdateAdvisorsList provides a mock function with given fields: ctx diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 3e48c3622ba..ecb7ad25ced 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -761,7 +761,7 @@ func (s *Server) ChangeSettings(ctx context.Context, req *serverv1.ChangeSetting var advisorsStarted bool if !oldSettings.IsAdvisorsEnabled() && newSettings.IsAdvisorsEnabled() { advisorsStarted = true - err := s.checksService.StartChecks(nil) + _, err := s.checksService.StartChecks(nil) if err != nil { s.l.Error(err) } diff --git a/ui/apps/pmm/src/api/advisors.ts b/ui/apps/pmm/src/api/advisors.ts index deae1f3035a..f954e033ce3 100644 --- a/ui/apps/pmm/src/api/advisors.ts +++ b/ui/apps/pmm/src/api/advisors.ts @@ -7,6 +7,7 @@ import { ListCheckResultsHistoryParams, MarkCheckResultsReadRequest, StartAdvisorChecksRequest, + StartAdvisorChecksResponse, } from 'types/advisors.types'; import { EmptyResponse, PaginatedResponse } from 'types/util.types'; import { api } from './api'; @@ -16,9 +17,15 @@ export const listAdvisors = async (): Promise => { return res.data.advisors; }; -export const startAdvisorChecks = async (names: string[]): Promise => { +export const startAdvisorChecks = async ( + names: string[] +): Promise => { const payload: StartAdvisorChecksRequest = { names }; - await api.post('/advisors/checks:start', payload); + const res = await api.post( + '/advisors/checks:start', + payload + ); + return res.data.runId; }; export const changeAdvisorChecks = async ( diff --git a/ui/apps/pmm/src/hooks/api/useAdvisors.ts b/ui/apps/pmm/src/hooks/api/useAdvisors.ts index 739ab7da8b4..bd490a70ed2 100644 --- a/ui/apps/pmm/src/hooks/api/useAdvisors.ts +++ b/ui/apps/pmm/src/hooks/api/useAdvisors.ts @@ -38,7 +38,7 @@ export const useAdvisors = (options?: Partial>) => }); export const useStartAdvisorChecks = ( - options?: Partial> + options?: Partial> ) => useMutation({ mutationKey: [KEYS.START_CHECKS], diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts index b47ffba92c5..d712816b5be 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts @@ -18,6 +18,7 @@ export const Messages = { runAll: 'Run all', runSelected: 'Run selected', addAdvisor: 'Add advisor', + viewResults: 'View results', run: 'Run', success: { checksStarted: diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx index 6c9298a69e3..8c14ead43e1 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -88,7 +88,7 @@ describe('AdvisorsList', () => { beforeEach(() => { vi.clearAllMocks(); vi.mocked(advisorsApi.listAdvisors).mockResolvedValue(TEST_ADVISORS); - vi.mocked(advisorsApi.startAdvisorChecks).mockResolvedValue(); + vi.mocked(advisorsApi.startAdvisorChecks).mockResolvedValue('run-123'); vi.mocked(advisorsApi.changeAdvisorChecks).mockResolvedValue(); }); @@ -146,6 +146,7 @@ describe('AdvisorsList', () => { expect( screen.getByText(Messages.success.checksStarted) ).toBeInTheDocument(); + expect(screen.getByTestId('view-run-results')).toBeInTheDocument(); }); it('runs checks matching the global search', async () => { diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index bd43afb582d..c26338f31da 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -6,7 +6,8 @@ import Typography from '@mui/material/Typography'; import AddOutlinedIcon from '@mui/icons-material/AddOutlined'; import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined'; import { Table } from '@percona/percona-ui'; -import { enqueueSnackbar } from 'notistack'; +import { closeSnackbar, enqueueSnackbar } from 'notistack'; +import { useNavigate } from 'react-router-dom'; import { Page } from 'components/page'; import { useAdvisors, @@ -22,6 +23,7 @@ import { Messages } from './AdvisorsList.messages'; import { getAdvisorsColumns } from './AdvisorsList.constants'; const AdvisorsList: FC = () => { + const navigate = useNavigate(); const { data: advisors = [], isLoading } = useAdvisors(); const { mutate: startChecks, isPending: isStarting } = useStartAdvisorChecks(); @@ -43,9 +45,25 @@ const AdvisorsList: FC = () => { const runChecks = useCallback( (names: string[], message: string) => startChecks(names, { - onSuccess: () => enqueueSnackbar(message, { variant: 'success' }), + onSuccess: (runId) => + enqueueSnackbar(message, { + variant: 'success', + action: (key) => ( + + ), + }), }), - [startChecks] + [startChecks, navigate] ); const handleToggleCheck = useCallback( diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index fd746032822..434917a6db4 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -11,6 +11,7 @@ import { } from 'utils/testUtils'; import { AdvisorCheckResultStatus, + AdvisorCheckTriggeredBy, AdvisorInterval, CheckResultHistoryItem, } from 'types/advisors.types'; @@ -37,6 +38,8 @@ const TEST_ITEM: CheckResultHistoryItem = { labels: {}, checkedAt: '2026-07-05T10:00:00Z', isRead: true, + runId: 'run-1', + triggeredBy: AdvisorCheckTriggeredBy.user, }; const TEST_ITEM_UNREAD: CheckResultHistoryItem = { @@ -50,11 +53,15 @@ const TEST_ITEM_UNREAD: CheckResultHistoryItem = { isRead: false, }; -const renderComponent = () => +const renderComponent = (initialEntry = '/advisors/insights') => render( wrapWithQueryProvider( wrapWithSnackbarProvider( - wrapWithUserProvider(wrapWithRouter()) + wrapWithUserProvider( + wrapWithRouter(, { + initialEntries: [initialEntry], + }) + ) ) ) ); @@ -103,6 +110,16 @@ describe('AdvisorInsights', () => { ); }); + it('passes the runId deep link to the API', async () => { + renderComponent('/advisors/insights?runId=run-42'); + + await waitForRows(); + + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ runId: 'run-42' }) + ); + }); + it('requests the next page on pagination change', async () => { renderComponent(); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 9fa2c90b1f3..6186bee7c8f 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -9,6 +9,7 @@ import { type MRT_Updater, } from 'material-react-table'; import { enqueueSnackbar } from 'notistack'; +import { useSearchParams } from 'react-router-dom'; import { Page } from 'components/page'; import { useAdvisors, @@ -26,6 +27,9 @@ import { Messages } from './AdvisorInsights.messages'; import { getInsightsColumns } from './AdvisorInsights.constants'; const AdvisorInsights: FC = () => { + const [searchParams] = useSearchParams(); + // deep link to the results of a concrete run, e.g. from the "View results" snackbar + const runId = searchParams.get('runId') || undefined; const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 100, @@ -43,13 +47,14 @@ const AdvisorInsights: FC = () => { return { pageIndex: pagination.pageIndex, pageSize: pagination.pageSize, + runId, serviceName: filterValue('serviceName'), category: filterValue('category'), severity: filterValue('severity') as Severity | undefined, status: filterValue('status') as AdvisorCheckResultStatus | undefined, isRead: isRead === undefined ? undefined : isRead === 'true', }; - }, [pagination, columnFilters]); + }, [pagination, columnFilters, runId]); const { data, isLoading, isFetching } = useCheckResultsHistory(params); const { data: advisors = [] } = useAdvisors(); diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index 63a32bd8276..8b002d5f878 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -63,6 +63,16 @@ export enum AdvisorCheckResultStatus { error = 'ADVISOR_CHECK_RESULT_STATUS_ERROR', } +export enum AdvisorCheckTriggeredBy { + unspecified = 'ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED', + user = 'ADVISOR_CHECK_TRIGGERED_BY_USER', + scheduler = 'ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER', +} + +export interface StartAdvisorChecksResponse { + runId: string; +} + export interface CheckResultHistoryItem { id: string; checkName: string; @@ -82,6 +92,8 @@ export interface CheckResultHistoryItem { labels: Record; checkedAt: string; isRead: boolean; + runId: string; + triggeredBy: AdvisorCheckTriggeredBy; } export interface ListCheckResultsHistoryParams { @@ -95,6 +107,8 @@ export interface ListCheckResultsHistoryParams { status?: AdvisorCheckResultStatus; severity?: Severity; isRead?: boolean; + runId?: string; + triggeredBy?: AdvisorCheckTriggeredBy; from?: string; to?: string; } From ed4e6ffec3962d909f07612ba9fa850d85041ce1 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 17:16:26 +0300 Subject: [PATCH 020/120] PMM-14109 Refactor cleanup logic into separate methods --- managed/utils/clean/check_results.go | 26 ++++++++++++++--------- managed/utils/clean/check_results_test.go | 10 +++------ managed/utils/clean/clean.go | 15 ++++++++----- managed/utils/clean/clean_test.go | 14 +++--------- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/managed/utils/clean/check_results.go b/managed/utils/clean/check_results.go index 77b8bac7a66..f38a90ac88a 100644 --- a/managed/utils/clean/check_results.go +++ b/managed/utils/clean/check_results.go @@ -42,16 +42,7 @@ func (c *CheckResults) Run(ctx context.Context, interval time.Duration) { l := logrus.WithField("component", "advisor-history-cleaner") for { - settings, err := models.GetSettings(c.db) - if err != nil { - l.Error(err) - } else { - olderThanTS := models.Now().Add(-1 * settings.AdvisorHistoryRetention) - err := models.CleanupOldCheckResults(c.db.Querier, olderThanTS) - if err != nil { - l.Error(err) - } - } + c.cleanup(l) select { case <-ctx.Done(): @@ -60,3 +51,18 @@ func (c *CheckResults) Run(ctx context.Context, interval time.Duration) { } } } + +// cleanup performs a single cleanup pass, removing check results past the configured retention. +func (c *CheckResults) cleanup(l *logrus.Entry) { + settings, err := models.GetSettings(c.db) + if err != nil { + l.Error(err) + return + } + + olderThanTS := models.Now().Add(-1 * settings.AdvisorHistoryRetention) + err = models.CleanupOldCheckResults(c.db.Querier, olderThanTS) + if err != nil { + l.Error(err) + } +} diff --git a/managed/utils/clean/check_results_test.go b/managed/utils/clean/check_results_test.go index 53910b1ee5a..8125d624e4d 100644 --- a/managed/utils/clean/check_results_test.go +++ b/managed/utils/clean/check_results_test.go @@ -16,10 +16,10 @@ package clean import ( - "context" "testing" "time" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/reform.v1" @@ -48,12 +48,8 @@ func TestCheckResultsCleaner(t *testing.T) { Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), })) - ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second) - defer cancel() - - go NewCheckResults(db).Run(ctx, 5*time.Second) - // Give the cleaner the chance to run one iteration. - time.Sleep(100 * time.Millisecond) + // Run a single cleanup pass synchronously; the ticker loop in Run is trivial plumbing. + NewCheckResults(db).cleanup(logrus.WithField("component", "test")) results, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: "svc"}, 0, 0) require.NoError(t, err) diff --git a/managed/utils/clean/clean.go b/managed/utils/clean/clean.go index 58bbd0cc94e..8a47fe7b858 100644 --- a/managed/utils/clean/clean.go +++ b/managed/utils/clean/clean.go @@ -43,11 +43,7 @@ func (c *Results) Run(ctx context.Context, interval time.Duration, olderThan tim l := logrus.WithField("component", "cleaner") for { - olderThanTS := models.Now().Add(-1 * olderThan) - err := models.CleanupOldActionResults(c.db.Querier, olderThanTS) - if err != nil { - l.Error(err) - } + c.cleanup(l, olderThan) select { case <-ctx.Done(): @@ -56,3 +52,12 @@ func (c *Results) Run(ctx context.Context, interval time.Duration, olderThan tim } } } + +// cleanup performs a single cleanup pass, removing action results older than the given age. +func (c *Results) cleanup(l *logrus.Entry, olderThan time.Duration) { + olderThanTS := models.Now().Add(-1 * olderThan) + err := models.CleanupOldActionResults(c.db.Querier, olderThanTS) + if err != nil { + l.Error(err) + } +} diff --git a/managed/utils/clean/clean_test.go b/managed/utils/clean/clean_test.go index b5eea559dce..e79e5d48fbf 100644 --- a/managed/utils/clean/clean_test.go +++ b/managed/utils/clean/clean_test.go @@ -13,14 +13,13 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -// Package clean has the old actions results cleaner tests. package clean import ( - "context" "testing" "time" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gopkg.in/reform.v1" @@ -82,15 +81,8 @@ func TestCleaner(t *testing.T) { db, q, teardown := setup(t) defer teardown(t) - ctx, cancel := context.WithTimeout(t.Context(), 1*time.Second) - defer cancel() - - c := New(db) - go func() { - c.Run(ctx, 5*time.Second, 5*time.Second) // delete rows older that 5 seconds - }() - // give the cleaner the chance to run - time.Sleep(100 * time.Millisecond) + // Run a single cleanup pass synchronously, deleting rows older than 5 seconds. + New(db).cleanup(logrus.WithField("component", "test"), 5*time.Second) _, err := models.FindActionResultByID(q, "A1") require.Error(t, err) From 15b92c37de81c6a7de4d222a2d796e669a09ade3 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 17:18:02 +0300 Subject: [PATCH 021/120] PMM-14109 Format the code --- api/accesscontrol/v1beta1/accesscontrol.pb.go | 1 + api/actions/v1/actions.pb.go | 1 + api/advisors/v1/advisors.pb.go | 1 + api/agent/v1/agent.pb.go | 1 + api/agent/v1/collector.pb.go | 1 + api/agentlocal/v1/agentlocal.pb.go | 1 + api/alerting/v1/alerting.pb.go | 1 + api/alerting/v1/params.pb.go | 1 + api/backup/v1/artifacts.pb.go | 1 + api/backup/v1/backup.pb.go | 1 + api/backup/v1/common.pb.go | 1 + api/backup/v1/errors.pb.go | 1 + api/backup/v1/locations.pb.go | 1 + api/backup/v1/restores.pb.go | 1 + api/common/common.pb.go | 1 + api/common/metrics_resolutions.pb.go | 1 + api/dump/v1beta1/dump.pb.go | 1 + api/extensions/v1/redact.pb.go | 1 + api/ha/v1beta1/ha.pb.go | 1 + api/inventory/v1/agent_status.pb.go | 1 + api/inventory/v1/agents.pb.go | 1 + api/inventory/v1/log_level.pb.go | 1 + api/inventory/v1/nodes.pb.go | 1 + api/inventory/v1/services.pb.go | 1 + api/management/v1/agent.pb.go | 1 + api/management/v1/annotation.pb.go | 1 + api/management/v1/azure.pb.go | 1 + api/management/v1/external.pb.go | 1 + api/management/v1/haproxy.pb.go | 1 + api/management/v1/metrics.pb.go | 1 + api/management/v1/mongodb.pb.go | 1 + api/management/v1/mysql.pb.go | 1 + api/management/v1/node.pb.go | 1 + api/management/v1/postgresql.pb.go | 1 + api/management/v1/proxysql.pb.go | 1 + api/management/v1/rds.pb.go | 1 + api/management/v1/service.pb.go | 1 + api/management/v1/severity.pb.go | 1 + api/management/v1/valkey.pb.go | 1 + api/qan/v1/collector.pb.go | 1 + api/qan/v1/filters.pb.go | 1 + api/qan/v1/object_details.pb.go | 1 + api/qan/v1/profile.pb.go | 1 + api/qan/v1/qan.pb.go | 1 + api/qan/v1/service.pb.go | 1 + api/realtimeanalytics/v1/collector.pb.go | 1 + api/realtimeanalytics/v1/query.pb.go | 1 + api/realtimeanalytics/v1/realtimeanalytics.pb.go | 1 + api/server/v1/httperror.pb.go | 1 + api/server/v1/server.pb.go | 1 + api/user/v1/user.pb.go | 1 + 51 files changed, 51 insertions(+) diff --git a/api/accesscontrol/v1beta1/accesscontrol.pb.go b/api/accesscontrol/v1beta1/accesscontrol.pb.go index ebec3bf05b7..f5e8ea4b004 100644 --- a/api/accesscontrol/v1beta1/accesscontrol.pb.go +++ b/api/accesscontrol/v1beta1/accesscontrol.pb.go @@ -844,6 +844,7 @@ var ( (*ListRolesResponse_RoleData)(nil), // 14: accesscontrol.v1beta1.ListRolesResponse.RoleData } ) + var file_accesscontrol_v1beta1_accesscontrol_proto_depIdxs = []int32{ 14, // 0: accesscontrol.v1beta1.ListRolesResponse.roles:type_name -> accesscontrol.v1beta1.ListRolesResponse.RoleData 0, // 1: accesscontrol.v1beta1.AccessControlService.CreateRole:input_type -> accesscontrol.v1beta1.CreateRoleRequest diff --git a/api/actions/v1/actions.pb.go b/api/actions/v1/actions.pb.go index 35461ae3739..f1cfdec8cfa 100644 --- a/api/actions/v1/actions.pb.go +++ b/api/actions/v1/actions.pb.go @@ -2649,6 +2649,7 @@ var ( (*StartServiceActionResponse)(nil), // 32: actions.v1.StartServiceActionResponse } ) + var file_actions_v1_actions_proto_depIdxs = []int32{ 3, // 0: actions.v1.StartServiceActionRequest.mysql_explain:type_name -> actions.v1.StartMySQLExplainActionParams 5, // 1: actions.v1.StartServiceActionRequest.mysql_explain_json:type_name -> actions.v1.StartMySQLExplainJSONActionParams diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index b55ddf66ec9..63139153449 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -2122,6 +2122,7 @@ var ( (*timestamppb.Timestamp)(nil), // 31: google.protobuf.Timestamp } ) + var file_advisors_v1_advisors_proto_depIdxs = []int32{ 30, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity 27, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry diff --git a/api/agent/v1/agent.pb.go b/api/agent/v1/agent.pb.go index 7f5d935624b..c2f2a8b6a9e 100644 --- a/api/agent/v1/agent.pb.go +++ b/api/agent/v1/agent.pb.go @@ -7221,6 +7221,7 @@ var ( (*v11.Metadata)(nil), // 104: backup.v1.Metadata } ) + var file_agent_v1_agent_proto_depIdxs = []int32{ 44, // 0: agent.v1.TextFiles.files:type_name -> agent.v1.TextFiles.FilesEntry 94, // 1: agent.v1.Pong.current_time:type_name -> google.protobuf.Timestamp diff --git a/api/agent/v1/collector.pb.go b/api/agent/v1/collector.pb.go index da17db39c64..65633c05d17 100644 --- a/api/agent/v1/collector.pb.go +++ b/api/agent/v1/collector.pb.go @@ -2827,6 +2827,7 @@ var ( v1.AgentType(0), // 9: inventory.v1.AgentType } ) + var file_agent_v1_collector_proto_depIdxs = []int32{ 3, // 0: agent.v1.MetricsBucket.common:type_name -> agent.v1.MetricsBucket.Common 4, // 1: agent.v1.MetricsBucket.mysql:type_name -> agent.v1.MetricsBucket.MySQL diff --git a/api/agentlocal/v1/agentlocal.pb.go b/api/agentlocal/v1/agentlocal.pb.go index 12053d57921..7bb13a7cb58 100644 --- a/api/agentlocal/v1/agentlocal.pb.go +++ b/api/agentlocal/v1/agentlocal.pb.go @@ -485,6 +485,7 @@ var ( v1.AgentStatus(0), // 8: inventory.v1.AgentStatus } ) + var file_agentlocal_v1_agentlocal_proto_depIdxs = []int32{ 6, // 0: agentlocal.v1.ServerInfo.latency:type_name -> google.protobuf.Duration 6, // 1: agentlocal.v1.ServerInfo.clock_drift:type_name -> google.protobuf.Duration diff --git a/api/alerting/v1/alerting.pb.go b/api/alerting/v1/alerting.pb.go index bccb6659d24..3b2c47d73ec 100644 --- a/api/alerting/v1/alerting.pb.go +++ b/api/alerting/v1/alerting.pb.go @@ -1459,6 +1459,7 @@ var ( (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp } ) + var file_alerting_v1_alerting_proto_depIdxs = []int32{ 22, // 0: alerting.v1.ParamDefinition.unit:type_name -> alerting.v1.ParamUnit 23, // 1: alerting.v1.ParamDefinition.type:type_name -> alerting.v1.ParamType diff --git a/api/alerting/v1/params.pb.go b/api/alerting/v1/params.pb.go index eb001a606db..69d88497102 100644 --- a/api/alerting/v1/params.pb.go +++ b/api/alerting/v1/params.pb.go @@ -163,6 +163,7 @@ var ( ParamType(0), // 1: alerting.v1.ParamType } ) + var file_alerting_v1_params_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/backup/v1/artifacts.pb.go b/api/backup/v1/artifacts.pb.go index e2352f61cd1..dde03ceefef 100644 --- a/api/backup/v1/artifacts.pb.go +++ b/api/backup/v1/artifacts.pb.go @@ -656,6 +656,7 @@ var ( (*Metadata)(nil), // 12: backup.v1.Metadata } ) + var file_backup_v1_artifacts_proto_depIdxs = []int32{ 9, // 0: backup.v1.Artifact.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.Artifact.status:type_name -> backup.v1.BackupStatus diff --git a/api/backup/v1/backup.pb.go b/api/backup/v1/backup.pb.go index 19241fc6afd..4d587217600 100644 --- a/api/backup/v1/backup.pb.go +++ b/api/backup/v1/backup.pb.go @@ -1276,6 +1276,7 @@ var ( (*ListPitrTimerangesResponse)(nil), // 27: backup.v1.ListPitrTimerangesResponse } ) + var file_backup_v1_backup_proto_depIdxs = []int32{ 15, // 0: backup.v1.StartBackupRequest.retry_interval:type_name -> google.protobuf.Duration 16, // 1: backup.v1.StartBackupRequest.data_model:type_name -> backup.v1.DataModel diff --git a/api/backup/v1/common.pb.go b/api/backup/v1/common.pb.go index f84ca11de32..c8274024e38 100644 --- a/api/backup/v1/common.pb.go +++ b/api/backup/v1/common.pb.go @@ -423,6 +423,7 @@ var ( (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp } ) + var file_backup_v1_common_proto_depIdxs = []int32{ 2, // 0: backup.v1.Metadata.file_list:type_name -> backup.v1.File 6, // 1: backup.v1.Metadata.restore_to:type_name -> google.protobuf.Timestamp diff --git a/api/backup/v1/errors.pb.go b/api/backup/v1/errors.pb.go index 5709e5ac243..902adc277c1 100644 --- a/api/backup/v1/errors.pb.go +++ b/api/backup/v1/errors.pb.go @@ -169,6 +169,7 @@ var ( (*Error)(nil), // 1: backup.v1.Error } ) + var file_backup_v1_errors_proto_depIdxs = []int32{ 0, // 0: backup.v1.Error.code:type_name -> backup.v1.ErrorCode 1, // [1:1] is the sub-list for method output_type diff --git a/api/backup/v1/locations.pb.go b/api/backup/v1/locations.pb.go index 72c13dece43..396b552ee80 100644 --- a/api/backup/v1/locations.pb.go +++ b/api/backup/v1/locations.pb.go @@ -833,6 +833,7 @@ var ( (*TestLocationConfigResponse)(nil), // 12: backup.v1.TestLocationConfigResponse } ) + var file_backup_v1_locations_proto_depIdxs = []int32{ 0, // 0: backup.v1.Location.filesystem_config:type_name -> backup.v1.FilesystemLocationConfig 1, // 1: backup.v1.Location.s3_config:type_name -> backup.v1.S3LocationConfig diff --git a/api/backup/v1/restores.pb.go b/api/backup/v1/restores.pb.go index 580c158b119..ee12d6b9285 100644 --- a/api/backup/v1/restores.pb.go +++ b/api/backup/v1/restores.pb.go @@ -625,6 +625,7 @@ var ( (*LogChunk)(nil), // 10: backup.v1.LogChunk } ) + var file_backup_v1_restores_proto_depIdxs = []int32{ 8, // 0: backup.v1.RestoreHistoryItem.data_model:type_name -> backup.v1.DataModel 0, // 1: backup.v1.RestoreHistoryItem.status:type_name -> backup.v1.RestoreStatus diff --git a/api/common/common.pb.go b/api/common/common.pb.go index 2303ccd29ab..0d05883daa1 100644 --- a/api/common/common.pb.go +++ b/api/common/common.pb.go @@ -147,6 +147,7 @@ var ( nil, // 2: common.StringMap.ValuesEntry } ) + var file_common_common_proto_depIdxs = []int32{ 2, // 0: common.StringMap.values:type_name -> common.StringMap.ValuesEntry 1, // [1:1] is the sub-list for method output_type diff --git a/api/common/metrics_resolutions.pb.go b/api/common/metrics_resolutions.pb.go index 389e4572992..75e587ba9a5 100644 --- a/api/common/metrics_resolutions.pb.go +++ b/api/common/metrics_resolutions.pb.go @@ -118,6 +118,7 @@ var ( (*durationpb.Duration)(nil), // 1: google.protobuf.Duration } ) + var file_common_metrics_resolutions_proto_depIdxs = []int32{ 1, // 0: common.MetricsResolutions.hr:type_name -> google.protobuf.Duration 1, // 1: common.MetricsResolutions.mr:type_name -> google.protobuf.Duration diff --git a/api/dump/v1beta1/dump.pb.go b/api/dump/v1beta1/dump.pb.go index 76f0e473adf..d031bce6b8f 100644 --- a/api/dump/v1beta1/dump.pb.go +++ b/api/dump/v1beta1/dump.pb.go @@ -897,6 +897,7 @@ var ( (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp } ) + var file_dump_v1beta1_dump_proto_depIdxs = []int32{ 0, // 0: dump.v1beta1.Dump.status:type_name -> dump.v1beta1.DumpStatus 14, // 1: dump.v1beta1.Dump.start_time:type_name -> google.protobuf.Timestamp diff --git a/api/extensions/v1/redact.pb.go b/api/extensions/v1/redact.pb.go index c850a90df3c..738ce213118 100644 --- a/api/extensions/v1/redact.pb.go +++ b/api/extensions/v1/redact.pb.go @@ -135,6 +135,7 @@ var ( (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions } ) + var file_extensions_v1_redact_proto_depIdxs = []int32{ 1, // 0: extensions.v1.sensitive:extendee -> google.protobuf.FieldOptions 0, // 1: extensions.v1.sensitive:type_name -> extensions.v1.RedactType diff --git a/api/ha/v1beta1/ha.pb.go b/api/ha/v1beta1/ha.pb.go index 655996ccdbc..f798cccbcc0 100644 --- a/api/ha/v1beta1/ha.pb.go +++ b/api/ha/v1beta1/ha.pb.go @@ -351,6 +351,7 @@ var ( (*StatusResponse)(nil), // 5: ha.v1beta1.StatusResponse } ) + var file_ha_v1beta1_ha_proto_depIdxs = []int32{ 0, // 0: ha.v1beta1.HANode.role:type_name -> ha.v1beta1.NodeRole 2, // 1: ha.v1beta1.ListNodesResponse.nodes:type_name -> ha.v1beta1.HANode diff --git a/api/inventory/v1/agent_status.pb.go b/api/inventory/v1/agent_status.pb.go index ace1432a5e8..1e23074d2fc 100644 --- a/api/inventory/v1/agent_status.pb.go +++ b/api/inventory/v1/agent_status.pb.go @@ -128,6 +128,7 @@ var ( AgentStatus(0), // 0: inventory.v1.AgentStatus } ) + var file_inventory_v1_agent_status_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/agents.pb.go b/api/inventory/v1/agents.pb.go index f5d83515360..3784fc8b7fc 100644 --- a/api/inventory/v1/agents.pb.go +++ b/api/inventory/v1/agents.pb.go @@ -12513,6 +12513,7 @@ var ( (*common.StringMap)(nil), // 112: common.StringMap } ) + var file_inventory_v1_agents_proto_depIdxs = []int32{ 68, // 0: inventory.v1.PMMAgent.custom_labels:type_name -> inventory.v1.PMMAgent.CustomLabelsEntry 108, // 1: inventory.v1.VMAgent.status:type_name -> inventory.v1.AgentStatus diff --git a/api/inventory/v1/log_level.pb.go b/api/inventory/v1/log_level.pb.go index 47f0373d578..ff4d79ca3f2 100644 --- a/api/inventory/v1/log_level.pb.go +++ b/api/inventory/v1/log_level.pb.go @@ -114,6 +114,7 @@ var ( LogLevel(0), // 0: inventory.v1.LogLevel } ) + var file_inventory_v1_log_level_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/inventory/v1/nodes.pb.go b/api/inventory/v1/nodes.pb.go index e0186c91815..447663477a9 100644 --- a/api/inventory/v1/nodes.pb.go +++ b/api/inventory/v1/nodes.pb.go @@ -2043,6 +2043,7 @@ var ( nil, // 28: inventory.v1.AddRemoteAzureNodeParams.CustomLabelsEntry } ) + var file_inventory_v1_nodes_proto_depIdxs = []int32{ 19, // 0: inventory.v1.GenericNode.custom_labels:type_name -> inventory.v1.GenericNode.CustomLabelsEntry 20, // 1: inventory.v1.ContainerNode.custom_labels:type_name -> inventory.v1.ContainerNode.CustomLabelsEntry diff --git a/api/inventory/v1/services.pb.go b/api/inventory/v1/services.pb.go index 23eeeb28b81..a8d1519b61f 100644 --- a/api/inventory/v1/services.pb.go +++ b/api/inventory/v1/services.pb.go @@ -3334,6 +3334,7 @@ var ( (*common.StringMap)(nil), // 43: common.StringMap } ) + var file_inventory_v1_services_proto_depIdxs = []int32{ 27, // 0: inventory.v1.MySQLService.custom_labels:type_name -> inventory.v1.MySQLService.CustomLabelsEntry 28, // 1: inventory.v1.MySQLService.extra_dsn_params:type_name -> inventory.v1.MySQLService.ExtraDsnParamsEntry diff --git a/api/management/v1/agent.pb.go b/api/management/v1/agent.pb.go index 8a745a48910..c76c750f869 100644 --- a/api/management/v1/agent.pb.go +++ b/api/management/v1/agent.pb.go @@ -1241,6 +1241,7 @@ var ( (*durationpb.Duration)(nil), // 17: google.protobuf.Duration } ) + var file_management_v1_agent_proto_depIdxs = []int32{ 8, // 0: management.v1.UniversalAgent.azure_options:type_name -> management.v1.UniversalAgent.AzureOptions 14, // 1: management.v1.UniversalAgent.created_at:type_name -> google.protobuf.Timestamp diff --git a/api/management/v1/annotation.pb.go b/api/management/v1/annotation.pb.go index 53bbe233c1b..ec781561e4c 100644 --- a/api/management/v1/annotation.pb.go +++ b/api/management/v1/annotation.pb.go @@ -164,6 +164,7 @@ var ( (*AddAnnotationResponse)(nil), // 1: management.v1.AddAnnotationResponse } ) + var file_management_v1_annotation_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/azure.pb.go b/api/management/v1/azure.pb.go index 863cff6d5ab..04a05c47ec1 100644 --- a/api/management/v1/azure.pb.go +++ b/api/management/v1/azure.pb.go @@ -726,6 +726,7 @@ var ( (*durationpb.Duration)(nil), // 7: google.protobuf.Duration } ) + var file_management_v1_azure_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverAzureDatabaseInstance.type:type_name -> management.v1.DiscoverAzureDatabaseType 2, // 1: management.v1.DiscoverAzureDatabaseResponse.azure_database_instance:type_name -> management.v1.DiscoverAzureDatabaseInstance diff --git a/api/management/v1/external.pb.go b/api/management/v1/external.pb.go index d990cb53abe..3632121e1c2 100644 --- a/api/management/v1/external.pb.go +++ b/api/management/v1/external.pb.go @@ -355,6 +355,7 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) + var file_management_v1_external_proto_depIdxs = []int32{ 3, // 0: management.v1.AddExternalServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddExternalServiceParams.custom_labels:type_name -> management.v1.AddExternalServiceParams.CustomLabelsEntry diff --git a/api/management/v1/haproxy.pb.go b/api/management/v1/haproxy.pb.go index 95cad534323..f3de5158762 100644 --- a/api/management/v1/haproxy.pb.go +++ b/api/management/v1/haproxy.pb.go @@ -333,6 +333,7 @@ var ( (*v1.ExternalExporter)(nil), // 6: inventory.v1.ExternalExporter } ) + var file_management_v1_haproxy_proto_depIdxs = []int32{ 3, // 0: management.v1.AddHAProxyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddHAProxyServiceParams.custom_labels:type_name -> management.v1.AddHAProxyServiceParams.CustomLabelsEntry diff --git a/api/management/v1/metrics.pb.go b/api/management/v1/metrics.pb.go index b552c7955fb..748642db7cb 100644 --- a/api/management/v1/metrics.pb.go +++ b/api/management/v1/metrics.pb.go @@ -103,6 +103,7 @@ var ( MetricsMode(0), // 0: management.v1.MetricsMode } ) + var file_management_v1_metrics_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/mongodb.pb.go b/api/management/v1/mongodb.pb.go index aad151306df..c25cc4f8282 100644 --- a/api/management/v1/mongodb.pb.go +++ b/api/management/v1/mongodb.pb.go @@ -559,6 +559,7 @@ var ( (*v1.RTAMongoDBAgent)(nil), // 11: inventory.v1.RTAMongoDBAgent } ) + var file_management_v1_mongodb_proto_depIdxs = []int32{ 3, // 0: management.v1.AddMongoDBServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMongoDBServiceParams.custom_labels:type_name -> management.v1.AddMongoDBServiceParams.CustomLabelsEntry diff --git a/api/management/v1/mysql.pb.go b/api/management/v1/mysql.pb.go index 70660a14379..18f64740d99 100644 --- a/api/management/v1/mysql.pb.go +++ b/api/management/v1/mysql.pb.go @@ -545,6 +545,7 @@ var ( (*v1.QANMySQLSlowlogAgent)(nil), // 11: inventory.v1.QANMySQLSlowlogAgent } ) + var file_management_v1_mysql_proto_depIdxs = []int32{ 4, // 0: management.v1.AddMySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddMySQLServiceParams.custom_labels:type_name -> management.v1.AddMySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/node.pb.go b/api/management/v1/node.pb.go index 53bb2be68db..149fb30ad94 100644 --- a/api/management/v1/node.pb.go +++ b/api/management/v1/node.pb.go @@ -1255,6 +1255,7 @@ var ( (*timestamppb.Timestamp)(nil), // 21: google.protobuf.Timestamp } ) + var file_management_v1_node_proto_depIdxs = []int32{ 16, // 0: management.v1.AddNodeParams.node_type:type_name -> inventory.v1.NodeType 11, // 1: management.v1.AddNodeParams.custom_labels:type_name -> management.v1.AddNodeParams.CustomLabelsEntry diff --git a/api/management/v1/postgresql.pb.go b/api/management/v1/postgresql.pb.go index 0e6f54ad033..0271ba48788 100644 --- a/api/management/v1/postgresql.pb.go +++ b/api/management/v1/postgresql.pb.go @@ -535,6 +535,7 @@ var ( (*v1.QANPostgreSQLPgStatMonitorAgent)(nil), // 10: inventory.v1.QANPostgreSQLPgStatMonitorAgent } ) + var file_management_v1_postgresql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddPostgreSQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddPostgreSQLServiceParams.custom_labels:type_name -> management.v1.AddPostgreSQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/proxysql.pb.go b/api/management/v1/proxysql.pb.go index 7d9dbbcfc07..e3142ed85df 100644 --- a/api/management/v1/proxysql.pb.go +++ b/api/management/v1/proxysql.pb.go @@ -395,6 +395,7 @@ var ( (*v1.ProxySQLExporter)(nil), // 8: inventory.v1.ProxySQLExporter } ) + var file_management_v1_proxysql_proto_depIdxs = []int32{ 3, // 0: management.v1.AddProxySQLServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddProxySQLServiceParams.custom_labels:type_name -> management.v1.AddProxySQLServiceParams.CustomLabelsEntry diff --git a/api/management/v1/rds.pb.go b/api/management/v1/rds.pb.go index b30d865e5fd..d4821f97cd9 100644 --- a/api/management/v1/rds.pb.go +++ b/api/management/v1/rds.pb.go @@ -876,6 +876,7 @@ var ( (*v1.QANPostgreSQLPgStatementsAgent)(nil), // 16: inventory.v1.QANPostgreSQLPgStatementsAgent } ) + var file_management_v1_rds_proto_depIdxs = []int32{ 0, // 0: management.v1.DiscoverRDSInstance.engine:type_name -> management.v1.DiscoverRDSEngine 1, // 1: management.v1.DiscoverRDSResponse.rds_instances:type_name -> management.v1.DiscoverRDSInstance diff --git a/api/management/v1/service.pb.go b/api/management/v1/service.pb.go index 6ea52fbc973..cbad04b7f53 100644 --- a/api/management/v1/service.pb.go +++ b/api/management/v1/service.pb.go @@ -1005,6 +1005,7 @@ var ( (*AddAzureDatabaseResponse)(nil), // 47: management.v1.AddAzureDatabaseResponse } ) + var file_management_v1_service_proto_depIdxs = []int32{ 9, // 0: management.v1.AddServiceRequest.mysql:type_name -> management.v1.AddMySQLServiceParams 10, // 1: management.v1.AddServiceRequest.mongodb:type_name -> management.v1.AddMongoDBServiceParams diff --git a/api/management/v1/severity.pb.go b/api/management/v1/severity.pb.go index 51c04a93a0e..6a14d366aa6 100644 --- a/api/management/v1/severity.pb.go +++ b/api/management/v1/severity.pb.go @@ -125,6 +125,7 @@ var ( Severity(0), // 0: management.v1.Severity } ) + var file_management_v1_severity_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/management/v1/valkey.pb.go b/api/management/v1/valkey.pb.go index 26cc4db7f99..a0fc2f73fe2 100644 --- a/api/management/v1/valkey.pb.go +++ b/api/management/v1/valkey.pb.go @@ -417,6 +417,7 @@ var ( (*v1.ValkeyExporter)(nil), // 8: inventory.v1.ValkeyExporter } ) + var file_management_v1_valkey_proto_depIdxs = []int32{ 3, // 0: management.v1.AddValkeyServiceParams.add_node:type_name -> management.v1.AddNodeParams 2, // 1: management.v1.AddValkeyServiceParams.custom_labels:type_name -> management.v1.AddValkeyServiceParams.CustomLabelsEntry diff --git a/api/qan/v1/collector.pb.go b/api/qan/v1/collector.pb.go index 3716a3a24d1..b680bbd8f77 100644 --- a/api/qan/v1/collector.pb.go +++ b/api/qan/v1/collector.pb.go @@ -2757,6 +2757,7 @@ var ( ExampleType(0), // 7: qan.v1.ExampleType } ) + var file_qan_v1_collector_proto_depIdxs = []int32{ 1, // 0: qan.v1.CollectRequest.metrics_bucket:type_name -> qan.v1.MetricsBucket 6, // 1: qan.v1.MetricsBucket.agent_type:type_name -> inventory.v1.AgentType diff --git a/api/qan/v1/filters.pb.go b/api/qan/v1/filters.pb.go index 390a687dbc4..fcbf5e7aead 100644 --- a/api/qan/v1/filters.pb.go +++ b/api/qan/v1/filters.pb.go @@ -293,6 +293,7 @@ var ( (*MapFieldEntry)(nil), // 6: qan.v1.MapFieldEntry } ) + var file_qan_v1_filters_proto_depIdxs = []int32{ 5, // 0: qan.v1.GetFilteredMetricsNamesRequest.period_start_from:type_name -> google.protobuf.Timestamp 5, // 1: qan.v1.GetFilteredMetricsNamesRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/object_details.pb.go b/api/qan/v1/object_details.pb.go index 53e6c06150b..f004bc0ec60 100644 --- a/api/qan/v1/object_details.pb.go +++ b/api/qan/v1/object_details.pb.go @@ -1645,6 +1645,7 @@ var ( ExampleType(0), // 29: qan.v1.ExampleType } ) + var file_qan_v1_object_details_proto_depIdxs = []int32{ 26, // 0: qan.v1.GetMetricsRequest.period_start_from:type_name -> google.protobuf.Timestamp 26, // 1: qan.v1.GetMetricsRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/profile.pb.go b/api/qan/v1/profile.pb.go index 7700b76dcd3..03ab97e871a 100644 --- a/api/qan/v1/profile.pb.go +++ b/api/qan/v1/profile.pb.go @@ -598,6 +598,7 @@ var ( (*Point)(nil), // 8: qan.v1.Point } ) + var file_qan_v1_profile_proto_depIdxs = []int32{ 7, // 0: qan.v1.GetReportRequest.period_start_from:type_name -> google.protobuf.Timestamp 7, // 1: qan.v1.GetReportRequest.period_start_to:type_name -> google.protobuf.Timestamp diff --git a/api/qan/v1/qan.pb.go b/api/qan/v1/qan.pb.go index 2d37431a7c0..c1d3bc6bb2e 100644 --- a/api/qan/v1/qan.pb.go +++ b/api/qan/v1/qan.pb.go @@ -1000,6 +1000,7 @@ var ( (*MapFieldEntry)(nil), // 2: qan.v1.MapFieldEntry } ) + var file_qan_v1_qan_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type diff --git a/api/qan/v1/service.pb.go b/api/qan/v1/service.pb.go index c5c688d9000..0e52423aa51 100644 --- a/api/qan/v1/service.pb.go +++ b/api/qan/v1/service.pb.go @@ -258,6 +258,7 @@ var ( (*GetQueryExampleResponse)(nil), // 24: qan.v1.GetQueryExampleResponse } ) + var file_qan_v1_service_proto_depIdxs = []int32{ 4, // 0: qan.v1.GetMetricsNamesResponse.data:type_name -> qan.v1.GetMetricsNamesResponse.DataEntry 5, // 1: qan.v1.QANService.GetReport:input_type -> qan.v1.GetReportRequest diff --git a/api/realtimeanalytics/v1/collector.pb.go b/api/realtimeanalytics/v1/collector.pb.go index b9b81466e7c..f149de0a6cf 100644 --- a/api/realtimeanalytics/v1/collector.pb.go +++ b/api/realtimeanalytics/v1/collector.pb.go @@ -140,6 +140,7 @@ var ( (*QueryData)(nil), // 2: realtimeanalytics.v1.QueryData } ) + var file_realtimeanalytics_v1_collector_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.CollectRequest.queries:type_name -> realtimeanalytics.v1.QueryData 0, // 1: realtimeanalytics.v1.CollectorService.Collect:input_type -> realtimeanalytics.v1.CollectRequest diff --git a/api/realtimeanalytics/v1/query.pb.go b/api/realtimeanalytics/v1/query.pb.go index b9ab1809d9a..43c4a1bdd5c 100644 --- a/api/realtimeanalytics/v1/query.pb.go +++ b/api/realtimeanalytics/v1/query.pb.go @@ -331,6 +331,7 @@ var ( (*durationpb.Duration)(nil), // 3: google.protobuf.Duration } ) + var file_realtimeanalytics_v1_query_proto_depIdxs = []int32{ 2, // 0: realtimeanalytics.v1.QueryMongoDBData.operation_start_time:type_name -> google.protobuf.Timestamp 3, // 1: realtimeanalytics.v1.QueryData.query_execution_duration:type_name -> google.protobuf.Duration diff --git a/api/realtimeanalytics/v1/realtimeanalytics.pb.go b/api/realtimeanalytics/v1/realtimeanalytics.pb.go index bd339f4bad9..8dbdbf8ccff 100644 --- a/api/realtimeanalytics/v1/realtimeanalytics.pb.go +++ b/api/realtimeanalytics/v1/realtimeanalytics.pb.go @@ -718,6 +718,7 @@ var ( (*QueryData)(nil), // 16: realtimeanalytics.v1.QueryData } ) + var file_realtimeanalytics_v1_realtimeanalytics_proto_depIdxs = []int32{ 12, // 0: realtimeanalytics.v1.ListServicesRequest.service_type:type_name -> inventory.v1.ServiceType 13, // 1: realtimeanalytics.v1.ListServicesResponse.mongodb:type_name -> inventory.v1.MongoDBService diff --git a/api/server/v1/httperror.pb.go b/api/server/v1/httperror.pb.go index ef269ba2292..8778ad26272 100644 --- a/api/server/v1/httperror.pb.go +++ b/api/server/v1/httperror.pb.go @@ -127,6 +127,7 @@ var ( (*anypb.Any)(nil), // 1: google.protobuf.Any } ) + var file_server_v1_httperror_proto_depIdxs = []int32{ 1, // 0: server.v1.HttpError.details:type_name -> google.protobuf.Any 1, // [1:1] is the sub-list for method output_type diff --git a/api/server/v1/server.pb.go b/api/server/v1/server.pb.go index 0bbc3212e77..ab1ab9b07ae 100644 --- a/api/server/v1/server.pb.go +++ b/api/server/v1/server.pb.go @@ -2015,6 +2015,7 @@ var ( (*common.StringArray)(nil), // 30: common.StringArray } ) + var file_server_v1_server_proto_depIdxs = []int32{ 27, // 0: server.v1.VersionInfo.timestamp:type_name -> google.protobuf.Timestamp 1, // 1: server.v1.VersionResponse.server:type_name -> server.v1.VersionInfo diff --git a/api/user/v1/user.pb.go b/api/user/v1/user.pb.go index 200364a0741..12a954ca3f4 100644 --- a/api/user/v1/user.pb.go +++ b/api/user/v1/user.pb.go @@ -507,6 +507,7 @@ var ( (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp } ) + var file_user_v1_user_proto_depIdxs = []int32{ 7, // 0: user.v1.GetUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp 7, // 1: user.v1.UpdateUserResponse.snoozed_at:type_name -> google.protobuf.Timestamp From 766b7b0952cdd8feb1cf1f861f453b0589100bd7 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 19:57:09 +0300 Subject: [PATCH 022/120] PMM-14109 Remove unused CategorizedAdvisor interface and related imports --- ui/apps/pmm/src/types/advisors.types.ts | 6 ----- ui/apps/pmm/src/utils/advisors.utils.ts | 34 +------------------------ 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index 8b002d5f878..2ce429e232f 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -32,12 +32,6 @@ export interface Advisor { checks: AdvisorCheck[]; } -export interface CategorizedAdvisor { - [category: string]: { - [summary: string]: Advisor; - }; -} - export interface ListAdvisorsResponse { advisors: Advisor[]; } diff --git a/ui/apps/pmm/src/utils/advisors.utils.ts b/ui/apps/pmm/src/utils/advisors.utils.ts index e1ae390b63b..4e914beaf66 100644 --- a/ui/apps/pmm/src/utils/advisors.utils.ts +++ b/ui/apps/pmm/src/utils/advisors.utils.ts @@ -1,9 +1,4 @@ -import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; -import { - Advisor, - AdvisorCheckRow, - CategorizedAdvisor, -} from 'types/advisors.types'; +import { Advisor, AdvisorCheckRow } from 'types/advisors.types'; export const flattenAdvisorChecks = (advisors: Advisor[]): AdvisorCheckRow[] => advisors.flatMap((advisor) => @@ -18,30 +13,3 @@ export const flattenAdvisorChecks = (advisors: Advisor[]): AdvisorCheckRow[] => enabled: check.enabled, })) ); - -export const groupAdvisorsIntoCategories = ( - advisors: Advisor[] -): CategorizedAdvisor => { - const result: CategorizedAdvisor = {}; - - advisors.forEach((advisor) => { - const { category, summary, checks } = advisor; - - const modifiedChecks = checks.map((check) => ({ - ...check, - familyName: check.family ? ADVISOR_FAMILY[check.family] : undefined, - intervalName: check.interval - ? ADVISOR_INTERVAL[check.interval] - : undefined, - })); - - if (!result[category]) { - result[category] = {}; - } - - if (!result[category][summary]) { - result[category][summary] = { ...advisor, checks: [...modifiedChecks] }; - } - }); - return result; -}; From b45f27c013b75c59553fbcdf502b1a00c7b1c8a3 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 21:38:40 +0300 Subject: [PATCH 023/120] PMM-14109 Add Advisor history retention to Settings --- ui/apps/pmm/src/App.tsx | 50 +++-- .../insights/AdvisorInsights.constants.tsx | 58 ++---- .../insights/AdvisorInsights.filters.ts | 26 +++ .../insights/AdvisorInsights.messages.ts | 9 + .../insights/AdvisorInsights.test.tsx | 41 +++- .../advisors/insights/AdvisorInsights.tsx | 185 ++++++++++++++---- .../src/pages/settings/Settings.messages.ts | 10 + .../components/advanced/Advanced.constants.ts | 14 ++ .../advanced/AdvancedSettingsForm.schema.ts | 21 ++ .../advanced/AdvancedSettingsForm.tsx | 83 +++++++- .../AdvancedSettingsForm.utils.test.ts | 63 ++++++ .../advanced/AdvancedSettingsForm.utils.ts | 21 +- ui/apps/pmm/src/types/settings.types.ts | 8 + 13 files changed, 481 insertions(+), 108 deletions(-) create mode 100644 ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.filters.ts create mode 100644 ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts diff --git a/ui/apps/pmm/src/App.tsx b/ui/apps/pmm/src/App.tsx index d645b8ae77d..f5ae3c47027 100644 --- a/ui/apps/pmm/src/App.tsx +++ b/ui/apps/pmm/src/App.tsx @@ -1,18 +1,20 @@ +import type { PaletteMode } from '@mui/material'; +import type { ThemeOptions } from '@mui/material/styles'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { RouterProvider } from 'react-router-dom'; -import router from './router'; -import { SnackbarProvider, CustomContentProps } from 'notistack'; import { + NotistackMuiSnackbar, ThemeContextProvider, pmmThemeOptions, - NotistackMuiSnackbar, } from '@percona/percona-ui'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { addApiErrorInterceptor, removeApiErrorInterceptor } from 'api/api'; import { ThemeClass } from 'components/theme-class'; -import { useEffect } from 'react'; +import { CustomContentProps, SnackbarProvider } from 'notistack'; import type { ComponentType } from 'react'; -import { addApiErrorInterceptor, removeApiErrorInterceptor } from 'api/api'; +import { useEffect } from 'react'; +import { RouterProvider } from 'react-router-dom'; +import router from './router'; const queryClient = new QueryClient({ defaultOptions: { @@ -23,10 +25,31 @@ const queryClient = new QueryClient({ }, }); +const DARK_BACKGROUND_COLOR = 'rgb(10, 10, 18)'; +// pmmThemeOptions with the dark background overridden; `paper` is included +// because most page surfaces (RTA, Grafana frame, settings) paint with it +const themeOptions = (mode: PaletteMode): ThemeOptions => { + const options = pmmThemeOptions(mode); + + if (mode !== 'dark') { + return options; + } + + return { + ...options, + palette: { + ...options.palette, + background: { + ...options.palette?.background, + default: DARK_BACKGROUND_COLOR, + paper: DARK_BACKGROUND_COLOR, + }, + }, + }; +}; const App = () => { - useEffect(() => { addApiErrorInterceptor(); return () => { @@ -35,7 +58,7 @@ const App = () => { }, []); return ( - + { // NOTE: using custom components disables notistack's custom actions, as per docs: https://notistack.com/features/basic#actions // If we need actions, we can add them to our custom component via useSnackbar(): https://notistack.com/features/customization#custom-component Components={{ - success: - NotistackMuiSnackbar as ComponentType, - error: - NotistackMuiSnackbar as ComponentType, + success: NotistackMuiSnackbar as ComponentType, + error: NotistackMuiSnackbar as ComponentType, info: NotistackMuiSnackbar as ComponentType, - warning: - NotistackMuiSnackbar as ComponentType, + warning: NotistackMuiSnackbar as ComponentType, }} // Render the snackbar on the right side of the screen to not interfere with navigation anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx index e4561517ac8..0006c5ebad1 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx @@ -2,10 +2,7 @@ import { type MRT_ColumnDef } from 'material-react-table'; import Chip from '@mui/material/Chip'; import Link from '@mui/material/Link'; import { format } from 'date-fns'; -import { - AdvisorCheckResultStatus, - CheckResultHistoryItem, -} from 'types/advisors.types'; +import { CheckResultHistoryItem } from 'types/advisors.types'; import { Severity } from 'types/severity.types'; import { ADVISOR_RESULT_STATUS, @@ -15,35 +12,23 @@ import { import { capitalize } from 'utils/text.utils'; import { Messages } from './AdvisorInsights.messages'; -const SEVERITY_OPTIONS = [ - Severity.emergency, - Severity.alert, - Severity.critical, - Severity.error, - Severity.warning, - Severity.notice, - Severity.info, - Severity.debug, -].map((severity) => ({ label: SEVERITY[severity], value: severity })); - -const STATUS_OPTIONS = [ - AdvisorCheckResultStatus.ok, - AdvisorCheckResultStatus.failed, - AdvisorCheckResultStatus.error, -].map((status) => ({ label: ADVISOR_RESULT_STATUS[status], value: status })); - -const READ_OPTIONS = [ - { label: Messages.read, value: 'true' }, - { label: Messages.unread, value: 'false' }, -]; +const SEVERITY_ORDER: Record = { + [Severity.emergency]: 1, + [Severity.alert]: 2, + [Severity.critical]: 3, + [Severity.error]: 4, + [Severity.warning]: 5, + [Severity.notice]: 6, + [Severity.info]: 7, + [Severity.debug]: 8, + [Severity.unspecified]: 9, +}; -export const getInsightsColumns = ( - categories: string[] -): MRT_ColumnDef[] => [ +export const getInsightsColumns = (): MRT_ColumnDef[] => [ { header: Messages.columns.summary, accessorKey: 'summary', - enableColumnFilter: false, + enableSorting: false, size: 300, Cell: ({ row }) => ( @@ -73,33 +58,26 @@ export const getInsightsColumns = ( id: 'category', header: Messages.columns.category, accessorFn: (row) => capitalize(row.category), - filterVariant: 'select', - filterSelectOptions: categories.map((category) => ({ - label: capitalize(category), - value: category, - })), size: 140, }, { id: 'severity', header: Messages.columns.severity, accessorFn: (row) => SEVERITY[row.severity], - filterVariant: 'select', - filterSelectOptions: SEVERITY_OPTIONS, + sortingFn: (rowA, rowB) => + SEVERITY_ORDER[rowA.original.severity] - + SEVERITY_ORDER[rowB.original.severity], size: 130, }, { id: 'status', header: Messages.columns.status, accessorFn: (row) => ADVISOR_RESULT_STATUS[row.status], - filterVariant: 'select', - filterSelectOptions: STATUS_OPTIONS, size: 120, }, { header: Messages.columns.checkedAt, accessorKey: 'checkedAt', - enableColumnFilter: false, size: 160, Cell: ({ row }) => row.original.checkedAt @@ -110,8 +88,6 @@ export const getInsightsColumns = ( id: 'isRead', header: Messages.columns.read, accessorFn: (row) => (row.isRead ? Messages.read : Messages.unread), - filterVariant: 'select', - filterSelectOptions: READ_OPTIONS, size: 110, Cell: ({ row }) => ( ({ label: SEVERITY[severity], value: severity })); + +export const STATUS_FILTER_OPTIONS = [ + AdvisorCheckResultStatus.ok, + AdvisorCheckResultStatus.failed, + AdvisorCheckResultStatus.error, +].map((status) => ({ label: ADVISOR_RESULT_STATUS[status], value: status })); + +export const READ_FILTER_OPTIONS = [ + { label: Messages.read, value: 'true' }, + { label: Messages.unread, value: 'false' }, +]; diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index 0f665dbd3a7..060027e9476 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -8,6 +8,15 @@ export const Messages = { markUnread: 'Mark unread', read: 'Read', unread: 'Unread', + filters: { + all: 'All', + service: 'Service', + servicePlaceholder: 'Filter by service name', + category: 'Category', + severity: 'Severity', + status: 'Status', + read: 'Read', + }, columns: { summary: 'Summary', service: 'Service', diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 434917a6db4..40a48611f72 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -147,9 +147,12 @@ describe('AdvisorInsights', () => { ) ); - fireEvent.change(screen.getByPlaceholderText('Filter by Service'), { - target: { value: 'mysql-prod' }, - }); + fireEvent.change( + screen.getByPlaceholderText(Messages.filters.servicePlaceholder), + { + target: { value: 'mysql-prod' }, + } + ); await waitFor(() => expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( @@ -158,6 +161,38 @@ describe('AdvisorInsights', () => { ); }); + it('makes every column sortable except summary', async () => { + renderComponent(); + + await waitForRows(); + + // 'hidden' skips the visibility computation, which crashes in jsdom: + // nwsapi chokes on MRT's unescaped React useId in the pagination select + const summaryHeader = screen.getByRole('columnheader', { + name: Messages.columns.summary, + hidden: true, + }); + expect(summaryHeader.querySelector('.MuiTableSortLabel-root')).toBeNull(); + + for (const name of [ + Messages.columns.service, + Messages.columns.category, + Messages.columns.severity, + Messages.columns.status, + Messages.columns.checkedAt, + Messages.columns.read, + ]) { + // sortable headers embed the sort hint in the accessible name + const header = screen.getByRole('columnheader', { + name: new RegExp(name), + hidden: true, + }); + expect( + header.querySelector('.MuiTableSortLabel-root') + ).not.toBeNull(); + } + }); + it('marks an unread insight as read', async () => { renderComponent(); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 6186bee7c8f..0d791a28be5 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -1,13 +1,11 @@ -import { FC, useMemo, useState } from 'react'; +import { FC, useMemo, useRef, useState } from 'react'; import Button from '@mui/material/Button'; +import MenuItem from '@mui/material/MenuItem'; import Stack from '@mui/material/Stack'; +import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; import { Table } from '@percona/percona-ui'; -import { - type MRT_ColumnFiltersState, - type MRT_PaginationState, - type MRT_Updater, -} from 'material-react-table'; +import { type MRT_PaginationState } from 'material-react-table'; import { enqueueSnackbar } from 'notistack'; import { useSearchParams } from 'react-router-dom'; import { Page } from 'components/page'; @@ -23,8 +21,74 @@ import { } from 'types/advisors.types'; import { Severity } from 'types/severity.types'; import { OrgRole } from 'types/user.types'; +import { capitalize } from 'utils/text.utils'; import { Messages } from './AdvisorInsights.messages'; import { getInsightsColumns } from './AdvisorInsights.constants'; +import { + READ_FILTER_OPTIONS, + SEVERITY_FILTER_OPTIONS, + STATUS_FILTER_OPTIONS, +} from './AdvisorInsights.filters'; + +const SERVICE_FILTER_DEBOUNCE_MS = 400; + +interface InsightFilters { + serviceName: string; + category: string; + severity: string; + status: string; + isRead: string; +} + +const NO_FILTERS: InsightFilters = { + serviceName: '', + category: '', + severity: '', + status: '', + isRead: '', +}; + +interface FilterOption { + label: string; + value: string; +} + +interface FilterSelectProps { + id: string; + label: string; + options: FilterOption[]; + value: string; + onChange: (value: string) => void; +} + +const FilterSelect: FC = ({ + id, + label, + options, + value, + onChange, +}) => ( + + onChange(e.target.value === Messages.filters.all ? '' : e.target.value) + } + sx={{ minWidth: 140 }} + data-testid={`${id}-filter`} + > + {Messages.filters.all} + {options.map((option) => ( + + {option.label} + + ))} + +); const AdvisorInsights: FC = () => { const [searchParams] = useSearchParams(); @@ -34,46 +98,52 @@ const AdvisorInsights: FC = () => { pageIndex: 0, pageSize: 100, }); - const [columnFilters, setColumnFilters] = useState( - [] - ); + const [filters, setFilters] = useState(NO_FILTERS); + const [serviceInput, setServiceInput] = useState(''); + const serviceTimer = useRef>(); + + const updateFilter = (name: keyof InsightFilters, value: string) => { + setFilters((current) => ({ ...current, [name]: value })); + // filters change the result set, so start from the first page + setPagination((current) => ({ ...current, pageIndex: 0 })); + }; - const params = useMemo(() => { - const filterValue = (id: string) => - (columnFilters.find((filter) => filter.id === id)?.value as string) || - undefined; - const isRead = filterValue('isRead'); + const handleServiceInputChange = (value: string) => { + setServiceInput(value); + clearTimeout(serviceTimer.current); + serviceTimer.current = setTimeout( + () => updateFilter('serviceName', value), + SERVICE_FILTER_DEBOUNCE_MS + ); + }; - return { + const params = useMemo( + () => ({ pageIndex: pagination.pageIndex, pageSize: pagination.pageSize, runId, - serviceName: filterValue('serviceName'), - category: filterValue('category'), - severity: filterValue('severity') as Severity | undefined, - status: filterValue('status') as AdvisorCheckResultStatus | undefined, - isRead: isRead === undefined ? undefined : isRead === 'true', - }; - }, [pagination, columnFilters, runId]); + serviceName: filters.serviceName || undefined, + category: filters.category || undefined, + severity: (filters.severity as Severity) || undefined, + status: (filters.status as AdvisorCheckResultStatus) || undefined, + isRead: filters.isRead === '' ? undefined : filters.isRead === 'true', + }), + [pagination, filters, runId] + ); const { data, isLoading, isFetching } = useCheckResultsHistory(params); const { data: advisors = [] } = useAdvisors(); const { mutate: markRead, isPending: isMarking } = useMarkCheckResultsRead(); - const categories = useMemo( - () => [...new Set(advisors.map((advisor) => advisor.category))].sort(), + const categoryOptions = useMemo( + () => + [...new Set(advisors.map((advisor) => advisor.category))] + .sort() + .map((category) => ({ label: capitalize(category), value: category })), [advisors] ); - const columns = useMemo(() => getInsightsColumns(categories), [categories]); - - const handleColumnFiltersChange = ( - updater: MRT_Updater - ) => { - setColumnFilters(updater); - // filters change the result set, so start from the first page - setPagination((current) => ({ ...current, pageIndex: 0 })); - }; + const columns = useMemo(() => getInsightsColumns(), []); const handleToggleRead = (item: CheckResultHistoryItem) => markRead( @@ -98,6 +168,46 @@ const AdvisorInsights: FC = () => { > {Messages.description} + + handleServiceInputChange(e.target.value)} + sx={{ minWidth: 220 }} + data-testid="service-filter" + /> + updateFilter('category', value)} + /> + updateFilter('severity', value)} + /> + updateFilter('status', value)} + /> + updateFilter('isRead', value)} + /> +
{ rowCount={data?.totalItems ?? 0} noDataMessage={Messages.noData} manualPagination - manualFiltering enablePagination - enableSorting={false} enableGlobalFilter={false} + enableColumnFilters={false} + enableColumnActions={false} enableHiding={false} enableStickyHeader state={{ pagination, - columnFilters, isLoading, showProgressBars: isFetching && !isLoading, }} - initialState={{ - showColumnFilters: true, - }} onPaginationChange={setPagination} - onColumnFiltersChange={handleColumnFiltersChange} enableRowActions positionActionsColumn="last" renderRowActions={({ row }) => ( diff --git a/ui/apps/pmm/src/pages/settings/Settings.messages.ts b/ui/apps/pmm/src/pages/settings/Settings.messages.ts index 85b2f143f80..af704a89aac 100644 --- a/ui/apps/pmm/src/pages/settings/Settings.messages.ts +++ b/ui/apps/pmm/src/pages/settings/Settings.messages.ts @@ -32,11 +32,21 @@ export const Messages = { sttRareIntervalLabel: 'Rare', sttStandardIntervalLabel: 'Standard', sttFrequentIntervalLabel: 'Frequent', + sttCheckIntervalLabel: 'Check run interval', sttCheckIntervalTooltip: 'How often Advisor checks run. Lower values catch issues faster but increase resource usage.', advisorsLink: 'https://per.co.na/advisors', advisorsTooltip: 'Run automated checks to identify potential database performance and configuration issues.', + advisorRetentionLabel: 'Advisor history retention', + advisorRetentionTooltip: + 'How long PMM keeps Advisor check results history. Older results are automatically deleted.', + advisorNotificationsLabel: 'Advisor notifications', + advisorNotificationsTooltip: + 'Send email notifications when Advisor checks detect issues.', + advisorSeverityThresholdLabel: 'Notification severity threshold', + advisorSeverityThresholdTooltip: + 'Least-severe level that triggers a notification.', azureDiscoverLabel: 'Microsoft Azure monitoring', azureDiscoverTooltip: 'Option to enable/disable Microsoft Azure DB instances discovery and monitoring', diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts index 8986ccc602e..d0e9c68f125 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts @@ -1,3 +1,4 @@ +import { Severity } from 'types/severity.types'; import { Messages } from '../../Settings.messages'; export const SECONDS = 60; @@ -10,6 +11,19 @@ export const MAX_DAYS = 3650; export const MIN_STT_CHECK_INTERVAL = 0.1; export const STT_CHECK_INTERVAL_STEP = 0.1; export const DEFAULT_DATA_RETENTION = '86400s'; +// 30 days, matches the pmm-managed default +export const DEFAULT_ADVISOR_RETENTION = '2592000s'; + +export const ADVISOR_SEVERITY_OPTIONS = [ + Severity.emergency, + Severity.alert, + Severity.critical, + Severity.error, + Severity.warning, + Severity.notice, + Severity.info, + Severity.debug, +]; export const STT_CHECK_INTERVALS = [ { diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts index 2a407bd2f2c..cc4c59e7657 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { Severity } from 'types/severity.types'; import { Messages } from '../../Settings.messages'; import { MAX_DAYS, @@ -38,6 +39,9 @@ export const advancedSettingsSchema = z rareInterval: z.string(), standardInterval: z.string(), frequentInterval: z.string(), + advisorRetention: z.string(), + advisorNotifications: z.boolean(), + advisorSeverityThreshold: z.nativeEnum(Severity), azureDiscover: z.boolean(), accessControl: z.boolean(), }) @@ -60,6 +64,23 @@ export const advancedSettingsSchema = z }); } } + + // the API requires a multiple of 24h, so whole days only + const retention = data.advisorRetention; + const days = parseFloat(retention); + if (retention === '' || isNaN(days) || !Number.isInteger(days)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: required, + path: ['advisorRetention'], + }); + } else if (days < MIN_DAYS || days > MAX_DAYS) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: retentionRange(MIN_DAYS, MAX_DAYS), + path: ['advisorRetention'], + }); + } }); export type AdvancedSettingsFormValues = z.infer; diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx index 0acd16591d4..89842a1b6e3 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx +++ b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx @@ -12,7 +12,9 @@ import CloseIcon from '@mui/icons-material/Close'; import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import WarningIcon from '@mui/icons-material/Warning'; -import { TextInput, SwitchInput } from '@percona/percona-ui'; +import MenuItem from '@mui/material/MenuItem'; +import { TextInput, SwitchInput, SelectInput } from '@percona/percona-ui'; +import { SEVERITY } from 'lib/constants'; import { zodResolver } from '@hookform/resolvers/zod'; import { FC, useEffect, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; @@ -20,6 +22,7 @@ import { enqueueSnackbar } from 'notistack'; import { useUpdateSettings } from 'hooks/api/useSettings'; import { Messages } from '../../Settings.messages'; import { + ADVISOR_SEVERITY_OPTIONS, FEATURE_MANAGEMENT_SETTINGS, MAX_DAYS, MIN_DAYS, @@ -27,7 +30,6 @@ import { STT_CHECK_INTERVALS, TECHNICAL_PREVIEW_DOC_URL, } from './Advanced.constants'; -import { MAX_LABEL_WIDTH } from '../../Settings.constants'; import { AdvancedSettingsFormProps } from './AdvancedSettingsForm.types'; import { AdvancedSettingsFormValues, @@ -54,6 +56,7 @@ export const AdvancedSettingsForm: FC = ({ const { handleSubmit, reset, watch, setValue } = methods; const sttEnabled = watch('stt'); + const advisorNotificationsEnabled = watch('advisorNotifications'); const [telemetryDialogOpen, setTelemetryDialogOpen] = useState(false); useEffect(() => { @@ -282,13 +285,11 @@ export const AdvancedSettingsForm: FC = ({ {sttEnabled && ( - - {m.sttCheckIntervalTooltip} - + /> {STT_CHECK_INTERVALS.map(({ name, label }) => ( = ({ /> ))} + + + + + + + {m.retentionUnits} + + + + + + + + {advisorNotificationsEnabled && ( + + {ADVISOR_SEVERITY_OPTIONS.map((severity) => ( + + {SEVERITY[severity]} + + ))} + + )} + )} diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts new file mode 100644 index 00000000000..a940cb5dc8a --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts @@ -0,0 +1,63 @@ +import { describe, it, expect } from 'vitest'; +import { Settings } from 'types/settings.types'; +import { Severity } from 'types/severity.types'; +import { toFormValues, toPayload } from './AdvancedSettingsForm.utils'; + +const TEST_SETTINGS: Settings = { + updatesEnabled: true, + telemetryEnabled: true, + advisorEnabled: true, + alertingEnabled: true, + pmmPublicAddress: 'pmm.local', + backupManagementEnabled: false, + azurediscoverEnabled: false, + enableAccessControl: false, + dataRetention: '2592000s', + advisorHistoryRetention: '1209600s', + advisorNotificationsEnabled: true, + advisorNotificationSeverityThreshold: Severity.warning, +}; + +describe('toFormValues', () => { + it('maps advisor notification settings', () => { + const values = toFormValues(TEST_SETTINGS); + + expect(values.advisorRetention).toBe('14'); + expect(values.advisorNotifications).toBe(true); + expect(values.advisorSeverityThreshold).toBe(Severity.warning); + }); + + it('falls back to defaults when advisor settings are missing', () => { + const values = toFormValues({ + ...TEST_SETTINGS, + advisorHistoryRetention: undefined, + advisorNotificationsEnabled: undefined, + advisorNotificationSeverityThreshold: undefined, + }); + + expect(values.advisorRetention).toBe('30'); + expect(values.advisorNotifications).toBe(false); + expect(values.advisorSeverityThreshold).toBe(Severity.error); + }); + + it('treats unspecified severity threshold as the default', () => { + const values = toFormValues({ + ...TEST_SETTINGS, + advisorNotificationSeverityThreshold: Severity.unspecified, + }); + + expect(values.advisorSeverityThreshold).toBe(Severity.error); + }); +}); + +describe('toPayload', () => { + it('maps advisor notification settings back to the API shape', () => { + const payload = toPayload(toFormValues(TEST_SETTINGS)); + + expect(payload.advisorHistoryRetention).toBe('1209600s'); + expect(payload.enableAdvisorNotifications).toBe(true); + expect(payload.advisorNotificationSeverityThreshold).toBe( + Severity.warning + ); + }); +}); diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.ts b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.ts index 17d11c3daaa..e7148fe63bc 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.ts @@ -1,6 +1,11 @@ import { Settings, UpdateSettingsPayload } from 'types/settings.types'; +import { Severity } from 'types/severity.types'; import { AdvancedSettingsFormValues } from './AdvancedSettingsForm.schema'; -import { DEFAULT_DATA_RETENTION, SECONDS_IN_DAY } from './Advanced.constants'; +import { + DEFAULT_ADVISOR_RETENTION, + DEFAULT_DATA_RETENTION, + SECONDS_IN_DAY, +} from './Advanced.constants'; import { convertCheckIntervalsToHours, convertHoursStringToSeconds, @@ -22,6 +27,17 @@ export const toFormValues = ( publicAddress: settings.pmmPublicAddress, stt: settings.advisorEnabled, ...convertCheckIntervalsToHours(settings.advisorRunIntervals), + advisorRetention: String( + convertSecondsToDays( + settings.advisorHistoryRetention ?? DEFAULT_ADVISOR_RETENTION + ) || '1' + ), + advisorNotifications: settings.advisorNotificationsEnabled ?? false, + advisorSeverityThreshold: + settings.advisorNotificationSeverityThreshold && + settings.advisorNotificationSeverityThreshold !== Severity.unspecified + ? settings.advisorNotificationSeverityThreshold + : Severity.error, azureDiscover: settings.azurediscoverEnabled, accessControl: settings.enableAccessControl, }); @@ -48,6 +64,9 @@ export const toPayload = ( enableInternalPgQan: values.enableInternalPgQan, enableAdvisor: values.stt, advisorRunIntervals, + advisorHistoryRetention: `${Math.round(parseFloat(values.advisorRetention)) * SECONDS_IN_DAY}s`, + enableAdvisorNotifications: values.advisorNotifications, + advisorNotificationSeverityThreshold: values.advisorSeverityThreshold, enableAzurediscover: values.azureDiscover, enableAccessControl: values.accessControl, }; diff --git a/ui/apps/pmm/src/types/settings.types.ts b/ui/apps/pmm/src/types/settings.types.ts index 56d302bab95..53acfc08af3 100644 --- a/ui/apps/pmm/src/types/settings.types.ts +++ b/ui/apps/pmm/src/types/settings.types.ts @@ -1,3 +1,5 @@ +import { Severity } from './severity.types'; + export interface ReadonlySettings { updatesEnabled: boolean; telemetryEnabled: boolean; @@ -32,6 +34,9 @@ export interface Settings extends ReadonlySettings { sshKey?: string; awsPartitions?: string[]; advisorRunIntervals?: AdvisorRunIntervals; + advisorHistoryRetention?: string; + advisorNotificationsEnabled?: boolean; + advisorNotificationSeverityThreshold?: Severity; telemetrySummaries?: string[]; enableInternalPgQan?: boolean; defaultRoleId?: number; @@ -47,6 +52,9 @@ export interface UpdateSettingsPayload { enableAlerting?: boolean; enableAdvisor?: boolean; advisorRunIntervals?: AdvisorRunIntervals; + advisorHistoryRetention?: string; + enableAdvisorNotifications?: boolean; + advisorNotificationSeverityThreshold?: Severity; enableBackupManagement?: boolean; enableAzurediscover?: boolean; enableUpdates?: boolean; From bdebeda379383d1d300b6e65eeb5217c6b26c324 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 5 Jul 2026 22:13:51 +0300 Subject: [PATCH 024/120] PMM-14190 Enhance Advisor Insights with more filtering options --- api/advisors/v1/advisors.pb.go | 236 ++++++--- api/advisors/v1/advisors.pb.gw.go | 92 +++- api/advisors/v1/advisors.pb.validate.go | 212 ++++++++ api/advisors/v1/advisors.proto | 17 + api/advisors/v1/advisors_grpc.pb.go | 57 ++- .../advisor_service/advisor_service_client.go | 46 ++ ..._check_results_filter_values_parameters.go | 124 +++++ ...t_check_results_filter_values_responses.go | 453 ++++++++++++++++++ api/advisors/v1/json/v1.json | 67 +++ api/descriptor.bin | Bin 828035 -> 829183 bytes api/swagger/swagger-dev.json | 67 +++ api/swagger/swagger.json | 67 +++ managed/models/check_result_helpers.go | 55 ++- managed/models/check_result_helpers_test.go | 72 ++- managed/services/checks/checks.go | 18 +- managed/services/management/checks.go | 16 + managed/services/management/checks_test.go | 35 ++ managed/services/management/deps.go | 1 + .../management/mock_checks_service_test.go | 39 ++ managed/utils/clean/check_results.go | 6 +- managed/utils/clean/check_results_test.go | 8 +- ui/apps/pmm/src/api/advisors.ts | 9 + ui/apps/pmm/src/hooks/api/useAdvisors.ts | 12 + .../insights/AdvisorInsights.messages.ts | 6 +- .../insights/AdvisorInsights.test.tsx | 97 +++- .../advisors/insights/AdvisorInsights.tsx | 103 +++- ui/apps/pmm/src/types/advisors.types.ts | 5 + 27 files changed, 1751 insertions(+), 169 deletions(-) create mode 100644 api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_responses.go diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index 63139153449..4a6e8b094be 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -1789,6 +1789,96 @@ func (x *ListCheckResultsHistoryResponse) GetResults() []*CheckResultHistoryItem return nil } +type ListCheckResultsFilterValuesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListCheckResultsFilterValuesRequest) Reset() { + *x = ListCheckResultsFilterValuesRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListCheckResultsFilterValuesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListCheckResultsFilterValuesRequest) ProtoMessage() {} + +func (x *ListCheckResultsFilterValuesRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListCheckResultsFilterValuesRequest.ProtoReflect.Descriptor instead. +func (*ListCheckResultsFilterValuesRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{21} +} + +type ListCheckResultsFilterValuesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Distinct service names present in the check results history, sorted alphabetically. + ServiceNames []string `protobuf:"bytes,1,rep,name=service_names,json=serviceNames,proto3" json:"service_names,omitempty"` + // Distinct node names present in the check results history, sorted alphabetically. + NodeNames []string `protobuf:"bytes,2,rep,name=node_names,json=nodeNames,proto3" json:"node_names,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListCheckResultsFilterValuesResponse) Reset() { + *x = ListCheckResultsFilterValuesResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListCheckResultsFilterValuesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListCheckResultsFilterValuesResponse) ProtoMessage() {} + +func (x *ListCheckResultsFilterValuesResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListCheckResultsFilterValuesResponse.ProtoReflect.Descriptor instead. +func (*ListCheckResultsFilterValuesResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{22} +} + +func (x *ListCheckResultsFilterValuesResponse) GetServiceNames() []string { + if x != nil { + return x.ServiceNames + } + return nil +} + +func (x *ListCheckResultsFilterValuesResponse) GetNodeNames() []string { + if x != nil { + return x.NodeNames + } + return nil +} + type MarkCheckResultsReadRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // IDs of the history records to update. @@ -1801,7 +1891,7 @@ type MarkCheckResultsReadRequest struct { func (x *MarkCheckResultsReadRequest) Reset() { *x = MarkCheckResultsReadRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[21] + mi := &file_advisors_v1_advisors_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1813,7 +1903,7 @@ func (x *MarkCheckResultsReadRequest) String() string { func (*MarkCheckResultsReadRequest) ProtoMessage() {} func (x *MarkCheckResultsReadRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[21] + mi := &file_advisors_v1_advisors_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1826,7 +1916,7 @@ func (x *MarkCheckResultsReadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkCheckResultsReadRequest.ProtoReflect.Descriptor instead. func (*MarkCheckResultsReadRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{21} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{23} } func (x *MarkCheckResultsReadRequest) GetIds() []string { @@ -1851,7 +1941,7 @@ type MarkCheckResultsReadResponse struct { func (x *MarkCheckResultsReadResponse) Reset() { *x = MarkCheckResultsReadResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[22] + mi := &file_advisors_v1_advisors_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1863,7 +1953,7 @@ func (x *MarkCheckResultsReadResponse) String() string { func (*MarkCheckResultsReadResponse) ProtoMessage() {} func (x *MarkCheckResultsReadResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[22] + mi := &file_advisors_v1_advisors_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1876,7 +1966,7 @@ func (x *MarkCheckResultsReadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkCheckResultsReadResponse.ProtoReflect.Descriptor instead. func (*MarkCheckResultsReadResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{22} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{24} } var File_advisors_v1_advisors_proto protoreflect.FileDescriptor @@ -2037,7 +2127,12 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "totalItems\x12\x1f\n" + "\vtotal_pages\x18\x02 \x01(\x05R\n" + "totalPages\x12=\n" + - "\aresults\x18\x03 \x03(\v2#.advisors.v1.CheckResultHistoryItemR\aresults\"R\n" + + "\aresults\x18\x03 \x03(\v2#.advisors.v1.CheckResultHistoryItemR\aresults\"%\n" + + "#ListCheckResultsFilterValuesRequest\"j\n" + + "$ListCheckResultsFilterValuesResponse\x12#\n" + + "\rservice_names\x18\x01 \x03(\tR\fserviceNames\x12\x1d\n" + + "\n" + + "node_names\x18\x02 \x03(\tR\tnodeNames\"R\n" + "\x1bMarkCheckResultsReadRequest\x12\x1a\n" + "\x03ids\x18\x01 \x03(\tB\b\xfaB\x05\x92\x01\x02\b\x01R\x03ids\x12\x17\n" + "\ais_read\x18\x02 \x01(\bR\x06isRead\"\x1e\n" + @@ -2060,11 +2155,12 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\x17AdvisorCheckTriggeredBy\x12*\n" + "&ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED\x10\x00\x12#\n" + "\x1fADVISOR_CHECK_TRIGGERED_BY_USER\x10\x01\x12(\n" + - "$ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER\x10\x022\xac\x0f\n" + + "$ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER\x10\x022\x8f\x12\n" + "\x0eAdvisorService\x12\xf3\x01\n" + "\x12ListFailedServices\x12&.advisors.v1.ListFailedServicesRequest\x1a'.advisors.v1.ListFailedServicesResponse\"\x8b\x01\x92Ae\x12\x14List Failed Services\x1aMReturns a list of services with failed checks and a summary of check results.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/failedServices\x12\xd5\x01\n" + "\x0fGetFailedChecks\x12#.advisors.v1.GetFailedChecksRequest\x1a$.advisors.v1.GetFailedChecksResponse\"w\x92AR\x12\x19Get Failed Advisor Checks\x1a5Returns the latest check results for a given service.\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/advisors/checks/failed\x12\x87\x02\n" + - "\x17ListCheckResultsHistory\x12+.advisors.v1.ListCheckResultsHistoryRequest\x1a,.advisors.v1.ListCheckResultsHistoryResponse\"\x90\x01\x92Aj\x12\"List Advisor Check Results History\x1aDReturns the history of Advisor check runs, including their outcomes.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/checks/history\x12\xb1\x02\n" + + "\x17ListCheckResultsHistory\x12+.advisors.v1.ListCheckResultsHistoryRequest\x1a,.advisors.v1.ListCheckResultsHistoryResponse\"\x90\x01\x92Aj\x12\"List Advisor Check Results History\x1aDReturns the history of Advisor check runs, including their outcomes.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/checks/history\x12\xe0\x02\n" + + "\x1cListCheckResultsFilterValues\x120.advisors.v1.ListCheckResultsFilterValuesRequest\x1a1.advisors.v1.ListCheckResultsFilterValuesResponse\"\xda\x01\x92A\xa6\x01\x12(List Advisor Check Results Filter Values\x1azReturns the distinct service and node names present in the Advisor check results history, for populating filter dropdowns.\x82\xd3\xe4\x93\x02*\x12(/v1/advisors/checks/history:filterValues\x12\xb1\x02\n" + "\x14MarkCheckResultsRead\x12(.advisors.v1.MarkCheckResultsReadRequest\x1a).advisors.v1.MarkCheckResultsReadResponse\"\xc3\x01\x92A\x90\x01\x12\x1fMark Advisor Check Results Read\x1amSets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.\x82\xd3\xe4\x93\x02):\x01*\"$/v1/advisors/checks/history:markRead\x12\xb0\x02\n" + "\x12StartAdvisorChecks\x12&.advisors.v1.StartAdvisorChecksRequest\x1a'.advisors.v1.StartAdvisorChecksResponse\"\xc8\x01\x92A\xa0\x01\x12\x14Start Advisor Checks\x1a\x87\x01Executes Advisor checks and returns when all checks are executed. All available checks will be started if check names aren't specified.\x82\xd3\xe4\x93\x02\x1e:\x01*\"\x19/v1/advisors/checks:start\x12\xc3\x01\n" + "\x11ListAdvisorChecks\x12%.advisors.v1.ListAdvisorChecksRequest\x1a&.advisors.v1.ListAdvisorChecksResponse\"_\x92AA\x12\x13List Advisor Checks\x1a*List advisor checks available to the user.\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/advisors/checks\x12\xa1\x01\n" + @@ -2086,48 +2182,50 @@ func file_advisors_v1_advisors_proto_rawDescGZIP() []byte { var ( file_advisors_v1_advisors_proto_enumTypes = make([]protoimpl.EnumInfo, 4) - file_advisors_v1_advisors_proto_msgTypes = make([]protoimpl.MessageInfo, 26) + file_advisors_v1_advisors_proto_msgTypes = make([]protoimpl.MessageInfo, 28) file_advisors_v1_advisors_proto_goTypes = []any{ - AdvisorCheckInterval(0), // 0: advisors.v1.AdvisorCheckInterval - AdvisorCheckFamily(0), // 1: advisors.v1.AdvisorCheckFamily - AdvisorCheckResultStatus(0), // 2: advisors.v1.AdvisorCheckResultStatus - AdvisorCheckTriggeredBy(0), // 3: advisors.v1.AdvisorCheckTriggeredBy - (*AdvisorCheckResult)(nil), // 4: advisors.v1.AdvisorCheckResult - (*CheckResultSummary)(nil), // 5: advisors.v1.CheckResultSummary - (*CheckResult)(nil), // 6: advisors.v1.CheckResult - (*AdvisorCheck)(nil), // 7: advisors.v1.AdvisorCheck - (*Advisor)(nil), // 8: advisors.v1.Advisor - (*ChangeAdvisorCheckParams)(nil), // 9: advisors.v1.ChangeAdvisorCheckParams - (*StartAdvisorChecksRequest)(nil), // 10: advisors.v1.StartAdvisorChecksRequest - (*StartAdvisorChecksResponse)(nil), // 11: advisors.v1.StartAdvisorChecksResponse - (*ListAdvisorChecksRequest)(nil), // 12: advisors.v1.ListAdvisorChecksRequest - (*ListAdvisorChecksResponse)(nil), // 13: advisors.v1.ListAdvisorChecksResponse - (*ListAdvisorsRequest)(nil), // 14: advisors.v1.ListAdvisorsRequest - (*ListAdvisorsResponse)(nil), // 15: advisors.v1.ListAdvisorsResponse - (*ChangeAdvisorChecksRequest)(nil), // 16: advisors.v1.ChangeAdvisorChecksRequest - (*ChangeAdvisorChecksResponse)(nil), // 17: advisors.v1.ChangeAdvisorChecksResponse - (*ListFailedServicesRequest)(nil), // 18: advisors.v1.ListFailedServicesRequest - (*ListFailedServicesResponse)(nil), // 19: advisors.v1.ListFailedServicesResponse - (*GetFailedChecksRequest)(nil), // 20: advisors.v1.GetFailedChecksRequest - (*GetFailedChecksResponse)(nil), // 21: advisors.v1.GetFailedChecksResponse - (*CheckResultHistoryItem)(nil), // 22: advisors.v1.CheckResultHistoryItem - (*ListCheckResultsHistoryRequest)(nil), // 23: advisors.v1.ListCheckResultsHistoryRequest - (*ListCheckResultsHistoryResponse)(nil), // 24: advisors.v1.ListCheckResultsHistoryResponse - (*MarkCheckResultsReadRequest)(nil), // 25: advisors.v1.MarkCheckResultsReadRequest - (*MarkCheckResultsReadResponse)(nil), // 26: advisors.v1.MarkCheckResultsReadResponse - nil, // 27: advisors.v1.AdvisorCheckResult.LabelsEntry - nil, // 28: advisors.v1.CheckResult.LabelsEntry - nil, // 29: advisors.v1.CheckResultHistoryItem.LabelsEntry - v1.Severity(0), // 30: management.v1.Severity - (*timestamppb.Timestamp)(nil), // 31: google.protobuf.Timestamp + AdvisorCheckInterval(0), // 0: advisors.v1.AdvisorCheckInterval + AdvisorCheckFamily(0), // 1: advisors.v1.AdvisorCheckFamily + AdvisorCheckResultStatus(0), // 2: advisors.v1.AdvisorCheckResultStatus + AdvisorCheckTriggeredBy(0), // 3: advisors.v1.AdvisorCheckTriggeredBy + (*AdvisorCheckResult)(nil), // 4: advisors.v1.AdvisorCheckResult + (*CheckResultSummary)(nil), // 5: advisors.v1.CheckResultSummary + (*CheckResult)(nil), // 6: advisors.v1.CheckResult + (*AdvisorCheck)(nil), // 7: advisors.v1.AdvisorCheck + (*Advisor)(nil), // 8: advisors.v1.Advisor + (*ChangeAdvisorCheckParams)(nil), // 9: advisors.v1.ChangeAdvisorCheckParams + (*StartAdvisorChecksRequest)(nil), // 10: advisors.v1.StartAdvisorChecksRequest + (*StartAdvisorChecksResponse)(nil), // 11: advisors.v1.StartAdvisorChecksResponse + (*ListAdvisorChecksRequest)(nil), // 12: advisors.v1.ListAdvisorChecksRequest + (*ListAdvisorChecksResponse)(nil), // 13: advisors.v1.ListAdvisorChecksResponse + (*ListAdvisorsRequest)(nil), // 14: advisors.v1.ListAdvisorsRequest + (*ListAdvisorsResponse)(nil), // 15: advisors.v1.ListAdvisorsResponse + (*ChangeAdvisorChecksRequest)(nil), // 16: advisors.v1.ChangeAdvisorChecksRequest + (*ChangeAdvisorChecksResponse)(nil), // 17: advisors.v1.ChangeAdvisorChecksResponse + (*ListFailedServicesRequest)(nil), // 18: advisors.v1.ListFailedServicesRequest + (*ListFailedServicesResponse)(nil), // 19: advisors.v1.ListFailedServicesResponse + (*GetFailedChecksRequest)(nil), // 20: advisors.v1.GetFailedChecksRequest + (*GetFailedChecksResponse)(nil), // 21: advisors.v1.GetFailedChecksResponse + (*CheckResultHistoryItem)(nil), // 22: advisors.v1.CheckResultHistoryItem + (*ListCheckResultsHistoryRequest)(nil), // 23: advisors.v1.ListCheckResultsHistoryRequest + (*ListCheckResultsHistoryResponse)(nil), // 24: advisors.v1.ListCheckResultsHistoryResponse + (*ListCheckResultsFilterValuesRequest)(nil), // 25: advisors.v1.ListCheckResultsFilterValuesRequest + (*ListCheckResultsFilterValuesResponse)(nil), // 26: advisors.v1.ListCheckResultsFilterValuesResponse + (*MarkCheckResultsReadRequest)(nil), // 27: advisors.v1.MarkCheckResultsReadRequest + (*MarkCheckResultsReadResponse)(nil), // 28: advisors.v1.MarkCheckResultsReadResponse + nil, // 29: advisors.v1.AdvisorCheckResult.LabelsEntry + nil, // 30: advisors.v1.CheckResult.LabelsEntry + nil, // 31: advisors.v1.CheckResultHistoryItem.LabelsEntry + v1.Severity(0), // 32: management.v1.Severity + (*timestamppb.Timestamp)(nil), // 33: google.protobuf.Timestamp } ) var file_advisors_v1_advisors_proto_depIdxs = []int32{ - 30, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity - 27, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry - 30, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity - 28, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry + 32, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity + 29, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry + 32, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity + 30, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry 0, // 4: advisors.v1.AdvisorCheck.interval:type_name -> advisors.v1.AdvisorCheckInterval 1, // 5: advisors.v1.AdvisorCheck.family:type_name -> advisors.v1.AdvisorCheckFamily 7, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck @@ -2139,34 +2237,36 @@ var file_advisors_v1_advisors_proto_depIdxs = []int32{ 6, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult 0, // 13: advisors.v1.CheckResultHistoryItem.interval:type_name -> advisors.v1.AdvisorCheckInterval 2, // 14: advisors.v1.CheckResultHistoryItem.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 30, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity - 29, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry - 31, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp + 32, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity + 31, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry + 33, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp 3, // 18: advisors.v1.CheckResultHistoryItem.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy 2, // 19: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 31, // 20: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp - 31, // 21: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp - 30, // 22: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity + 33, // 20: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp + 33, // 21: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp + 32, // 22: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity 3, // 23: advisors.v1.ListCheckResultsHistoryRequest.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy 22, // 24: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem 18, // 25: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest 20, // 26: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest 23, // 27: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest - 25, // 28: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest - 10, // 29: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest - 12, // 30: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest - 14, // 31: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest - 16, // 32: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest - 19, // 33: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse - 21, // 34: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse - 24, // 35: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse - 26, // 36: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse - 11, // 37: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse - 13, // 38: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse - 15, // 39: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse - 17, // 40: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse - 33, // [33:41] is the sub-list for method output_type - 25, // [25:33] is the sub-list for method input_type + 25, // 28: advisors.v1.AdvisorService.ListCheckResultsFilterValues:input_type -> advisors.v1.ListCheckResultsFilterValuesRequest + 27, // 29: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest + 10, // 30: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest + 12, // 31: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest + 14, // 32: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest + 16, // 33: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest + 19, // 34: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse + 21, // 35: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse + 24, // 36: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse + 26, // 37: advisors.v1.AdvisorService.ListCheckResultsFilterValues:output_type -> advisors.v1.ListCheckResultsFilterValuesResponse + 28, // 38: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse + 11, // 39: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse + 13, // 40: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse + 15, // 41: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse + 17, // 42: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse + 34, // [34:43] is the sub-list for method output_type + 25, // [25:34] is the sub-list for method input_type 25, // [25:25] is the sub-list for extension type_name 25, // [25:25] is the sub-list for extension extendee 0, // [0:25] is the sub-list for field type_name @@ -2186,7 +2286,7 @@ func file_advisors_v1_advisors_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_advisors_v1_advisors_proto_rawDesc), len(file_advisors_v1_advisors_proto_rawDesc)), NumEnums: 4, - NumMessages: 26, + NumMessages: 28, NumExtensions: 0, NumServices: 1, }, diff --git a/api/advisors/v1/advisors.pb.gw.go b/api/advisors/v1/advisors.pb.gw.go index fff3231a1ab..15f60fabae3 100644 --- a/api/advisors/v1/advisors.pb.gw.go +++ b/api/advisors/v1/advisors.pb.gw.go @@ -126,6 +126,27 @@ func local_request_AdvisorService_ListCheckResultsHistory_0(ctx context.Context, return msg, metadata, err } +func request_AdvisorService_ListCheckResultsFilterValues_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListCheckResultsFilterValuesRequest + metadata runtime.ServerMetadata + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.ListCheckResultsFilterValues(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_ListCheckResultsFilterValues_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq ListCheckResultsFilterValuesRequest + metadata runtime.ServerMetadata + ) + msg, err := server.ListCheckResultsFilterValues(ctx, &protoReq) + return msg, metadata, err +} + func request_AdvisorService_MarkCheckResultsRead_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq MarkCheckResultsReadRequest @@ -315,6 +336,26 @@ func RegisterAdvisorServiceHandlerServer(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ListCheckResultsHistory_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_ListCheckResultsFilterValues_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/ListCheckResultsFilterValues", runtime.WithHTTPPathPattern("/v1/advisors/checks/history:filterValues")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_ListCheckResultsFilterValues_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_ListCheckResultsFilterValues_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_AdvisorService_MarkCheckResultsRead_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -506,6 +547,23 @@ func RegisterAdvisorServiceHandlerClient(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ListCheckResultsHistory_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_ListCheckResultsFilterValues_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/ListCheckResultsFilterValues", runtime.WithHTTPPathPattern("/v1/advisors/checks/history:filterValues")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_ListCheckResultsFilterValues_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_ListCheckResultsFilterValues_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodPost, pattern_AdvisorService_MarkCheckResultsRead_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -595,23 +653,25 @@ func RegisterAdvisorServiceHandlerClient(ctx context.Context, mux *runtime.Serve } var ( - pattern_AdvisorService_ListFailedServices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "failedServices"}, "")) - pattern_AdvisorService_GetFailedChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "failed"}, "")) - pattern_AdvisorService_ListCheckResultsHistory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "")) - pattern_AdvisorService_MarkCheckResultsRead_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "markRead")) - pattern_AdvisorService_StartAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "start")) - pattern_AdvisorService_ListAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "")) - pattern_AdvisorService_ListAdvisors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "advisors"}, "")) - pattern_AdvisorService_ChangeAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "batchChange")) + pattern_AdvisorService_ListFailedServices_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "failedServices"}, "")) + pattern_AdvisorService_GetFailedChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "failed"}, "")) + pattern_AdvisorService_ListCheckResultsHistory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "")) + pattern_AdvisorService_ListCheckResultsFilterValues_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "filterValues")) + pattern_AdvisorService_MarkCheckResultsRead_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "markRead")) + pattern_AdvisorService_StartAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "start")) + pattern_AdvisorService_ListAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "")) + pattern_AdvisorService_ListAdvisors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "advisors"}, "")) + pattern_AdvisorService_ChangeAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "batchChange")) ) var ( - forward_AdvisorService_ListFailedServices_0 = runtime.ForwardResponseMessage - forward_AdvisorService_GetFailedChecks_0 = runtime.ForwardResponseMessage - forward_AdvisorService_ListCheckResultsHistory_0 = runtime.ForwardResponseMessage - forward_AdvisorService_MarkCheckResultsRead_0 = runtime.ForwardResponseMessage - forward_AdvisorService_StartAdvisorChecks_0 = runtime.ForwardResponseMessage - forward_AdvisorService_ListAdvisorChecks_0 = runtime.ForwardResponseMessage - forward_AdvisorService_ListAdvisors_0 = runtime.ForwardResponseMessage - forward_AdvisorService_ChangeAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListFailedServices_0 = runtime.ForwardResponseMessage + forward_AdvisorService_GetFailedChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListCheckResultsHistory_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListCheckResultsFilterValues_0 = runtime.ForwardResponseMessage + forward_AdvisorService_MarkCheckResultsRead_0 = runtime.ForwardResponseMessage + forward_AdvisorService_StartAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ListAdvisors_0 = runtime.ForwardResponseMessage + forward_AdvisorService_ChangeAdvisorChecks_0 = runtime.ForwardResponseMessage ) diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 570511b8501..46976e924c6 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -2730,6 +2730,218 @@ var _ interface { ErrorName() string } = ListCheckResultsHistoryResponseValidationError{} +// Validate checks the field values on ListCheckResultsFilterValuesRequest with +// the rules defined in the proto definition for this message. If any rules +// are violated, the first error encountered is returned, or nil if there are +// no violations. +func (m *ListCheckResultsFilterValuesRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListCheckResultsFilterValuesRequest +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// ListCheckResultsFilterValuesRequestMultiError, or nil if none found. +func (m *ListCheckResultsFilterValuesRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *ListCheckResultsFilterValuesRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return ListCheckResultsFilterValuesRequestMultiError(errors) + } + + return nil +} + +// ListCheckResultsFilterValuesRequestMultiError is an error wrapping multiple +// validation errors returned by +// ListCheckResultsFilterValuesRequest.ValidateAll() if the designated +// constraints aren't met. +type ListCheckResultsFilterValuesRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListCheckResultsFilterValuesRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListCheckResultsFilterValuesRequestMultiError) AllErrors() []error { return m } + +// ListCheckResultsFilterValuesRequestValidationError is the validation error +// returned by ListCheckResultsFilterValuesRequest.Validate if the designated +// constraints aren't met. +type ListCheckResultsFilterValuesRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListCheckResultsFilterValuesRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListCheckResultsFilterValuesRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListCheckResultsFilterValuesRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListCheckResultsFilterValuesRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListCheckResultsFilterValuesRequestValidationError) ErrorName() string { + return "ListCheckResultsFilterValuesRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e ListCheckResultsFilterValuesRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListCheckResultsFilterValuesRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListCheckResultsFilterValuesRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListCheckResultsFilterValuesRequestValidationError{} + +// Validate checks the field values on ListCheckResultsFilterValuesResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the first error encountered is returned, or nil if +// there are no violations. +func (m *ListCheckResultsFilterValuesResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on ListCheckResultsFilterValuesResponse +// with the rules defined in the proto definition for this message. If any +// rules are violated, the result is a list of violation errors wrapped in +// ListCheckResultsFilterValuesResponseMultiError, or nil if none found. +func (m *ListCheckResultsFilterValuesResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *ListCheckResultsFilterValuesResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return ListCheckResultsFilterValuesResponseMultiError(errors) + } + + return nil +} + +// ListCheckResultsFilterValuesResponseMultiError is an error wrapping multiple +// validation errors returned by +// ListCheckResultsFilterValuesResponse.ValidateAll() if the designated +// constraints aren't met. +type ListCheckResultsFilterValuesResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m ListCheckResultsFilterValuesResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m ListCheckResultsFilterValuesResponseMultiError) AllErrors() []error { return m } + +// ListCheckResultsFilterValuesResponseValidationError is the validation error +// returned by ListCheckResultsFilterValuesResponse.Validate if the designated +// constraints aren't met. +type ListCheckResultsFilterValuesResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ListCheckResultsFilterValuesResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ListCheckResultsFilterValuesResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ListCheckResultsFilterValuesResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ListCheckResultsFilterValuesResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ListCheckResultsFilterValuesResponseValidationError) ErrorName() string { + return "ListCheckResultsFilterValuesResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e ListCheckResultsFilterValuesResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sListCheckResultsFilterValuesResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = ListCheckResultsFilterValuesResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ListCheckResultsFilterValuesResponseValidationError{} + // Validate checks the field values on MarkCheckResultsReadRequest with the // rules defined in the proto definition for this message. If any rules are // violated, the first error encountered is returned, or nil if there are no violations. diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index 19ecf4ca367..0f3145b6761 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -271,6 +271,15 @@ message ListCheckResultsHistoryResponse { repeated CheckResultHistoryItem results = 3; } +message ListCheckResultsFilterValuesRequest {} + +message ListCheckResultsFilterValuesResponse { + // Distinct service names present in the check results history, sorted alphabetically. + repeated string service_names = 1; + // Distinct node names present in the check results history, sorted alphabetically. + repeated string node_names = 2; +} + message MarkCheckResultsReadRequest { // IDs of the history records to update. repeated string ids = 1 [(validate.rules).repeated.min_items = 1]; @@ -306,6 +315,14 @@ service AdvisorService { description: "Returns the history of Advisor check runs, including their outcomes." }; } + // ListCheckResultsFilterValues returns the distinct values usable as history filters. + rpc ListCheckResultsFilterValues(ListCheckResultsFilterValuesRequest) returns (ListCheckResultsFilterValuesResponse) { + option (google.api.http) = {get: "/v1/advisors/checks/history:filterValues"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "List Advisor Check Results Filter Values" + description: "Returns the distinct service and node names present in the Advisor check results history, for populating filter dropdowns." + }; + } // MarkCheckResultsRead sets the read state on Advisor check history records. rpc MarkCheckResultsRead(MarkCheckResultsReadRequest) returns (MarkCheckResultsReadResponse) { option (google.api.http) = { diff --git a/api/advisors/v1/advisors_grpc.pb.go b/api/advisors/v1/advisors_grpc.pb.go index 11092635e35..86453aeeb6c 100644 --- a/api/advisors/v1/advisors_grpc.pb.go +++ b/api/advisors/v1/advisors_grpc.pb.go @@ -20,14 +20,15 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - AdvisorService_ListFailedServices_FullMethodName = "/advisors.v1.AdvisorService/ListFailedServices" - AdvisorService_GetFailedChecks_FullMethodName = "/advisors.v1.AdvisorService/GetFailedChecks" - AdvisorService_ListCheckResultsHistory_FullMethodName = "/advisors.v1.AdvisorService/ListCheckResultsHistory" - AdvisorService_MarkCheckResultsRead_FullMethodName = "/advisors.v1.AdvisorService/MarkCheckResultsRead" - AdvisorService_StartAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/StartAdvisorChecks" - AdvisorService_ListAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisorChecks" - AdvisorService_ListAdvisors_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisors" - AdvisorService_ChangeAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ChangeAdvisorChecks" + AdvisorService_ListFailedServices_FullMethodName = "/advisors.v1.AdvisorService/ListFailedServices" + AdvisorService_GetFailedChecks_FullMethodName = "/advisors.v1.AdvisorService/GetFailedChecks" + AdvisorService_ListCheckResultsHistory_FullMethodName = "/advisors.v1.AdvisorService/ListCheckResultsHistory" + AdvisorService_ListCheckResultsFilterValues_FullMethodName = "/advisors.v1.AdvisorService/ListCheckResultsFilterValues" + AdvisorService_MarkCheckResultsRead_FullMethodName = "/advisors.v1.AdvisorService/MarkCheckResultsRead" + AdvisorService_StartAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/StartAdvisorChecks" + AdvisorService_ListAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisorChecks" + AdvisorService_ListAdvisors_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisors" + AdvisorService_ChangeAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ChangeAdvisorChecks" ) // AdvisorServiceClient is the client API for AdvisorService service. @@ -42,6 +43,8 @@ type AdvisorServiceClient interface { GetFailedChecks(ctx context.Context, in *GetFailedChecksRequest, opts ...grpc.CallOption) (*GetFailedChecksResponse, error) // ListCheckResultsHistory returns the history of Advisor check runs. ListCheckResultsHistory(ctx context.Context, in *ListCheckResultsHistoryRequest, opts ...grpc.CallOption) (*ListCheckResultsHistoryResponse, error) + // ListCheckResultsFilterValues returns the distinct values usable as history filters. + ListCheckResultsFilterValues(ctx context.Context, in *ListCheckResultsFilterValuesRequest, opts ...grpc.CallOption) (*ListCheckResultsFilterValuesResponse, error) // MarkCheckResultsRead sets the read state on Advisor check history records. MarkCheckResultsRead(ctx context.Context, in *MarkCheckResultsReadRequest, opts ...grpc.CallOption) (*MarkCheckResultsReadResponse, error) // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. @@ -92,6 +95,16 @@ func (c *advisorServiceClient) ListCheckResultsHistory(ctx context.Context, in * return out, nil } +func (c *advisorServiceClient) ListCheckResultsFilterValues(ctx context.Context, in *ListCheckResultsFilterValuesRequest, opts ...grpc.CallOption) (*ListCheckResultsFilterValuesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListCheckResultsFilterValuesResponse) + err := c.cc.Invoke(ctx, AdvisorService_ListCheckResultsFilterValues_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *advisorServiceClient) MarkCheckResultsRead(ctx context.Context, in *MarkCheckResultsReadRequest, opts ...grpc.CallOption) (*MarkCheckResultsReadResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MarkCheckResultsReadResponse) @@ -154,6 +167,8 @@ type AdvisorServiceServer interface { GetFailedChecks(context.Context, *GetFailedChecksRequest) (*GetFailedChecksResponse, error) // ListCheckResultsHistory returns the history of Advisor check runs. ListCheckResultsHistory(context.Context, *ListCheckResultsHistoryRequest) (*ListCheckResultsHistoryResponse, error) + // ListCheckResultsFilterValues returns the distinct values usable as history filters. + ListCheckResultsFilterValues(context.Context, *ListCheckResultsFilterValuesRequest) (*ListCheckResultsFilterValuesResponse, error) // MarkCheckResultsRead sets the read state on Advisor check history records. MarkCheckResultsRead(context.Context, *MarkCheckResultsReadRequest) (*MarkCheckResultsReadResponse, error) // StartAdvisorChecks executes Advisor checks and returns when all checks are executed. @@ -186,6 +201,10 @@ func (UnimplementedAdvisorServiceServer) ListCheckResultsHistory(context.Context return nil, status.Error(codes.Unimplemented, "method ListCheckResultsHistory not implemented") } +func (UnimplementedAdvisorServiceServer) ListCheckResultsFilterValues(context.Context, *ListCheckResultsFilterValuesRequest) (*ListCheckResultsFilterValuesResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListCheckResultsFilterValues not implemented") +} + func (UnimplementedAdvisorServiceServer) MarkCheckResultsRead(context.Context, *MarkCheckResultsReadRequest) (*MarkCheckResultsReadResponse, error) { return nil, status.Error(codes.Unimplemented, "method MarkCheckResultsRead not implemented") } @@ -280,6 +299,24 @@ func _AdvisorService_ListCheckResultsHistory_Handler(srv interface{}, ctx contex return interceptor(ctx, in, info, handler) } +func _AdvisorService_ListCheckResultsFilterValues_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListCheckResultsFilterValuesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).ListCheckResultsFilterValues(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_ListCheckResultsFilterValues_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).ListCheckResultsFilterValues(ctx, req.(*ListCheckResultsFilterValuesRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AdvisorService_MarkCheckResultsRead_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MarkCheckResultsReadRequest) if err := dec(in); err != nil { @@ -389,6 +426,10 @@ var AdvisorService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListCheckResultsHistory", Handler: _AdvisorService_ListCheckResultsHistory_Handler, }, + { + MethodName: "ListCheckResultsFilterValues", + Handler: _AdvisorService_ListCheckResultsFilterValues_Handler, + }, { MethodName: "MarkCheckResultsRead", Handler: _AdvisorService_MarkCheckResultsRead_Handler, diff --git a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go index 5945cba665d..bb6dd3f9638 100644 --- a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go +++ b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go @@ -59,6 +59,8 @@ type ClientService interface { ListAdvisors(params *ListAdvisorsParams, opts ...ClientOption) (*ListAdvisorsOK, error) + ListCheckResultsFilterValues(params *ListCheckResultsFilterValuesParams, opts ...ClientOption) (*ListCheckResultsFilterValuesOK, error) + ListCheckResultsHistory(params *ListCheckResultsHistoryParams, opts ...ClientOption) (*ListCheckResultsHistoryOK, error) ListFailedServices(params *ListFailedServicesParams, opts ...ClientOption) (*ListFailedServicesOK, error) @@ -246,6 +248,50 @@ func (a *Client) ListAdvisors(params *ListAdvisorsParams, opts ...ClientOption) return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +ListCheckResultsFilterValues lists advisor check results filter values + +Returns the distinct service and node names present in the Advisor check results history, for populating filter dropdowns. +*/ +func (a *Client) ListCheckResultsFilterValues(params *ListCheckResultsFilterValuesParams, opts ...ClientOption) (*ListCheckResultsFilterValuesOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewListCheckResultsFilterValuesParams() + } + op := &runtime.ClientOperation{ + ID: "ListCheckResultsFilterValues", + Method: "GET", + PathPattern: "/v1/advisors/checks/history:filterValues", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &ListCheckResultsFilterValuesReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*ListCheckResultsFilterValuesOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*ListCheckResultsFilterValuesDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* ListCheckResultsHistory lists advisor check results history diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_parameters.go b/api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_parameters.go new file mode 100644 index 00000000000..3e8caf2ff20 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_parameters.go @@ -0,0 +1,124 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewListCheckResultsFilterValuesParams creates a new ListCheckResultsFilterValuesParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewListCheckResultsFilterValuesParams() *ListCheckResultsFilterValuesParams { + return &ListCheckResultsFilterValuesParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewListCheckResultsFilterValuesParamsWithTimeout creates a new ListCheckResultsFilterValuesParams object +// with the ability to set a timeout on a request. +func NewListCheckResultsFilterValuesParamsWithTimeout(timeout time.Duration) *ListCheckResultsFilterValuesParams { + return &ListCheckResultsFilterValuesParams{ + timeout: timeout, + } +} + +// NewListCheckResultsFilterValuesParamsWithContext creates a new ListCheckResultsFilterValuesParams object +// with the ability to set a context for a request. +func NewListCheckResultsFilterValuesParamsWithContext(ctx context.Context) *ListCheckResultsFilterValuesParams { + return &ListCheckResultsFilterValuesParams{ + Context: ctx, + } +} + +// NewListCheckResultsFilterValuesParamsWithHTTPClient creates a new ListCheckResultsFilterValuesParams object +// with the ability to set a custom HTTPClient for a request. +func NewListCheckResultsFilterValuesParamsWithHTTPClient(client *http.Client) *ListCheckResultsFilterValuesParams { + return &ListCheckResultsFilterValuesParams{ + HTTPClient: client, + } +} + +/* +ListCheckResultsFilterValuesParams contains all the parameters to send to the API endpoint + + for the list check results filter values operation. + + Typically these are written to a http.Request. +*/ +type ListCheckResultsFilterValuesParams struct { + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the list check results filter values params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListCheckResultsFilterValuesParams) WithDefaults() *ListCheckResultsFilterValuesParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the list check results filter values params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *ListCheckResultsFilterValuesParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the list check results filter values params +func (o *ListCheckResultsFilterValuesParams) WithTimeout(timeout time.Duration) *ListCheckResultsFilterValuesParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the list check results filter values params +func (o *ListCheckResultsFilterValuesParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the list check results filter values params +func (o *ListCheckResultsFilterValuesParams) WithContext(ctx context.Context) *ListCheckResultsFilterValuesParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the list check results filter values params +func (o *ListCheckResultsFilterValuesParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the list check results filter values params +func (o *ListCheckResultsFilterValuesParams) WithHTTPClient(client *http.Client) *ListCheckResultsFilterValuesParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the list check results filter values params +func (o *ListCheckResultsFilterValuesParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WriteToRequest writes these params to a swagger request +func (o *ListCheckResultsFilterValuesParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_responses.go b/api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_responses.go new file mode 100644 index 00000000000..ef02cfc8efb --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_filter_values_responses.go @@ -0,0 +1,453 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ListCheckResultsFilterValuesReader is a Reader for the ListCheckResultsFilterValues structure. +type ListCheckResultsFilterValuesReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *ListCheckResultsFilterValuesReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewListCheckResultsFilterValuesOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewListCheckResultsFilterValuesDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewListCheckResultsFilterValuesOK creates a ListCheckResultsFilterValuesOK with default headers values +func NewListCheckResultsFilterValuesOK() *ListCheckResultsFilterValuesOK { + return &ListCheckResultsFilterValuesOK{} +} + +/* +ListCheckResultsFilterValuesOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type ListCheckResultsFilterValuesOK struct { + Payload *ListCheckResultsFilterValuesOKBody +} + +// IsSuccess returns true when this list check results filter values Ok response has a 2xx status code +func (o *ListCheckResultsFilterValuesOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this list check results filter values Ok response has a 3xx status code +func (o *ListCheckResultsFilterValuesOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this list check results filter values Ok response has a 4xx status code +func (o *ListCheckResultsFilterValuesOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this list check results filter values Ok response has a 5xx status code +func (o *ListCheckResultsFilterValuesOK) IsServerError() bool { + return false +} + +// IsCode returns true when this list check results filter values Ok response a status code equal to that given +func (o *ListCheckResultsFilterValuesOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the list check results filter values Ok response +func (o *ListCheckResultsFilterValuesOK) Code() int { + return 200 +} + +func (o *ListCheckResultsFilterValuesOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history:filterValues][%d] listCheckResultsFilterValuesOk %s", 200, payload) +} + +func (o *ListCheckResultsFilterValuesOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history:filterValues][%d] listCheckResultsFilterValuesOk %s", 200, payload) +} + +func (o *ListCheckResultsFilterValuesOK) GetPayload() *ListCheckResultsFilterValuesOKBody { + return o.Payload +} + +func (o *ListCheckResultsFilterValuesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListCheckResultsFilterValuesOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewListCheckResultsFilterValuesDefault creates a ListCheckResultsFilterValuesDefault with default headers values +func NewListCheckResultsFilterValuesDefault(code int) *ListCheckResultsFilterValuesDefault { + return &ListCheckResultsFilterValuesDefault{ + _statusCode: code, + } +} + +/* +ListCheckResultsFilterValuesDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type ListCheckResultsFilterValuesDefault struct { + _statusCode int + + Payload *ListCheckResultsFilterValuesDefaultBody +} + +// IsSuccess returns true when this list check results filter values default response has a 2xx status code +func (o *ListCheckResultsFilterValuesDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this list check results filter values default response has a 3xx status code +func (o *ListCheckResultsFilterValuesDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this list check results filter values default response has a 4xx status code +func (o *ListCheckResultsFilterValuesDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this list check results filter values default response has a 5xx status code +func (o *ListCheckResultsFilterValuesDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this list check results filter values default response a status code equal to that given +func (o *ListCheckResultsFilterValuesDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the list check results filter values default response +func (o *ListCheckResultsFilterValuesDefault) Code() int { + return o._statusCode +} + +func (o *ListCheckResultsFilterValuesDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history:filterValues][%d] ListCheckResultsFilterValues default %s", o._statusCode, payload) +} + +func (o *ListCheckResultsFilterValuesDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/history:filterValues][%d] ListCheckResultsFilterValues default %s", o._statusCode, payload) +} + +func (o *ListCheckResultsFilterValuesDefault) GetPayload() *ListCheckResultsFilterValuesDefaultBody { + return o.Payload +} + +func (o *ListCheckResultsFilterValuesDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(ListCheckResultsFilterValuesDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +ListCheckResultsFilterValuesDefaultBody list check results filter values default body +swagger:model ListCheckResultsFilterValuesDefaultBody +*/ +type ListCheckResultsFilterValuesDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*ListCheckResultsFilterValuesDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this list check results filter values default body +func (o *ListCheckResultsFilterValuesDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListCheckResultsFilterValuesDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListCheckResultsFilterValues default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListCheckResultsFilterValues default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list check results filter values default body based on the context it is used +func (o *ListCheckResultsFilterValuesDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListCheckResultsFilterValuesDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ListCheckResultsFilterValues default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ListCheckResultsFilterValues default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *ListCheckResultsFilterValuesDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListCheckResultsFilterValuesDefaultBody) UnmarshalBinary(b []byte) error { + var res ListCheckResultsFilterValuesDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListCheckResultsFilterValuesDefaultBodyDetailsItems0 list check results filter values default body details items0 +swagger:model ListCheckResultsFilterValuesDefaultBodyDetailsItems0 +*/ +type ListCheckResultsFilterValuesDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // list check results filter values default body details items0 + ListCheckResultsFilterValuesDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *ListCheckResultsFilterValuesDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv ListCheckResultsFilterValuesDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.ListCheckResultsFilterValuesDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o ListCheckResultsFilterValuesDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.ListCheckResultsFilterValuesDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.ListCheckResultsFilterValuesDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this list check results filter values default body details items0 +func (o *ListCheckResultsFilterValuesDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list check results filter values default body details items0 based on context it is used +func (o *ListCheckResultsFilterValuesDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListCheckResultsFilterValuesDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListCheckResultsFilterValuesDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res ListCheckResultsFilterValuesDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +ListCheckResultsFilterValuesOKBody list check results filter values OK body +swagger:model ListCheckResultsFilterValuesOKBody +*/ +type ListCheckResultsFilterValuesOKBody struct { + // Distinct service names present in the check results history, sorted alphabetically. + ServiceNames []string `json:"service_names"` + + // Distinct node names present in the check results history, sorted alphabetically. + NodeNames []string `json:"node_names"` +} + +// Validate validates this list check results filter values OK body +func (o *ListCheckResultsFilterValuesOKBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list check results filter values OK body based on context it is used +func (o *ListCheckResultsFilterValuesOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListCheckResultsFilterValuesOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListCheckResultsFilterValuesOKBody) UnmarshalBinary(b []byte) error { + var res ListCheckResultsFilterValuesOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index 38fc50c3621..b19a56b5f07 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -736,6 +736,73 @@ } } }, + "/v1/advisors/checks/history:filterValues": { + "get": { + "description": "Returns the distinct service and node names present in the Advisor check results history, for populating filter dropdowns.", + "tags": [ + "AdvisorService" + ], + "summary": "List Advisor Check Results Filter Values", + "operationId": "ListCheckResultsFilterValues", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "service_names": { + "description": "Distinct service names present in the check results history, sorted alphabetically.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "node_names": { + "description": "Distinct node names present in the check results history, sorted alphabetically.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks/history:markRead": { "post": { "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", diff --git a/api/descriptor.bin b/api/descriptor.bin index b04dcf58e84b59a0661ed71b933430eb732976b1..95ad8f462ef5a51a19b97245a34713a379abbbe7 100644 GIT binary patch delta 2919 zcmb7_Yitx%6vub}bNB9Y2gMH1mX^m@o~eM8hekk{>Cmn)oPU3DrsuBtla zB%Y2|*Ez`w=T-WfDtSrtxcjnXZB0DsxHqpydX;n$B3=`7UWi9uagv3wjXrHE+DK)B z6iO;YvHRFuqc}6T*0=#IvN8jb#zmBzh3I^@Ce{GAZ=KPl;~n^l%G9eax4-h3N=^nB zk7^8BecX5JjNF1WcxB2?I*GYem5v>a$85=MD<^hs z!bv*ulwB2<%iVk5Y}>W8uRXgaVb|8w)>TI-`9*uSnw}j?)YQgmUW+IDFF4w=1f|se zFKTZM_1=5!tql+z$=ph&&+L(u;hHFG1ja1l6m2dbI?RzTzGcV)+O#i!B9&s1!_wD(X@6ls)#}R`2A{ zu9T<3PLpkUF6=p!RFjz3*G|?XQclc{R@csn&T>*!mC@?zdHsdoG$h-Yd45PpOJQ~M zLqmoo-E|lwLRS*bRD`saqWg;~a)j~pf9-(g`=5A0!gF(YLDkag?DG(wi*B}>ZGpv? zAyE2(9&Q0GU51EJnER|3^TCb4E4FDHqsuR6zaNlk;`i&@n#BV_OUVkN(Za|(Ty{(ZL(CH30gJCd;JVw|Xhf|Qh~$eYg7E-Z;EljKH@4EKNH>BP%BoU_ z#TwCRpdV6`Mm##r4`~Zmf{m5@axq)KZ+nT9%rSyMvJw?p3463?=hb8uUj??7T;++d zTC_MKC37u8;y&?UL~E3`8oVb-zC!KSfX@<>6m-zyO~58Mw#t~8ZUR?RrraPUHX&bq z3NoauCOkYrL(6m545o%I-)iV)n4>kcCsC1R*rPNwW%2c38?(?sCZX5E+?a!w8l`Oj zFV)aeq4pnxKPjdvXjptRu-%QWHm0OEgLlzbpv2ASI@}K_Ycrmh?S}-N$xRv>I+L5U zCsC11Zqgv=EnwTS&`{7@U~W^;X*pM^QQB7UK^j^r)czCjXN9An4U6vpK7&CQ$lWe# zJ8`E=b*}nBvFno2S=Ds4X0H=F?OlmU?*btfgU;#>@DlCXAg&$gKF$vbY6m9Q`610@ zC)i|t`V2jjoiHcqjr1fcvJ>`1y^#jZWEa>TIg|0~_!(*_yI}57Lyj~ z6~hYc2455u qMp}oL2G?a2%UFGiUYm5ged!P?oJ4iqr>t}@V@R4IXVJ% zEbAzw9UXyrEbGV<$-F2N#*CKLd6y3(ghz8JOoVNM3XDR7s7}egN-ri$d+sf{zrF)mDTp-U9sM zZvDt8PlpM-1>DkTVM=a6`(A!XnJp-L+z$!-JlGHo9@gOJVGh>do|z!?tiUh8yqE)*8m0XN-c^H3h1<KN;`RpzHAx@Q0geGG?YD1bzuz{qm7_tS{GxywOu3C4nOKBr%6d@rH=|72p5(>t|Z2W^HXrn}kl9>3Q@x=#| zB}(EmlJ=5dQ6Vk1(EqI~Sj{1oProoqY=U7M7`ly%FKGHc5EZ7Qdhm_FH|thR=RcDKXhcAWsJCVLY9 z*ctuRC)Pb)3(ph??n!oX>rUjfQcR!M@-Q;1Eqk8#9Y%Jg+N(erO-GQq6?OEBJ^Bc; zdG)-Kl;H@}4IGau{bEP48&qey8Xa18V|jB@@*&-LY*$k9JsgGHZure+IsDz^14atB zDF#U;ZgLcj?W!j3DK&izd5lx#RA4uKm^D&(48FQoJ)CtK+dct3#8RU0@t=bBs%I^< zr>O@x8C6b-XNo-_d&}(g*w};oT1V-zs|OpNPD+OEg|wG$HaqBEgzXMGmbghT8n-%V zkD*UM_NUOEG|(py_FL#ygJ?9ieFj?NppC-E_ko^LJ1sOc4FF>h_1hbxkvGJ$=#Nuk zLva9fzXJrf7{H3nNy+{JJh?9^8Go>P=WzIg)jN+RZZcTCb1?o8Lw0h@8 zW7{yO#o-%;j~@ZOs9v)8Lem8BRdj7o>?#T#tqD-QLlbPCK*J+R$<7IEec9chV1&;h zPcy<&J1!zdXE8j@5b?moB4;dtn*XN-T7ChlxuaX*4CL7~k+6x*AUtamnfEXfGkpnK z&!d(oLi>}T_dK=FCSt5I@NL(y*i)1os9c?X$>wr(`XvV{o9U0|ShDjRX=ZN7>)kWo0$H=vI^_e8#? zS>RH%c7&hE=R~uhW$sOUcF&@2eNu9wS!~*wl#DqCx!HZszMHK%gqs|BEOC=LG;VbF z;4^sz@?r|^Tks0Pi)b+)w7GbrvF&@%$~zQ3{s+(&^_+bP(lihJ9JP&#LXjAJ9;6)_ zv3VX#S0yDo=h5^;QZo1gWSavg2fl!?)q%$nH(5YqivuSHzYKXL1t$xB8R3;GxY5}5 zBWQ&KHwqvB6X;R(ngtIuEdswsEo0)9V!+^wAp1X_g9mJ0M189x4cNJeEgcRaV1%oX z*V7pa+zeescs-q=SmcbqfY!M{vBooWtvW-d+r}G^H`7FcO>_g{&2)y0#7w_}R=Ge% eVXWUiD2xkUl9$hmcm=$&yq54%rNVeP_RoKGVI`RW diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index 990d5709873..9b24f9cf6ef 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -2049,6 +2049,73 @@ } } }, + "/v1/advisors/checks/history:filterValues": { + "get": { + "description": "Returns the distinct service and node names present in the Advisor check results history, for populating filter dropdowns.", + "tags": [ + "AdvisorService" + ], + "summary": "List Advisor Check Results Filter Values", + "operationId": "ListCheckResultsFilterValues", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "service_names": { + "description": "Distinct service names present in the check results history, sorted alphabetically.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "node_names": { + "description": "Distinct node names present in the check results history, sorted alphabetically.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks/history:markRead": { "post": { "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 758ac74cc5c..528d33f1252 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1532,6 +1532,73 @@ } } }, + "/v1/advisors/checks/history:filterValues": { + "get": { + "description": "Returns the distinct service and node names present in the Advisor check results history, for populating filter dropdowns.", + "tags": [ + "AdvisorService" + ], + "summary": "List Advisor Check Results Filter Values", + "operationId": "ListCheckResultsFilterValues", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "service_names": { + "description": "Distinct service names present in the check results history, sorted alphabetically.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 0 + }, + "node_names": { + "description": "Distinct node names present in the check results history, sorted alphabetically.", + "type": "array", + "items": { + "type": "string" + }, + "x-order": 1 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks/history:markRead": { "post": { "description": "Sets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.", diff --git a/managed/models/check_result_helpers.go b/managed/models/check_result_helpers.go index 5b2ec348eb8..6259fe19558 100644 --- a/managed/models/check_result_helpers.go +++ b/managed/models/check_result_helpers.go @@ -16,6 +16,7 @@ package models import ( + "context" "fmt" "strings" "time" @@ -25,11 +26,11 @@ import ( ) // CreateCheckResult inserts a single Advisor check result into the history. -func CreateCheckResult(q *reform.Querier, r *CheckResult) error { +func CreateCheckResult(ctx context.Context, q *reform.Querier, r *CheckResult) error { if r.ID == "" { r.ID = uuid.NewString() } - return q.Insert(r) + return q.WithContext(ctx).Insert(r) } // CheckResultFilters specifies filters for querying Advisor check results history. @@ -112,7 +113,7 @@ func checkResultConditions(q *reform.Querier, filters CheckResultFilters) (strin // FindCheckResults returns Advisor check results history matching the filters, ordered by // checked_at descending. When pageSize is greater than zero, the results are paginated. -func FindCheckResults(q *reform.Querier, filters CheckResultFilters, pageIndex, pageSize int) ([]*CheckResult, error) { +func FindCheckResults(ctx context.Context, q *reform.Querier, filters CheckResultFilters, pageIndex, pageSize int) ([]*CheckResult, error) { tail, args := checkResultConditions(q, filters) tail += " ORDER BY checked_at DESC" if pageSize > 0 { @@ -122,7 +123,7 @@ func FindCheckResults(q *reform.Querier, filters CheckResultFilters, pageIndex, args = append(args, pageIndex*pageSize) } - rows, err := q.SelectAllFrom(CheckResultTable, tail, args...) + rows, err := q.WithContext(ctx).SelectAllFrom(CheckResultTable, tail, args...) if err != nil { return nil, fmt.Errorf("failed to select check results: %w", err) } @@ -135,19 +136,53 @@ func FindCheckResults(q *reform.Querier, filters CheckResultFilters, pageIndex, } // CountCheckResults returns the number of Advisor check results history rows matching the filters. -func CountCheckResults(q *reform.Querier, filters CheckResultFilters) (int, error) { +func CountCheckResults(ctx context.Context, q *reform.Querier, filters CheckResultFilters) (int, error) { where, args := checkResultConditions(q, filters) var count int - err := q.QueryRow("SELECT count(*) FROM "+CheckResultTable.Name()+" "+where, args...).Scan(&count) + err := q.QueryRowContext(ctx, "SELECT count(*) FROM "+CheckResultTable.Name()+" "+where, args...).Scan(&count) if err != nil { return 0, fmt.Errorf("failed to count check results: %w", err) } return count, nil } +// FindCheckResultFilterValues returns the distinct service and node names present in the +// Advisor check results history, each sorted alphabetically. +func FindCheckResultFilterValues(ctx context.Context, q *reform.Querier) ([]string, []string, error) { + distinct := func(column string) ([]string, error) { + rows, err := q.QueryContext(ctx, "SELECT DISTINCT "+column+" FROM "+CheckResultTable.Name()+ + " ORDER BY "+column) + if err != nil { + return nil, fmt.Errorf("failed to select distinct %s: %w", column, err) + } + defer rows.Close() //nolint:errcheck + + var values []string + for rows.Next() { + var value string + err = rows.Scan(&value) + if err != nil { + return nil, fmt.Errorf("failed to scan distinct %s: %w", column, err) + } + values = append(values, value) + } + return values, rows.Err() + } + + serviceNames, err := distinct("service_name") + if err != nil { + return nil, nil, err + } + nodeNames, err := distinct("node_name") + if err != nil { + return nil, nil, err + } + return serviceNames, nodeNames, nil +} + // MarkCheckResultsRead sets the read state on the check results with the given IDs. -func MarkCheckResultsRead(q *reform.Querier, ids []string, isRead bool) error { +func MarkCheckResultsRead(ctx context.Context, q *reform.Querier, ids []string, isRead bool) error { if len(ids) == 0 { return nil } @@ -161,7 +196,7 @@ func MarkCheckResultsRead(q *reform.Querier, ids []string, isRead bool) error { query := "UPDATE " + CheckResultTable.Name() + " SET is_read = " + q.Placeholder(1) + " WHERE id IN (" + strings.Join(placeholders, ", ") + ")" - _, err := q.Exec(query, args...) + _, err := q.ExecContext(ctx, query, args...) if err != nil { return fmt.Errorf("failed to mark check results as read: %w", err) } @@ -169,7 +204,7 @@ func MarkCheckResultsRead(q *reform.Querier, ids []string, isRead bool) error { } // CleanupOldCheckResults deletes Advisor check results older than a specified date. -func CleanupOldCheckResults(q *reform.Querier, olderThan time.Time) error { - _, err := q.DeleteFrom(CheckResultTable, " WHERE checked_at <= $1", olderThan) +func CleanupOldCheckResults(ctx context.Context, q *reform.Querier, olderThan time.Time) error { + _, err := q.WithContext(ctx).DeleteFrom(CheckResultTable, " WHERE checked_at <= $1", olderThan) return err } diff --git a/managed/models/check_result_helpers_test.go b/managed/models/check_result_helpers_test.go index 8b3547447b7..bf4991b53ec 100644 --- a/managed/models/check_result_helpers_test.go +++ b/managed/models/check_result_helpers_test.go @@ -17,6 +17,7 @@ package models_test import ( "fmt" + "strings" "testing" "time" @@ -40,7 +41,7 @@ func TestCheckResults(t *testing.T) { create := func(t *testing.T, cr *models.CheckResult) *models.CheckResult { t.Helper() - require.NoError(t, models.CreateCheckResult(q, cr)) + require.NoError(t, models.CreateCheckResult(t.Context(), q, cr)) return cr } @@ -67,7 +68,7 @@ func TestCheckResults(t *testing.T) { create(t, cr) require.NotEmpty(t, cr.ID) // generated by CreateCheckResult - got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 0, 0) + got, err := models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, cr.ID, got[0].ID) @@ -94,42 +95,42 @@ func TestCheckResults(t *testing.T) { }) // service_name: case-insensitive substring. - got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, ServiceName: "prod"}, 0, 0) + got, err := models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, ServiceName: "prod"}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, "ProdMySQL", got[0].ServiceName) // node_name: case-insensitive substring. - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, NodeName: "node-b"}, 0, 0) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, NodeName: "node-b"}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, "node-B", got[0].NodeName) // category: exact. - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, Category: "security"}, 0, 0) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, Category: "security"}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) // check_name: exact. - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, CheckName: "old_ver"}, 0, 0) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, CheckName: "old_ver"}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) // severity: exact. sev := models.CheckSeverityCritical - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, Severity: &sev}, 0, 0) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, Severity: &sev}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, models.CheckSeverityCritical, got[0].Severity) // status. st := models.CheckResultOK - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, Status: &st}, 0, 0) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, Status: &st}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, models.CheckResultOK, got[0].Status) - count, err := models.CountCheckResults(q, models.CheckResultFilters{ServiceID: svc}) + count, err := models.CountCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc}) require.NoError(t, err) assert.Equal(t, 2, count) }) @@ -146,7 +147,7 @@ func TestCheckResults(t *testing.T) { }) from := models.Now().Add(-24 * time.Hour) - got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, From: &from}, 0, 0) + got, err := models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, From: &from}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) }) @@ -162,19 +163,19 @@ func TestCheckResults(t *testing.T) { } // First page, newest first. - got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 0, 2) + got, err := models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc}, 0, 2) require.NoError(t, err) require.Len(t, got, 2) assert.Equal(t, "c4", got[0].CheckName) assert.Equal(t, "c3", got[1].CheckName) // Last page holds the single oldest row. - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 2, 2) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc}, 2, 2) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, "c0", got[0].CheckName) - count, err := models.CountCheckResults(q, models.CheckResultFilters{ServiceID: svc}) + count, err := models.CountCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc}) require.NoError(t, err) assert.Equal(t, 5, count) }) @@ -190,23 +191,23 @@ func TestCheckResults(t *testing.T) { Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), }) - require.NoError(t, models.MarkCheckResultsRead(q, []string{cr1.ID}, true)) + require.NoError(t, models.MarkCheckResultsRead(t.Context(), q, []string{cr1.ID}, true)) isRead := true - got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, IsRead: &isRead}, 0, 0) + got, err := models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, IsRead: &isRead}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, cr1.ID, got[0].ID) notRead := false - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, IsRead: ¬Read}, 0, 0) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, IsRead: ¬Read}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, cr2.ID, got[0].ID) // Unmark. - require.NoError(t, models.MarkCheckResultsRead(q, []string{cr1.ID}, false)) - got, err = models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc, IsRead: ¬Read}, 0, 0) + require.NoError(t, models.MarkCheckResultsRead(t.Context(), q, []string{cr1.ID}, false)) + got, err = models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc, IsRead: ¬Read}, 0, 0) require.NoError(t, err) require.Len(t, got, 2) }) @@ -222,11 +223,42 @@ func TestCheckResults(t *testing.T) { Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), }) - require.NoError(t, models.CleanupOldCheckResults(q, models.Now().Add(-24*time.Hour))) + require.NoError(t, models.CleanupOldCheckResults(t.Context(), q, models.Now().Add(-24*time.Hour))) - got, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: svc}, 0, 0) + got, err := models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: svc}, 0, 0) require.NoError(t, err) require.Len(t, got, 1) assert.Equal(t, "new", got[0].CheckName) }) + + t.Run("filter values", func(t *testing.T) { + // two results on the same service/node to prove deduplication + for range 2 { + create(t, &models.CheckResult{ + CheckName: "c", ServiceID: "svc-fv", ServiceName: "fv-svc-b", NodeName: "fv-node-b", + Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), + }) + } + create(t, &models.CheckResult{ + CheckName: "c", ServiceID: "svc-fv", ServiceName: "fv-svc-a", NodeName: "fv-node-a", + Status: models.CheckResultOK, Summary: "s", CheckedAt: models.Now(), + }) + + serviceNames, nodeNames, err := models.FindCheckResultFilterValues(t.Context(), q) + require.NoError(t, err) + + // other subtests insert their own rows, so assert on ours only + assert.Equal(t, []string{"fv-svc-a", "fv-svc-b"}, filterByPrefix(serviceNames, "fv-svc-")) + assert.Equal(t, []string{"fv-node-a", "fv-node-b"}, filterByPrefix(nodeNames, "fv-node-")) + }) +} + +func filterByPrefix(values []string, prefix string) []string { + var result []string + for _, v := range values { + if strings.HasPrefix(v, prefix) { + result = append(result, v) + } + } + return result } diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index 82fd0828f9b..e9304c89b14 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -251,13 +251,13 @@ func (s *Service) GetChecksResults(_ context.Context, serviceID string) ([]servi // GetCheckResultsHistory returns Advisor check results history matching the filters, // together with the total number of matching rows (ignoring pagination). -func (s *Service) GetCheckResultsHistory(_ context.Context, filters models.CheckResultFilters, pageIndex, pageSize int) ([]*models.CheckResult, int, error) { - results, err := models.FindCheckResults(s.db.Querier, filters, pageIndex, pageSize) +func (s *Service) GetCheckResultsHistory(ctx context.Context, filters models.CheckResultFilters, pageIndex, pageSize int) ([]*models.CheckResult, int, error) { + results, err := models.FindCheckResults(ctx, s.db.Querier, filters, pageIndex, pageSize) if err != nil { return nil, 0, err } - total, err := models.CountCheckResults(s.db.Querier, filters) + total, err := models.CountCheckResults(ctx, s.db.Querier, filters) if err != nil { return nil, 0, err } @@ -265,9 +265,15 @@ func (s *Service) GetCheckResultsHistory(_ context.Context, filters models.Check return results, total, nil } +// GetCheckResultsFilterValues returns the distinct service and node names present in the +// Advisor check results history. +func (s *Service) GetCheckResultsFilterValues(ctx context.Context) ([]string, []string, error) { + return models.FindCheckResultFilterValues(ctx, s.db.Querier) +} + // MarkCheckResultsRead sets the read state on the check results history with the given IDs. -func (s *Service) MarkCheckResultsRead(_ context.Context, ids []string, isRead bool) error { - return models.MarkCheckResultsRead(s.db.Querier, ids, isRead) +func (s *Service) MarkCheckResultsRead(ctx context.Context, ids []string, isRead bool) error { + return models.MarkCheckResultsRead(ctx, s.db.Querier, ids, isRead) } // runChecksGroup downloads and executes Advisors checks that should run in the interval specified by intervalGroup. @@ -841,7 +847,7 @@ func (s *Service) saveCheckResultsHistory(ctx context.Context, history []*models return s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { for _, r := range history { - err := models.CreateCheckResult(tx.Querier, r) + err := models.CreateCheckResult(ctx, tx.Querier, r) if err != nil { return err } diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index 11d4d66da33..f8ee6dc489b 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -273,6 +273,22 @@ func (s *ChecksAPIService) ListCheckResultsHistory( }, nil } +// ListCheckResultsFilterValues returns the distinct values usable as history filters. +func (s *ChecksAPIService) ListCheckResultsFilterValues( + ctx context.Context, + _ *advisorsv1.ListCheckResultsFilterValuesRequest, +) (*advisorsv1.ListCheckResultsFilterValuesResponse, error) { + serviceNames, nodeNames, err := s.checksService.GetCheckResultsFilterValues(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get check results filter values: %w", err) + } + + return &advisorsv1.ListCheckResultsFilterValuesResponse{ + ServiceNames: serviceNames, + NodeNames: nodeNames, + }, nil +} + // MarkCheckResultsRead sets the read state on the specified Advisor check history records. func (s *ChecksAPIService) MarkCheckResultsRead( ctx context.Context, diff --git a/managed/services/management/checks_test.go b/managed/services/management/checks_test.go index 64165a37cf3..05aa53a237f 100644 --- a/managed/services/management/checks_test.go +++ b/managed/services/management/checks_test.go @@ -208,6 +208,41 @@ func TestGetFailedChecks(t *testing.T) { }) } +func TestListCheckResultsFilterValues(t *testing.T) { + t.Parallel() + + t.Run("internal error", func(t *testing.T) { + t.Parallel() + + var checksService mockChecksService + checksService.On("GetCheckResultsFilterValues", mock.Anything). + Return(nil, nil, errors.New("random error")) + + s := NewChecksAPIService(&checksService) + + resp, err := s.ListCheckResultsFilterValues(t.Context(), &advisorsv1.ListCheckResultsFilterValuesRequest{}) + require.EqualError(t, err, "failed to get check results filter values: random error") + assert.Nil(t, resp) + }) + + t.Run("returns distinct values", func(t *testing.T) { + t.Parallel() + + var checksService mockChecksService + checksService.On("GetCheckResultsFilterValues", mock.Anything). + Return([]string{"mysql-1", "pg-1"}, []string{"node-a"}, nil) + + s := NewChecksAPIService(&checksService) + + resp, err := s.ListCheckResultsFilterValues(t.Context(), &advisorsv1.ListCheckResultsFilterValuesRequest{}) + require.NoError(t, err) + assert.Equal(t, &advisorsv1.ListCheckResultsFilterValuesResponse{ + ServiceNames: []string{"mysql-1", "pg-1"}, + NodeNames: []string{"node-a"}, + }, resp) + }) +} + func TestListCheckResultsHistory(t *testing.T) { t.Parallel() diff --git a/managed/services/management/deps.go b/managed/services/management/deps.go index b0c98f9074d..8f72087fae2 100644 --- a/managed/services/management/deps.go +++ b/managed/services/management/deps.go @@ -60,6 +60,7 @@ type checksService interface { GetAdvisors() ([]check.Advisor, error) GetChecksResults(ctx context.Context, serviceID string) ([]services.CheckResult, error) GetCheckResultsHistory(ctx context.Context, filters models.CheckResultFilters, pageIndex, pageSize int) ([]*models.CheckResult, int, error) + GetCheckResultsFilterValues(ctx context.Context) ([]string, []string, error) MarkCheckResultsRead(ctx context.Context, ids []string, isRead bool) error GetDisabledChecks() ([]string, error) DisableChecks(checkNames []string) error diff --git a/managed/services/management/mock_checks_service_test.go b/managed/services/management/mock_checks_service_test.go index ac20fc75a9a..34c53c9bb45 100644 --- a/managed/services/management/mock_checks_service_test.go +++ b/managed/services/management/mock_checks_service_test.go @@ -101,6 +101,45 @@ func (_m *mockChecksService) GetAdvisors() ([]check.Advisor, error) { return r0, r1 } +// GetCheckResultsFilterValues provides a mock function with given fields: ctx +func (_m *mockChecksService) GetCheckResultsFilterValues(ctx context.Context) ([]string, []string, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetCheckResultsFilterValues") + } + + var r0 []string + var r1 []string + var r2 error + if rf, ok := ret.Get(0).(func(context.Context) ([]string, []string, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []string); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) []string); ok { + r1 = rf(ctx) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).([]string) + } + } + + if rf, ok := ret.Get(2).(func(context.Context) error); ok { + r2 = rf(ctx) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + // GetCheckResultsHistory provides a mock function with given fields: ctx, filters, pageIndex, pageSize func (_m *mockChecksService) GetCheckResultsHistory(ctx context.Context, filters models.CheckResultFilters, pageIndex int, pageSize int) ([]*models.CheckResult, int, error) { ret := _m.Called(ctx, filters, pageIndex, pageSize) diff --git a/managed/utils/clean/check_results.go b/managed/utils/clean/check_results.go index f38a90ac88a..2de6ceb933c 100644 --- a/managed/utils/clean/check_results.go +++ b/managed/utils/clean/check_results.go @@ -42,7 +42,7 @@ func (c *CheckResults) Run(ctx context.Context, interval time.Duration) { l := logrus.WithField("component", "advisor-history-cleaner") for { - c.cleanup(l) + c.cleanup(ctx, l) select { case <-ctx.Done(): @@ -53,7 +53,7 @@ func (c *CheckResults) Run(ctx context.Context, interval time.Duration) { } // cleanup performs a single cleanup pass, removing check results past the configured retention. -func (c *CheckResults) cleanup(l *logrus.Entry) { +func (c *CheckResults) cleanup(ctx context.Context, l *logrus.Entry) { settings, err := models.GetSettings(c.db) if err != nil { l.Error(err) @@ -61,7 +61,7 @@ func (c *CheckResults) cleanup(l *logrus.Entry) { } olderThanTS := models.Now().Add(-1 * settings.AdvisorHistoryRetention) - err = models.CleanupOldCheckResults(c.db.Querier, olderThanTS) + err = models.CleanupOldCheckResults(ctx, c.db.Querier, olderThanTS) if err != nil { l.Error(err) } diff --git a/managed/utils/clean/check_results_test.go b/managed/utils/clean/check_results_test.go index 8125d624e4d..3bf9a8ac54a 100644 --- a/managed/utils/clean/check_results_test.go +++ b/managed/utils/clean/check_results_test.go @@ -39,19 +39,19 @@ func TestCheckResultsCleaner(t *testing.T) { q := db.Querier // Default retention is 30 days, so this row is past it and must be removed. - require.NoError(t, models.CreateCheckResult(q, &models.CheckResult{ + require.NoError(t, models.CreateCheckResult(t.Context(), q, &models.CheckResult{ CheckName: "old", ServiceID: "svc", ServiceName: "svc", NodeName: "node", Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now().Add(-31 * 24 * time.Hour), })) - require.NoError(t, models.CreateCheckResult(q, &models.CheckResult{ + require.NoError(t, models.CreateCheckResult(t.Context(), q, &models.CheckResult{ CheckName: "new", ServiceID: "svc", ServiceName: "svc", NodeName: "node", Status: models.CheckResultFailed, Summary: "s", CheckedAt: models.Now(), })) // Run a single cleanup pass synchronously; the ticker loop in Run is trivial plumbing. - NewCheckResults(db).cleanup(logrus.WithField("component", "test")) + NewCheckResults(db).cleanup(t.Context(), logrus.WithField("component", "test")) - results, err := models.FindCheckResults(q, models.CheckResultFilters{ServiceID: "svc"}, 0, 0) + results, err := models.FindCheckResults(t.Context(), q, models.CheckResultFilters{ServiceID: "svc"}, 0, 0) require.NoError(t, err) require.Len(t, results, 1) assert.Equal(t, "new", results[0].CheckName) diff --git a/ui/apps/pmm/src/api/advisors.ts b/ui/apps/pmm/src/api/advisors.ts index f954e033ce3..2814137601a 100644 --- a/ui/apps/pmm/src/api/advisors.ts +++ b/ui/apps/pmm/src/api/advisors.ts @@ -4,6 +4,7 @@ import { ChangeAdvisorChecksRequest, CheckResultHistoryItem, ListAdvisorsResponse, + ListCheckResultsFilterValuesResponse, ListCheckResultsHistoryParams, MarkCheckResultsReadRequest, StartAdvisorChecksRequest, @@ -50,3 +51,11 @@ export const markCheckResultsRead = async ( ): Promise => { await api.post('/advisors/checks/history:markRead', payload); }; + +export const listCheckResultsFilterValues = + async (): Promise => { + const res = await api.get( + '/advisors/checks/history:filterValues' + ); + return res.data; + }; diff --git a/ui/apps/pmm/src/hooks/api/useAdvisors.ts b/ui/apps/pmm/src/hooks/api/useAdvisors.ts index bd490a70ed2..fc1fe6bfec9 100644 --- a/ui/apps/pmm/src/hooks/api/useAdvisors.ts +++ b/ui/apps/pmm/src/hooks/api/useAdvisors.ts @@ -9,6 +9,7 @@ import { import { changeAdvisorChecks, listAdvisors, + listCheckResultsFilterValues, listCheckResultsHistory, markCheckResultsRead, startAdvisorChecks, @@ -17,6 +18,7 @@ import { Advisor, ChangeAdvisorCheckParams, CheckResultHistoryItem, + ListCheckResultsFilterValuesResponse, ListCheckResultsHistoryParams, MarkCheckResultsReadRequest, } from 'types/advisors.types'; @@ -27,6 +29,7 @@ const KEYS = { START_CHECKS: 'advisors:start-checks', CHANGE_CHECKS: 'advisors:change-checks', HISTORY: 'advisors:history', + HISTORY_FILTER_VALUES: 'advisors:history-filter-values', MARK_READ: 'advisors:mark-read', }; @@ -60,6 +63,15 @@ export const useCheckResultsHistory = ( ...options, }); +export const useCheckResultsFilterValues = ( + options?: Partial> +) => + useQuery({ + queryKey: [KEYS.HISTORY_FILTER_VALUES], + queryFn: () => listCheckResultsFilterValues(), + ...options, + }); + export const useMarkCheckResultsRead = ( options?: Partial< UseMutationOptions diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index 060027e9476..b186c379e96 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -10,8 +10,12 @@ export const Messages = { unread: 'Unread', filters: { all: 'All', + clear: 'Clear filters', + refresh: 'Refresh', + refreshTooltip: + 'Reload the check results and re-populate the filter options.', service: 'Service', - servicePlaceholder: 'Filter by service name', + node: 'Node', category: 'Category', severity: 'Severity', status: 'Status', diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 40a48611f72..6f85980e74a 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -1,4 +1,10 @@ -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { + fireEvent, + render, + screen, + waitFor, + within, +} from '@testing-library/react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import AdvisorInsights from './AdvisorInsights'; import { Messages } from './AdvisorInsights.messages'; @@ -82,8 +88,23 @@ describe('AdvisorInsights', () => { results: [TEST_ITEM, TEST_ITEM_UNREAD], }); vi.mocked(advisorsApi.markCheckResultsRead).mockResolvedValue(); + vi.mocked(advisorsApi.listCheckResultsFilterValues).mockResolvedValue({ + serviceNames: ['mysql-prod', 'postgresql-prod'], + nodeNames: ['node-1', 'node-2'], + }); }); + const selectFilterOption = async (filterTestId: string, option: string) => { + fireEvent.mouseDown( + within(screen.getByTestId(filterTestId)).getByRole('combobox') + ); + + // 'hidden' skips the visibility computation, which crashes in jsdom: + // nwsapi expands ':scope' with the listbox's unescaped React useId + const listbox = await screen.findByRole('listbox', { hidden: true }); + fireEvent.click(within(listbox).getByText(option)); + }; + it('renders history items with read state', async () => { renderComponent(); @@ -147,12 +168,7 @@ describe('AdvisorInsights', () => { ) ); - fireEvent.change( - screen.getByPlaceholderText(Messages.filters.servicePlaceholder), - { - target: { value: 'mysql-prod' }, - } - ); + await selectFilterOption('serviceName-filter', 'mysql-prod'); await waitFor(() => expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( @@ -161,6 +177,73 @@ describe('AdvisorInsights', () => { ); }); + it('passes the node filter to the API', async () => { + renderComponent(); + + await waitForRows(); + + await selectFilterOption('nodeName-filter', 'node-2'); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ nodeName: 'node-2', pageIndex: 0 }) + ) + ); + }); + + it('clears all filters and resets to the first page', async () => { + renderComponent(); + + await waitForRows(); + + expect(screen.getByTestId('clear-filters')).toBeDisabled(); + + await selectFilterOption('serviceName-filter', 'mysql-prod'); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ serviceName: 'mysql-prod' }) + ) + ); + + fireEvent.click(screen.getByTestId('clear-filters')); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenLastCalledWith( + expect.objectContaining({ serviceName: undefined, pageIndex: 0 }) + ) + ); + expect(screen.getByTestId('clear-filters')).toBeDisabled(); + }); + + it('refetches results and filter data on refresh', async () => { + renderComponent(); + + await waitForRows(); + + const historyCalls = vi.mocked(advisorsApi.listCheckResultsHistory).mock + .calls.length; + const advisorsCalls = vi.mocked(advisorsApi.listAdvisors).mock.calls + .length; + const filterValuesCalls = vi.mocked( + advisorsApi.listCheckResultsFilterValues + ).mock.calls.length; + + fireEvent.click(screen.getByTestId('refresh-insights')); + + await waitFor(() => { + expect( + vi.mocked(advisorsApi.listCheckResultsHistory).mock.calls.length + ).toBe(historyCalls + 1); + expect(vi.mocked(advisorsApi.listAdvisors).mock.calls.length).toBe( + advisorsCalls + 1 + ); + expect( + vi.mocked(advisorsApi.listCheckResultsFilterValues).mock.calls.length + ).toBe(filterValuesCalls + 1); + }); + }); + it('makes every column sortable except summary', async () => { renderComponent(); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 0d791a28be5..96c88d5df00 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -1,19 +1,23 @@ -import { FC, useMemo, useRef, useState } from 'react'; import Button from '@mui/material/Button'; +import FilterAltOffOutlinedIcon from '@mui/icons-material/FilterAltOffOutlined'; +import RefreshOutlinedIcon from '@mui/icons-material/RefreshOutlined'; import MenuItem from '@mui/material/MenuItem'; import Stack from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; +import Tooltip from '@mui/material/Tooltip'; import Typography from '@mui/material/Typography'; import { Table } from '@percona/percona-ui'; -import { type MRT_PaginationState } from 'material-react-table'; -import { enqueueSnackbar } from 'notistack'; -import { useSearchParams } from 'react-router-dom'; import { Page } from 'components/page'; import { useAdvisors, + useCheckResultsFilterValues, useCheckResultsHistory, useMarkCheckResultsRead, } from 'hooks/api/useAdvisors'; +import { type MRT_PaginationState } from 'material-react-table'; +import { enqueueSnackbar } from 'notistack'; +import { FC, useMemo, useState } from 'react'; +import { useSearchParams } from 'react-router-dom'; import { AdvisorCheckResultStatus, CheckResultHistoryItem, @@ -22,18 +26,17 @@ import { import { Severity } from 'types/severity.types'; import { OrgRole } from 'types/user.types'; import { capitalize } from 'utils/text.utils'; -import { Messages } from './AdvisorInsights.messages'; import { getInsightsColumns } from './AdvisorInsights.constants'; import { READ_FILTER_OPTIONS, SEVERITY_FILTER_OPTIONS, STATUS_FILTER_OPTIONS, } from './AdvisorInsights.filters'; - -const SERVICE_FILTER_DEBOUNCE_MS = 400; +import { Messages } from './AdvisorInsights.messages'; interface InsightFilters { serviceName: string; + nodeName: string; category: string; severity: string; status: string; @@ -42,6 +45,7 @@ interface InsightFilters { const NO_FILTERS: InsightFilters = { serviceName: '', + nodeName: '', category: '', severity: '', status: '', @@ -99,8 +103,6 @@ const AdvisorInsights: FC = () => { pageSize: 100, }); const [filters, setFilters] = useState(NO_FILTERS); - const [serviceInput, setServiceInput] = useState(''); - const serviceTimer = useRef>(); const updateFilter = (name: keyof InsightFilters, value: string) => { setFilters((current) => ({ ...current, [name]: value })); @@ -108,13 +110,11 @@ const AdvisorInsights: FC = () => { setPagination((current) => ({ ...current, pageIndex: 0 })); }; - const handleServiceInputChange = (value: string) => { - setServiceInput(value); - clearTimeout(serviceTimer.current); - serviceTimer.current = setTimeout( - () => updateFilter('serviceName', value), - SERVICE_FILTER_DEBOUNCE_MS - ); + const hasActiveFilters = Object.values(filters).some(Boolean); + + const handleClearFilters = () => { + setFilters(NO_FILTERS); + setPagination((current) => ({ ...current, pageIndex: 0 })); }; const params = useMemo( @@ -123,6 +123,7 @@ const AdvisorInsights: FC = () => { pageSize: pagination.pageSize, runId, serviceName: filters.serviceName || undefined, + nodeName: filters.nodeName || undefined, category: filters.category || undefined, severity: (filters.severity as Severity) || undefined, status: (filters.status as AdvisorCheckResultStatus) || undefined, @@ -131,10 +132,20 @@ const AdvisorInsights: FC = () => { [pagination, filters, runId] ); - const { data, isLoading, isFetching } = useCheckResultsHistory(params); - const { data: advisors = [] } = useAdvisors(); + const { data, isLoading, isFetching, refetch } = + useCheckResultsHistory(params); + const { data: advisors = [], refetch: refetchAdvisors } = useAdvisors(); + const { data: filterValues, refetch: refetchFilterValues } = + useCheckResultsFilterValues(); const { mutate: markRead, isPending: isMarking } = useMarkCheckResultsRead(); + // reloads the results and the data behind the filter dropdowns + const handleRefresh = () => { + refetch(); + refetchAdvisors(); + refetchFilterValues(); + }; + const categoryOptions = useMemo( () => [...new Set(advisors.map((advisor) => advisor.category))] @@ -143,6 +154,24 @@ const AdvisorInsights: FC = () => { [advisors] ); + const serviceOptions = useMemo( + () => + (filterValues?.serviceNames ?? []).map((name) => ({ + label: name, + value: name, + })), + [filterValues] + ); + + const nodeOptions = useMemo( + () => + (filterValues?.nodeNames ?? []).map((name) => ({ + label: name, + value: name, + })), + [filterValues] + ); + const columns = useMemo(() => getInsightsColumns(), []); const handleToggleRead = (item: CheckResultHistoryItem) => @@ -169,15 +198,19 @@ const AdvisorInsights: FC = () => { {Messages.description} - handleServiceInputChange(e.target.value)} - sx={{ minWidth: 220 }} - data-testid="service-filter" + options={serviceOptions} + value={filters.serviceName} + onChange={(value) => updateFilter('serviceName', value)} + /> + updateFilter('nodeName', value)} /> { value={filters.isRead} onChange={(value) => updateFilter('isRead', value)} /> + + + +
{ noDataMessage={Messages.noData} manualPagination enablePagination + enableTopToolbar={false} enableGlobalFilter={false} enableColumnFilters={false} enableColumnActions={false} diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index 2ce429e232f..727cc018125 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -112,6 +112,11 @@ export interface MarkCheckResultsReadRequest { isRead: boolean; } +export interface ListCheckResultsFilterValuesResponse { + serviceNames: string[]; + nodeNames: string[]; +} + export interface AdvisorCheckRow { checkName: string; summary: string; From 0b0531c9afee0755272fcab172605bc80135bffe Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Mon, 6 Jul 2026 02:09:10 +0300 Subject: [PATCH 025/120] PMM-14109 Expand/Collapse the check result details --- .../insights/AdvisorInsights.constants.tsx | 4 +- .../insights/AdvisorInsights.messages.ts | 44 ++- .../insights/AdvisorInsights.test.tsx | 267 ++++++++++++++++- .../advisors/insights/AdvisorInsights.tsx | 261 ++++++++++++++++- .../insights/AdvisorInsights.utils.ts | 58 ++++ .../details-pane/InsightDetailsPane.tsx | 271 ++++++++++++++++++ .../advisors/insights/details-pane/index.ts | 1 + 7 files changed, 888 insertions(+), 18 deletions(-) create mode 100644 ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts create mode 100644 ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/insights/details-pane/index.ts diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx index 0006c5ebad1..2ed5c5c2cc2 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx @@ -30,6 +30,7 @@ export const getInsightsColumns = (): MRT_ColumnDef[] => accessorKey: 'summary', enableSorting: false, size: 300, + grow: true, Cell: ({ row }) => ( {row.original.summary} @@ -88,7 +89,8 @@ export const getInsightsColumns = (): MRT_ColumnDef[] => id: 'isRead', header: Messages.columns.read, accessorFn: (row) => (row.isRead ? Messages.read : Messages.unread), - size: 110, + size: 90, + grow: false, Cell: ({ row }) => ( `Run: ${runId}…`, clear: 'Clear filters', refresh: 'Refresh', refreshTooltip: @@ -31,6 +66,11 @@ export const Messages = { read: 'Read', }, success: { + rerunStarted: (check: string) => + `Check "${check}" started. The results will be available shortly.`, + checkEnabled: (check: string) => `Check "${check}" enabled`, + checkDisabled: (check: string) => `Check "${check}" disabled`, + copied: 'Insight copied to clipboard', markedRead: 'Insight marked as read', markedUnread: 'Insight marked as unread', }, diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 6f85980e74a..2d1aca48b43 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -16,15 +16,47 @@ import { wrapWithUserProvider, } from 'utils/testUtils'; import { + Advisor, AdvisorCheckResultStatus, AdvisorCheckTriggeredBy, + AdvisorFamily, AdvisorInterval, CheckResultHistoryItem, } from 'types/advisors.types'; import { Severity } from 'types/severity.types'; +import { format } from 'date-fns'; +import { TIME_FORMAT } from 'lib/constants'; vi.mock('api/advisors'); +const TEST_ADVISORS: Advisor[] = [ + { + name: 'test_advisor', + summary: 'Test advisor', + description: '', + comment: '', + category: 'configuration', + checks: [ + { + name: 'mysql_version_check', + enabled: true, + summary: 'MySQL version check', + description: '', + interval: AdvisorInterval.standard, + family: AdvisorFamily.mysql, + }, + { + name: 'postgresql_super_role', + enabled: false, + summary: 'PostgreSQL super role', + description: '', + interval: AdvisorInterval.rare, + family: AdvisorFamily.postgresql, + }, + ], + }, +]; + const TEST_ITEM: CheckResultHistoryItem = { id: 'result-1', checkName: 'mysql_version_check', @@ -51,12 +83,15 @@ const TEST_ITEM: CheckResultHistoryItem = { const TEST_ITEM_UNREAD: CheckResultHistoryItem = { ...TEST_ITEM, id: 'result-2', + checkName: 'postgresql_super_role', serviceName: 'postgresql-prod', serviceType: 'postgresql', summary: 'PostgreSQL super role detected', description: 'A user has the SUPER role', severity: Severity.error, isRead: false, + // recorded before run grouping existed + runId: '', }; const renderComponent = (initialEntry = '/advisors/insights') => @@ -81,13 +116,15 @@ const waitForRows = async () => { describe('AdvisorInsights', () => { beforeEach(() => { vi.clearAllMocks(); - vi.mocked(advisorsApi.listAdvisors).mockResolvedValue([]); + vi.mocked(advisorsApi.listAdvisors).mockResolvedValue(TEST_ADVISORS); vi.mocked(advisorsApi.listCheckResultsHistory).mockResolvedValue({ totalItems: 250, totalPages: 3, results: [TEST_ITEM, TEST_ITEM_UNREAD], }); vi.mocked(advisorsApi.markCheckResultsRead).mockResolvedValue(); + vi.mocked(advisorsApi.startAdvisorChecks).mockResolvedValue('run-123'); + vi.mocked(advisorsApi.changeAdvisorChecks).mockResolvedValue(); vi.mocked(advisorsApi.listCheckResultsFilterValues).mockResolvedValue({ serviceNames: ['mysql-prod', 'postgresql-prod'], nodeNames: ['node-1', 'node-2'], @@ -276,12 +313,13 @@ describe('AdvisorInsights', () => { } }); - it('marks an unread insight as read', async () => { + it('marks an unread insight as read via the row menu', async () => { renderComponent(); await waitForRows(); - fireEvent.click(screen.getByTestId('insight-result-2-toggle-read')); + fireEvent.click(screen.getByTestId('insight-result-2-actions')); + fireEvent.click(await screen.findByTestId('action-toggle-read')); await waitFor(() => expect(advisorsApi.markCheckResultsRead).toHaveBeenCalledWith( @@ -294,12 +332,13 @@ describe('AdvisorInsights', () => { ).toBeInTheDocument(); }); - it('marks a read insight as unread', async () => { + it('marks a read insight as unread via the row menu', async () => { renderComponent(); await waitForRows(); - fireEvent.click(screen.getByTestId('insight-result-1-toggle-read')); + fireEvent.click(screen.getByTestId('insight-result-1-actions')); + fireEvent.click(await screen.findByTestId('action-toggle-read')); await waitFor(() => expect(advisorsApi.markCheckResultsRead).toHaveBeenCalledWith( @@ -308,4 +347,222 @@ describe('AdvisorInsights', () => { ) ); }); + + it('opens and closes the details pane from the row menu', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-1-actions')); + fireEvent.click(await screen.findByTestId('action-view-details')); + + const pane = await screen.findByTestId('insight-details-pane'); + expect(pane).toBeInTheDocument(); + expect(screen.getByText(Messages.details.title)).toBeInTheDocument(); + expect(screen.getByTestId('insight-details-maximize')).toBeInTheDocument(); + + // content from the selected insight + expect(within(pane).getByText('MySQL is outdated')).toBeInTheDocument(); + expect( + within(pane).getByText('Newer version of MySQL is available') + ).toBeInTheDocument(); + expect( + within(pane).getByText('MySQL Version/mysql_version_check') + ).toBeInTheDocument(); + // the underlying check is enabled in the advisors fixture + expect( + within(screen.getByTestId('details-field-advisor-status')).getByText( + Messages.details.enabled + ) + ).toBeInTheDocument(); + // not-yet-populated fields render an em-dash + expect(within(pane).getAllByText('—').length).toBeGreaterThanOrEqual(5); + // no labels on this insight, so no labels section + expect( + within(pane).queryByText(Messages.details.otherLabels) + ).not.toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('insight-details-close')); + + await waitFor(() => + expect( + screen.queryByTestId('insight-details-pane') + ).not.toBeInTheDocument() + ); + }); + + it('copies the insight as a narrative text', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-1-actions')); + fireEvent.click(await screen.findByTestId('action-copy-as-text')); + + const checkedAt = format(new Date(TEST_ITEM.checkedAt), TIME_FORMAT); + const expected = + `The Advisor Check "MySQL is outdated" completed at ${checkedAt} ` + + 'with status "Failed" and severity "Warning".\n' + + '\n' + + 'Check Details:\n' + + ' ID: result-1\n' + + ' Check Name: mysql_version_check\n' + + ' Advisor: MySQL Version\n' + + ' Category: Version_configuration\n' + + ' Service Name: mysql-prod\n' + + ' Service Type: mysql\n' + + ' Node Name: node-1\n' + + ' Interval: Standard\n' + + ' Triggered By: User\n' + + ' Check Run ID: run-1\n' + + ' Read: Read\n' + + ' Description: Newer version of MySQL is available\n' + + ' Read More: https://percona.com'; + + await waitFor(() => + expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expected) + ); + expect( + await screen.findByText(Messages.success.copied) + ).toBeInTheDocument(); + }); + + it('dims rows whose checks are disabled', async () => { + renderComponent(); + + await waitForRows(); + + // postgresql_super_role is disabled in the advisors fixture + await waitFor(() => + expect(screen.getByTestId('insight-row-result-2')).toHaveAttribute( + 'data-check-disabled', + 'true' + ) + ); + expect(screen.getByTestId('insight-row-result-1')).not.toHaveAttribute( + 'data-check-disabled' + ); + }); + + it('disables an enabled check from the row menu', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-1-actions')); + const item = await screen.findByTestId('action-disable-check'); + expect(item).toHaveTextContent(Messages.actions.disableCheck); + + const advisorsCalls = vi.mocked(advisorsApi.listAdvisors).mock.calls + .length; + fireEvent.click(item); + + await waitFor(() => + expect(advisorsApi.changeAdvisorChecks).toHaveBeenCalledWith( + [{ name: 'mysql_version_check', enable: false }], + expect.anything() + ) + ); + expect( + await screen.findByText( + Messages.success.checkDisabled('MySQL version check') + ) + ).toBeInTheDocument(); + // the advisors list refetches, so the menu reflects the new state + await waitFor(() => + expect( + vi.mocked(advisorsApi.listAdvisors).mock.calls.length + ).toBeGreaterThan(advisorsCalls) + ); + }); + + it('offers enabling for a disabled check', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-2-actions')); + const item = await screen.findByTestId('action-disable-check'); + expect(item).toHaveTextContent(Messages.actions.enableCheck); + + fireEvent.click(item); + + await waitFor(() => + expect(advisorsApi.changeAdvisorChecks).toHaveBeenCalledWith( + [{ name: 'postgresql_super_role', enable: true }], + expect.anything() + ) + ); + }); + + it('disables re-run for disabled checks and run filter for rows without run ID', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-2-actions')); + await screen.findByTestId('action-view-details'); + + expect(screen.getByTestId('action-rerun-now')).toHaveAttribute( + 'aria-disabled', + 'true' + ); + expect(screen.getByTestId('action-filter-by-run-id')).toHaveAttribute( + 'aria-disabled', + 'true' + ); + }); + + it('filters by run ID from the row menu and clears via the chip', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-1-actions')); + fireEvent.click(await screen.findByTestId('action-filter-by-run-id')); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ runId: 'run-1', pageIndex: 0 }) + ) + ); + + const chip = await screen.findByTestId('run-id-filter-chip'); + fireEvent.click(within(chip).getByTestId('CancelIcon')); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenLastCalledWith( + expect.objectContaining({ runId: undefined }) + ) + ); + }); + + it('re-runs the check from the row menu and links to the new run', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.click(screen.getByTestId('insight-result-1-actions')); + fireEvent.click(await screen.findByTestId('action-rerun-now')); + + await waitFor(() => + expect(advisorsApi.startAdvisorChecks).toHaveBeenCalledWith( + ['mysql_version_check'], + expect.anything() + ) + ); + expect( + await screen.findByText( + Messages.success.rerunStarted('MySQL version check') + ) + ).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId('view-run-results')); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenLastCalledWith( + expect.objectContaining({ runId: 'run-123' }) + ) + ); + }); }); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 96c88d5df00..51133d1c30d 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -1,6 +1,19 @@ import Button from '@mui/material/Button'; +import Chip from '@mui/material/Chip'; +import BlockOutlinedIcon from '@mui/icons-material/BlockOutlined'; +import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined'; +import ContentCopyOutlinedIcon from '@mui/icons-material/ContentCopyOutlined'; import FilterAltOffOutlinedIcon from '@mui/icons-material/FilterAltOffOutlined'; +import FilterAltOutlinedIcon from '@mui/icons-material/FilterAltOutlined'; +import MarkEmailReadOutlinedIcon from '@mui/icons-material/MarkEmailReadOutlined'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; import RefreshOutlinedIcon from '@mui/icons-material/RefreshOutlined'; +import ReplayOutlinedIcon from '@mui/icons-material/ReplayOutlined'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import IconButton from '@mui/material/IconButton'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import Stack from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; @@ -10,12 +23,14 @@ import { Table } from '@percona/percona-ui'; import { Page } from 'components/page'; import { useAdvisors, + useChangeAdvisorChecks, useCheckResultsFilterValues, useCheckResultsHistory, useMarkCheckResultsRead, + useStartAdvisorChecks, } from 'hooks/api/useAdvisors'; import { type MRT_PaginationState } from 'material-react-table'; -import { enqueueSnackbar } from 'notistack'; +import { closeSnackbar, enqueueSnackbar } from 'notistack'; import { FC, useMemo, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { @@ -27,6 +42,8 @@ import { Severity } from 'types/severity.types'; import { OrgRole } from 'types/user.types'; import { capitalize } from 'utils/text.utils'; import { getInsightsColumns } from './AdvisorInsights.constants'; +import { insightToText } from './AdvisorInsights.utils'; +import { InsightDetailsPane } from './details-pane'; import { READ_FILTER_OPTIONS, SEVERITY_FILTER_OPTIONS, @@ -57,6 +74,11 @@ interface FilterOption { value: string; } +interface RowActionMenuState { + anchor: HTMLElement; + insight: CheckResultHistoryItem; +} + interface FilterSelectProps { id: string; label: string; @@ -95,7 +117,7 @@ const FilterSelect: FC = ({ ); const AdvisorInsights: FC = () => { - const [searchParams] = useSearchParams(); + const [searchParams, setSearchParams] = useSearchParams(); // deep link to the results of a concrete run, e.g. from the "View results" snackbar const runId = searchParams.get('runId') || undefined; const [pagination, setPagination] = useState({ @@ -110,10 +132,13 @@ const AdvisorInsights: FC = () => { setPagination((current) => ({ ...current, pageIndex: 0 })); }; - const hasActiveFilters = Object.values(filters).some(Boolean); + const hasActiveFilters = Object.values(filters).some(Boolean) || !!runId; const handleClearFilters = () => { setFilters(NO_FILTERS); + if (runId) { + setSearchParams({}); + } setPagination((current) => ({ ...current, pageIndex: 0 })); }; @@ -132,12 +157,80 @@ const AdvisorInsights: FC = () => { [pagination, filters, runId] ); + const [actionMenu, setActionMenu] = useState( + null + ); + const [detailsInsight, setDetailsInsight] = + useState(null); + const { data, isLoading, isFetching, refetch } = useCheckResultsHistory(params); const { data: advisors = [], refetch: refetchAdvisors } = useAdvisors(); const { data: filterValues, refetch: refetchFilterValues } = useCheckResultsFilterValues(); const { mutate: markRead, isPending: isMarking } = useMarkCheckResultsRead(); + const { mutate: startChecks, isPending: isStarting } = + useStartAdvisorChecks(); + const { mutate: changeChecks, isPending: isChangingCheck } = + useChangeAdvisorChecks(); + + const checksByName = useMemo( + () => + new Map( + advisors.flatMap((advisor) => advisor.checks).map((c) => [c.name, c]) + ), + [advisors] + ); + + const applyRunIdFilter = (newRunId: string) => { + setSearchParams(newRunId ? { runId: newRunId } : {}); + setPagination((current) => ({ ...current, pageIndex: 0 })); + }; + + const handleRerun = (insight: CheckResultHistoryItem) => { + const checkSummary = + checksByName.get(insight.checkName)?.summary ?? insight.checkName; + startChecks([insight.checkName], { + onSuccess: (newRunId) => + enqueueSnackbar(Messages.success.rerunStarted(checkSummary), { + variant: 'success', + action: (key) => ( + + ), + }), + }); + }; + + const handleToggleCheckEnabled = (insight: CheckResultHistoryItem) => { + const check = checksByName.get(insight.checkName); + if (!check) { + return; + } + changeChecks([{ name: check.name, enable: !check.enabled }], { + onSuccess: () => + enqueueSnackbar( + check.enabled + ? Messages.success.checkDisabled(check.summary) + : Messages.success.checkEnabled(check.summary), + { variant: 'success' } + ), + }); + }; + + const handleCopyAsText = async (insight: CheckResultHistoryItem) => { + await navigator.clipboard.writeText(insightToText(insight)); + enqueueSnackbar(Messages.success.copied, { variant: 'success' }); + }; // reloads the results and the data behind the filter dropdowns const handleRefresh = () => { @@ -240,6 +333,14 @@ const AdvisorInsights: FC = () => { value={filters.isRead} onChange={(value) => updateFilter('isRead', value)} /> + {runId && ( + applyRunIdFilter('')} + sx={{ alignSelf: 'center' }} + data-testid="run-id-filter-chip" + /> + )} + + )} + muiTableBodyRowProps={({ row }) => { + const check = checksByName.get(row.original.checkName); + // dim results of disabled checks; unknown checks stay normal + // to avoid flicker while the advisors list loads + const checkDisabled = check ? !check.enabled : false; + + return { + 'data-testid': `insight-row-${row.original.id}`, + 'data-check-disabled': checkDisabled ? 'true' : undefined, + sx: checkDisabled ? { opacity: 0.5 } : undefined, + }; + }} muiTableContainerProps={{ sx: { flex: 1, @@ -300,6 +416,131 @@ const AdvisorInsights: FC = () => { }, }} /> + setActionMenu(null)} + > + { + if (actionMenu) { + setDetailsInsight(actionMenu.insight); + } + setActionMenu(null); + }} + data-testid="action-view-details" + > + + + + {Messages.actions.viewDetails} + + { + if (actionMenu) { + handleToggleRead(actionMenu.insight); + } + setActionMenu(null); + }} + data-testid="action-toggle-read" + > + + + + {Messages.actions.toggleRead} + + { + if (actionMenu) { + handleRerun(actionMenu.insight); + } + setActionMenu(null); + }} + data-testid="action-rerun-now" + > + + + + {Messages.actions.rerunNow} + + { + if (actionMenu) { + applyRunIdFilter(actionMenu.insight.runId); + } + setActionMenu(null); + }} + data-testid="action-filter-by-run-id" + > + + + + {Messages.actions.filterByRunId} + + { + if (actionMenu) { + handleCopyAsText(actionMenu.insight); + } + setActionMenu(null); + }} + data-testid="action-copy-as-text" + > + + + + {Messages.actions.copyAsText} + + { + if (actionMenu) { + handleToggleCheckEnabled(actionMenu.insight); + } + setActionMenu(null); + }} + data-testid="action-disable-check" + > + + {actionMenu && + checksByName.get(actionMenu.insight.checkName)?.enabled === + false ? ( + + ) : ( + + )} + + + {actionMenu && + checksByName.get(actionMenu.insight.checkName)?.enabled === false + ? Messages.actions.enableCheck + : Messages.actions.disableCheck} + + + + setDetailsInsight(null)} + /> ); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts new file mode 100644 index 00000000000..7103bf408ce --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts @@ -0,0 +1,58 @@ +import { format } from 'date-fns'; +import { + AdvisorCheckTriggeredBy, + CheckResultHistoryItem, +} from 'types/advisors.types'; +import { + ADVISOR_INTERVAL, + ADVISOR_RESULT_STATUS, + SEVERITY, + TIME_FORMAT, +} from 'lib/constants'; +import { capitalize } from 'utils/text.utils'; + +const TRIGGERED_BY_LABEL: Record = { + [AdvisorCheckTriggeredBy.user]: 'User', + [AdvisorCheckTriggeredBy.scheduler]: 'Scheduler', + [AdvisorCheckTriggeredBy.unspecified]: '', +}; + +// renders an insight as a human-readable narrative for "Copy as text" +export const insightToText = (item: CheckResultHistoryItem): string => { + const checkedAt = item.checkedAt + ? format(new Date(item.checkedAt), TIME_FORMAT) + : ''; + const labels = Object.entries(item.labels ?? {}) + .map(([key, value]) => `${key}=${value}`) + .join(', '); + + const details: Array<[string, string]> = [ + ['ID', item.id], + ['Check Name', item.checkName], + ['Advisor', item.advisorName], + ['Category', capitalize(item.category)], + ['Service Name', item.serviceName], + ['Service Type', item.serviceType], + ['Node Name', item.nodeName], + ['Interval', ADVISOR_INTERVAL[item.interval]], + ['Triggered By', TRIGGERED_BY_LABEL[item.triggeredBy]], + ['Check Run ID', item.runId], + ['Read', item.isRead ? 'Read' : 'Unread'], + ['Description', item.description], + ['Read More', item.readMoreUrl], + ['Labels', labels], + ]; + + const detailLines = details + .filter(([, value]) => !!value) + .map(([name, value]) => ` ${name}: ${value}`) + .join('\n'); + + return ( + `The Advisor Check "${item.summary}" completed at ${checkedAt} ` + + `with status "${ADVISOR_RESULT_STATUS[item.status]}" and severity "${SEVERITY[item.severity]}".\n` + + `\n` + + `Check Details:\n` + + detailLines + ); +}; diff --git a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx new file mode 100644 index 00000000000..9d059a0a177 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx @@ -0,0 +1,271 @@ +import { FC, ReactNode, useEffect, useState } from 'react'; +import CloseIcon from '@mui/icons-material/Close'; +import CloseFullscreenOutlinedIcon from '@mui/icons-material/CloseFullscreenOutlined'; +import OpenInFullOutlinedIcon from '@mui/icons-material/OpenInFullOutlined'; +import Box from '@mui/material/Box'; +import Chip from '@mui/material/Chip'; +import Divider from '@mui/material/Divider'; +import Drawer from '@mui/material/Drawer'; +import IconButton from '@mui/material/IconButton'; +import Link from '@mui/material/Link'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { CopyToClipboardButton } from '@percona/percona-ui'; +import { format } from 'date-fns'; +import { + DRAWER_CLOSED_WIDTH, + DRAWER_WIDTH, +} from 'components/sidebar/drawer/Drawer.constants'; +import { useNavigation } from 'contexts/navigation/navigation.hooks'; +import { CheckResultHistoryItem } from 'types/advisors.types'; +import { Severity } from 'types/severity.types'; +import { + ADVISOR_INTERVAL, + ADVISOR_RESULT_STATUS, + SEVERITY, + TIME_FORMAT, +} from 'lib/constants'; +import { capitalize } from 'utils/text.utils'; +import { Messages } from '../AdvisorInsights.messages'; + +const EM_DASH = '—'; + +const SEVERITY_CHIP_COLOR: Record< + Severity, + 'error' | 'warning' | 'info' | 'default' +> = { + [Severity.emergency]: 'error', + [Severity.alert]: 'error', + [Severity.critical]: 'error', + [Severity.error]: 'error', + [Severity.warning]: 'warning', + [Severity.notice]: 'info', + [Severity.info]: 'info', + [Severity.debug]: 'default', + [Severity.unspecified]: 'default', +}; + +interface FieldProps { + label: string; + children: ReactNode; + // grid columns to span (out of 4) + span?: number; +} + +const Field: FC = ({ label, children, span = 1 }) => ( + + + {label} + + {children} + + +); + +interface InsightDetailsPaneProps { + insight: CheckResultHistoryItem | null; + // enabled state of the underlying check; undefined when unknown + checkEnabled?: boolean; + onClose: () => void; +} + +export const InsightDetailsPane: FC = ({ + insight, + checkEnabled, + onClose, +}) => { + const [maximized, setMaximized] = useState(false); + const { navOpen } = useNavigation(); + const open = !!insight; + // when maximized, take all the space except the main navigation + const sidebarWidth = navOpen ? DRAWER_WIDTH : DRAWER_CLOSED_WIDTH; + + // start each viewing at the default height + useEffect(() => { + if (!open) { + setMaximized(false); + } + }, [open]); + + const m = Messages.details; + const labels = Object.entries(insight?.labels ?? {}); + + return ( + + theme.transitions.create(['height', 'left'], { + duration: theme.transitions.duration.short, + }), + }, + }, + }} + > + + {m.title} + + setMaximized((current) => !current)} + data-testid="insight-details-maximize" + > + {maximized ? ( + + ) : ( + + )} + + + + + + + {insight && ( + + + + {insight.summary} + + + + + + + {ADVISOR_RESULT_STATUS[insight.status]} + + + + + {checkEnabled === undefined + ? EM_DASH + : checkEnabled + ? m.enabled + : m.disabled} + + + + + + {insight.description || EM_DASH} + + + + + {insight.readMoreUrl ? ( + + {insight.readMoreUrl} + + ) : ( + {EM_DASH} + )} + + + + + {insight.serviceName} + + + + + + {insight.nodeName} + + + + + + {capitalize(insight.category)} + + + + {EM_DASH} + + + + {EM_DASH} + + + {EM_DASH} + + + {EM_DASH} + + + {EM_DASH} + + + + + {insight.checkedAt + ? format(new Date(insight.checkedAt), TIME_FORMAT) + : EM_DASH} + + + + + {ADVISOR_INTERVAL[insight.interval]} + + + + {EM_DASH} + + + + {insight.advisorName + ? `${insight.advisorName}/${insight.checkName}` + : insight.checkName} + + + + + {labels.length > 0 && ( + + {m.otherLabels} + + {labels.map(([key, value]) => ( + + ))} + + + )} + + )} + + ); +}; diff --git a/ui/apps/pmm/src/pages/advisors/insights/details-pane/index.ts b/ui/apps/pmm/src/pages/advisors/insights/details-pane/index.ts new file mode 100644 index 00000000000..720d70cd85f --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/insights/details-pane/index.ts @@ -0,0 +1 @@ +export { InsightDetailsPane } from './InsightDetailsPane'; From 9b605645964531d438c676d96248f12710234deb Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Mon, 6 Jul 2026 02:36:19 +0300 Subject: [PATCH 026/120] PMM-14109 Add new fields to CheckResultHistoryItem and update related components - Introduced new fields: environment, cluster, replication_set, and outcome to CheckResultHistoryItem in advisors.proto. - Updated validation logic in advisors.pb.validate.go to include new fields. - Modified JSON representations in list_check_results_history_responses.go and v1.json to accommodate new fields. - Adjusted database schema and models to reflect new fields in CheckResult. - Enhanced tests to validate new fields and ensure proper functionality in AdvisorInsights components. --- api/advisors/v1/advisors.pb.go | 80 +++++++++++++----- api/advisors/v1/advisors.pb.validate.go | 8 ++ api/advisors/v1/advisors.proto | 26 ++++-- .../list_check_results_history_responses.go | 12 +++ api/advisors/v1/json/v1.json | 38 +++++++-- api/descriptor.bin | Bin 829183 -> 829812 bytes api/swagger/swagger-dev.json | 38 +++++++-- api/swagger/swagger.json | 38 +++++++-- managed/models/check_result_model.go | 44 +++++----- managed/models/check_result_model_reform.go | 42 ++++++--- managed/models/database.go | 4 + .../checks/check_result_record_test.go | 24 ++++-- managed/services/checks/checks.go | 63 ++++++++------ managed/services/management/checks.go | 44 +++++----- managed/services/types.go | 25 +++--- .../insights/AdvisorInsights.messages.ts | 1 + .../insights/AdvisorInsights.test.tsx | 19 ++++- .../insights/AdvisorInsights.utils.ts | 4 + .../details-pane/InsightDetailsPane.tsx | 18 +++- ui/apps/pmm/src/types/advisors.types.ts | 4 + 20 files changed, 373 insertions(+), 159 deletions(-) diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index 4a6e8b094be..a20711f9798 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -1372,24 +1372,32 @@ type CheckResultHistoryItem struct { NodeId string `protobuf:"bytes,10,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` // Name of the node the service runs on. NodeName string `protobuf:"bytes,11,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"` + // Environment of the monitored service on which the check ran. + Environment string `protobuf:"bytes,12,opt,name=environment,proto3" json:"environment,omitempty"` + // Cluster of the monitored service on which the check ran. + Cluster string `protobuf:"bytes,13,opt,name=cluster,proto3" json:"cluster,omitempty"` + // Replication set of the monitored service on which the check ran. + ReplicationSet string `protobuf:"bytes,14,opt,name=replication_set,json=replicationSet,proto3" json:"replication_set,omitempty"` // Outcome of the check run. - Status AdvisorCheckResultStatus `protobuf:"varint,12,opt,name=status,proto3,enum=advisors.v1.AdvisorCheckResultStatus" json:"status,omitempty"` + Status AdvisorCheckResultStatus `protobuf:"varint,15,opt,name=status,proto3,enum=advisors.v1.AdvisorCheckResultStatus" json:"status,omitempty"` // Short human-readable summary of the result. - Summary string `protobuf:"bytes,13,opt,name=summary,proto3" json:"summary,omitempty"` + Summary string `protobuf:"bytes,16,opt,name=summary,proto3" json:"summary,omitempty"` // Long human-readable description of the result. - Description string `protobuf:"bytes,14,opt,name=description,proto3" json:"description,omitempty"` + Description string `protobuf:"bytes,17,opt,name=description,proto3" json:"description,omitempty"` // URL containing information on how to resolve a detected issue. - ReadMoreUrl string `protobuf:"bytes,15,opt,name=read_more_url,json=readMoreUrl,proto3" json:"read_more_url,omitempty"` + ReadMoreUrl string `protobuf:"bytes,18,opt,name=read_more_url,json=readMoreUrl,proto3" json:"read_more_url,omitempty"` + // Output returned by the check run (finding details or execution error). + Outcome string `protobuf:"bytes,19,opt,name=outcome,proto3" json:"outcome,omitempty"` // Severity of the result. - Severity v1.Severity `protobuf:"varint,16,opt,name=severity,proto3,enum=management.v1.Severity" json:"severity,omitempty"` + Severity v1.Severity `protobuf:"varint,20,opt,name=severity,proto3,enum=management.v1.Severity" json:"severity,omitempty"` // Result labels. - Labels map[string]string `protobuf:"bytes,17,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Labels map[string]string `protobuf:"bytes,21,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Time when the check ran. - CheckedAt *timestamppb.Timestamp `protobuf:"bytes,18,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"` + CheckedAt *timestamppb.Timestamp `protobuf:"bytes,22,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"` // Whether the result has been marked as read. - IsRead bool `protobuf:"varint,19,opt,name=is_read,json=isRead,proto3" json:"is_read,omitempty"` + IsRead bool `protobuf:"varint,23,opt,name=is_read,json=isRead,proto3" json:"is_read,omitempty"` // The actor that initiated the run. - TriggeredBy AdvisorCheckTriggeredBy `protobuf:"varint,20,opt,name=triggered_by,json=triggeredBy,proto3,enum=advisors.v1.AdvisorCheckTriggeredBy" json:"triggered_by,omitempty"` + TriggeredBy AdvisorCheckTriggeredBy `protobuf:"varint,24,opt,name=triggered_by,json=triggeredBy,proto3,enum=advisors.v1.AdvisorCheckTriggeredBy" json:"triggered_by,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1501,6 +1509,27 @@ func (x *CheckResultHistoryItem) GetNodeName() string { return "" } +func (x *CheckResultHistoryItem) GetEnvironment() string { + if x != nil { + return x.Environment + } + return "" +} + +func (x *CheckResultHistoryItem) GetCluster() string { + if x != nil { + return x.Cluster + } + return "" +} + +func (x *CheckResultHistoryItem) GetReplicationSet() string { + if x != nil { + return x.ReplicationSet + } + return "" +} + func (x *CheckResultHistoryItem) GetStatus() AdvisorCheckResultStatus { if x != nil { return x.Status @@ -1529,6 +1558,13 @@ func (x *CheckResultHistoryItem) GetReadMoreUrl() string { return "" } +func (x *CheckResultHistoryItem) GetOutcome() string { + if x != nil { + return x.Outcome + } + return "" +} + func (x *CheckResultHistoryItem) GetSeverity() v1.Severity { if x != nil { return x.Severity @@ -2066,7 +2102,7 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "totalItems\x12\x1f\n" + "\vtotal_pages\x18\x02 \x01(\x05R\n" + "totalPages\x122\n" + - "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\xec\x06\n" + + "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\xeb\a\n" + "\x16CheckResultHistoryItem\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x15\n" + "\x06run_id\x18\x02 \x01(\tR\x05runId\x12\x1d\n" + @@ -2081,17 +2117,21 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\fservice_type\x18\t \x01(\tR\vserviceType\x12\x17\n" + "\anode_id\x18\n" + " \x01(\tR\x06nodeId\x12\x1b\n" + - "\tnode_name\x18\v \x01(\tR\bnodeName\x12=\n" + - "\x06status\x18\f \x01(\x0e2%.advisors.v1.AdvisorCheckResultStatusR\x06status\x12\x18\n" + - "\asummary\x18\r \x01(\tR\asummary\x12 \n" + - "\vdescription\x18\x0e \x01(\tR\vdescription\x12\"\n" + - "\rread_more_url\x18\x0f \x01(\tR\vreadMoreUrl\x123\n" + - "\bseverity\x18\x10 \x01(\x0e2\x17.management.v1.SeverityR\bseverity\x12G\n" + - "\x06labels\x18\x11 \x03(\v2/.advisors.v1.CheckResultHistoryItem.LabelsEntryR\x06labels\x129\n" + + "\tnode_name\x18\v \x01(\tR\bnodeName\x12 \n" + + "\venvironment\x18\f \x01(\tR\venvironment\x12\x18\n" + + "\acluster\x18\r \x01(\tR\acluster\x12'\n" + + "\x0freplication_set\x18\x0e \x01(\tR\x0ereplicationSet\x12=\n" + + "\x06status\x18\x0f \x01(\x0e2%.advisors.v1.AdvisorCheckResultStatusR\x06status\x12\x18\n" + + "\asummary\x18\x10 \x01(\tR\asummary\x12 \n" + + "\vdescription\x18\x11 \x01(\tR\vdescription\x12\"\n" + + "\rread_more_url\x18\x12 \x01(\tR\vreadMoreUrl\x12\x18\n" + + "\aoutcome\x18\x13 \x01(\tR\aoutcome\x123\n" + + "\bseverity\x18\x14 \x01(\x0e2\x17.management.v1.SeverityR\bseverity\x12G\n" + + "\x06labels\x18\x15 \x03(\v2/.advisors.v1.CheckResultHistoryItem.LabelsEntryR\x06labels\x129\n" + "\n" + - "checked_at\x18\x12 \x01(\v2\x1a.google.protobuf.TimestampR\tcheckedAt\x12\x17\n" + - "\ais_read\x18\x13 \x01(\bR\x06isRead\x12G\n" + - "\ftriggered_by\x18\x14 \x01(\x0e2$.advisors.v1.AdvisorCheckTriggeredByR\vtriggeredBy\x1a9\n" + + "checked_at\x18\x16 \x01(\v2\x1a.google.protobuf.TimestampR\tcheckedAt\x12\x17\n" + + "\ais_read\x18\x17 \x01(\bR\x06isRead\x12G\n" + + "\ftriggered_by\x18\x18 \x01(\x0e2$.advisors.v1.AdvisorCheckTriggeredByR\vtriggeredBy\x1a9\n" + "\vLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc1\x05\n" + diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 46976e924c6..9a2b42cbe26 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -2246,6 +2246,12 @@ func (m *CheckResultHistoryItem) validate(all bool) error { // no validation rules for NodeName + // no validation rules for Environment + + // no validation rules for Cluster + + // no validation rules for ReplicationSet + // no validation rules for Status // no validation rules for Summary @@ -2254,6 +2260,8 @@ func (m *CheckResultHistoryItem) validate(all bool) error { // no validation rules for ReadMoreUrl + // no validation rules for Outcome + // no validation rules for Severity // no validation rules for Labels diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index 0f3145b6761..7dbdc458c3a 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -211,24 +211,32 @@ message CheckResultHistoryItem { string node_id = 10; // Name of the node the service runs on. string node_name = 11; + // Environment of the monitored service on which the check ran. + string environment = 12; + // Cluster of the monitored service on which the check ran. + string cluster = 13; + // Replication set of the monitored service on which the check ran. + string replication_set = 14; // Outcome of the check run. - AdvisorCheckResultStatus status = 12; + AdvisorCheckResultStatus status = 15; // Short human-readable summary of the result. - string summary = 13; + string summary = 16; // Long human-readable description of the result. - string description = 14; + string description = 17; // URL containing information on how to resolve a detected issue. - string read_more_url = 15; + string read_more_url = 18; + // Output returned by the check run (finding details or execution error). + string outcome = 19; // Severity of the result. - management.v1.Severity severity = 16; + management.v1.Severity severity = 20; // Result labels. - map labels = 17; + map labels = 21; // Time when the check ran. - google.protobuf.Timestamp checked_at = 18; + google.protobuf.Timestamp checked_at = 22; // Whether the result has been marked as read. - bool is_read = 19; + bool is_read = 23; // The actor that initiated the run. - AdvisorCheckTriggeredBy triggered_by = 20; + AdvisorCheckTriggeredBy triggered_by = 24; } message ListCheckResultsHistoryRequest { diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go index b4773bf49cc..01390a84844 100644 --- a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go @@ -569,6 +569,15 @@ type ListCheckResultsHistoryOKBodyResultsItems0 struct { // Name of the node the service runs on. NodeName string `json:"node_name,omitempty"` + // Environment of the monitored service on which the check ran. + Environment string `json:"environment,omitempty"` + + // Cluster of the monitored service on which the check ran. + Cluster string `json:"cluster,omitempty"` + + // Replication set of the monitored service on which the check ran. + ReplicationSet string `json:"replication_set,omitempty"` + // AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service. // // - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue. @@ -586,6 +595,9 @@ type ListCheckResultsHistoryOKBodyResultsItems0 struct { // URL containing information on how to resolve a detected issue. ReadMoreURL string `json:"read_more_url,omitempty"` + // Output returned by the check run (finding details or execution error). + Outcome string `json:"outcome,omitempty"` + // Severity represents severity level of the check result or alert. // Enum: ["SEVERITY_UNSPECIFIED","SEVERITY_EMERGENCY","SEVERITY_ALERT","SEVERITY_CRITICAL","SEVERITY_ERROR","SEVERITY_WARNING","SEVERITY_NOTICE","SEVERITY_INFO","SEVERITY_DEBUG"] Severity *string `json:"severity,omitempty"` diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index b19a56b5f07..1a293ec9061 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -621,6 +621,21 @@ "type": "string", "x-order": 10 }, + "environment": { + "description": "Environment of the monitored service on which the check ran.", + "type": "string", + "x-order": 11 + }, + "cluster": { + "description": "Cluster of the monitored service on which the check ran.", + "type": "string", + "x-order": 12 + }, + "replication_set": { + "description": "Replication set of the monitored service on which the check ran.", + "type": "string", + "x-order": 13 + }, "status": { "description": "AdvisorCheckResultStatus represents the outcome of an Advisor check run against a service.\n\n - ADVISOR_CHECK_RESULT_STATUS_OK: The check ran and found no issue.\n - ADVISOR_CHECK_RESULT_STATUS_FAILED: The check ran and detected an issue.\n - ADVISOR_CHECK_RESULT_STATUS_ERROR: The check could not be executed.", "type": "string", @@ -631,22 +646,27 @@ "ADVISOR_CHECK_RESULT_STATUS_FAILED", "ADVISOR_CHECK_RESULT_STATUS_ERROR" ], - "x-order": 11 + "x-order": 14 }, "summary": { "description": "Short human-readable summary of the result.", "type": "string", - "x-order": 12 + "x-order": 15 }, "description": { "description": "Long human-readable description of the result.", "type": "string", - "x-order": 13 + "x-order": 16 }, "read_more_url": { "description": "URL containing information on how to resolve a detected issue.", "type": "string", - "x-order": 14 + "x-order": 17 + }, + "outcome": { + "description": "Output returned by the check run (finding details or execution error).", + "type": "string", + "x-order": 18 }, "severity": { "description": "Severity represents severity level of the check result or alert.", @@ -663,7 +683,7 @@ "SEVERITY_INFO", "SEVERITY_DEBUG" ], - "x-order": 15 + "x-order": 19 }, "labels": { "description": "Result labels.", @@ -671,18 +691,18 @@ "additionalProperties": { "type": "string" }, - "x-order": 16 + "x-order": 20 }, "checked_at": { "description": "Time when the check ran.", "type": "string", "format": "date-time", - "x-order": 17 + "x-order": 21 }, "is_read": { "description": "Whether the result has been marked as read.", "type": "boolean", - "x-order": 18 + "x-order": 22 }, "triggered_by": { "description": "AdvisorCheckTriggeredBy represents the actor that initiated an Advisor check run.\n\n - ADVISOR_CHECK_TRIGGERED_BY_USER: The run was started by a user via the API or UI.\n - ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER: The run was started by the built-in scheduler.", @@ -693,7 +713,7 @@ "ADVISOR_CHECK_TRIGGERED_BY_USER", "ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER" ], - "x-order": 19 + "x-order": 23 } } }, diff --git a/api/descriptor.bin b/api/descriptor.bin index 95ad8f462ef5a51a19b97245a34713a379abbbe7..fd52f5acc857b081ed5222d3ee98fc42d49e314c 100644 GIT binary patch delta 4360 zcmY*ceQ;FO70*5Q?cLq?0!iL(HpvFUBMAhM1e2gt3?LtV)Im|}SJ66!WYv_IIGc^5 zGdfYxVHgH=7$#S%F^UnyT0o)1RtIhEpw&wKXl4J^Hd58Cwa@W4f_{B9<9J{~QQjR&LG z7tOInXJ%QZtFyGgV^hX9Op?#0c$vH}&GY5apYb>=?75$fXGL=23SKqa#hU0fPCB)$ z<%*7U>bi8BTWW_px-!ijcce;V`qu!ujdr9nbyq6gnz^SmF1IbouaFO};PG&=$EP?A zGi3L2UMhdJg4eNxWQqKVGStQstVE7$y+77#+yu9y7 ze)uMj4;;Uj$IIEV0r5C54poI*>k~#1d$DakceLM;YR|~gC;0_) z9j1PZ#_ch7NUh`wmXsNo4?llXelF8~@-<2%XL}3Vx;itdwDuu)_41ktSLqdFTx%br zisSd6KcK;!`>@IsA$(~nyXPFd6~DQD|2U8#!II%UFr5zi?{q9FLQg!YrZ|zyuwR&wR=-; zZEbI9ZNJTHNoAI`wsm?PX)kqms<}(oIF(L!q^H)|_AGxVU8opj*_>Ud7|i7yL#c-t zmD)90MGQ#peVR|IkAXJC%7RkIKpV=HIu6=lM#Xl8rp1Bej6OcDJ`UPpmKbM}jDvQV zO$fXcgLZ^bxjjYGih<<4eSC6#F=$8FxL_xXK|8{xo@2ZuP^w`@!fb2;NPgVMFQ`v| zHq63fgLR+{v!a-RC5U#EQJGz@qm=;3InVGJSCoKulqG{`C7>Nu(eiDwVy-yO@*W{( zJ2tme6^^rrzcNO7mTR40WZRAK2&j;J>bA(V+f}V$fY1}n@y{0^*e6&~QtJUkoD*z( zMF1lTPMBvG*-^!fY>jZu_vV@v4BhT*h zt;AJo3Vu8-XK&!uO{bYt6|8}*)2w=00M#N^TW269l66LT@PjHOf4+g&G@W5iL9hlM z&alEDs09yaSTe{ngdHAL=V_tVfFwrc=mvgq?I;`P84n>)Mp;$0fdZ7Xin2&k6p|g! z@k{E?vT?!A2vE+liIs*DhTjJW#rdJ8gcXwie2!mU_W(ux;Sr-SI1f;%KQLny0cWM+ zT%tMHfR!X~>gSi%t)!@H97n)eNyYwvh*1=rhZW}>&50@`Kj`Pv>mH_Pk>Nzad6?n> z#|CGW;`lYR6_V4Q=aXw!QFiBSa8^;mpSCe_Q0di#x>xBqxD-~)`<~~MnpTtJcPiGP z?yIRX*g16_tftx-MufT!)~KixwFg`WYvh6Fc~$KiiUvEE56T*H{R<^VV-R$$3hJL_ z+z)GI-9|p=#*?faU8b;-6$dI9^BQB*%3xtyk>H$Oh20*2}U@d`j*597T21`W%Ij zO^?dP(-ibek8Iz>E4zDw62?h6>Y>W1Mx$z<9-3Zj+n6$#d{0nbot`mj_B}xnfBYm| z@g(IvW71Uf?MaGE*Dexz{Pe1*&4>!%2v+otf75=8Pu`Uf|a^^^)Ts7p#GY zUUL0O00teD(#t{D!`q2Q^yy$n_^WDDcon6Fj{sC9c>& zd7F${HC8uJ#CKkz)%Gjr=fOFkYxT>eoB6C;`UB@Mg3?c}-$a0L-XAm(Aljy%k_+|R zQgCZT-Ddq%zCc%`L~q?j!p)#YJfLfBl*cyn#vg1Xb1T3IryHrr)rBv0t<98IqYGb( z<(nx|Z7;V;LU*y+xZy}+ZNZGOHTd1r- z2~iM1w$Pj#0*JzHC2NsVu70()z59BlGC2!v2+5k@WGi_K>;m73<%(@&ZAU&uc33Z3 z7f~i>JB92*dq%|AKzo_QB$xsV!oNadxsBHs)-YG>Bzj%G{|mmPdnXB9Uu6ezCnfZG zQV^`2H0w$uTAhXgvUIuCuSWC$ISY(v-vlQE5UTLTFBZ{%uDM*bVQn)@a=c_UYIbh3DpthciANy~qeoVRi{S2oaoOQO-pR~Cf- z9f=>?DJ`G7VmHwr<$J&6E#13G=%EJD9K_vJb%{~Q!P-q%cLfll-zMv7b5OVu{WdvQ znVS11IC-1AC8p-Md&N6sy_Xfuwdi-qc~6TzSJhnEK>GuU3*bGla5wZWiAR}zvsMj9 zdx-uj4{YH#b?+ge-zp$mVD6#v^Nmb(@9v@bKQZxfbBjNb^%3I7^Z~bg-7q>IL4kk7 zeIpY5fJDRhY`8){BvJ5x-aaPllgqN{SUR1L$@xU5qqHj%H2s;xxh5NBK{kIO@gTEr z)!Bqxv6tvj&o-Xw-ka;y5Quwoy{cXWdsVOcU59^n#6Ge<%_b8v$?PNN(`+)n5y||W zM2$(tw;`GRxnz{L17v-cOD3d~IY7>5*<_Rnn*O1B*xwpuK{5wPJQZw>aK#|e5jp*3 zY|S7E{RToM1ek+Vdal_T^;j9C3$G0zBz{g-lQ~er9H`I9xzMQgO>pu#d9zIo1XK@^ z^+k3EgcdzS&KFv=o;=D1+P_Ftn=Vimgg;DTo_)36fv_uviN2QSy~3~R9wwomIuIQO zahPKIA*~=-!&HB<5gmr;FUdO3hz=XkUy?J^i1tlz@+EnVMl@LBC|Sp|qQhGBQF4yw zL@OI;$4FEd(aM7GU#Y(ETNmT%B+;mB+>X{gNkTv3pi&V}QgWtIsaPjz-cl1jg770` zeUm*m5p!-v$oU2W{3h^?$nQTSYQJa0xjB_PH_F>-vc5e(n@vP#bDErQbvCLAlnI*t lOJcG~Mp+>1%&NsZI6ezs2%o?g#uvdC#b*yJ-r;Qj`hRCzs)7Ij delta 3991 zcmY*bYj9Q770zD!+MauaTNT#`U|C6EMAOEA1d>sa1asx4EHFr`LuNa(ab zIw8eahru}3q1(|6DHX!A2?|YYb$HYcZSg^&l`0buF<>dA7#>neDgE|7``lZ9oFCsh z`}@|n_TFoqbM1K5o%gHOKEs}&eSGl}`p>SON0;zEhc1bpX)E~;nLE`H4UJ11*EAGn z%41LRv2x)PJdb7ld@UQovgNZ+@RDRsl8uTia97tYUH*+#tLq+KUGG&pc0=6{>Q=98 z{83@9Y+7KCl5RbB!qFrjCV4WonbMDoz zvpnmh{G^@NRAxc-B#Y!3nJlQDWCeo^%!X>OQk|n|*+BB4U+{-2vq9@+k$A8Uv|cu- z$iN)baGFt}Q>JM-KyuDzK0b1SUAJtg98Y$Gi+F(9fjCgMn%pjEf&>iTq2QNB>%OU537uVeU=Rl zwl50ySvGpC5%W-YA0uIQ(*u$Z{F2{uw+C7u3ug!GKl~2G#ZyE zLDC7$xFYXu=h<^Tib3Q&O9Z)N5IL`MXF6oXJaK_#JWI@R9d4Ca)C+b8L*Y2{p<|pqp zD;U!Ct90s4#RzKs^5AQH>XQC+4yK|k>YqH;AV)tNIxJ8?j((P$W^yo-qn{10H7f`y zFRL3iLgyeL`Pdd-R(_d9{B4a9LG&_<7Z?hMtpR1LSX1zFKz426r8NW0EeY1Z)&MIV z6F{|yl~)*u#>Q+9u{5l()G+H5$ud|X;0|m%86nT~=D?b3jOAdkqyo*#hI-+IEq_L{<(wSUvY~?Jj1cU zxyADRMvhSgoZE^sR&yc>$@{kPaTT{&Bx*PjaBj1_fa8F3Cw+vDLb81uA6b4UeTEJ= zcUZj8NVwSZX2J=S=scKm&GO1NKBA_XT)%~5qy}Cy6$fXi23|9jk2eZx;H@J#9j+BH z@YczN+j&X(I*J5mm7E^Z+=*l0BmTc{++qUK=> zRZY~rndgb;DB}gwn|WCI9NA^sPoD0*^+aJkZ~#4PJ;~=KFR2E=()DEf_ZbkP>&e{b zJYuM1gJO@uMAjI3qG!P(Kri~Ia_4HD(%U1Khjf!UI9VyU9w~6qbPy-*(vo^`) zyLt89o5*}45QOL^ih6qE3q5NyWt8cSFU0cAWS2V291paQf~{{ac7}p zi452l9Ynk3j9>8uO&uh31F1O9yn_Z+DI*FZNe4}RB!Jl1ZDh?-&edCM&ylx_Rmh#` zz(^_tk!_Tm;pF%tmM6B8wF~t`ov>c?Gh2n+T@-S1o$n>MXtpuJ9Fj4`buNdE?j2c1RQG76EHx+lHUeh4Bx>77RZiZ{u6D`lFr={L!JD{WfEK>H1e zYGYbOkp8zMzU9C@zXs!i*Gqhg?aLZZ~Pfr=pg84|V5e0>CAPxKM}L+;$i=QZ__ z(0?~D9R{(FV*3ACL9qI$@;+la4AbYxnq*9ejp=jbPBfs^nV*%D&i$dOf)VP>k`#I zYSP ''), summary VARCHAR NOT NULL, description TEXT NOT NULL, + outcome TEXT NOT NULL, read_more_url VARCHAR NOT NULL, severity VARCHAR NOT NULL, labels TEXT, diff --git a/managed/services/checks/check_result_record_test.go b/managed/services/checks/check_result_record_test.go index 1d465cbee63..d6821ded1ec 100644 --- a/managed/services/checks/check_result_record_test.go +++ b/managed/services/checks/check_result_record_test.go @@ -30,13 +30,16 @@ import ( func TestNewCheckResultRecord(t *testing.T) { t.Parallel() - c := check.Check{Name: "chk", Summary: "Check title", Advisor: "adv", Interval: check.Standard} + c := check.Check{Name: "chk", Summary: "Check title", Description: "Check description", Advisor: "adv", Interval: check.Standard} target := services.Target{ - ServiceID: "sid", - ServiceName: "sname", - ServiceType: models.MySQLServiceType, - NodeID: "nid", - NodeName: "nname", + ServiceID: "sid", + ServiceName: "sname", + ServiceType: models.MySQLServiceType, + NodeID: "nid", + NodeName: "nname", + Environment: "prod", + Cluster: "cluster-1", + ReplicationSet: "rs-1", } checkedAt := models.Now() ri := runInfo{runID: "run-1", triggeredBy: models.CheckTriggeredByUser} @@ -65,7 +68,11 @@ func TestNewCheckResultRecord(t *testing.T) { assert.Equal(t, "nname", rec.NodeName) assert.Equal(t, models.CheckResultFailed, rec.Status) assert.Equal(t, "sum", rec.Summary) - assert.Equal(t, "desc", rec.Description) + assert.Equal(t, "Check description", rec.Description) + assert.Equal(t, "desc", rec.Outcome) + assert.Equal(t, "prod", rec.Environment) + assert.Equal(t, "cluster-1", rec.Cluster) + assert.Equal(t, "rs-1", rec.ReplicationSet) assert.Equal(t, "https://example.com", rec.ReadMoreURL) assert.Equal(t, models.CheckSeverityError, rec.Severity) assert.Equal(t, checkedAt, rec.CheckedAt) @@ -100,7 +107,8 @@ func TestNewCheckResultRecord(t *testing.T) { assert.Equal(t, models.CheckResultError, rec.Status) assert.Equal(t, "Check title", rec.Summary) - assert.Equal(t, "execution failed", rec.Description) + assert.Equal(t, "Check description", rec.Description) + assert.Equal(t, "execution failed", rec.Outcome) assert.Equal(t, models.CheckSeverityDebug, rec.Severity) }) } diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index e9304c89b14..d44b8118f4a 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -776,23 +776,27 @@ func newCheckResultRecord( ri runInfo, ) *models.CheckResult { r := &models.CheckResult{ - CheckName: c.Name, - AdvisorName: c.Advisor, - Category: category, - Interval: models.Interval(c.Interval), - ServiceID: target.ServiceID, - ServiceName: target.ServiceName, - ServiceType: target.ServiceType, - NodeID: target.NodeID, - NodeName: target.NodeName, - Status: status, - Summary: result.Summary, - Description: result.Description, - ReadMoreURL: result.ReadMoreURL, - Severity: convertCommonSeverity(result.Severity), - CheckedAt: checkedAt, - RunID: ri.runID, - TriggeredBy: ri.triggeredBy, + CheckName: c.Name, + AdvisorName: c.Advisor, + Category: category, + Interval: models.Interval(c.Interval), + ServiceID: target.ServiceID, + ServiceName: target.ServiceName, + ServiceType: target.ServiceType, + NodeID: target.NodeID, + NodeName: target.NodeName, + Environment: target.Environment, + Cluster: target.Cluster, + ReplicationSet: target.ReplicationSet, + Status: status, + Summary: result.Summary, + Description: c.Description, + Outcome: result.Description, + ReadMoreURL: result.ReadMoreURL, + Severity: convertCommonSeverity(result.Severity), + CheckedAt: checkedAt, + RunID: ri.runID, + TriggeredBy: ri.triggeredBy, } // OK and error outcomes carry no finding; fall back to the check's own summary if r.Summary == "" { @@ -1563,17 +1567,20 @@ func (s *Service) findTargets(serviceType models.ServiceType, minPMMAgentVersion } targets = append(targets, services.Target{ - AgentID: pmmAgent.AgentID, - ServiceID: service.ServiceID, - ServiceName: service.ServiceName, - ServiceType: service.ServiceType, - NodeID: node.NodeID, - NodeName: node.NodeName, - Labels: labels, - DSN: DSN, - Files: agent.Files(), - TDP: agent.TemplateDelimiters(service), - TLSSkipVerify: agent.TLSSkipVerify, + AgentID: pmmAgent.AgentID, + ServiceID: service.ServiceID, + ServiceName: service.ServiceName, + ServiceType: service.ServiceType, + NodeID: node.NodeID, + NodeName: node.NodeName, + Environment: service.Environment, + Cluster: service.Cluster, + ReplicationSet: service.ReplicationSet, + Labels: labels, + DSN: DSN, + Files: agent.Files(), + TDP: agent.TemplateDelimiters(service), + TLSSkipVerify: agent.TLSSkipVerify, }) return nil }) diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index f8ee6dc489b..d12334799fb 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -235,26 +235,30 @@ func (s *ChecksAPIService) ListCheckResultsHistory( } items = append(items, &advisorsv1.CheckResultHistoryItem{ - Id: r.ID, - CheckName: r.CheckName, - AdvisorName: r.AdvisorName, - Category: r.Category, - Interval: convertModelInterval(r.Interval), - ServiceId: r.ServiceID, - ServiceName: r.ServiceName, - ServiceType: string(r.ServiceType), - NodeId: r.NodeID, - NodeName: r.NodeName, - Status: convertModelResultStatus(r.Status), - Summary: r.Summary, - Description: r.Description, - ReadMoreUrl: r.ReadMoreURL, - Severity: convertModelSeverity(r.Severity), - Labels: labels, - CheckedAt: timestamppb.New(r.CheckedAt), - IsRead: r.IsRead, - RunId: r.RunID, - TriggeredBy: convertModelTriggeredBy(r.TriggeredBy), + Id: r.ID, + CheckName: r.CheckName, + RunId: r.RunID, + AdvisorName: r.AdvisorName, + Category: r.Category, + Severity: convertModelSeverity(r.Severity), + Interval: convertModelInterval(r.Interval), + ServiceId: r.ServiceID, + ServiceName: r.ServiceName, + ServiceType: string(r.ServiceType), + NodeId: r.NodeID, + NodeName: r.NodeName, + Environment: r.Environment, + Cluster: r.Cluster, + ReplicationSet: r.ReplicationSet, + Status: convertModelResultStatus(r.Status), + Summary: r.Summary, + Description: r.Description, + Outcome: r.Outcome, + ReadMoreUrl: r.ReadMoreURL, + Labels: labels, + CheckedAt: timestamppb.New(r.CheckedAt), + IsRead: r.IsRead, + TriggeredBy: convertModelTriggeredBy(r.TriggeredBy), }) } diff --git a/managed/services/types.go b/managed/services/types.go index 55a0606406c..3660666cb36 100644 --- a/managed/services/types.go +++ b/managed/services/types.go @@ -24,17 +24,20 @@ import ( // Target contains required info about advisor check target. type Target struct { - AgentID string - ServiceID string - ServiceName string - ServiceType models.ServiceType - NodeID string - NodeName string - Labels map[string]string - DSN string - Files map[string]string - TDP *models.DelimiterPair - TLSSkipVerify bool + AgentID string + ServiceID string + ServiceName string + ServiceType models.ServiceType + NodeID string + NodeName string + Environment string + Cluster string + ReplicationSet string + Labels map[string]string + DSN string + Files map[string]string + TDP *models.DelimiterPair + TLSSkipVerify bool } // Copy creates a copy of the Target instance. diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index c6fb8586c57..2bc8726ae70 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -26,6 +26,7 @@ export const Messages = { enabled: 'Enabled', disabled: 'Disabled', description: 'Description', + outcome: 'Outcome', readMore: 'Read more', service: 'Service', node: 'Node', diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 2d1aca48b43..4c7438e800d 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -78,6 +78,10 @@ const TEST_ITEM: CheckResultHistoryItem = { isRead: true, runId: 'run-1', triggeredBy: AdvisorCheckTriggeredBy.user, + outcome: 'Installed version: 5.7.30', + environment: 'prod', + cluster: 'mysql-cluster', + replicationSet: 'rs1', }; const TEST_ITEM_UNREAD: CheckResultHistoryItem = { @@ -375,8 +379,15 @@ describe('AdvisorInsights', () => { Messages.details.enabled ) ).toBeInTheDocument(); - // not-yet-populated fields render an em-dash - expect(within(pane).getAllByText('—').length).toBeGreaterThanOrEqual(5); + // populated topology fields and outcome + expect(within(pane).getByText('prod')).toBeInTheDocument(); + expect(within(pane).getByText('mysql-cluster')).toBeInTheDocument(); + expect(within(pane).getByText('rs1')).toBeInTheDocument(); + expect( + within(pane).getByText('Installed version: 5.7.30') + ).toBeInTheDocument(); + // not-yet-populated fields (Region, AZ, First detected) render an em-dash + expect(within(pane).getAllByText('—').length).toBeGreaterThanOrEqual(3); // no labels on this insight, so no labels section expect( within(pane).queryByText(Messages.details.otherLabels) @@ -412,11 +423,15 @@ describe('AdvisorInsights', () => { ' Service Name: mysql-prod\n' + ' Service Type: mysql\n' + ' Node Name: node-1\n' + + ' Environment: prod\n' + + ' Cluster: mysql-cluster\n' + + ' Replication Set: rs1\n' + ' Interval: Standard\n' + ' Triggered By: User\n' + ' Check Run ID: run-1\n' + ' Read: Read\n' + ' Description: Newer version of MySQL is available\n' + + ' Outcome: Installed version: 5.7.30\n' + ' Read More: https://percona.com'; await waitFor(() => diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts index 7103bf408ce..24fc70fe43e 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts @@ -34,11 +34,15 @@ export const insightToText = (item: CheckResultHistoryItem): string => { ['Service Name', item.serviceName], ['Service Type', item.serviceType], ['Node Name', item.nodeName], + ['Environment', item.environment], + ['Cluster', item.cluster], + ['Replication Set', item.replicationSet], ['Interval', ADVISOR_INTERVAL[item.interval]], ['Triggered By', TRIGGERED_BY_LABEL[item.triggeredBy]], ['Check Run ID', item.runId], ['Read', item.isRead ? 'Read' : 'Unread'], ['Description', item.description], + ['Outcome', item.outcome], ['Read More', item.readMoreUrl], ['Labels', labels], ]; diff --git a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx index 9d059a0a177..0f637ed51cf 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx @@ -181,6 +181,12 @@ export const InsightDetailsPane: FC = ({ + + + {insight.outcome || EM_DASH} + + + {insight.readMoreUrl ? ( = ({ - {EM_DASH} + + {insight.environment || EM_DASH} + - {EM_DASH} + + {insight.cluster || EM_DASH} + - {EM_DASH} + + {insight.replicationSet || EM_DASH} + {EM_DASH} diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index 727cc018125..d15039fd84d 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -88,6 +88,10 @@ export interface CheckResultHistoryItem { isRead: boolean; runId: string; triggeredBy: AdvisorCheckTriggeredBy; + outcome: string; + environment: string; + cluster: string; + replicationSet: string; } export interface ListCheckResultsHistoryParams { From 0715e72c1cee9aaef11dd1e45809c4a90605aecf Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Mon, 6 Jul 2026 12:55:36 +0300 Subject: [PATCH 027/120] PMM-14109 Adjust sidebar positioning in InsightDetailsPane --- .../advisors/insights/details-pane/InsightDetailsPane.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx index 0f637ed51cf..48d98bec667 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx @@ -81,7 +81,7 @@ export const InsightDetailsPane: FC = ({ const [maximized, setMaximized] = useState(false); const { navOpen } = useNavigation(); const open = !!insight; - // when maximized, take all the space except the main navigation + // the pane never covers the main navigation const sidebarWidth = navOpen ? DRAWER_WIDTH : DRAWER_CLOSED_WIDTH; // start each viewing at the default height @@ -105,7 +105,7 @@ export const InsightDetailsPane: FC = ({ 'data-testid': 'insight-details-pane', sx: { height: maximized ? '100vh' : '60vh', - left: { xs: 0, md: maximized ? sidebarWidth : 0 }, + left: { xs: 0, md: sidebarWidth }, p: 2, transition: (theme) => theme.transitions.create(['height', 'left'], { From 6cdfae3eb0a0652a556fce8451fd694a36e86af1 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Tue, 7 Jul 2026 08:51:39 +0300 Subject: [PATCH 028/120] PMM-14109 Improve advisor output by adding outcome and summary fields, updating labels, and enhancing test coverage --- .../checks/check_result_record_test.go | 1 + managed/services/checks/checks.go | 1 + .../insights/AdvisorInsights.messages.ts | 4 +- .../insights/AdvisorInsights.test.tsx | 20 ++++-- .../insights/AdvisorInsights.utils.ts | 6 +- .../details-pane/InsightDetailsPane.tsx | 72 +++++++++++-------- 6 files changed, 67 insertions(+), 37 deletions(-) diff --git a/managed/services/checks/check_result_record_test.go b/managed/services/checks/check_result_record_test.go index d6821ded1ec..68bdec6e576 100644 --- a/managed/services/checks/check_result_record_test.go +++ b/managed/services/checks/check_result_record_test.go @@ -91,6 +91,7 @@ func TestNewCheckResultRecord(t *testing.T) { assert.Equal(t, models.CheckResultOK, rec.Status) assert.Equal(t, "Check title", rec.Summary) + assert.Equal(t, "Check passed", rec.Outcome) assert.Equal(t, models.CheckSeverityInfo, rec.Severity) labels, err := rec.GetLabels() diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index d44b8118f4a..f23d5b6cbdc 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -805,6 +805,7 @@ func newCheckResultRecord( switch status { case models.CheckResultOK: r.Severity = models.CheckSeverityInfo + r.Outcome = "Check passed" case models.CheckResultError: // the check could not be executed, which is a diagnostic concern, not a database issue r.Severity = models.CheckSeverityDebug diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index 2bc8726ae70..f10df60feb5 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -19,7 +19,7 @@ export const Messages = { title: 'Details', maximize: 'Maximize', close: 'Close', - insight: 'Insight', + summary: 'Summary', severity: 'Severity', status: 'Status', advisorStatus: 'Advisor status', @@ -38,7 +38,7 @@ export const Messages = { az: 'AZ', checkedAt: 'Checked at', checkInterval: 'Check interval', - firstDetected: 'First detected', + checkId: 'Check ID', checkName: 'Check name', otherLabels: 'Other labels', }, diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 4c7438e800d..7db3e316b0e 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -371,7 +371,9 @@ describe('AdvisorInsights', () => { within(pane).getByText('Newer version of MySQL is available') ).toBeInTheDocument(); expect( - within(pane).getByText('MySQL Version/mysql_version_check') + within( + screen.getByTestId('details-field-check-name') + ).getByText('mysql_version_check') ).toBeInTheDocument(); // the underlying check is enabled in the advisors fixture expect( @@ -386,8 +388,14 @@ describe('AdvisorInsights', () => { expect( within(pane).getByText('Installed version: 5.7.30') ).toBeInTheDocument(); - // not-yet-populated fields (Region, AZ, First detected) render an em-dash - expect(within(pane).getAllByText('—').length).toBeGreaterThanOrEqual(3); + // not-yet-populated fields (Region, AZ) render an em-dash + expect(within(pane).getAllByText('—').length).toBeGreaterThanOrEqual(2); + // the history record ID is shown as Check ID + expect( + within(screen.getByTestId('details-field-check-id')).getByText( + 'result-1' + ) + ).toBeInTheDocument(); // no labels on this insight, so no labels section expect( within(pane).queryByText(Messages.details.otherLabels) @@ -413,10 +421,11 @@ describe('AdvisorInsights', () => { const checkedAt = format(new Date(TEST_ITEM.checkedAt), TIME_FORMAT); const expected = `The Advisor Check "MySQL is outdated" completed at ${checkedAt} ` + - 'with status "Failed" and severity "Warning".\n' + + 'with status "Failed".\n' + '\n' + 'Check Details:\n' + ' ID: result-1\n' + + ' Check Run ID: run-1\n' + ' Check Name: mysql_version_check\n' + ' Advisor: MySQL Version\n' + ' Category: Version_configuration\n' + @@ -428,10 +437,11 @@ describe('AdvisorInsights', () => { ' Replication Set: rs1\n' + ' Interval: Standard\n' + ' Triggered By: User\n' + - ' Check Run ID: run-1\n' + ' Read: Read\n' + + ' Summary: MySQL is outdated\n' + ' Description: Newer version of MySQL is available\n' + ' Outcome: Installed version: 5.7.30\n' + + ' Severity: Warning\n' + ' Read More: https://percona.com'; await waitFor(() => diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts index 24fc70fe43e..489d0b4e66b 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts @@ -28,6 +28,7 @@ export const insightToText = (item: CheckResultHistoryItem): string => { const details: Array<[string, string]> = [ ['ID', item.id], + ['Check Run ID', item.runId], ['Check Name', item.checkName], ['Advisor', item.advisorName], ['Category', capitalize(item.category)], @@ -39,10 +40,11 @@ export const insightToText = (item: CheckResultHistoryItem): string => { ['Replication Set', item.replicationSet], ['Interval', ADVISOR_INTERVAL[item.interval]], ['Triggered By', TRIGGERED_BY_LABEL[item.triggeredBy]], - ['Check Run ID', item.runId], ['Read', item.isRead ? 'Read' : 'Unread'], + ['Summary', item.summary], ['Description', item.description], ['Outcome', item.outcome], + ['Severity', SEVERITY[item.severity]], ['Read More', item.readMoreUrl], ['Labels', labels], ]; @@ -54,7 +56,7 @@ export const insightToText = (item: CheckResultHistoryItem): string => { return ( `The Advisor Check "${item.summary}" completed at ${checkedAt} ` + - `with status "${ADVISOR_RESULT_STATUS[item.status]}" and severity "${SEVERITY[item.severity]}".\n` + + `with status "${ADVISOR_RESULT_STATUS[item.status]}".\n` + `\n` + `Check Details:\n` + detailLines diff --git a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx index 48d98bec667..b3500883280 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx @@ -150,7 +150,7 @@ export const InsightDetailsPane: FC = ({ rowGap: 3, }} > - + {insight.summary} @@ -181,12 +181,6 @@ export const InsightDetailsPane: FC = ({ - - - {insight.outcome || EM_DASH} - - - {insight.readMoreUrl ? ( = ({ )} + + + {insight.outcome || EM_DASH} + + + + + + {capitalize(insight.category)} + + {insight.serviceName} @@ -214,26 +219,36 @@ export const InsightDetailsPane: FC = ({ - - - {capitalize(insight.category)} - - - - {insight.environment || EM_DASH} - + + + {insight.environment || EM_DASH} + + {insight.environment && ( + + )} + - - {insight.cluster || EM_DASH} - + + + {insight.cluster || EM_DASH} + + {insight.cluster && ( + + )} + - - {insight.replicationSet || EM_DASH} - + + + {insight.replicationSet || EM_DASH} + + {insight.replicationSet && ( + + )} + {EM_DASH} @@ -254,15 +269,16 @@ export const InsightDetailsPane: FC = ({ {ADVISOR_INTERVAL[insight.interval]} - - {EM_DASH} + + + + {insight.id} + + + - - {insight.advisorName - ? `${insight.advisorName}/${insight.checkName}` - : insight.checkName} - + {insight.checkName} From f2586006a6b20d155eda18eda9b225a77fe1d734 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Wed, 8 Jul 2026 20:01:53 +0300 Subject: [PATCH 029/120] PMM-14109 Fix grafana datasource lookup after grafana-openapi-client-go migration The merge with main brought in the grafana-openapi-client-go migration (PMM-15181), which replaced the client's numeric-ID datasource lookup with GetDatasourceUIDByName. Update the server.grafanaClient interface and the advisor notifications reconciler to use GetDatasourceUIDByName(ctx, "Metrics"), matching the existing pattern in managed/services/alerting, and regenerate the mock plus its test expectations. --- .../services/server/advisor_notifications.go | 3 ++- .../server/advisor_notifications_test.go | 4 ++-- managed/services/server/deps.go | 2 +- .../server/mock_grafana_client_test.go | 20 +++++++++---------- managed/services/server/server_test.go | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/managed/services/server/advisor_notifications.go b/managed/services/server/advisor_notifications.go index d47c24f3a9d..41265d324b9 100644 --- a/managed/services/server/advisor_notifications.go +++ b/managed/services/server/advisor_notifications.go @@ -115,7 +115,8 @@ func (s *Server) reconcileAdvisorNotifications(ctx context.Context, settings *mo s.l.Debugf("Failed to delete existing advisor notifications rule group (ignored): %v", err) } - datasourceUID, err := s.grafanaClient.GetDatasourceUIDByID(ctx, 1) // 1 is the Metrics datasource ID in PMM. + // "Metrics" is the VictoriaMetrics datasource provisioned by PMM. + datasourceUID, err := s.grafanaClient.GetDatasourceUIDByName(ctx, "Metrics") if err != nil { return fmt.Errorf("failed to get metrics datasource UID: %w", err) } diff --git a/managed/services/server/advisor_notifications_test.go b/managed/services/server/advisor_notifications_test.go index cbb3279c10e..47b4533c750 100644 --- a/managed/services/server/advisor_notifications_test.go +++ b/managed/services/server/advisor_notifications_test.go @@ -78,7 +78,7 @@ func TestReconcileAdvisorNotifications(t *testing.T) { s, gc := newServer(t) gc.On("CreateFolderWithUID", mock.Anything, advisorNotificationsFolderTitle, advisorNotificationsFolderUID).Return(nil) gc.On("DeleteAlertRuleGroup", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup).Return(nil) - gc.On("GetDatasourceUIDByID", mock.Anything, int64(1)).Return("ds-uid", nil) + gc.On("GetDatasourceUIDByName", mock.Anything, "Metrics").Return("ds-uid", nil) gc.On( "CreateAlertRule", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup, advisorNotificationsRuleInterval, mock.MatchedBy(func(rule *services.Rule) bool { @@ -109,7 +109,7 @@ func TestReconcileAdvisorNotifications(t *testing.T) { s, gc := newServer(t) gc.On("CreateFolderWithUID", mock.Anything, mock.Anything, mock.Anything).Return(nil) gc.On("DeleteAlertRuleGroup", mock.Anything, mock.Anything, mock.Anything).Return(nil) - gc.On("GetDatasourceUIDByID", mock.Anything, int64(1)).Return("", errors.New("boom")) + gc.On("GetDatasourceUIDByName", mock.Anything, "Metrics").Return("", errors.New("boom")) err := s.reconcileAdvisorNotifications(t.Context(), enabledSettings()) require.Error(t, err) diff --git a/managed/services/server/deps.go b/managed/services/server/deps.go index 2a05d27db2f..bd485d00b81 100644 --- a/managed/services/server/deps.go +++ b/managed/services/server/deps.go @@ -35,7 +35,7 @@ type healthChecker interface { //nolint:iface // We use it instead of real type for testing and to avoid dependency cycle. type grafanaClient interface { //nolint:iface healthChecker - GetDatasourceUIDByID(ctx context.Context, id int64) (string, error) + GetDatasourceUIDByName(ctx context.Context, name string) (string, error) CreateFolderWithUID(ctx context.Context, title, uid string) error CreateAlertRule(ctx context.Context, folderUID, groupName, interval string, rule *services.Rule) error DeleteAlertRuleGroup(ctx context.Context, folderUID, groupName string) error diff --git a/managed/services/server/mock_grafana_client_test.go b/managed/services/server/mock_grafana_client_test.go index 119975c57e0..8c76377503e 100644 --- a/managed/services/server/mock_grafana_client_test.go +++ b/managed/services/server/mock_grafana_client_test.go @@ -69,27 +69,27 @@ func (_m *mockGrafanaClient) DeleteAlertRuleGroup(ctx context.Context, folderUID return r0 } -// GetDatasourceUIDByID provides a mock function with given fields: ctx, id -func (_m *mockGrafanaClient) GetDatasourceUIDByID(ctx context.Context, id int64) (string, error) { - ret := _m.Called(ctx, id) +// GetDatasourceUIDByName provides a mock function with given fields: ctx, name +func (_m *mockGrafanaClient) GetDatasourceUIDByName(ctx context.Context, name string) (string, error) { + ret := _m.Called(ctx, name) if len(ret) == 0 { - panic("no return value specified for GetDatasourceUIDByID") + panic("no return value specified for GetDatasourceUIDByName") } var r0 string var r1 error - if rf, ok := ret.Get(0).(func(context.Context, int64) (string, error)); ok { - return rf(ctx, id) + if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok { + return rf(ctx, name) } - if rf, ok := ret.Get(0).(func(context.Context, int64) string); ok { - r0 = rf(ctx, id) + if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + r0 = rf(ctx, name) } else { r0 = ret.Get(0).(string) } - if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { - r1 = rf(ctx, id) + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, name) } else { r1 = ret.Error(1) } diff --git a/managed/services/server/server_test.go b/managed/services/server/server_test.go index 052b17feb20..33bd6eda143 100644 --- a/managed/services/server/server_test.go +++ b/managed/services/server/server_test.go @@ -89,7 +89,7 @@ func TestServer(t *testing.T) { mgrafana.On("IsReady", mock.Anything).Return(nil) mgrafana.On("CreateFolderWithUID", mock.Anything, mock.Anything, mock.Anything).Return(nil) mgrafana.On("DeleteAlertRuleGroup", mock.Anything, mock.Anything, mock.Anything).Return(nil) - mgrafana.On("GetDatasourceUIDByID", mock.Anything, mock.Anything).Return("ds-uid", nil) + mgrafana.On("GetDatasourceUIDByName", mock.Anything, mock.Anything).Return("ds-uid", nil) mgrafana.On("CreateAlertRule", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) s, err := NewServer(&Params{ From ea8960dd99af8be83498c041793f92f09a21cd48 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Wed, 8 Jul 2026 20:02:00 +0300 Subject: [PATCH 030/120] PMM-14109 Apply prettier formatting to advisor UI files main added a UI format-check gate (PMM-7, #5572). These advisor files predate that gate and were never run through prettier. Reformat them so `make -C ui format-check` passes. --- ui/apps/pmm/src/api/advisors.ts | 4 +- ui/apps/pmm/src/hooks/api/useAdvisors.ts | 8 +- ui/apps/pmm/src/lib/constants.ts | 13 +- .../src/pages/advisors/AdvisorsList.test.tsx | 7 +- .../pmm/src/pages/advisors/AdvisorsList.tsx | 3 +- .../insights/AdvisorInsights.constants.tsx | 161 +++++++++--------- .../insights/AdvisorInsights.test.tsx | 20 +-- .../advisors/insights/AdvisorInsights.tsx | 4 +- .../AdvancedSettingsForm.utils.test.ts | 4 +- 9 files changed, 99 insertions(+), 125 deletions(-) diff --git a/ui/apps/pmm/src/api/advisors.ts b/ui/apps/pmm/src/api/advisors.ts index 2814137601a..be65ed27e34 100644 --- a/ui/apps/pmm/src/api/advisors.ts +++ b/ui/apps/pmm/src/api/advisors.ts @@ -18,9 +18,7 @@ export const listAdvisors = async (): Promise => { return res.data.advisors; }; -export const startAdvisorChecks = async ( - names: string[] -): Promise => { +export const startAdvisorChecks = async (names: string[]): Promise => { const payload: StartAdvisorChecksRequest = { names }; const res = await api.post( '/advisors/checks:start', diff --git a/ui/apps/pmm/src/hooks/api/useAdvisors.ts b/ui/apps/pmm/src/hooks/api/useAdvisors.ts index fc1fe6bfec9..d35a3efabd3 100644 --- a/ui/apps/pmm/src/hooks/api/useAdvisors.ts +++ b/ui/apps/pmm/src/hooks/api/useAdvisors.ts @@ -51,9 +51,7 @@ export const useStartAdvisorChecks = ( export const useCheckResultsHistory = ( params: ListCheckResultsHistoryParams, - options?: Partial< - UseQueryOptions> - > + options?: Partial>> ) => useQuery({ queryKey: [KEYS.HISTORY, params], @@ -91,9 +89,7 @@ export const useMarkCheckResultsRead = ( }; export const useChangeAdvisorChecks = ( - options?: Partial< - UseMutationOptions - > + options?: Partial> ) => { const queryClient = useQueryClient(); diff --git a/ui/apps/pmm/src/lib/constants.ts b/ui/apps/pmm/src/lib/constants.ts index eba07ab5ed1..d3e6787156a 100644 --- a/ui/apps/pmm/src/lib/constants.ts +++ b/ui/apps/pmm/src/lib/constants.ts @@ -40,13 +40,12 @@ export const ADVISOR_INTERVAL: Record = { [AdvisorInterval.unspecified]: 'Unspecified', }; -export const ADVISOR_RESULT_STATUS: Record = - { - [AdvisorCheckResultStatus.ok]: 'OK', - [AdvisorCheckResultStatus.failed]: 'Failed', - [AdvisorCheckResultStatus.error]: 'Error', - [AdvisorCheckResultStatus.unspecified]: 'Unspecified', - }; +export const ADVISOR_RESULT_STATUS: Record = { + [AdvisorCheckResultStatus.ok]: 'OK', + [AdvisorCheckResultStatus.failed]: 'Failed', + [AdvisorCheckResultStatus.error]: 'Error', + [AdvisorCheckResultStatus.unspecified]: 'Unspecified', +}; export const SEVERITY: Record = { [Severity.emergency]: 'Emergency', diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx index 8c14ead43e1..0bf5fb69cb0 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -15,11 +15,7 @@ import { wrapWithSnackbarProvider, wrapWithUserProvider, } from 'utils/testUtils'; -import { - Advisor, - AdvisorFamily, - AdvisorInterval, -} from 'types/advisors.types'; +import { Advisor, AdvisorFamily, AdvisorInterval } from 'types/advisors.types'; vi.mock('api/advisors'); @@ -83,7 +79,6 @@ const waitForRows = async () => { ); }; - describe('AdvisorsList', () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index c26338f31da..70de15458c9 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -32,8 +32,7 @@ const AdvisorsList: FC = () => { const rows = useMemo(() => flattenAdvisorChecks(advisors), [advisors]); const categories = useMemo( - () => - [...new Set(rows.map((row) => capitalize(row.category)))].sort(), + () => [...new Set(rows.map((row) => capitalize(row.category)))].sort(), [rows] ); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx index 2ed5c5c2cc2..8dc4cf9d38e 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx @@ -4,11 +4,7 @@ import Link from '@mui/material/Link'; import { format } from 'date-fns'; import { CheckResultHistoryItem } from 'types/advisors.types'; import { Severity } from 'types/severity.types'; -import { - ADVISOR_RESULT_STATUS, - SEVERITY, - TIME_FORMAT, -} from 'lib/constants'; +import { ADVISOR_RESULT_STATUS, SEVERITY, TIME_FORMAT } from 'lib/constants'; import { capitalize } from 'utils/text.utils'; import { Messages } from './AdvisorInsights.messages'; @@ -24,80 +20,81 @@ const SEVERITY_ORDER: Record = { [Severity.unspecified]: 9, }; -export const getInsightsColumns = (): MRT_ColumnDef[] => [ - { - header: Messages.columns.summary, - accessorKey: 'summary', - enableSorting: false, - size: 300, - grow: true, - Cell: ({ row }) => ( - - {row.original.summary} - {row.original.readMoreUrl && ( - <> - {' '} - - {Messages.readMore} - - - )} - - ), - }, - { - id: 'serviceName', - header: Messages.columns.service, - accessorKey: 'serviceName', - size: 160, - }, - { - id: 'category', - header: Messages.columns.category, - accessorFn: (row) => capitalize(row.category), - size: 140, - }, - { - id: 'severity', - header: Messages.columns.severity, - accessorFn: (row) => SEVERITY[row.severity], - sortingFn: (rowA, rowB) => - SEVERITY_ORDER[rowA.original.severity] - - SEVERITY_ORDER[rowB.original.severity], - size: 130, - }, - { - id: 'status', - header: Messages.columns.status, - accessorFn: (row) => ADVISOR_RESULT_STATUS[row.status], - size: 120, - }, - { - header: Messages.columns.checkedAt, - accessorKey: 'checkedAt', - size: 160, - Cell: ({ row }) => - row.original.checkedAt - ? format(new Date(row.original.checkedAt), TIME_FORMAT) - : null, - }, - { - id: 'isRead', - header: Messages.columns.read, - accessorFn: (row) => (row.isRead ? Messages.read : Messages.unread), - size: 90, - grow: false, - Cell: ({ row }) => ( - - ), - }, -]; +export const getInsightsColumns = + (): MRT_ColumnDef[] => [ + { + header: Messages.columns.summary, + accessorKey: 'summary', + enableSorting: false, + size: 300, + grow: true, + Cell: ({ row }) => ( + + {row.original.summary} + {row.original.readMoreUrl && ( + <> + {' '} + + {Messages.readMore} + + + )} + + ), + }, + { + id: 'serviceName', + header: Messages.columns.service, + accessorKey: 'serviceName', + size: 160, + }, + { + id: 'category', + header: Messages.columns.category, + accessorFn: (row) => capitalize(row.category), + size: 140, + }, + { + id: 'severity', + header: Messages.columns.severity, + accessorFn: (row) => SEVERITY[row.severity], + sortingFn: (rowA, rowB) => + SEVERITY_ORDER[rowA.original.severity] - + SEVERITY_ORDER[rowB.original.severity], + size: 130, + }, + { + id: 'status', + header: Messages.columns.status, + accessorFn: (row) => ADVISOR_RESULT_STATUS[row.status], + size: 120, + }, + { + header: Messages.columns.checkedAt, + accessorKey: 'checkedAt', + size: 160, + Cell: ({ row }) => + row.original.checkedAt + ? format(new Date(row.original.checkedAt), TIME_FORMAT) + : null, + }, + { + id: 'isRead', + header: Messages.columns.read, + accessorFn: (row) => (row.isRead ? Messages.read : Messages.unread), + size: 90, + grow: false, + Cell: ({ row }) => ( + + ), + }, + ]; diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 7db3e316b0e..1be5e7fe2e9 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -264,8 +264,7 @@ describe('AdvisorInsights', () => { const historyCalls = vi.mocked(advisorsApi.listCheckResultsHistory).mock .calls.length; - const advisorsCalls = vi.mocked(advisorsApi.listAdvisors).mock.calls - .length; + const advisorsCalls = vi.mocked(advisorsApi.listAdvisors).mock.calls.length; const filterValuesCalls = vi.mocked( advisorsApi.listCheckResultsFilterValues ).mock.calls.length; @@ -311,9 +310,7 @@ describe('AdvisorInsights', () => { name: new RegExp(name), hidden: true, }); - expect( - header.querySelector('.MuiTableSortLabel-root') - ).not.toBeNull(); + expect(header.querySelector('.MuiTableSortLabel-root')).not.toBeNull(); } }); @@ -371,9 +368,9 @@ describe('AdvisorInsights', () => { within(pane).getByText('Newer version of MySQL is available') ).toBeInTheDocument(); expect( - within( - screen.getByTestId('details-field-check-name') - ).getByText('mysql_version_check') + within(screen.getByTestId('details-field-check-name')).getByText( + 'mysql_version_check' + ) ).toBeInTheDocument(); // the underlying check is enabled in the advisors fixture expect( @@ -392,9 +389,7 @@ describe('AdvisorInsights', () => { expect(within(pane).getAllByText('—').length).toBeGreaterThanOrEqual(2); // the history record ID is shown as Check ID expect( - within(screen.getByTestId('details-field-check-id')).getByText( - 'result-1' - ) + within(screen.getByTestId('details-field-check-id')).getByText('result-1') ).toBeInTheDocument(); // no labels on this insight, so no labels section expect( @@ -478,8 +473,7 @@ describe('AdvisorInsights', () => { const item = await screen.findByTestId('action-disable-check'); expect(item).toHaveTextContent(Messages.actions.disableCheck); - const advisorsCalls = vi.mocked(advisorsApi.listAdvisors).mock.calls - .length; + const advisorsCalls = vi.mocked(advisorsApi.listAdvisors).mock.calls.length; fireEvent.click(item); await waitFor(() => diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 51133d1c30d..6b4c7bd6055 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -157,9 +157,7 @@ const AdvisorInsights: FC = () => { [pagination, filters, runId] ); - const [actionMenu, setActionMenu] = useState( - null - ); + const [actionMenu, setActionMenu] = useState(null); const [detailsInsight, setDetailsInsight] = useState(null); diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts index a940cb5dc8a..a8edcd13d1a 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts @@ -56,8 +56,6 @@ describe('toPayload', () => { expect(payload.advisorHistoryRetention).toBe('1209600s'); expect(payload.enableAdvisorNotifications).toBe(true); - expect(payload.advisorNotificationSeverityThreshold).toBe( - Severity.warning - ); + expect(payload.advisorNotificationSeverityThreshold).toBe(Severity.warning); }); }); From 705b7132be089c2ee7fbffff28f17ea3e8cbb73e Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Mon, 13 Jul 2026 13:55:52 +0300 Subject: [PATCH 031/120] [ADVISOR-456] Refactor advisor checks to use batch ID instead of run ID - Updated protobuf definitions to replace `run_id` with `batch_id` in relevant messages. - Modified validation logic to reflect the change from `run_id` to `batch_id`. - Adjusted API parameters and responses to utilize `batch_id`. - Updated client-side code to handle `batch_id` in API calls and state management. - Refactored database schema and model definitions to store and query `batch_id` instead of `run_id`. - Updated tests to ensure functionality aligns with the new `batch_id` implementation. --- api/advisors/v1/advisors.pb.go | 42 +++++------ api/advisors/v1/advisors.pb.validate.go | 6 +- api/advisors/v1/advisors.proto | 12 ++-- .../list_check_results_history_parameters.go | 66 +++++++++--------- .../list_check_results_history_responses.go | 4 +- .../start_advisor_checks_responses.go | 4 +- api/advisors/v1/json/v1.json | 12 ++-- api/descriptor.bin | Bin 827699 -> 827719 bytes api/swagger/swagger-dev.json | 12 ++-- api/swagger/swagger.json | 12 ++-- managed/models/check_result_helpers.go | 8 +-- managed/models/check_result_model.go | 2 +- managed/models/check_result_model_reform.go | 10 +-- managed/models/database.go | 4 +- .../checks/check_result_record_test.go | 4 +- managed/services/checks/checks.go | 12 ++-- managed/services/management/checks.go | 10 +-- ui/apps/pmm/src/api/advisors.ts | 2 +- .../pmm/src/pages/advisors/AdvisorsList.tsx | 4 +- .../insights/AdvisorInsights.messages.ts | 6 +- .../insights/AdvisorInsights.test.tsx | 40 +++++------ .../advisors/insights/AdvisorInsights.tsx | 38 +++++----- .../insights/AdvisorInsights.utils.ts | 2 +- .../details-pane/InsightDetailsPane.tsx | 12 ++-- ui/apps/pmm/src/types/advisors.types.ts | 6 +- 25 files changed, 165 insertions(+), 165 deletions(-) diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index a20711f9798..b7eeb59f420 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -858,8 +858,8 @@ func (x *StartAdvisorChecksRequest) GetNames() []string { type StartAdvisorChecksResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - // ID assigned to this run; all check results produced by it share this run_id. - RunId string `protobuf:"bytes,1,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // ID assigned to this batch; all check results produced by it share this batch_id. + BatchId string `protobuf:"bytes,1,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -894,9 +894,9 @@ func (*StartAdvisorChecksResponse) Descriptor() ([]byte, []int) { return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{7} } -func (x *StartAdvisorChecksResponse) GetRunId() string { +func (x *StartAdvisorChecksResponse) GetBatchId() string { if x != nil { - return x.RunId + return x.BatchId } return "" } @@ -1352,8 +1352,8 @@ type CheckResultHistoryItem struct { state protoimpl.MessageState `protogen:"open.v1"` // Unique identifier of the history record. Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - // ID of the run this result belongs to; all results produced by one execution share it. - RunId string `protobuf:"bytes,2,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // ID of the batch this result belongs to; all results produced by one execution share it. + BatchId string `protobuf:"bytes,2,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` // Name of the check that ran. CheckName string `protobuf:"bytes,3,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` // Name of the advisor the check belongs to. @@ -1439,9 +1439,9 @@ func (x *CheckResultHistoryItem) GetId() string { return "" } -func (x *CheckResultHistoryItem) GetRunId() string { +func (x *CheckResultHistoryItem) GetBatchId() string { if x != nil { - return x.RunId + return x.BatchId } return "" } @@ -1626,8 +1626,8 @@ type ListCheckResultsHistoryRequest struct { CheckName string `protobuf:"bytes,11,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` // Filter by severity. Severity *v1.Severity `protobuf:"varint,12,opt,name=severity,proto3,enum=management.v1.Severity,oneof" json:"severity,omitempty"` - // Filter by run ID. - RunId string `protobuf:"bytes,13,opt,name=run_id,json=runId,proto3" json:"run_id,omitempty"` + // Filter by batch ID. + BatchId string `protobuf:"bytes,13,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` // Filter by the actor that initiated the run. TriggeredBy *AdvisorCheckTriggeredBy `protobuf:"varint,14,opt,name=triggered_by,json=triggeredBy,proto3,enum=advisors.v1.AdvisorCheckTriggeredBy,oneof" json:"triggered_by,omitempty"` unknownFields protoimpl.UnknownFields @@ -1748,9 +1748,9 @@ func (x *ListCheckResultsHistoryRequest) GetSeverity() v1.Severity { return v1.Severity(0) } -func (x *ListCheckResultsHistoryRequest) GetRunId() string { +func (x *ListCheckResultsHistoryRequest) GetBatchId() string { if x != nil { - return x.RunId + return x.BatchId } return "" } @@ -2073,9 +2073,9 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\binterval\x18\x04 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\bintervalB\t\n" + "\a_enable\"1\n" + "\x19StartAdvisorChecksRequest\x12\x14\n" + - "\x05names\x18\x01 \x03(\tR\x05names\"3\n" + - "\x1aStartAdvisorChecksResponse\x12\x15\n" + - "\x06run_id\x18\x01 \x01(\tR\x05runId\"\x1a\n" + + "\x05names\x18\x01 \x03(\tR\x05names\"7\n" + + "\x1aStartAdvisorChecksResponse\x12\x19\n" + + "\bbatch_id\x18\x01 \x01(\tR\abatchId\"\x1a\n" + "\x18ListAdvisorChecksRequest\"N\n" + "\x19ListAdvisorChecksResponse\x121\n" + "\x06checks\x18\x01 \x03(\v2\x19.advisors.v1.AdvisorCheckR\x06checks\"\x15\n" + @@ -2102,10 +2102,10 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "totalItems\x12\x1f\n" + "\vtotal_pages\x18\x02 \x01(\x05R\n" + "totalPages\x122\n" + - "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\xeb\a\n" + + "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\xef\a\n" + "\x16CheckResultHistoryItem\x12\x0e\n" + - "\x02id\x18\x01 \x01(\tR\x02id\x12\x15\n" + - "\x06run_id\x18\x02 \x01(\tR\x05runId\x12\x1d\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12\x19\n" + + "\bbatch_id\x18\x02 \x01(\tR\abatchId\x12\x1d\n" + "\n" + "check_name\x18\x03 \x01(\tR\tcheckName\x12!\n" + "\fadvisor_name\x18\x04 \x01(\tR\vadvisorName\x12\x1a\n" + @@ -2134,7 +2134,7 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\ftriggered_by\x18\x18 \x01(\x0e2$.advisors.v1.AdvisorCheckTriggeredByR\vtriggeredBy\x1a9\n" + "\vLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc1\x05\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc5\x05\n" + "\x1eListCheckResultsHistoryRequest\x12)\n" + "\tpage_size\x18\x01 \x01(\x05B\a\xfaB\x04\x1a\x02(\x01H\x00R\bpageSize\x88\x01\x01\x12+\n" + "\n" + @@ -2151,8 +2151,8 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + " \x01(\tR\bcategory\x12\x1d\n" + "\n" + "check_name\x18\v \x01(\tR\tcheckName\x128\n" + - "\bseverity\x18\f \x01(\x0e2\x17.management.v1.SeverityH\x04R\bseverity\x88\x01\x01\x12\x15\n" + - "\x06run_id\x18\r \x01(\tR\x05runId\x12L\n" + + "\bseverity\x18\f \x01(\x0e2\x17.management.v1.SeverityH\x04R\bseverity\x88\x01\x01\x12\x19\n" + + "\bbatch_id\x18\r \x01(\tR\abatchId\x12L\n" + "\ftriggered_by\x18\x0e \x01(\x0e2$.advisors.v1.AdvisorCheckTriggeredByH\x05R\vtriggeredBy\x88\x01\x01B\f\n" + "\n" + "_page_sizeB\r\n" + diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 9a2b42cbe26..5164428b57a 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -886,7 +886,7 @@ func (m *StartAdvisorChecksResponse) validate(all bool) error { var errors []error - // no validation rules for RunId + // no validation rules for BatchId if len(errors) > 0 { return StartAdvisorChecksResponseMultiError(errors) @@ -2226,7 +2226,7 @@ func (m *CheckResultHistoryItem) validate(all bool) error { // no validation rules for Id - // no validation rules for RunId + // no validation rules for BatchId // no validation rules for CheckName @@ -2470,7 +2470,7 @@ func (m *ListCheckResultsHistoryRequest) validate(all bool) error { // no validation rules for CheckName - // no validation rules for RunId + // no validation rules for BatchId if m.PageSize != nil { if m.GetPageSize() < 1 { diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index 7dbdc458c3a..62f803a16cb 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -141,8 +141,8 @@ message StartAdvisorChecksRequest { } message StartAdvisorChecksResponse { - // ID assigned to this run; all check results produced by it share this run_id. - string run_id = 1; + // ID assigned to this batch; all check results produced by it share this batch_id. + string batch_id = 1; } message ListAdvisorChecksRequest {} @@ -191,8 +191,8 @@ message GetFailedChecksResponse { message CheckResultHistoryItem { // Unique identifier of the history record. string id = 1; - // ID of the run this result belongs to; all results produced by one execution share it. - string run_id = 2; + // ID of the batch this result belongs to; all results produced by one execution share it. + string batch_id = 2; // Name of the check that ran. string check_name = 3; // Name of the advisor the check belongs to. @@ -264,8 +264,8 @@ message ListCheckResultsHistoryRequest { string check_name = 11; // Filter by severity. optional management.v1.Severity severity = 12; - // Filter by run ID. - string run_id = 13; + // Filter by batch ID. + string batch_id = 13; // Filter by the actor that initiated the run. optional AdvisorCheckTriggeredBy triggered_by = 14; } diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go index 55c153ed500..853d69cc24d 100644 --- a/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_parameters.go @@ -58,6 +58,12 @@ ListCheckResultsHistoryParams contains all the parameters to send to the API end Typically these are written to a http.Request. */ type ListCheckResultsHistoryParams struct { + /* BatchID. + + Filter by batch ID. + */ + BatchID *string + /* Category. Filter by advisor category. @@ -106,12 +112,6 @@ type ListCheckResultsHistoryParams struct { */ PageSize *int32 - /* RunID. - - Filter by run ID. - */ - RunID *string - /* ServiceID. Filter by service ID. @@ -233,6 +233,17 @@ func (o *ListCheckResultsHistoryParams) SetHTTPClient(client *http.Client) { o.HTTPClient = client } +// WithBatchID adds the batchID to the list check results history params +func (o *ListCheckResultsHistoryParams) WithBatchID(batchID *string) *ListCheckResultsHistoryParams { + o.SetBatchID(batchID) + return o +} + +// SetBatchID adds the batchId to the list check results history params +func (o *ListCheckResultsHistoryParams) SetBatchID(batchID *string) { + o.BatchID = batchID +} + // WithCategory adds the category to the list check results history params func (o *ListCheckResultsHistoryParams) WithCategory(category *string) *ListCheckResultsHistoryParams { o.SetCategory(category) @@ -310,17 +321,6 @@ func (o *ListCheckResultsHistoryParams) SetPageSize(pageSize *int32) { o.PageSize = pageSize } -// WithRunID adds the runID to the list check results history params -func (o *ListCheckResultsHistoryParams) WithRunID(runID *string) *ListCheckResultsHistoryParams { - o.SetRunID(runID) - return o -} - -// SetRunID adds the runId to the list check results history params -func (o *ListCheckResultsHistoryParams) SetRunID(runID *string) { - o.RunID = runID -} - // WithServiceID adds the serviceID to the list check results history params func (o *ListCheckResultsHistoryParams) WithServiceID(serviceID *string) *ListCheckResultsHistoryParams { o.SetServiceID(serviceID) @@ -394,6 +394,22 @@ func (o *ListCheckResultsHistoryParams) WriteToRequest(r runtime.ClientRequest, } var res []error + if o.BatchID != nil { + + // query param batch_id + var qrBatchID string + + if o.BatchID != nil { + qrBatchID = *o.BatchID + } + qBatchID := qrBatchID + if qBatchID != "" { + if err := r.SetQueryParam("batch_id", qBatchID); err != nil { + return err + } + } + } + if o.Category != nil { // query param category @@ -506,22 +522,6 @@ func (o *ListCheckResultsHistoryParams) WriteToRequest(r runtime.ClientRequest, } } - if o.RunID != nil { - - // query param run_id - var qrRunID string - - if o.RunID != nil { - qrRunID = *o.RunID - } - qRunID := qrRunID - if qRunID != "" { - if err := r.SetQueryParam("run_id", qRunID); err != nil { - return err - } - } - } - if o.ServiceID != nil { // query param service_id diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go index 01390a84844..5b420a830d8 100644 --- a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go @@ -538,8 +538,8 @@ type ListCheckResultsHistoryOKBodyResultsItems0 struct { // Unique identifier of the history record. ID string `json:"id,omitempty"` - // ID of the run this result belongs to; all results produced by one execution share it. - RunID string `json:"run_id,omitempty"` + // ID of the batch this result belongs to; all results produced by one execution share it. + BatchID string `json:"batch_id,omitempty"` // Name of the check that ran. CheckName string `json:"check_name,omitempty"` diff --git a/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go b/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go index 9c3e2635ec6..943b3d3ed75 100644 --- a/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go +++ b/api/advisors/v1/json/client/advisor_service/start_advisor_checks_responses.go @@ -454,8 +454,8 @@ StartAdvisorChecksOKBody start advisor checks OK body swagger:model StartAdvisorChecksOKBody */ type StartAdvisorChecksOKBody struct { - // ID assigned to this run; all check results produced by it share this run_id. - RunID string `json:"run_id,omitempty"` + // ID assigned to this batch; all check results produced by it share this batch_id. + BatchID string `json:"batch_id,omitempty"` } // Validate validates this start advisor checks OK body diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index 1a293ec9061..5aa9cac84f5 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -517,8 +517,8 @@ }, { "type": "string", - "description": "Filter by run ID.", - "name": "run_id", + "description": "Filter by batch ID.", + "name": "batch_id", "in": "query" }, { @@ -564,8 +564,8 @@ "type": "string", "x-order": 0 }, - "run_id": { - "description": "ID of the run this result belongs to; all results produced by one execution share it.", + "batch_id": { + "description": "ID of the batch this result belongs to; all results produced by one execution share it.", "type": "string", "x-order": 1 }, @@ -1024,8 +1024,8 @@ "schema": { "type": "object", "properties": { - "run_id": { - "description": "ID assigned to this run; all check results produced by it share this run_id.", + "batch_id": { + "description": "ID assigned to this batch; all check results produced by it share this batch_id.", "type": "string", "x-order": 0 } diff --git a/api/descriptor.bin b/api/descriptor.bin index c8f67ab978d9fe2bca108b281701efb924237814..3e27066ec46613c39d99c41c2bf493f20347a4e1 100644 GIT binary patch delta 408 zcmdmd$msYXqlOm77N#xC5phhd8@ETrF>hpNHs_L>&R@kWB`GAy#gUX)lAIBrnIgfc zz^K6)#17_fw@qVaWM+In-9D39O9ELH6SAt>Oy>2>j7PWY<}&jzp(x`;R_2?}%*x00 zqlk-Lh?RliAJcR}LmrXs1+~l%MfnrBSXkJZ7=&0RFfxfr1x-(w%q+?ZcEj|F$;^5h zFz4xUaq)7of|N3X)N%^KxXd7~i0Jk+lbPqR%BKU36Ji1?IRr8;Qo++jAwNx_BqLP; zVrJ`1=5PUsUZ66d-a{b0Z)P&b@;NC3^$Iib2(ffCF^NlwD!66ll%y6ZBvnH60?mRt x0;mXRLpKxD5kM}`pl&7+vG&dt%s|Wn#H>Kf2E^<@%mKulK+Ltha|QRR9{>aiW{&^> delta 402 zcmX?p$Y}E+qlOm77N#xC5phf(H*AlJW8TQlXgr-KjagPil#8vXG%r3gMS@X*QG+vx z70BD}n8wV=%<`I@OKiGf4zt+wm`r9tB$Z4Em93e~>zP>&vU15yH!Nco-|nBw{D~1s zDKA24WIi)1ALEDZ@wLqVMAc)sSXkJZ7=&0RFfxfq`6+n1C?pmaXQt<+rYMx;E0knp z7ApXqGQDjwvz{8ng?e0Eyj-jxU5p@Yocu5@Gl(lBy#3B(<~gjgsX&v3n1D(SflLku znVg>nG%yux-t?Kw;Q|nyKt({Ehd?_2&18<{b5I286lUTPV(DgL5|t8GaLddoNi9-H zss!l-ngewJPzliVZYHP$fLx$4-AqCv?Q>T!12GE_vjQ<25VHd@2M}`tG1vCFE4Wwv F004eVXOsW{ diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index 7ca9068e4c2..6f45a1d054c 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -1830,8 +1830,8 @@ }, { "type": "string", - "description": "Filter by run ID.", - "name": "run_id", + "description": "Filter by batch ID.", + "name": "batch_id", "in": "query" }, { @@ -1877,8 +1877,8 @@ "type": "string", "x-order": 0 }, - "run_id": { - "description": "ID of the run this result belongs to; all results produced by one execution share it.", + "batch_id": { + "description": "ID of the batch this result belongs to; all results produced by one execution share it.", "type": "string", "x-order": 1 }, @@ -2337,8 +2337,8 @@ "schema": { "type": "object", "properties": { - "run_id": { - "description": "ID assigned to this run; all check results produced by it share this run_id.", + "batch_id": { + "description": "ID assigned to this batch; all check results produced by it share this batch_id.", "type": "string", "x-order": 0 } diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 1e1f895b434..42f39d2e4cc 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -1313,8 +1313,8 @@ }, { "type": "string", - "description": "Filter by run ID.", - "name": "run_id", + "description": "Filter by batch ID.", + "name": "batch_id", "in": "query" }, { @@ -1360,8 +1360,8 @@ "type": "string", "x-order": 0 }, - "run_id": { - "description": "ID of the run this result belongs to; all results produced by one execution share it.", + "batch_id": { + "description": "ID of the batch this result belongs to; all results produced by one execution share it.", "type": "string", "x-order": 1 }, @@ -1820,8 +1820,8 @@ "schema": { "type": "object", "properties": { - "run_id": { - "description": "ID assigned to this run; all check results produced by it share this run_id.", + "batch_id": { + "description": "ID assigned to this batch; all check results produced by it share this batch_id.", "type": "string", "x-order": 0 } diff --git a/managed/models/check_result_helpers.go b/managed/models/check_result_helpers.go index 6259fe19558..124315d69ee 100644 --- a/managed/models/check_result_helpers.go +++ b/managed/models/check_result_helpers.go @@ -42,7 +42,7 @@ type CheckResultFilters struct { NodeName string Category string CheckName string - RunID string + BatchID string TriggeredBy *CheckTriggeredBy Severity *CheckSeverity Status *CheckResultStatus @@ -76,9 +76,9 @@ func checkResultConditions(q *reform.Querier, filters CheckResultFilters) (strin conditions = append(conditions, "check_name = "+q.Placeholder(len(args)+1)) args = append(args, filters.CheckName) } - if filters.RunID != "" { - conditions = append(conditions, "run_id = "+q.Placeholder(len(args)+1)) - args = append(args, filters.RunID) + if filters.BatchID != "" { + conditions = append(conditions, "batch_id = "+q.Placeholder(len(args)+1)) + args = append(args, filters.BatchID) } if filters.TriggeredBy != nil { conditions = append(conditions, "triggered_by = "+q.Placeholder(len(args)+1)) diff --git a/managed/models/check_result_model.go b/managed/models/check_result_model.go index d93842e60e0..b5376f29506 100644 --- a/managed/models/check_result_model.go +++ b/managed/models/check_result_model.go @@ -90,7 +90,7 @@ type CheckResult struct { Labels []byte `reform:"labels"` CheckedAt time.Time `reform:"checked_at"` IsRead bool `reform:"is_read"` - RunID string `reform:"run_id"` + BatchID string `reform:"batch_id"` TriggeredBy CheckTriggeredBy `reform:"triggered_by"` } diff --git a/managed/models/check_result_model_reform.go b/managed/models/check_result_model_reform.go index f59d0c722e4..645139bc5c0 100644 --- a/managed/models/check_result_model_reform.go +++ b/managed/models/check_result_model_reform.go @@ -50,7 +50,7 @@ func (v *checkResultTableType) Columns() []string { "labels", "checked_at", "is_read", - "run_id", + "batch_id", "triggered_by", } } @@ -98,7 +98,7 @@ var CheckResultTable = &checkResultTableType{ {Name: "Labels", Type: "[]uint8", Column: "labels"}, {Name: "CheckedAt", Type: "time.Time", Column: "checked_at"}, {Name: "IsRead", Type: "bool", Column: "is_read"}, - {Name: "RunID", Type: "string", Column: "run_id"}, + {Name: "BatchID", Type: "string", Column: "batch_id"}, {Name: "TriggeredBy", Type: "CheckTriggeredBy", Column: "triggered_by"}, }, PKFieldIndex: 0, @@ -131,7 +131,7 @@ func (s CheckResult) String() string { res[19] = "Labels: " + reform.Inspect(s.Labels, true) res[20] = "CheckedAt: " + reform.Inspect(s.CheckedAt, true) res[21] = "IsRead: " + reform.Inspect(s.IsRead, true) - res[22] = "RunID: " + reform.Inspect(s.RunID, true) + res[22] = "BatchID: " + reform.Inspect(s.BatchID, true) res[23] = "TriggeredBy: " + reform.Inspect(s.TriggeredBy, true) return strings.Join(res, ", ") } @@ -162,7 +162,7 @@ func (s *CheckResult) Values() []interface{} { s.Labels, s.CheckedAt, s.IsRead, - s.RunID, + s.BatchID, s.TriggeredBy, } } @@ -193,7 +193,7 @@ func (s *CheckResult) Pointers() []interface{} { &s.Labels, &s.CheckedAt, &s.IsRead, - &s.RunID, + &s.BatchID, &s.TriggeredBy, } } diff --git a/managed/models/database.go b/managed/models/database.go index 939a7ec005c..c426b003a79 100644 --- a/managed/models/database.go +++ b/managed/models/database.go @@ -1188,7 +1188,7 @@ var databaseSchema = [][]string{ 119: { `CREATE TABLE check_results ( id VARCHAR NOT NULL, - run_id VARCHAR NOT NULL, + batch_id VARCHAR NOT NULL, check_name VARCHAR NOT NULL CHECK (check_name <> ''), advisor_name VARCHAR NOT NULL, category VARCHAR NOT NULL, @@ -1214,7 +1214,7 @@ var databaseSchema = [][]string{ PRIMARY KEY (id) )`, - `CREATE INDEX check_results_run_id_idx ON check_results (run_id)`, + `CREATE INDEX check_results_batch_id_idx ON check_results (batch_id)`, `CREATE INDEX check_results_service_id_idx ON check_results (service_id)`, `CREATE INDEX check_results_checked_at_idx ON check_results (checked_at)`, }, diff --git a/managed/services/checks/check_result_record_test.go b/managed/services/checks/check_result_record_test.go index 68bdec6e576..33eb0c42882 100644 --- a/managed/services/checks/check_result_record_test.go +++ b/managed/services/checks/check_result_record_test.go @@ -42,7 +42,7 @@ func TestNewCheckResultRecord(t *testing.T) { ReplicationSet: "rs-1", } checkedAt := models.Now() - ri := runInfo{runID: "run-1", triggeredBy: models.CheckTriggeredByUser} + ri := runInfo{batchID: "batch-1", triggeredBy: models.CheckTriggeredByUser} t.Run("failed finding maps all fields", func(t *testing.T) { t.Parallel() @@ -76,7 +76,7 @@ func TestNewCheckResultRecord(t *testing.T) { assert.Equal(t, "https://example.com", rec.ReadMoreURL) assert.Equal(t, models.CheckSeverityError, rec.Severity) assert.Equal(t, checkedAt, rec.CheckedAt) - assert.Equal(t, "run-1", rec.RunID) + assert.Equal(t, "batch-1", rec.BatchID) assert.Equal(t, models.CheckTriggeredByUser, rec.TriggeredBy) labels, err := rec.GetLabels() diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index c3be9ea4629..45bdff7771d 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -299,11 +299,11 @@ func (s *Service) runChecksGroup(ctx context.Context, intervalGroup check.Interv } s.UpdateAdvisorsList(ctx) - ri := runInfo{runID: uuid.NewString(), triggeredBy: models.CheckTriggeredByScheduler} + ri := runInfo{batchID: uuid.NewString(), triggeredBy: models.CheckTriggeredByScheduler} return s.run(ctx, intervalGroup, nil, ri) } -// StartChecks downloads and executes advisor checks in asynchronous way and returns the run ID. +// StartChecks downloads and executes advisor checks in asynchronous way and returns the batch ID. // If checkNames specified then only matched checks will be executed. func (s *Service) StartChecks(checkNames []string) (string, error) { settings, err := models.GetSettings(s.db) @@ -315,7 +315,7 @@ func (s *Service) StartChecks(checkNames []string) (string, error) { return "", services.ErrAdvisorsDisabled } - ri := runInfo{runID: uuid.NewString(), triggeredBy: models.CheckTriggeredByUser} + ri := runInfo{batchID: uuid.NewString(), triggeredBy: models.CheckTriggeredByUser} // Hand the request off to runChecksLoop, which owns the service lifecycle // context. The loop only runs on the leader node, so a non-blocking send @@ -326,12 +326,12 @@ func (s *Service) StartChecks(checkNames []string) (string, error) { s.l.Warn("Advisor checks run is already pending, skipping the request.") } - return ri.runID, nil + return ri.batchID, nil } // runInfo identifies a single Advisor checks execution batch. type runInfo struct { - runID string + batchID string triggeredBy models.CheckTriggeredBy } @@ -811,7 +811,7 @@ func newCheckResultRecord( ReadMoreURL: result.ReadMoreURL, Severity: convertCommonSeverity(result.Severity), CheckedAt: checkedAt, - RunID: ri.runID, + BatchID: ri.batchID, TriggeredBy: ri.triggeredBy, } // OK and error outcomes carry no finding; fall back to the check's own summary diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index d12334799fb..6892476eae5 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -196,7 +196,7 @@ func (s *ChecksAPIService) ListCheckResultsHistory( NodeName: req.NodeName, Category: req.Category, CheckName: req.CheckName, - RunID: req.RunId, + BatchID: req.BatchId, IsRead: req.IsRead, } if req.Status != nil { @@ -237,7 +237,7 @@ func (s *ChecksAPIService) ListCheckResultsHistory( items = append(items, &advisorsv1.CheckResultHistoryItem{ Id: r.ID, CheckName: r.CheckName, - RunId: r.RunID, + BatchId: r.BatchID, AdvisorName: r.AdvisorName, Category: r.Category, Severity: convertModelSeverity(r.Severity), @@ -306,10 +306,10 @@ func (s *ChecksAPIService) MarkCheckResultsRead( return &advisorsv1.MarkCheckResultsReadResponse{}, nil } -// StartAdvisorChecks executes advisor checks and returns the ID assigned to this run. +// StartAdvisorChecks executes advisor checks and returns the ID assigned to this batch. func (s *ChecksAPIService) StartAdvisorChecks(_ context.Context, req *advisorsv1.StartAdvisorChecksRequest) (*advisorsv1.StartAdvisorChecksResponse, error) { // Start only specified checks from any group. - runID, err := s.checksService.StartChecks(req.Names) + batchID, err := s.checksService.StartChecks(req.Names) if err != nil { if errors.Is(err, services.ErrAdvisorsDisabled) { return nil, status.Errorf(codes.FailedPrecondition, "%v.", err) @@ -318,7 +318,7 @@ func (s *ChecksAPIService) StartAdvisorChecks(_ context.Context, req *advisorsv1 return nil, fmt.Errorf("failed to start advisor checks: %w", err) } - return &advisorsv1.StartAdvisorChecksResponse{RunId: runID}, nil + return &advisorsv1.StartAdvisorChecksResponse{BatchId: batchID}, nil } // ListAdvisorChecks returns a list of available advisor checks and their statuses. diff --git a/ui/apps/pmm/src/api/advisors.ts b/ui/apps/pmm/src/api/advisors.ts index be65ed27e34..31ce0a6d13e 100644 --- a/ui/apps/pmm/src/api/advisors.ts +++ b/ui/apps/pmm/src/api/advisors.ts @@ -24,7 +24,7 @@ export const startAdvisorChecks = async (names: string[]): Promise => { '/advisors/checks:start', payload ); - return res.data.runId; + return res.data.batchId; }; export const changeAdvisorChecks = async ( diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index 70de15458c9..b5a9d586100 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -44,7 +44,7 @@ const AdvisorsList: FC = () => { const runChecks = useCallback( (names: string[], message: string) => startChecks(names, { - onSuccess: (runId) => + onSuccess: (batchId) => enqueueSnackbar(message, { variant: 'success', action: (key) => ( @@ -53,7 +53,7 @@ const AdvisorsList: FC = () => { size="small" onClick={() => { closeSnackbar(key); - navigate(`/advisors/insights?runId=${runId}`); + navigate(`/advisors/insights?batchId=${batchId}`); }} data-testid="view-run-results" > diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index f10df60feb5..d38000d763a 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -10,7 +10,7 @@ export const Messages = { viewDetails: 'View details', toggleRead: 'Toggle read', rerunNow: 'Re-run now', - filterByRunId: 'Filter by run ID', + filterByBatchId: 'Filter by batch ID', copyAsText: 'Copy as text', disableCheck: 'Disable check', enableCheck: 'Enable check', @@ -40,12 +40,12 @@ export const Messages = { checkInterval: 'Check interval', checkId: 'Check ID', checkName: 'Check name', - otherLabels: 'Other labels', + labels: 'Labels', }, viewResults: 'View results', filters: { all: 'All', - run: (runId: string) => `Run: ${runId}…`, + batch: (batchId: string) => `Batch: ${batchId}…`, clear: 'Clear filters', refresh: 'Refresh', refreshTooltip: diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 1be5e7fe2e9..c99664bd420 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -76,7 +76,7 @@ const TEST_ITEM: CheckResultHistoryItem = { labels: {}, checkedAt: '2026-07-05T10:00:00Z', isRead: true, - runId: 'run-1', + batchId: 'batch-1', triggeredBy: AdvisorCheckTriggeredBy.user, outcome: 'Installed version: 5.7.30', environment: 'prod', @@ -94,8 +94,8 @@ const TEST_ITEM_UNREAD: CheckResultHistoryItem = { description: 'A user has the SUPER role', severity: Severity.error, isRead: false, - // recorded before run grouping existed - runId: '', + // recorded before batch grouping existed + batchId: '', }; const renderComponent = (initialEntry = '/advisors/insights') => @@ -127,7 +127,7 @@ describe('AdvisorInsights', () => { results: [TEST_ITEM, TEST_ITEM_UNREAD], }); vi.mocked(advisorsApi.markCheckResultsRead).mockResolvedValue(); - vi.mocked(advisorsApi.startAdvisorChecks).mockResolvedValue('run-123'); + vi.mocked(advisorsApi.startAdvisorChecks).mockResolvedValue('batch-123'); vi.mocked(advisorsApi.changeAdvisorChecks).mockResolvedValue(); vi.mocked(advisorsApi.listCheckResultsFilterValues).mockResolvedValue({ serviceNames: ['mysql-prod', 'postgresql-prod'], @@ -172,13 +172,13 @@ describe('AdvisorInsights', () => { ); }); - it('passes the runId deep link to the API', async () => { - renderComponent('/advisors/insights?runId=run-42'); + it('passes the batchId deep link to the API', async () => { + renderComponent('/advisors/insights?batchId=batch-42'); await waitForRows(); expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( - expect.objectContaining({ runId: 'run-42' }) + expect.objectContaining({ batchId: 'batch-42' }) ); }); @@ -391,10 +391,8 @@ describe('AdvisorInsights', () => { expect( within(screen.getByTestId('details-field-check-id')).getByText('result-1') ).toBeInTheDocument(); - // no labels on this insight, so no labels section - expect( - within(pane).queryByText(Messages.details.otherLabels) - ).not.toBeInTheDocument(); + // the labels section title is always shown, even without labels + expect(within(pane).getByText(Messages.details.labels)).toBeInTheDocument(); fireEvent.click(screen.getByTestId('insight-details-close')); @@ -420,7 +418,7 @@ describe('AdvisorInsights', () => { '\n' + 'Check Details:\n' + ' ID: result-1\n' + - ' Check Run ID: run-1\n' + + ' Batch ID: batch-1\n' + ' Check Name: mysql_version_check\n' + ' Advisor: MySQL Version\n' + ' Category: Version_configuration\n' + @@ -514,7 +512,7 @@ describe('AdvisorInsights', () => { ); }); - it('disables re-run for disabled checks and run filter for rows without run ID', async () => { + it('disables re-run for disabled checks and batch filter for rows without batch ID', async () => { renderComponent(); await waitForRows(); @@ -526,37 +524,37 @@ describe('AdvisorInsights', () => { 'aria-disabled', 'true' ); - expect(screen.getByTestId('action-filter-by-run-id')).toHaveAttribute( + expect(screen.getByTestId('action-filter-by-batch-id')).toHaveAttribute( 'aria-disabled', 'true' ); }); - it('filters by run ID from the row menu and clears via the chip', async () => { + it('filters by batch ID from the row menu and clears via the chip', async () => { renderComponent(); await waitForRows(); fireEvent.click(screen.getByTestId('insight-result-1-actions')); - fireEvent.click(await screen.findByTestId('action-filter-by-run-id')); + fireEvent.click(await screen.findByTestId('action-filter-by-batch-id')); await waitFor(() => expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( - expect.objectContaining({ runId: 'run-1', pageIndex: 0 }) + expect.objectContaining({ batchId: 'batch-1', pageIndex: 0 }) ) ); - const chip = await screen.findByTestId('run-id-filter-chip'); + const chip = await screen.findByTestId('batch-id-filter-chip'); fireEvent.click(within(chip).getByTestId('CancelIcon')); await waitFor(() => expect(advisorsApi.listCheckResultsHistory).toHaveBeenLastCalledWith( - expect.objectContaining({ runId: undefined }) + expect.objectContaining({ batchId: undefined }) ) ); }); - it('re-runs the check from the row menu and links to the new run', async () => { + it('re-runs the check from the row menu and links to the new batch', async () => { renderComponent(); await waitForRows(); @@ -580,7 +578,7 @@ describe('AdvisorInsights', () => { await waitFor(() => expect(advisorsApi.listCheckResultsHistory).toHaveBeenLastCalledWith( - expect.objectContaining({ runId: 'run-123' }) + expect.objectContaining({ batchId: 'batch-123' }) ) ); }); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 6b4c7bd6055..a488b4bc536 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -118,8 +118,8 @@ const FilterSelect: FC = ({ const AdvisorInsights: FC = () => { const [searchParams, setSearchParams] = useSearchParams(); - // deep link to the results of a concrete run, e.g. from the "View results" snackbar - const runId = searchParams.get('runId') || undefined; + // deep link to the results of a concrete batch, e.g. from the "View results" snackbar + const batchId = searchParams.get('batchId') || undefined; const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 100, @@ -132,11 +132,11 @@ const AdvisorInsights: FC = () => { setPagination((current) => ({ ...current, pageIndex: 0 })); }; - const hasActiveFilters = Object.values(filters).some(Boolean) || !!runId; + const hasActiveFilters = Object.values(filters).some(Boolean) || !!batchId; const handleClearFilters = () => { setFilters(NO_FILTERS); - if (runId) { + if (batchId) { setSearchParams({}); } setPagination((current) => ({ ...current, pageIndex: 0 })); @@ -146,7 +146,7 @@ const AdvisorInsights: FC = () => { () => ({ pageIndex: pagination.pageIndex, pageSize: pagination.pageSize, - runId, + batchId, serviceName: filters.serviceName || undefined, nodeName: filters.nodeName || undefined, category: filters.category || undefined, @@ -154,7 +154,7 @@ const AdvisorInsights: FC = () => { status: (filters.status as AdvisorCheckResultStatus) || undefined, isRead: filters.isRead === '' ? undefined : filters.isRead === 'true', }), - [pagination, filters, runId] + [pagination, filters, batchId] ); const [actionMenu, setActionMenu] = useState(null); @@ -180,8 +180,8 @@ const AdvisorInsights: FC = () => { [advisors] ); - const applyRunIdFilter = (newRunId: string) => { - setSearchParams(newRunId ? { runId: newRunId } : {}); + const applyBatchIdFilter = (newBatchId: string) => { + setSearchParams(newBatchId ? { batchId: newBatchId } : {}); setPagination((current) => ({ ...current, pageIndex: 0 })); }; @@ -189,7 +189,7 @@ const AdvisorInsights: FC = () => { const checkSummary = checksByName.get(insight.checkName)?.summary ?? insight.checkName; startChecks([insight.checkName], { - onSuccess: (newRunId) => + onSuccess: (newBatchId) => enqueueSnackbar(Messages.success.rerunStarted(checkSummary), { variant: 'success', action: (key) => ( @@ -198,7 +198,7 @@ const AdvisorInsights: FC = () => { size="small" onClick={() => { closeSnackbar(key); - applyRunIdFilter(newRunId); + applyBatchIdFilter(newBatchId); }} data-testid="view-run-results" > @@ -331,12 +331,12 @@ const AdvisorInsights: FC = () => { value={filters.isRead} onChange={(value) => updateFilter('isRead', value)} /> - {runId && ( + {batchId && ( applyRunIdFilter('')} + label={Messages.filters.batch(batchId.slice(0, 8))} + onDelete={() => applyBatchIdFilter('')} sx={{ alignSelf: 'center' }} - data-testid="run-id-filter-chip" + data-testid="batch-id-filter-chip" /> )}
{ {Messages.run} )} - renderTopToolbarCustomActions={({ table }) => { - const { globalFilter, columnFilters } = table.getState(); - // no active search/filter means no selection ("all") - const hasSelection = - !!globalFilter || - columnFilters.some( - (filter) => filter.value !== undefined && filter.value !== '' - ); - // enabled checks currently visible after global search + filters - const selectedNames = hasSelection - ? table - .getFilteredRowModel() - .rows.map((row) => row.original) - .filter((row) => row.enabled) - .map((row) => row.checkName) - : []; - - return ( - - - - - - ); - }} - muiSearchTextFieldProps={{ - // inline style: MRT's toolbar overwrites any `sx` passed here - style: { width: 400 }, - }} - muiTopToolbarProps={{ - sx: { - // search on the left, action buttons on the right, - // flush with the table edges - [`& > .${boxClasses.root}`]: { - alignItems: 'center', - flexDirection: 'row-reverse', - px: 0, - }, - }, - }} muiTableContainerProps={{ sx: { flex: 1, diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index d38000d763a..42e072404b3 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -45,7 +45,7 @@ export const Messages = { viewResults: 'View results', filters: { all: 'All', - batch: (batchId: string) => `Batch: ${batchId}…`, + batchId: 'Batch ID', clear: 'Clear filters', refresh: 'Refresh', refreshTooltip: diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index c99664bd420..475bbb07973 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -361,6 +361,10 @@ describe('AdvisorInsights', () => { expect(pane).toBeInTheDocument(); expect(screen.getByText(Messages.details.title)).toBeInTheDocument(); expect(screen.getByTestId('insight-details-maximize')).toBeInTheDocument(); + // opened from the menu, the pane starts at the default (non-maximized) height + expect( + within(pane).getByTestId('OpenInFullOutlinedIcon') + ).toBeInTheDocument(); // content from the selected insight expect(within(pane).getByText('MySQL is outdated')).toBeInTheDocument(); @@ -403,6 +407,21 @@ describe('AdvisorInsights', () => { ); }); + it('opens the details overlay maximized on row double-click', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.dblClick(screen.getByTestId('insight-row-result-1')); + + const pane = await screen.findByTestId('insight-details-pane'); + expect(within(pane).getByText('MySQL is outdated')).toBeInTheDocument(); + // a maximized pane shows the "collapse" toggle icon + expect( + within(pane).getByTestId('CloseFullscreenOutlinedIcon') + ).toBeInTheDocument(); + }); + it('copies the insight as a narrative text', async () => { renderComponent(); @@ -530,7 +549,7 @@ describe('AdvisorInsights', () => { ); }); - it('filters by batch ID from the row menu and clears via the chip', async () => { + it('filters by batch ID from the row menu, populates the input, then clears', async () => { renderComponent(); await waitForRows(); @@ -544,14 +563,40 @@ describe('AdvisorInsights', () => { ) ); - const chip = await screen.findByTestId('batch-id-filter-chip'); - fireEvent.click(within(chip).getByTestId('CancelIcon')); + // the batch-id input reflects the applied filter + const input = within(screen.getByTestId('batch-id-filter')).getByRole( + 'textbox', + { hidden: true } + ); + expect(input).toHaveValue('batch-1'); + + fireEvent.click(screen.getByTestId('clear-filters')); await waitFor(() => expect(advisorsApi.listCheckResultsHistory).toHaveBeenLastCalledWith( expect.objectContaining({ batchId: undefined }) ) ); + expect(input).toHaveValue(''); + }); + + it('filters by a batch ID typed into the input and committed with Enter', async () => { + renderComponent(); + + await waitForRows(); + + const input = within(screen.getByTestId('batch-id-filter')).getByRole( + 'textbox', + { hidden: true } + ); + fireEvent.change(input, { target: { value: 'batch-77' } }); + fireEvent.keyDown(input, { key: 'Enter' }); + + await waitFor(() => + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ batchId: 'batch-77', pageIndex: 0 }) + ) + ); }); it('re-runs the check from the row menu and links to the new batch', async () => { diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index a488b4bc536..56a01b18b1f 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -1,5 +1,4 @@ import Button from '@mui/material/Button'; -import Chip from '@mui/material/Chip'; import BlockOutlinedIcon from '@mui/icons-material/BlockOutlined'; import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined'; import ContentCopyOutlinedIcon from '@mui/icons-material/ContentCopyOutlined'; @@ -10,11 +9,13 @@ import MoreVertIcon from '@mui/icons-material/MoreVert'; import RefreshOutlinedIcon from '@mui/icons-material/RefreshOutlined'; import ReplayOutlinedIcon from '@mui/icons-material/ReplayOutlined'; import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import Box from '@mui/material/Box'; import IconButton from '@mui/material/IconButton'; import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemText from '@mui/material/ListItemText'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; +import { paperClasses } from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; import TextField from '@mui/material/TextField'; import Tooltip from '@mui/material/Tooltip'; @@ -31,7 +32,7 @@ import { } from 'hooks/api/useAdvisors'; import { type MRT_PaginationState } from 'material-react-table'; import { closeSnackbar, enqueueSnackbar } from 'notistack'; -import { FC, useMemo, useState } from 'react'; +import { FC, useEffect, useMemo, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; import { AdvisorCheckResultStatus, @@ -125,6 +126,15 @@ const AdvisorInsights: FC = () => { pageSize: 100, }); const [filters, setFilters] = useState(NO_FILTERS); + // local mirror of the batch-id URL param, committed on blur/Enter so typing + // does not refetch (and spam history) on every keystroke + const [batchIdInput, setBatchIdInput] = useState(batchId ?? ''); + + // keep the input in sync when the param changes elsewhere (row action, + // "View results" deep link, "Clear filters") + useEffect(() => { + setBatchIdInput(batchId ?? ''); + }, [batchId]); const updateFilter = (name: keyof InsightFilters, value: string) => { setFilters((current) => ({ ...current, [name]: value })); @@ -160,6 +170,12 @@ const AdvisorInsights: FC = () => { const [actionMenu, setActionMenu] = useState(null); const [detailsInsight, setDetailsInsight] = useState(null); + const [detailsMaximized, setDetailsMaximized] = useState(false); + + const openDetails = (insight: CheckResultHistoryItem, maximized = false) => { + setDetailsMaximized(maximized); + setDetailsInsight(insight); + }; const { data, isLoading, isFetching, refetch } = useCheckResultsHistory(params); @@ -185,6 +201,13 @@ const AdvisorInsights: FC = () => { setPagination((current) => ({ ...current, pageIndex: 0 })); }; + const commitBatchIdInput = () => { + const trimmed = batchIdInput.trim(); + if (trimmed !== (batchId ?? '')) { + applyBatchIdFilter(trimmed); + } + }; + const handleRerun = (insight: CheckResultHistoryItem) => { const checkSummary = checksByName.get(insight.checkName)?.summary ?? insight.checkName; @@ -284,9 +307,25 @@ const AdvisorInsights: FC = () => { title={Messages.title} fullWidth wide + fillViewport roles={[OrgRole.Editor, OrgRole.Admin]} > - + .${paperClasses.root}`]: { + flex: 1, + display: 'flex', + flexDirection: 'column', + minHeight: 0, + overflow: 'hidden', + }, + }} + > {Messages.description} { value={filters.isRead} onChange={(value) => updateFilter('isRead', value)} /> - {batchId && ( - applyBatchIdFilter('')} - sx={{ alignSelf: 'center' }} - data-testid="batch-id-filter-chip" - /> - )} - + setBatchIdInput(e.target.value)} + onBlur={commitBatchIdInput} + onKeyDown={(e) => { + if (e.key === 'Enter') { + commitBatchIdInput(); + } + }} + sx={{ minWidth: 260 }} + data-testid="batch-id-filter" + /> + + + + + + + - + +
{ return { 'data-testid': `insight-row-${row.original.id}`, 'data-check-disabled': checkDisabled ? 'true' : undefined, + // double-click opens the details overlay maximized + onDoubleClick: () => openDetails(row.original, true), sx: checkDisabled ? { opacity: 0.5 } : undefined, }; }} @@ -422,7 +476,7 @@ const AdvisorInsights: FC = () => { { if (actionMenu) { - setDetailsInsight(actionMenu.insight); + openDetails(actionMenu.insight); } setActionMenu(null); }} @@ -532,6 +586,7 @@ const AdvisorInsights: FC = () => { void; } export const InsightDetailsPane: FC = ({ insight, checkEnabled, + initialMaximized = false, onClose, }) => { const [maximized, setMaximized] = useState(false); @@ -84,12 +87,10 @@ export const InsightDetailsPane: FC = ({ // the pane never covers the main navigation const sidebarWidth = navOpen ? DRAWER_WIDTH : DRAWER_CLOSED_WIDTH; - // start each viewing at the default height + // apply the requested height on each open, reset on close useEffect(() => { - if (!open) { - setMaximized(false); - } - }, [open]); + setMaximized(open ? initialMaximized : false); + }, [open, initialMaximized]); const m = Messages.details; const labels = Object.entries(insight?.labels ?? {}); From b5b43834f8cb4d44afc9805570331cb384e04921 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Tue, 14 Jul 2026 15:59:41 +0300 Subject: [PATCH 033/120] PMM-14109 Enhance advisor output and functionality, including filter clear option and improved insights display --- managed/data/checks/postgresql_fsync.yml | 2 +- ui/apps/pmm/src/components/page/Page.tsx | 3 +- .../navigation/navigation.constants.ts | 4 +- .../contexts/navigation/navigation.utils.tsx | 2 +- .../pages/advisors/AdvisorsList.messages.ts | 1 + .../src/pages/advisors/AdvisorsList.test.tsx | 26 ++++++++ .../pmm/src/pages/advisors/AdvisorsList.tsx | 20 ++++++ .../insights/AdvisorInsights.messages.ts | 1 + .../advisors/insights/AdvisorInsights.tsx | 1 + .../details-pane/InsightDetailsPane.tsx | 65 +++++++++++-------- 10 files changed, 93 insertions(+), 32 deletions(-) diff --git a/managed/data/checks/postgresql_fsync.yml b/managed/data/checks/postgresql_fsync.yml index 8661e1d2969..cb67418a6b4 100644 --- a/managed/data/checks/postgresql_fsync.yml +++ b/managed/data/checks/postgresql_fsync.yml @@ -3,7 +3,7 @@ checks: - version: 2 name: postgresql_fsync summary: PostgreSQL fsync is set to off - description: This check returns a error if the fsync configuration option is off which can lead to database corruption. + description: This check returns an error if the fsync configuration option is off which can lead to database corruption. family: POSTGRESQL #author: Jobin Augustine advisor: configuration_generic diff --git a/ui/apps/pmm/src/components/page/Page.tsx b/ui/apps/pmm/src/components/page/Page.tsx index d92c09c933a..60ff408c0e9 100644 --- a/ui/apps/pmm/src/components/page/Page.tsx +++ b/ui/apps/pmm/src/components/page/Page.tsx @@ -101,7 +101,8 @@ export const Page: FC = ({ )} - + {/* footer === null explicitly opts out of the divider + footer */} + {footer !== null && } {footer !== undefined ? footer :
} diff --git a/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts b/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts index c14d9c16e99..33ed931643e 100644 --- a/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts +++ b/ui/apps/pmm/src/contexts/navigation/navigation.constants.ts @@ -540,8 +540,8 @@ export const NAV_ADVISORS: NavItem = { url: `${PMM_NEW_NAV_PATH}/advisors`, }; -// the sidebar links a parent item to its first child's url, -// so the checks list must be an explicit (and first) child +// the sidebar links a parent item to its first child's url, so the Advisors +// children are listed explicitly (Insights is first, see addAdvisors) export const NAV_ADVISORS_CHECKS: NavItem = { id: 'advisors-checks', text: 'Advisor checks', diff --git a/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx b/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx index 4fab9a79965..041398aa4f9 100644 --- a/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx +++ b/ui/apps/pmm/src/contexts/navigation/navigation.utils.tsx @@ -167,7 +167,7 @@ export const addExplore = (exploreMetricsEnabled: boolean): NavItem => { export const addAdvisors = (): NavItem => ({ ...NAV_ADVISORS, - children: [NAV_ADVISORS_CHECKS, NAV_ADVISORS_INSIGHTS], + children: [NAV_ADVISORS_INSIGHTS, NAV_ADVISORS_CHECKS], }); export const addAccount = ( diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts index 20b10870f95..8653a8f8fc5 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts @@ -22,6 +22,7 @@ export const Messages = { vendor: 'Vendor', interval: 'Interval', status: 'Status', + clear: 'Clear filters', }, runAll: 'Run all', runSelected: 'Run selected', diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx index 9dbd9409f53..92ec56dbd6a 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -153,6 +153,32 @@ describe('AdvisorsList', () => { ).toBeInTheDocument(); }); + it('clears an active filter via the clear-filters button', async () => { + renderComponent(); + + await waitForRows(); + + expect(screen.getByTestId('clear-filters')).toBeDisabled(); + + await selectFilterOption('vendor-filter', 'PostgreSQL'); + + await waitFor(() => + expect( + screen.queryByTestId('check-mysql_version_check-run') + ).not.toBeInTheDocument() + ); + expect(screen.getByTestId('clear-filters')).not.toBeDisabled(); + + fireEvent.click(screen.getByTestId('clear-filters')); + + await waitFor(() => + expect( + screen.getByTestId('check-mysql_version_check-run') + ).toBeInTheDocument() + ); + expect(screen.getByTestId('clear-filters')).toBeDisabled(); + }); + it('runs all checks', async () => { renderComponent(); diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index 7d81b98d324..3b2bad07cd1 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -9,6 +9,7 @@ import TextField from '@mui/material/TextField'; import Tooltip from '@mui/material/Tooltip'; import Typography from '@mui/material/Typography'; import AddOutlinedIcon from '@mui/icons-material/AddOutlined'; +import FilterAltOffOutlinedIcon from '@mui/icons-material/FilterAltOffOutlined'; import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined'; import PlaylistAddCheckOutlinedIcon from '@mui/icons-material/PlaylistAddCheckOutlined'; import { Table } from '@percona/percona-ui'; @@ -97,6 +98,11 @@ const AdvisorsList: FC = () => { const updateFilter = (name: keyof CheckFilters, value: string) => setFilters((current) => ({ ...current, [name]: value })); + const handleClearFilters = () => { + setSearch(''); + setFilters(NO_FILTERS); + }; + const rows = useMemo(() => flattenAdvisorChecks(advisors), [advisors]); const categoryOptions = useMemo( @@ -240,6 +246,7 @@ const AdvisorsList: FC = () => { fullWidth wide fillViewport + footer={null} roles={[OrgRole.Editor, OrgRole.Admin]} > { value={filters.status} onChange={(value) => updateFilter('status', value)} /> + + + + + + + @@ -345,6 +364,7 @@ const AdvisorsList: FC = () => { }, }} enableStickyHeader + enablePagination enableTopToolbar={false} enableGlobalFilter={false} enableColumnFilters={false} diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index 42e072404b3..8b0e1c6dedb 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -40,6 +40,7 @@ export const Messages = { checkInterval: 'Check interval', checkId: 'Check ID', checkName: 'Check name', + batchId: 'Batch ID', labels: 'Labels', }, viewResults: 'View results', diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 56a01b18b1f..105156e265e 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -308,6 +308,7 @@ const AdvisorInsights: FC = () => { fullWidth wide fillViewport + footer={null} roles={[OrgRole.Editor, OrgRole.Admin]} > = ({ rowGap: 3, }} > - - {insight.summary} + + {insight.checkName} + + + + + {insight.id} + + + + + + + {ADVISOR_INTERVAL[insight.interval]} + + + + + {insight.checkedAt + ? format(new Date(insight.checkedAt), TIME_FORMAT) + : EM_DASH} + + + + + + + {insight.batchId || EM_DASH} + + {insight.batchId && ( + + )} + = ({ + + {insight.summary} + + {insight.description || EM_DASH} @@ -211,7 +246,7 @@ export const InsightDetailsPane: FC = ({ {insight.serviceName} - + @@ -257,30 +292,6 @@ export const InsightDetailsPane: FC = ({ {EM_DASH} - - - - {insight.checkedAt - ? format(new Date(insight.checkedAt), TIME_FORMAT) - : EM_DASH} - - - - - {ADVISOR_INTERVAL[insight.interval]} - - - - - - {insight.id} - - - - - - {insight.checkName} - From 556f646afdb98e641c6a91ebf7fe2aa899d9638f Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Tue, 14 Jul 2026 21:37:09 +0300 Subject: [PATCH 034/120] PMM-14109 Enhance filtering functionality with URL-based state management --- .../pages/advisors/AdvisorsList.messages.ts | 8 +- .../src/pages/advisors/AdvisorsList.test.tsx | 19 ++- .../pmm/src/pages/advisors/AdvisorsList.tsx | 103 ++++++++++--- .../insights/AdvisorInsights.messages.ts | 2 +- .../insights/AdvisorInsights.test.tsx | 18 +++ .../advisors/insights/AdvisorInsights.tsx | 138 ++++++++++++------ 6 files changed, 214 insertions(+), 74 deletions(-) diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts index 8653a8f8fc5..8b3af75b953 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts @@ -1,7 +1,7 @@ export const Messages = { - title: 'Advisors', + title: 'Advisor checks', description: - 'Advisors run automated checks against your connected databases to identify potential security threats, performance degradation, data loss and data corruption.', + 'Run automated checks against your connected databases to identify potential security threats, performance degradation, data loss and data corruption.', noData: 'No advisor checks found', columns: { check: 'Check', @@ -31,9 +31,9 @@ export const Messages = { run: 'Run', success: { checksStarted: - 'Advisor checks started. The results will be available shortly.', + 'Advisor checks started, batch ID copied to clipboard', checkStarted: (summary: string) => - `Check "${summary}" started. The results will be available shortly.`, + `Check "${summary}" started, batch ID copied to clipboard`, checkEnabled: (summary: string) => `Check "${summary}" enabled`, checkDisabled: (summary: string) => `Check "${summary}" disabled`, intervalChanged: (summary: string, interval: string) => diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx index 92ec56dbd6a..76853e91f9e 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -64,11 +64,13 @@ const TEST_ADVISORS: Advisor[] = [ }, ]; -const renderComponent = () => +const renderComponent = (initialEntry = '/advisors') => render( wrapWithQueryProvider( wrapWithSnackbarProvider( - wrapWithUserProvider(wrapWithRouter()) + wrapWithUserProvider( + wrapWithRouter(, { initialEntries: [initialEntry] }) + ) ) ) ); @@ -153,6 +155,18 @@ describe('AdvisorsList', () => { ).toBeInTheDocument(); }); + it('reads the vendor filter from the URL (deep link)', async () => { + renderComponent('/advisors?vendor=PostgreSQL'); + + await waitFor(() => + expect(screen.getByText('PostgreSQL super role')).toBeInTheDocument() + ); + + expect( + screen.queryByTestId('check-mysql_version_check-run') + ).not.toBeInTheDocument(); + }); + it('clears an active filter via the clear-filters button', async () => { renderComponent(); @@ -196,6 +210,7 @@ describe('AdvisorsList', () => { screen.getByText(Messages.success.checksStarted) ).toBeInTheDocument(); expect(screen.getByTestId('view-run-results')).toBeInTheDocument(); + expect(navigator.clipboard.writeText).toHaveBeenCalledWith('run-123'); }); it('runs checks matching the global search', async () => { diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index 3b2bad07cd1..f75ecb33568 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback, useMemo, useState } from 'react'; +import { FC, useCallback, useMemo } from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import IconButton from '@mui/material/IconButton'; @@ -13,8 +13,12 @@ import FilterAltOffOutlinedIcon from '@mui/icons-material/FilterAltOffOutlined'; import PlayArrowOutlinedIcon from '@mui/icons-material/PlayArrowOutlined'; import PlaylistAddCheckOutlinedIcon from '@mui/icons-material/PlaylistAddCheckOutlined'; import { Table } from '@percona/percona-ui'; +import { + type MRT_PaginationState, + type MRT_Updater, +} from 'material-react-table'; import { closeSnackbar, enqueueSnackbar } from 'notistack'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useSearchParams } from 'react-router-dom'; import { Page } from 'components/page'; import { useAdvisors, @@ -36,12 +40,7 @@ interface CheckFilters { status: string; } -const NO_FILTERS: CheckFilters = { - category: '', - vendor: '', - interval: '', - status: '', -}; +const DEFAULT_PAGE_SIZE = 50; interface FilterOption { label: string; @@ -92,15 +91,78 @@ const AdvisorsList: FC = () => { useStartAdvisorChecks(); const { mutate: changeChecks } = useChangeAdvisorChecks(); - const [search, setSearch] = useState(''); - const [filters, setFilters] = useState(NO_FILTERS); + const [searchParams, setSearchParams] = useSearchParams(); + + // the URL query string is the single source of truth for filters + + // pagination, so a shared link reproduces the exact same view + const search = searchParams.get('search') || ''; + const filters = useMemo( + () => ({ + category: searchParams.get('category') || '', + vendor: searchParams.get('vendor') || '', + interval: searchParams.get('interval') || '', + status: searchParams.get('status') || '', + }), + [searchParams] + ); + const pagination: MRT_PaginationState = { + pageIndex: Math.max(0, (Number(searchParams.get('page')) || 1) - 1), + pageSize: Number(searchParams.get('pageSize')) || DEFAULT_PAGE_SIZE, + }; + + // apply query-string changes; filter/search changes reset to the first page + const patchParams = ( + mutate: (params: URLSearchParams) => void, + { resetPage = true }: { resetPage?: boolean } = {} + ) => { + const next = new URLSearchParams(searchParams); + mutate(next); + if (resetPage) { + next.delete('page'); + } + setSearchParams(next, { replace: true }); + }; + + const setSearch = (value: string) => + patchParams((p) => { + if (value) { + p.set('search', value); + } else { + p.delete('search'); + } + }); const updateFilter = (name: keyof CheckFilters, value: string) => - setFilters((current) => ({ ...current, [name]: value })); + patchParams((p) => { + if (value) { + p.set(name, value); + } else { + p.delete(name); + } + }); const handleClearFilters = () => { - setSearch(''); - setFilters(NO_FILTERS); + // keep the chosen page size; drop every filter, search and the page + const next = new URLSearchParams(); + const pageSize = searchParams.get('pageSize'); + if (pageSize) { + next.set('pageSize', pageSize); + } + setSearchParams(next, { replace: true }); + }; + + const handlePaginationChange = ( + updater: MRT_Updater + ) => { + const nextPagination = + typeof updater === 'function' ? updater(pagination) : updater; + patchParams( + (p) => { + p.set('page', String(nextPagination.pageIndex + 1)); + p.set('pageSize', String(nextPagination.pageSize)); + }, + { resetPage: false } + ); }; const rows = useMemo(() => flattenAdvisorChecks(advisors), [advisors]); @@ -181,7 +243,8 @@ const AdvisorsList: FC = () => { const runChecks = useCallback( (names: string[], message: string) => startChecks(names, { - onSuccess: (batchId) => + onSuccess: (batchId) => { + void navigator.clipboard.writeText(batchId); enqueueSnackbar(message, { variant: 'success', action: (key) => ( @@ -197,7 +260,8 @@ const AdvisorsList: FC = () => { {Messages.viewResults} ), - }), + }); + }, }), [startChecks, navigate] ); @@ -356,13 +420,8 @@ const AdvisorsList: FC = () => { columns={columns} data={filteredRows} noDataMessage={Messages.noData} - state={{ isLoading }} - initialState={{ - pagination: { - pageSize: 50, - pageIndex: 0, - }, - }} + state={{ isLoading, pagination }} + onPaginationChange={handlePaginationChange} enableStickyHeader enablePagination enableTopToolbar={false} diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index 8b0e1c6dedb..8b1630b3497 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -69,7 +69,7 @@ export const Messages = { }, success: { rerunStarted: (check: string) => - `Check "${check}" started. The results will be available shortly.`, + `Check "${check}" started, batch ID copied to clipboard.`, checkEnabled: (check: string) => `Check "${check}" enabled`, checkDisabled: (check: string) => `Check "${check}" disabled`, copied: 'Insight copied to clipboard', diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index 475bbb07973..ae4e7b5711e 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -182,6 +182,23 @@ describe('AdvisorInsights', () => { ); }); + it('reads filters and pagination from the URL (deep link)', async () => { + renderComponent( + '/advisors/insights?category=version_configuration&service=mysql-prod&page=2&pageSize=50' + ); + + await waitForRows(); + + expect(advisorsApi.listCheckResultsHistory).toHaveBeenCalledWith( + expect.objectContaining({ + category: 'version_configuration', + serviceName: 'mysql-prod', + pageIndex: 1, + pageSize: 50, + }) + ); + }); + it('requests the next page on pagination change', async () => { renderComponent(); @@ -618,6 +635,7 @@ describe('AdvisorInsights', () => { Messages.success.rerunStarted('MySQL version check') ) ).toBeInTheDocument(); + expect(navigator.clipboard.writeText).toHaveBeenCalledWith('batch-123'); fireEvent.click(screen.getByTestId('view-run-results')); diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 105156e265e..251b149296f 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -30,7 +30,10 @@ import { useMarkCheckResultsRead, useStartAdvisorChecks, } from 'hooks/api/useAdvisors'; -import { type MRT_PaginationState } from 'material-react-table'; +import { + type MRT_PaginationState, + type MRT_Updater, +} from 'material-react-table'; import { closeSnackbar, enqueueSnackbar } from 'notistack'; import { FC, useEffect, useMemo, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; @@ -61,15 +64,18 @@ interface InsightFilters { isRead: string; } -const NO_FILTERS: InsightFilters = { - serviceName: '', - nodeName: '', - category: '', - severity: '', - status: '', - isRead: '', +// URL query-string key for each filter field (deep-linkable filters) +const FILTER_PARAM: Record = { + serviceName: 'service', + nodeName: 'node', + category: 'category', + severity: 'severity', + status: 'status', + isRead: 'read', }; +const DEFAULT_PAGE_SIZE = 100; + interface FilterOption { label: string; value: string; @@ -119,53 +125,75 @@ const FilterSelect: FC = ({ const AdvisorInsights: FC = () => { const [searchParams, setSearchParams] = useSearchParams(); - // deep link to the results of a concrete batch, e.g. from the "View results" snackbar + + // the URL query string is the single source of truth for filters + + // pagination, so a shared link reproduces the exact same view const batchId = searchParams.get('batchId') || undefined; - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 100, - }); - const [filters, setFilters] = useState(NO_FILTERS); + const filters: InsightFilters = { + serviceName: searchParams.get(FILTER_PARAM.serviceName) || '', + nodeName: searchParams.get(FILTER_PARAM.nodeName) || '', + category: searchParams.get(FILTER_PARAM.category) || '', + severity: searchParams.get(FILTER_PARAM.severity) || '', + status: searchParams.get(FILTER_PARAM.status) || '', + isRead: searchParams.get(FILTER_PARAM.isRead) || '', + }; + const pagination: MRT_PaginationState = { + pageIndex: Math.max(0, (Number(searchParams.get('page')) || 1) - 1), + pageSize: Number(searchParams.get('pageSize')) || DEFAULT_PAGE_SIZE, + }; + // local mirror of the batch-id URL param, committed on blur/Enter so typing // does not refetch (and spam history) on every keystroke const [batchIdInput, setBatchIdInput] = useState(batchId ?? ''); - - // keep the input in sync when the param changes elsewhere (row action, - // "View results" deep link, "Clear filters") useEffect(() => { setBatchIdInput(batchId ?? ''); }, [batchId]); - const updateFilter = (name: keyof InsightFilters, value: string) => { - setFilters((current) => ({ ...current, [name]: value })); - // filters change the result set, so start from the first page - setPagination((current) => ({ ...current, pageIndex: 0 })); + // apply query-string changes; filter changes reset back to the first page + const patchParams = ( + mutate: (params: URLSearchParams) => void, + { resetPage = true }: { resetPage?: boolean } = {} + ) => { + const next = new URLSearchParams(searchParams); + mutate(next); + if (resetPage) { + next.delete('page'); + } + setSearchParams(next, { replace: true }); }; + const updateFilter = (name: keyof InsightFilters, value: string) => + patchParams((p) => { + if (value) { + p.set(FILTER_PARAM[name], value); + } else { + p.delete(FILTER_PARAM[name]); + } + }); + const hasActiveFilters = Object.values(filters).some(Boolean) || !!batchId; const handleClearFilters = () => { - setFilters(NO_FILTERS); - if (batchId) { - setSearchParams({}); + // keep the chosen page size; drop every filter, the batch and the page + const next = new URLSearchParams(); + const pageSize = searchParams.get('pageSize'); + if (pageSize) { + next.set('pageSize', pageSize); } - setPagination((current) => ({ ...current, pageIndex: 0 })); + setSearchParams(next, { replace: true }); }; - const params = useMemo( - () => ({ - pageIndex: pagination.pageIndex, - pageSize: pagination.pageSize, - batchId, - serviceName: filters.serviceName || undefined, - nodeName: filters.nodeName || undefined, - category: filters.category || undefined, - severity: (filters.severity as Severity) || undefined, - status: (filters.status as AdvisorCheckResultStatus) || undefined, - isRead: filters.isRead === '' ? undefined : filters.isRead === 'true', - }), - [pagination, filters, batchId] - ); + const params: ListCheckResultsHistoryParams = { + pageIndex: pagination.pageIndex, + pageSize: pagination.pageSize, + batchId, + serviceName: filters.serviceName || undefined, + nodeName: filters.nodeName || undefined, + category: filters.category || undefined, + severity: (filters.severity as Severity) || undefined, + status: (filters.status as AdvisorCheckResultStatus) || undefined, + isRead: filters.isRead === '' ? undefined : filters.isRead === 'true', + }; const [actionMenu, setActionMenu] = useState(null); const [detailsInsight, setDetailsInsight] = @@ -196,9 +224,27 @@ const AdvisorInsights: FC = () => { [advisors] ); - const applyBatchIdFilter = (newBatchId: string) => { - setSearchParams(newBatchId ? { batchId: newBatchId } : {}); - setPagination((current) => ({ ...current, pageIndex: 0 })); + const applyBatchIdFilter = (newBatchId: string) => + patchParams((p) => { + if (newBatchId) { + p.set('batchId', newBatchId); + } else { + p.delete('batchId'); + } + }); + + const handlePaginationChange = ( + updater: MRT_Updater + ) => { + const nextPagination = + typeof updater === 'function' ? updater(pagination) : updater; + patchParams( + (p) => { + p.set('page', String(nextPagination.pageIndex + 1)); + p.set('pageSize', String(nextPagination.pageSize)); + }, + { resetPage: false } + ); }; const commitBatchIdInput = () => { @@ -212,7 +258,8 @@ const AdvisorInsights: FC = () => { const checkSummary = checksByName.get(insight.checkName)?.summary ?? insight.checkName; startChecks([insight.checkName], { - onSuccess: (newBatchId) => + onSuccess: (newBatchId) => { + void navigator.clipboard.writeText(newBatchId); enqueueSnackbar(Messages.success.rerunStarted(checkSummary), { variant: 'success', action: (key) => ( @@ -228,7 +275,8 @@ const AdvisorInsights: FC = () => { {Messages.viewResults} ), - }), + }); + }, }); }; @@ -429,7 +477,7 @@ const AdvisorInsights: FC = () => { isLoading, showProgressBars: isFetching && !isLoading, }} - onPaginationChange={setPagination} + onPaginationChange={handlePaginationChange} enableRowActions positionActionsColumn="last" renderRowActions={({ row }) => ( From c828273870bb376e757fb04465da4f366cf7d2bb Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Wed, 15 Jul 2026 01:28:32 +0300 Subject: [PATCH 035/120] PMM-14109 Add Get Advisor Check Script API and UI Integration - Implemented the GetAdvisorCheckScript API endpoint to retrieve the source script of a specific advisor check by name. - Added corresponding response models for successful and error responses in the API. - Updated the Swagger documentation to include the new endpoint and its specifications. - Created a new UI component for displaying the advisor check script details, including a copy-to-clipboard feature. - Integrated the new API call into the existing advisors list page, allowing users to view the script by double-clicking on a check. - Added unit tests for the new API functionality and UI interactions. --- .gitignore | 5 +- Makefile | 1 + api/advisors/v1/advisors.pb.go | 301 ++++++++---- api/advisors/v1/advisors.pb.gw.go | 78 +++ api/advisors/v1/advisors.pb.validate.go | 212 +++++++++ api/advisors/v1/advisors.proto | 19 + api/advisors/v1/advisors_grpc.pb.go | 41 ++ .../advisor_service/advisor_service_client.go | 46 ++ .../get_advisor_check_script_parameters.go | 146 ++++++ .../get_advisor_check_script_responses.go | 450 ++++++++++++++++++ api/advisors/v1/json/v1.json | 65 +++ api/descriptor.bin | Bin 827719 -> 828599 bytes api/swagger/swagger-dev.json | 65 +++ api/swagger/swagger.json | 65 +++ managed/Makefile | 8 - managed/services/management/checks.go | 15 + managed/services/management/checks_test.go | 26 + ui/apps/pmm/src/api/advisors.ts | 8 + ui/apps/pmm/src/hooks/api/useAdvisors.ts | 14 + .../pages/advisors/AdvisorsList.messages.ts | 21 +- .../src/pages/advisors/AdvisorsList.test.tsx | 34 ++ .../pmm/src/pages/advisors/AdvisorsList.tsx | 23 +- .../details-pane/AdvisorCheckDetailsPane.tsx | 255 ++++++++++ .../src/pages/advisors/details-pane/index.ts | 1 + .../insights/AdvisorInsights.messages.ts | 2 +- ui/apps/pmm/src/types/advisors.types.ts | 4 + 26 files changed, 1789 insertions(+), 116 deletions(-) create mode 100644 api/advisors/v1/json/client/advisor_service/get_advisor_check_script_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/get_advisor_check_script_responses.go create mode 100644 ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/details-pane/index.ts diff --git a/.gitignore b/.gitignore index 18597938a5e..7f5f0d6e425 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,9 @@ bin/ # System Files .DS_Store - + # Temporary (build, config, etc) /tmp/ - .env .netrc .modules @@ -22,7 +21,7 @@ build.log build/.cache/ packer.log ci.yml - +Makefile.local # PMM specific /dev/clickhouse-backups/ diff --git a/Makefile b/Makefile index 02a452d3304..8e937aaca9a 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ include Makefile.include -include documentation/Makefile +-include Makefile.local ifeq ($(PROFILES),) PROFILES := 'pmm' diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index b7eeb59f420..fa940ef9f16 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -981,6 +981,96 @@ func (x *ListAdvisorChecksResponse) GetChecks() []*AdvisorCheck { return nil } +type GetAdvisorCheckScriptRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Machine-readable name (ID) of the check. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAdvisorCheckScriptRequest) Reset() { + *x = GetAdvisorCheckScriptRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAdvisorCheckScriptRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAdvisorCheckScriptRequest) ProtoMessage() {} + +func (x *GetAdvisorCheckScriptRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAdvisorCheckScriptRequest.ProtoReflect.Descriptor instead. +func (*GetAdvisorCheckScriptRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{10} +} + +func (x *GetAdvisorCheckScriptRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type GetAdvisorCheckScriptResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Source script (Starlark) of the check. + Script string `protobuf:"bytes,1,opt,name=script,proto3" json:"script,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAdvisorCheckScriptResponse) Reset() { + *x = GetAdvisorCheckScriptResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAdvisorCheckScriptResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAdvisorCheckScriptResponse) ProtoMessage() {} + +func (x *GetAdvisorCheckScriptResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAdvisorCheckScriptResponse.ProtoReflect.Descriptor instead. +func (*GetAdvisorCheckScriptResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{11} +} + +func (x *GetAdvisorCheckScriptResponse) GetScript() string { + if x != nil { + return x.Script + } + return "" +} + type ListAdvisorsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -989,7 +1079,7 @@ type ListAdvisorsRequest struct { func (x *ListAdvisorsRequest) Reset() { *x = ListAdvisorsRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[10] + mi := &file_advisors_v1_advisors_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1001,7 +1091,7 @@ func (x *ListAdvisorsRequest) String() string { func (*ListAdvisorsRequest) ProtoMessage() {} func (x *ListAdvisorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[10] + mi := &file_advisors_v1_advisors_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1014,7 +1104,7 @@ func (x *ListAdvisorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAdvisorsRequest.ProtoReflect.Descriptor instead. func (*ListAdvisorsRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{10} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{12} } type ListAdvisorsResponse struct { @@ -1026,7 +1116,7 @@ type ListAdvisorsResponse struct { func (x *ListAdvisorsResponse) Reset() { *x = ListAdvisorsResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[11] + mi := &file_advisors_v1_advisors_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1038,7 +1128,7 @@ func (x *ListAdvisorsResponse) String() string { func (*ListAdvisorsResponse) ProtoMessage() {} func (x *ListAdvisorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[11] + mi := &file_advisors_v1_advisors_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1051,7 +1141,7 @@ func (x *ListAdvisorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAdvisorsResponse.ProtoReflect.Descriptor instead. func (*ListAdvisorsResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{11} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{13} } func (x *ListAdvisorsResponse) GetAdvisors() []*Advisor { @@ -1070,7 +1160,7 @@ type ChangeAdvisorChecksRequest struct { func (x *ChangeAdvisorChecksRequest) Reset() { *x = ChangeAdvisorChecksRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[12] + mi := &file_advisors_v1_advisors_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1082,7 +1172,7 @@ func (x *ChangeAdvisorChecksRequest) String() string { func (*ChangeAdvisorChecksRequest) ProtoMessage() {} func (x *ChangeAdvisorChecksRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[12] + mi := &file_advisors_v1_advisors_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1095,7 +1185,7 @@ func (x *ChangeAdvisorChecksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeAdvisorChecksRequest.ProtoReflect.Descriptor instead. func (*ChangeAdvisorChecksRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{12} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{14} } func (x *ChangeAdvisorChecksRequest) GetParams() []*ChangeAdvisorCheckParams { @@ -1113,7 +1203,7 @@ type ChangeAdvisorChecksResponse struct { func (x *ChangeAdvisorChecksResponse) Reset() { *x = ChangeAdvisorChecksResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[13] + mi := &file_advisors_v1_advisors_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1125,7 +1215,7 @@ func (x *ChangeAdvisorChecksResponse) String() string { func (*ChangeAdvisorChecksResponse) ProtoMessage() {} func (x *ChangeAdvisorChecksResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[13] + mi := &file_advisors_v1_advisors_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1138,7 +1228,7 @@ func (x *ChangeAdvisorChecksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeAdvisorChecksResponse.ProtoReflect.Descriptor instead. func (*ChangeAdvisorChecksResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{13} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{15} } type ListFailedServicesRequest struct { @@ -1149,7 +1239,7 @@ type ListFailedServicesRequest struct { func (x *ListFailedServicesRequest) Reset() { *x = ListFailedServicesRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[14] + mi := &file_advisors_v1_advisors_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1161,7 +1251,7 @@ func (x *ListFailedServicesRequest) String() string { func (*ListFailedServicesRequest) ProtoMessage() {} func (x *ListFailedServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[14] + mi := &file_advisors_v1_advisors_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1174,7 +1264,7 @@ func (x *ListFailedServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListFailedServicesRequest.ProtoReflect.Descriptor instead. func (*ListFailedServicesRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{14} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{16} } type ListFailedServicesResponse struct { @@ -1186,7 +1276,7 @@ type ListFailedServicesResponse struct { func (x *ListFailedServicesResponse) Reset() { *x = ListFailedServicesResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[15] + mi := &file_advisors_v1_advisors_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1198,7 +1288,7 @@ func (x *ListFailedServicesResponse) String() string { func (*ListFailedServicesResponse) ProtoMessage() {} func (x *ListFailedServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[15] + mi := &file_advisors_v1_advisors_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1211,7 +1301,7 @@ func (x *ListFailedServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListFailedServicesResponse.ProtoReflect.Descriptor instead. func (*ListFailedServicesResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{15} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{17} } func (x *ListFailedServicesResponse) GetResult() []*CheckResultSummary { @@ -1235,7 +1325,7 @@ type GetFailedChecksRequest struct { func (x *GetFailedChecksRequest) Reset() { *x = GetFailedChecksRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[16] + mi := &file_advisors_v1_advisors_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1247,7 +1337,7 @@ func (x *GetFailedChecksRequest) String() string { func (*GetFailedChecksRequest) ProtoMessage() {} func (x *GetFailedChecksRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[16] + mi := &file_advisors_v1_advisors_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1260,7 +1350,7 @@ func (x *GetFailedChecksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFailedChecksRequest.ProtoReflect.Descriptor instead. func (*GetFailedChecksRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{16} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{18} } func (x *GetFailedChecksRequest) GetPageSize() int32 { @@ -1298,7 +1388,7 @@ type GetFailedChecksResponse struct { func (x *GetFailedChecksResponse) Reset() { *x = GetFailedChecksResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[17] + mi := &file_advisors_v1_advisors_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1310,7 +1400,7 @@ func (x *GetFailedChecksResponse) String() string { func (*GetFailedChecksResponse) ProtoMessage() {} func (x *GetFailedChecksResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[17] + mi := &file_advisors_v1_advisors_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1323,7 +1413,7 @@ func (x *GetFailedChecksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFailedChecksResponse.ProtoReflect.Descriptor instead. func (*GetFailedChecksResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{17} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{19} } func (x *GetFailedChecksResponse) GetTotalItems() int32 { @@ -1404,7 +1494,7 @@ type CheckResultHistoryItem struct { func (x *CheckResultHistoryItem) Reset() { *x = CheckResultHistoryItem{} - mi := &file_advisors_v1_advisors_proto_msgTypes[18] + mi := &file_advisors_v1_advisors_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1416,7 +1506,7 @@ func (x *CheckResultHistoryItem) String() string { func (*CheckResultHistoryItem) ProtoMessage() {} func (x *CheckResultHistoryItem) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[18] + mi := &file_advisors_v1_advisors_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1429,7 +1519,7 @@ func (x *CheckResultHistoryItem) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckResultHistoryItem.ProtoReflect.Descriptor instead. func (*CheckResultHistoryItem) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{18} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{20} } func (x *CheckResultHistoryItem) GetId() string { @@ -1636,7 +1726,7 @@ type ListCheckResultsHistoryRequest struct { func (x *ListCheckResultsHistoryRequest) Reset() { *x = ListCheckResultsHistoryRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[19] + mi := &file_advisors_v1_advisors_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1648,7 +1738,7 @@ func (x *ListCheckResultsHistoryRequest) String() string { func (*ListCheckResultsHistoryRequest) ProtoMessage() {} func (x *ListCheckResultsHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[19] + mi := &file_advisors_v1_advisors_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1661,7 +1751,7 @@ func (x *ListCheckResultsHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListCheckResultsHistoryRequest.ProtoReflect.Descriptor instead. func (*ListCheckResultsHistoryRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{19} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{21} } func (x *ListCheckResultsHistoryRequest) GetPageSize() int32 { @@ -1776,7 +1866,7 @@ type ListCheckResultsHistoryResponse struct { func (x *ListCheckResultsHistoryResponse) Reset() { *x = ListCheckResultsHistoryResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[20] + mi := &file_advisors_v1_advisors_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1788,7 +1878,7 @@ func (x *ListCheckResultsHistoryResponse) String() string { func (*ListCheckResultsHistoryResponse) ProtoMessage() {} func (x *ListCheckResultsHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[20] + mi := &file_advisors_v1_advisors_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1801,7 +1891,7 @@ func (x *ListCheckResultsHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListCheckResultsHistoryResponse.ProtoReflect.Descriptor instead. func (*ListCheckResultsHistoryResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{20} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{22} } func (x *ListCheckResultsHistoryResponse) GetTotalItems() int32 { @@ -1833,7 +1923,7 @@ type ListCheckResultsFilterValuesRequest struct { func (x *ListCheckResultsFilterValuesRequest) Reset() { *x = ListCheckResultsFilterValuesRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[21] + mi := &file_advisors_v1_advisors_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1845,7 +1935,7 @@ func (x *ListCheckResultsFilterValuesRequest) String() string { func (*ListCheckResultsFilterValuesRequest) ProtoMessage() {} func (x *ListCheckResultsFilterValuesRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[21] + mi := &file_advisors_v1_advisors_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1858,7 +1948,7 @@ func (x *ListCheckResultsFilterValuesRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ListCheckResultsFilterValuesRequest.ProtoReflect.Descriptor instead. func (*ListCheckResultsFilterValuesRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{21} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{23} } type ListCheckResultsFilterValuesResponse struct { @@ -1873,7 +1963,7 @@ type ListCheckResultsFilterValuesResponse struct { func (x *ListCheckResultsFilterValuesResponse) Reset() { *x = ListCheckResultsFilterValuesResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[22] + mi := &file_advisors_v1_advisors_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1885,7 +1975,7 @@ func (x *ListCheckResultsFilterValuesResponse) String() string { func (*ListCheckResultsFilterValuesResponse) ProtoMessage() {} func (x *ListCheckResultsFilterValuesResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[22] + mi := &file_advisors_v1_advisors_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1898,7 +1988,7 @@ func (x *ListCheckResultsFilterValuesResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ListCheckResultsFilterValuesResponse.ProtoReflect.Descriptor instead. func (*ListCheckResultsFilterValuesResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{22} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{24} } func (x *ListCheckResultsFilterValuesResponse) GetServiceNames() []string { @@ -1927,7 +2017,7 @@ type MarkCheckResultsReadRequest struct { func (x *MarkCheckResultsReadRequest) Reset() { *x = MarkCheckResultsReadRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[23] + mi := &file_advisors_v1_advisors_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1939,7 +2029,7 @@ func (x *MarkCheckResultsReadRequest) String() string { func (*MarkCheckResultsReadRequest) ProtoMessage() {} func (x *MarkCheckResultsReadRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[23] + mi := &file_advisors_v1_advisors_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1952,7 +2042,7 @@ func (x *MarkCheckResultsReadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkCheckResultsReadRequest.ProtoReflect.Descriptor instead. func (*MarkCheckResultsReadRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{23} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{25} } func (x *MarkCheckResultsReadRequest) GetIds() []string { @@ -1977,7 +2067,7 @@ type MarkCheckResultsReadResponse struct { func (x *MarkCheckResultsReadResponse) Reset() { *x = MarkCheckResultsReadResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[24] + mi := &file_advisors_v1_advisors_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1989,7 +2079,7 @@ func (x *MarkCheckResultsReadResponse) String() string { func (*MarkCheckResultsReadResponse) ProtoMessage() {} func (x *MarkCheckResultsReadResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[24] + mi := &file_advisors_v1_advisors_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2002,7 +2092,7 @@ func (x *MarkCheckResultsReadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkCheckResultsReadResponse.ProtoReflect.Descriptor instead. func (*MarkCheckResultsReadResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{24} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{26} } var File_advisors_v1_advisors_proto protoreflect.FileDescriptor @@ -2078,7 +2168,11 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\bbatch_id\x18\x01 \x01(\tR\abatchId\"\x1a\n" + "\x18ListAdvisorChecksRequest\"N\n" + "\x19ListAdvisorChecksResponse\x121\n" + - "\x06checks\x18\x01 \x03(\v2\x19.advisors.v1.AdvisorCheckR\x06checks\"\x15\n" + + "\x06checks\x18\x01 \x03(\v2\x19.advisors.v1.AdvisorCheckR\x06checks\"2\n" + + "\x1cGetAdvisorCheckScriptRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"7\n" + + "\x1dGetAdvisorCheckScriptResponse\x12\x16\n" + + "\x06script\x18\x01 \x01(\tR\x06script\"\x15\n" + "\x13ListAdvisorsRequest\"H\n" + "\x14ListAdvisorsResponse\x120\n" + "\badvisors\x18\x01 \x03(\v2\x14.advisors.v1.AdvisorR\badvisors\"[\n" + @@ -2195,7 +2289,7 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\x17AdvisorCheckTriggeredBy\x12*\n" + "&ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED\x10\x00\x12#\n" + "\x1fADVISOR_CHECK_TRIGGERED_BY_USER\x10\x01\x12(\n" + - "$ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER\x10\x022\x8f\x12\n" + + "$ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER\x10\x022\x87\x14\n" + "\x0eAdvisorService\x12\xf3\x01\n" + "\x12ListFailedServices\x12&.advisors.v1.ListFailedServicesRequest\x1a'.advisors.v1.ListFailedServicesResponse\"\x8b\x01\x92Ae\x12\x14List Failed Services\x1aMReturns a list of services with failed checks and a summary of check results.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/failedServices\x12\xd5\x01\n" + "\x0fGetFailedChecks\x12#.advisors.v1.GetFailedChecksRequest\x1a$.advisors.v1.GetFailedChecksResponse\"w\x92AR\x12\x19Get Failed Advisor Checks\x1a5Returns the latest check results for a given service.\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/advisors/checks/failed\x12\x87\x02\n" + @@ -2203,7 +2297,8 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\x1cListCheckResultsFilterValues\x120.advisors.v1.ListCheckResultsFilterValuesRequest\x1a1.advisors.v1.ListCheckResultsFilterValuesResponse\"\xda\x01\x92A\xa6\x01\x12(List Advisor Check Results Filter Values\x1azReturns the distinct service and node names present in the Advisor check results history, for populating filter dropdowns.\x82\xd3\xe4\x93\x02*\x12(/v1/advisors/checks/history:filterValues\x12\xb1\x02\n" + "\x14MarkCheckResultsRead\x12(.advisors.v1.MarkCheckResultsReadRequest\x1a).advisors.v1.MarkCheckResultsReadResponse\"\xc3\x01\x92A\x90\x01\x12\x1fMark Advisor Check Results Read\x1amSets the read state on the specified Advisor check history records. Set is_read to false to mark them unread.\x82\xd3\xe4\x93\x02):\x01*\"$/v1/advisors/checks/history:markRead\x12\xb0\x02\n" + "\x12StartAdvisorChecks\x12&.advisors.v1.StartAdvisorChecksRequest\x1a'.advisors.v1.StartAdvisorChecksResponse\"\xc8\x01\x92A\xa0\x01\x12\x14Start Advisor Checks\x1a\x87\x01Executes Advisor checks and returns when all checks are executed. All available checks will be started if check names aren't specified.\x82\xd3\xe4\x93\x02\x1e:\x01*\"\x19/v1/advisors/checks:start\x12\xc3\x01\n" + - "\x11ListAdvisorChecks\x12%.advisors.v1.ListAdvisorChecksRequest\x1a&.advisors.v1.ListAdvisorChecksResponse\"_\x92AA\x12\x13List Advisor Checks\x1a*List advisor checks available to the user.\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/advisors/checks\x12\xa1\x01\n" + + "\x11ListAdvisorChecks\x12%.advisors.v1.ListAdvisorChecksRequest\x1a&.advisors.v1.ListAdvisorChecksResponse\"_\x92AA\x12\x13List Advisor Checks\x1a*List advisor checks available to the user.\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/advisors/checks\x12\xf5\x01\n" + + "\x15GetAdvisorCheckScript\x12).advisors.v1.GetAdvisorCheckScriptRequest\x1a*.advisors.v1.GetAdvisorCheckScriptResponse\"\x84\x01\x92AX\x12\x18Get Advisor Check Script\x1a management.v1.Severity - 29, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry - 32, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity - 30, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry + 34, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity + 31, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry + 34, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity + 32, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry 0, // 4: advisors.v1.AdvisorCheck.interval:type_name -> advisors.v1.AdvisorCheckInterval 1, // 5: advisors.v1.AdvisorCheck.family:type_name -> advisors.v1.AdvisorCheckFamily 7, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck @@ -2277,36 +2374,38 @@ var file_advisors_v1_advisors_proto_depIdxs = []int32{ 6, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult 0, // 13: advisors.v1.CheckResultHistoryItem.interval:type_name -> advisors.v1.AdvisorCheckInterval 2, // 14: advisors.v1.CheckResultHistoryItem.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 32, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity - 31, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry - 33, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp + 34, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity + 33, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry + 35, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp 3, // 18: advisors.v1.CheckResultHistoryItem.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy 2, // 19: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 33, // 20: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp - 33, // 21: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp - 32, // 22: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity + 35, // 20: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp + 35, // 21: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp + 34, // 22: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity 3, // 23: advisors.v1.ListCheckResultsHistoryRequest.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy - 22, // 24: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem - 18, // 25: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest - 20, // 26: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest - 23, // 27: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest - 25, // 28: advisors.v1.AdvisorService.ListCheckResultsFilterValues:input_type -> advisors.v1.ListCheckResultsFilterValuesRequest - 27, // 29: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest + 24, // 24: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem + 20, // 25: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest + 22, // 26: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest + 25, // 27: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest + 27, // 28: advisors.v1.AdvisorService.ListCheckResultsFilterValues:input_type -> advisors.v1.ListCheckResultsFilterValuesRequest + 29, // 29: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest 10, // 30: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest 12, // 31: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest - 14, // 32: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest - 16, // 33: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest - 19, // 34: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse - 21, // 35: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse - 24, // 36: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse - 26, // 37: advisors.v1.AdvisorService.ListCheckResultsFilterValues:output_type -> advisors.v1.ListCheckResultsFilterValuesResponse - 28, // 38: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse - 11, // 39: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse - 13, // 40: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse - 15, // 41: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse - 17, // 42: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse - 34, // [34:43] is the sub-list for method output_type - 25, // [25:34] is the sub-list for method input_type + 14, // 32: advisors.v1.AdvisorService.GetAdvisorCheckScript:input_type -> advisors.v1.GetAdvisorCheckScriptRequest + 16, // 33: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest + 18, // 34: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest + 21, // 35: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse + 23, // 36: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse + 26, // 37: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse + 28, // 38: advisors.v1.AdvisorService.ListCheckResultsFilterValues:output_type -> advisors.v1.ListCheckResultsFilterValuesResponse + 30, // 39: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse + 11, // 40: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse + 13, // 41: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse + 15, // 42: advisors.v1.AdvisorService.GetAdvisorCheckScript:output_type -> advisors.v1.GetAdvisorCheckScriptResponse + 17, // 43: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse + 19, // 44: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse + 35, // [35:45] is the sub-list for method output_type + 25, // [25:35] is the sub-list for method input_type 25, // [25:25] is the sub-list for extension type_name 25, // [25:25] is the sub-list for extension extendee 0, // [0:25] is the sub-list for field type_name @@ -2318,15 +2417,15 @@ func file_advisors_v1_advisors_proto_init() { return } file_advisors_v1_advisors_proto_msgTypes[5].OneofWrappers = []any{} - file_advisors_v1_advisors_proto_msgTypes[16].OneofWrappers = []any{} - file_advisors_v1_advisors_proto_msgTypes[19].OneofWrappers = []any{} + file_advisors_v1_advisors_proto_msgTypes[18].OneofWrappers = []any{} + file_advisors_v1_advisors_proto_msgTypes[21].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_advisors_v1_advisors_proto_rawDesc), len(file_advisors_v1_advisors_proto_rawDesc)), NumEnums: 4, - NumMessages: 28, + NumMessages: 30, NumExtensions: 0, NumServices: 1, }, diff --git a/api/advisors/v1/advisors.pb.gw.go b/api/advisors/v1/advisors.pb.gw.go index 15f60fabae3..464e0fab1b0 100644 --- a/api/advisors/v1/advisors.pb.gw.go +++ b/api/advisors/v1/advisors.pb.gw.go @@ -222,6 +222,45 @@ func local_request_AdvisorService_ListAdvisorChecks_0(ctx context.Context, marsh return msg, metadata, err } +func request_AdvisorService_GetAdvisorCheckScript_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetAdvisorCheckScriptRequest + metadata runtime.ServerMetadata + err error + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := client.GetAdvisorCheckScript(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_GetAdvisorCheckScript_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetAdvisorCheckScriptRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := server.GetAdvisorCheckScript(ctx, &protoReq) + return msg, metadata, err +} + func request_AdvisorService_ListAdvisors_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var ( protoReq ListAdvisorsRequest @@ -416,6 +455,26 @@ func RegisterAdvisorServiceHandlerServer(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ListAdvisorChecks_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_GetAdvisorCheckScript_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/GetAdvisorCheckScript", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}/script")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_GetAdvisorCheckScript_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_GetAdvisorCheckScript_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodGet, pattern_AdvisorService_ListAdvisors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -615,6 +674,23 @@ func RegisterAdvisorServiceHandlerClient(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ListAdvisorChecks_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_GetAdvisorCheckScript_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/GetAdvisorCheckScript", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}/script")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_GetAdvisorCheckScript_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_GetAdvisorCheckScript_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) mux.Handle(http.MethodGet, pattern_AdvisorService_ListAdvisors_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -660,6 +736,7 @@ var ( pattern_AdvisorService_MarkCheckResultsRead_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v1", "advisors", "checks", "history"}, "markRead")) pattern_AdvisorService_StartAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "start")) pattern_AdvisorService_ListAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "")) + pattern_AdvisorService_GetAdvisorCheckScript_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"v1", "advisors", "checks", "name", "script"}, "")) pattern_AdvisorService_ListAdvisors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "advisors"}, "")) pattern_AdvisorService_ChangeAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "batchChange")) ) @@ -672,6 +749,7 @@ var ( forward_AdvisorService_MarkCheckResultsRead_0 = runtime.ForwardResponseMessage forward_AdvisorService_StartAdvisorChecks_0 = runtime.ForwardResponseMessage forward_AdvisorService_ListAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_GetAdvisorCheckScript_0 = runtime.ForwardResponseMessage forward_AdvisorService_ListAdvisors_0 = runtime.ForwardResponseMessage forward_AdvisorService_ChangeAdvisorChecks_0 = runtime.ForwardResponseMessage ) diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 5164428b57a..6320643d0bb 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -1209,6 +1209,218 @@ var _ interface { ErrorName() string } = ListAdvisorChecksResponseValidationError{} +// Validate checks the field values on GetAdvisorCheckScriptRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetAdvisorCheckScriptRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetAdvisorCheckScriptRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetAdvisorCheckScriptRequestMultiError, or nil if none found. +func (m *GetAdvisorCheckScriptRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetAdvisorCheckScriptRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Name + + if len(errors) > 0 { + return GetAdvisorCheckScriptRequestMultiError(errors) + } + + return nil +} + +// GetAdvisorCheckScriptRequestMultiError is an error wrapping multiple +// validation errors returned by GetAdvisorCheckScriptRequest.ValidateAll() if +// the designated constraints aren't met. +type GetAdvisorCheckScriptRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetAdvisorCheckScriptRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetAdvisorCheckScriptRequestMultiError) AllErrors() []error { return m } + +// GetAdvisorCheckScriptRequestValidationError is the validation error returned +// by GetAdvisorCheckScriptRequest.Validate if the designated constraints +// aren't met. +type GetAdvisorCheckScriptRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetAdvisorCheckScriptRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetAdvisorCheckScriptRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetAdvisorCheckScriptRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetAdvisorCheckScriptRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetAdvisorCheckScriptRequestValidationError) ErrorName() string { + return "GetAdvisorCheckScriptRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetAdvisorCheckScriptRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetAdvisorCheckScriptRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetAdvisorCheckScriptRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetAdvisorCheckScriptRequestValidationError{} + +// Validate checks the field values on GetAdvisorCheckScriptResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetAdvisorCheckScriptResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetAdvisorCheckScriptResponse with +// the rules defined in the proto definition for this message. If any rules +// are violated, the result is a list of violation errors wrapped in +// GetAdvisorCheckScriptResponseMultiError, or nil if none found. +func (m *GetAdvisorCheckScriptResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetAdvisorCheckScriptResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Script + + if len(errors) > 0 { + return GetAdvisorCheckScriptResponseMultiError(errors) + } + + return nil +} + +// GetAdvisorCheckScriptResponseMultiError is an error wrapping multiple +// validation errors returned by GetAdvisorCheckScriptResponse.ValidateAll() +// if the designated constraints aren't met. +type GetAdvisorCheckScriptResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetAdvisorCheckScriptResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetAdvisorCheckScriptResponseMultiError) AllErrors() []error { return m } + +// GetAdvisorCheckScriptResponseValidationError is the validation error +// returned by GetAdvisorCheckScriptResponse.Validate if the designated +// constraints aren't met. +type GetAdvisorCheckScriptResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetAdvisorCheckScriptResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetAdvisorCheckScriptResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetAdvisorCheckScriptResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetAdvisorCheckScriptResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetAdvisorCheckScriptResponseValidationError) ErrorName() string { + return "GetAdvisorCheckScriptResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetAdvisorCheckScriptResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetAdvisorCheckScriptResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetAdvisorCheckScriptResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetAdvisorCheckScriptResponseValidationError{} + // Validate checks the field values on ListAdvisorsRequest with the rules // defined in the proto definition for this message. If any rules are // violated, the first error encountered is returned, or nil if there are no violations. diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index 62f803a16cb..db2735a5f31 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -151,6 +151,16 @@ message ListAdvisorChecksResponse { repeated AdvisorCheck checks = 1; } +message GetAdvisorCheckScriptRequest { + // Machine-readable name (ID) of the check. + string name = 1; +} + +message GetAdvisorCheckScriptResponse { + // Source script (Starlark) of the check. + string script = 1; +} + message ListAdvisorsRequest {} message ListAdvisorsResponse { @@ -361,6 +371,15 @@ service AdvisorService { description: "List advisor checks available to the user." }; } + // GetAdvisorCheckScript returns the source script of a single advisor check. + rpc GetAdvisorCheckScript(GetAdvisorCheckScriptRequest) returns (GetAdvisorCheckScriptResponse) { + // deeper path than /checks/{failed,history} so the wildcard cannot shadow them + option (google.api.http) = {get: "/v1/advisors/checks/{name}/script"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get Advisor Check Script" + description: "Returns the source script of a single advisor check by name." + }; + } // ListAdvisors returns a list of advisors available for the user. rpc ListAdvisors(ListAdvisorsRequest) returns (ListAdvisorsResponse) { option (google.api.http) = {get: "/v1/advisors"}; diff --git a/api/advisors/v1/advisors_grpc.pb.go b/api/advisors/v1/advisors_grpc.pb.go index 86453aeeb6c..aea03328025 100644 --- a/api/advisors/v1/advisors_grpc.pb.go +++ b/api/advisors/v1/advisors_grpc.pb.go @@ -27,6 +27,7 @@ const ( AdvisorService_MarkCheckResultsRead_FullMethodName = "/advisors.v1.AdvisorService/MarkCheckResultsRead" AdvisorService_StartAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/StartAdvisorChecks" AdvisorService_ListAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisorChecks" + AdvisorService_GetAdvisorCheckScript_FullMethodName = "/advisors.v1.AdvisorService/GetAdvisorCheckScript" AdvisorService_ListAdvisors_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisors" AdvisorService_ChangeAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ChangeAdvisorChecks" ) @@ -51,6 +52,8 @@ type AdvisorServiceClient interface { StartAdvisorChecks(ctx context.Context, in *StartAdvisorChecksRequest, opts ...grpc.CallOption) (*StartAdvisorChecksResponse, error) // ListAdvisorChecks returns a list of advisor checks available to the user.. ListAdvisorChecks(ctx context.Context, in *ListAdvisorChecksRequest, opts ...grpc.CallOption) (*ListAdvisorChecksResponse, error) + // GetAdvisorCheckScript returns the source script of a single advisor check. + GetAdvisorCheckScript(ctx context.Context, in *GetAdvisorCheckScriptRequest, opts ...grpc.CallOption) (*GetAdvisorCheckScriptResponse, error) // ListAdvisors returns a list of advisors available for the user. ListAdvisors(ctx context.Context, in *ListAdvisorsRequest, opts ...grpc.CallOption) (*ListAdvisorsResponse, error) // ChangeAdvisorChecks enables/disables Advisor checks or changes their exec interval. @@ -135,6 +138,16 @@ func (c *advisorServiceClient) ListAdvisorChecks(ctx context.Context, in *ListAd return out, nil } +func (c *advisorServiceClient) GetAdvisorCheckScript(ctx context.Context, in *GetAdvisorCheckScriptRequest, opts ...grpc.CallOption) (*GetAdvisorCheckScriptResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAdvisorCheckScriptResponse) + err := c.cc.Invoke(ctx, AdvisorService_GetAdvisorCheckScript_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *advisorServiceClient) ListAdvisors(ctx context.Context, in *ListAdvisorsRequest, opts ...grpc.CallOption) (*ListAdvisorsResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListAdvisorsResponse) @@ -175,6 +188,8 @@ type AdvisorServiceServer interface { StartAdvisorChecks(context.Context, *StartAdvisorChecksRequest) (*StartAdvisorChecksResponse, error) // ListAdvisorChecks returns a list of advisor checks available to the user.. ListAdvisorChecks(context.Context, *ListAdvisorChecksRequest) (*ListAdvisorChecksResponse, error) + // GetAdvisorCheckScript returns the source script of a single advisor check. + GetAdvisorCheckScript(context.Context, *GetAdvisorCheckScriptRequest) (*GetAdvisorCheckScriptResponse, error) // ListAdvisors returns a list of advisors available for the user. ListAdvisors(context.Context, *ListAdvisorsRequest) (*ListAdvisorsResponse, error) // ChangeAdvisorChecks enables/disables Advisor checks or changes their exec interval. @@ -217,6 +232,10 @@ func (UnimplementedAdvisorServiceServer) ListAdvisorChecks(context.Context, *Lis return nil, status.Error(codes.Unimplemented, "method ListAdvisorChecks not implemented") } +func (UnimplementedAdvisorServiceServer) GetAdvisorCheckScript(context.Context, *GetAdvisorCheckScriptRequest) (*GetAdvisorCheckScriptResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetAdvisorCheckScript not implemented") +} + func (UnimplementedAdvisorServiceServer) ListAdvisors(context.Context, *ListAdvisorsRequest) (*ListAdvisorsResponse, error) { return nil, status.Error(codes.Unimplemented, "method ListAdvisors not implemented") } @@ -371,6 +390,24 @@ func _AdvisorService_ListAdvisorChecks_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } +func _AdvisorService_GetAdvisorCheckScript_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAdvisorCheckScriptRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).GetAdvisorCheckScript(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_GetAdvisorCheckScript_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).GetAdvisorCheckScript(ctx, req.(*GetAdvisorCheckScriptRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AdvisorService_ListAdvisors_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListAdvisorsRequest) if err := dec(in); err != nil { @@ -442,6 +479,10 @@ var AdvisorService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListAdvisorChecks", Handler: _AdvisorService_ListAdvisorChecks_Handler, }, + { + MethodName: "GetAdvisorCheckScript", + Handler: _AdvisorService_GetAdvisorCheckScript_Handler, + }, { MethodName: "ListAdvisors", Handler: _AdvisorService_ListAdvisors_Handler, diff --git a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go index bb6dd3f9638..b1a85794199 100644 --- a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go +++ b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go @@ -53,6 +53,8 @@ type ClientOption func(*runtime.ClientOperation) type ClientService interface { ChangeAdvisorChecks(params *ChangeAdvisorChecksParams, opts ...ClientOption) (*ChangeAdvisorChecksOK, error) + GetAdvisorCheckScript(params *GetAdvisorCheckScriptParams, opts ...ClientOption) (*GetAdvisorCheckScriptOK, error) + GetFailedChecks(params *GetFailedChecksParams, opts ...ClientOption) (*GetFailedChecksOK, error) ListAdvisorChecks(params *ListAdvisorChecksParams, opts ...ClientOption) (*ListAdvisorChecksOK, error) @@ -116,6 +118,50 @@ func (a *Client) ChangeAdvisorChecks(params *ChangeAdvisorChecksParams, opts ... return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +GetAdvisorCheckScript gets advisor check script + +Returns the source script of a single advisor check by name. +*/ +func (a *Client) GetAdvisorCheckScript(params *GetAdvisorCheckScriptParams, opts ...ClientOption) (*GetAdvisorCheckScriptOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetAdvisorCheckScriptParams() + } + op := &runtime.ClientOperation{ + ID: "GetAdvisorCheckScript", + Method: "GET", + PathPattern: "/v1/advisors/checks/{name}/script", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetAdvisorCheckScriptReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*GetAdvisorCheckScriptOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetAdvisorCheckScriptDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* GetFailedChecks gets failed advisor checks diff --git a/api/advisors/v1/json/client/advisor_service/get_advisor_check_script_parameters.go b/api/advisors/v1/json/client/advisor_service/get_advisor_check_script_parameters.go new file mode 100644 index 00000000000..e85fb8ea46f --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/get_advisor_check_script_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewGetAdvisorCheckScriptParams creates a new GetAdvisorCheckScriptParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewGetAdvisorCheckScriptParams() *GetAdvisorCheckScriptParams { + return &GetAdvisorCheckScriptParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetAdvisorCheckScriptParamsWithTimeout creates a new GetAdvisorCheckScriptParams object +// with the ability to set a timeout on a request. +func NewGetAdvisorCheckScriptParamsWithTimeout(timeout time.Duration) *GetAdvisorCheckScriptParams { + return &GetAdvisorCheckScriptParams{ + timeout: timeout, + } +} + +// NewGetAdvisorCheckScriptParamsWithContext creates a new GetAdvisorCheckScriptParams object +// with the ability to set a context for a request. +func NewGetAdvisorCheckScriptParamsWithContext(ctx context.Context) *GetAdvisorCheckScriptParams { + return &GetAdvisorCheckScriptParams{ + Context: ctx, + } +} + +// NewGetAdvisorCheckScriptParamsWithHTTPClient creates a new GetAdvisorCheckScriptParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetAdvisorCheckScriptParamsWithHTTPClient(client *http.Client) *GetAdvisorCheckScriptParams { + return &GetAdvisorCheckScriptParams{ + HTTPClient: client, + } +} + +/* +GetAdvisorCheckScriptParams contains all the parameters to send to the API endpoint + + for the get advisor check script operation. + + Typically these are written to a http.Request. +*/ +type GetAdvisorCheckScriptParams struct { + /* Name. + + Machine-readable name (ID) of the check. + */ + Name string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get advisor check script params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetAdvisorCheckScriptParams) WithDefaults() *GetAdvisorCheckScriptParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get advisor check script params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetAdvisorCheckScriptParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) WithTimeout(timeout time.Duration) *GetAdvisorCheckScriptParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) WithContext(ctx context.Context) *GetAdvisorCheckScriptParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) WithHTTPClient(client *http.Client) *GetAdvisorCheckScriptParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithName adds the name to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) WithName(name string) *GetAdvisorCheckScriptParams { + o.SetName(name) + return o +} + +// SetName adds the name to the get advisor check script params +func (o *GetAdvisorCheckScriptParams) SetName(name string) { + o.Name = name +} + +// WriteToRequest writes these params to a swagger request +func (o *GetAdvisorCheckScriptParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param name + if err := r.SetPathParam("name", o.Name); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/get_advisor_check_script_responses.go b/api/advisors/v1/json/client/advisor_service/get_advisor_check_script_responses.go new file mode 100644 index 00000000000..34f1887c394 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/get_advisor_check_script_responses.go @@ -0,0 +1,450 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GetAdvisorCheckScriptReader is a Reader for the GetAdvisorCheckScript structure. +type GetAdvisorCheckScriptReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetAdvisorCheckScriptReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetAdvisorCheckScriptOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetAdvisorCheckScriptDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetAdvisorCheckScriptOK creates a GetAdvisorCheckScriptOK with default headers values +func NewGetAdvisorCheckScriptOK() *GetAdvisorCheckScriptOK { + return &GetAdvisorCheckScriptOK{} +} + +/* +GetAdvisorCheckScriptOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetAdvisorCheckScriptOK struct { + Payload *GetAdvisorCheckScriptOKBody +} + +// IsSuccess returns true when this get advisor check script Ok response has a 2xx status code +func (o *GetAdvisorCheckScriptOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get advisor check script Ok response has a 3xx status code +func (o *GetAdvisorCheckScriptOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get advisor check script Ok response has a 4xx status code +func (o *GetAdvisorCheckScriptOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get advisor check script Ok response has a 5xx status code +func (o *GetAdvisorCheckScriptOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get advisor check script Ok response a status code equal to that given +func (o *GetAdvisorCheckScriptOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get advisor check script Ok response +func (o *GetAdvisorCheckScriptOK) Code() int { + return 200 +} + +func (o *GetAdvisorCheckScriptOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/script][%d] getAdvisorCheckScriptOk %s", 200, payload) +} + +func (o *GetAdvisorCheckScriptOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/script][%d] getAdvisorCheckScriptOk %s", 200, payload) +} + +func (o *GetAdvisorCheckScriptOK) GetPayload() *GetAdvisorCheckScriptOKBody { + return o.Payload +} + +func (o *GetAdvisorCheckScriptOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetAdvisorCheckScriptOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetAdvisorCheckScriptDefault creates a GetAdvisorCheckScriptDefault with default headers values +func NewGetAdvisorCheckScriptDefault(code int) *GetAdvisorCheckScriptDefault { + return &GetAdvisorCheckScriptDefault{ + _statusCode: code, + } +} + +/* +GetAdvisorCheckScriptDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetAdvisorCheckScriptDefault struct { + _statusCode int + + Payload *GetAdvisorCheckScriptDefaultBody +} + +// IsSuccess returns true when this get advisor check script default response has a 2xx status code +func (o *GetAdvisorCheckScriptDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get advisor check script default response has a 3xx status code +func (o *GetAdvisorCheckScriptDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get advisor check script default response has a 4xx status code +func (o *GetAdvisorCheckScriptDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get advisor check script default response has a 5xx status code +func (o *GetAdvisorCheckScriptDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get advisor check script default response a status code equal to that given +func (o *GetAdvisorCheckScriptDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get advisor check script default response +func (o *GetAdvisorCheckScriptDefault) Code() int { + return o._statusCode +} + +func (o *GetAdvisorCheckScriptDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/script][%d] GetAdvisorCheckScript default %s", o._statusCode, payload) +} + +func (o *GetAdvisorCheckScriptDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/script][%d] GetAdvisorCheckScript default %s", o._statusCode, payload) +} + +func (o *GetAdvisorCheckScriptDefault) GetPayload() *GetAdvisorCheckScriptDefaultBody { + return o.Payload +} + +func (o *GetAdvisorCheckScriptDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetAdvisorCheckScriptDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetAdvisorCheckScriptDefaultBody get advisor check script default body +swagger:model GetAdvisorCheckScriptDefaultBody +*/ +type GetAdvisorCheckScriptDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetAdvisorCheckScriptDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get advisor check script default body +func (o *GetAdvisorCheckScriptDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetAdvisorCheckScriptDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetAdvisorCheckScript default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetAdvisorCheckScript default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get advisor check script default body based on the context it is used +func (o *GetAdvisorCheckScriptDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetAdvisorCheckScriptDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetAdvisorCheckScript default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetAdvisorCheckScript default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckScriptDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckScriptDefaultBody) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckScriptDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetAdvisorCheckScriptDefaultBodyDetailsItems0 get advisor check script default body details items0 +swagger:model GetAdvisorCheckScriptDefaultBodyDetailsItems0 +*/ +type GetAdvisorCheckScriptDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get advisor check script default body details items0 + GetAdvisorCheckScriptDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetAdvisorCheckScriptDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetAdvisorCheckScriptDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetAdvisorCheckScriptDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetAdvisorCheckScriptDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetAdvisorCheckScriptDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetAdvisorCheckScriptDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get advisor check script default body details items0 +func (o *GetAdvisorCheckScriptDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get advisor check script default body details items0 based on context it is used +func (o *GetAdvisorCheckScriptDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckScriptDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckScriptDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckScriptDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetAdvisorCheckScriptOKBody get advisor check script OK body +swagger:model GetAdvisorCheckScriptOKBody +*/ +type GetAdvisorCheckScriptOKBody struct { + // Source script (Starlark) of the check. + Script string `json:"script,omitempty"` +} + +// Validate validates this get advisor check script OK body +func (o *GetAdvisorCheckScriptOKBody) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get advisor check script OK body based on context it is used +func (o *GetAdvisorCheckScriptOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckScriptOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckScriptOKBody) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckScriptOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index 5aa9cac84f5..087a082ec6c 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -897,6 +897,71 @@ } } }, + "/v1/advisors/checks/{name}/script": { + "get": { + "description": "Returns the source script of a single advisor check by name.", + "tags": [ + "AdvisorService" + ], + "summary": "Get Advisor Check Script", + "operationId": "GetAdvisorCheckScript", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check.", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "script": { + "description": "Source script (Starlark) of the check.", + "type": "string", + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks:batchChange": { "post": { "description": "Enables/disables advisor checks or changes their exec interval.", diff --git a/api/descriptor.bin b/api/descriptor.bin index 3e27066ec46613c39d99c41c2bf493f20347a4e1..cc221296811765fad61ebef146c377439e3faa98 100644 GIT binary patch delta 6841 zcma)AeRNgTm49cSo0IqMC6L^_myeeKmjvXa0)n9t#Zo?`U|qC;r5#(9h>tc?hG-I) zvbwq+2&@c)3`1G2<443;3K3Mk{D_R!i43+#tqYN|D5VY+#xm4}XeonZnappWd+xim z%dXWwvhsfWp5NZTz0b!!_x^1E_?|b$uUIWs)ARBhchMhvdhWPO&QA^=@78`P*FNRm zWzB6Zt<%1fTln313tOA-YoD9De`&6*ebYx@PEV|BbO-*GL2dW7ENRR66|QPCv?>vZ z5vjQr_3TLjK@?c5RKjg+d@Xnb{RPPVb_kT~OOTN#xAB+vzJwN@vd|0@v{?RS=ixP>A zQh(H4oYo8OOnN;XKafW&CiZj5aeeiONOTI}daiU_;X99rXG7KtZqEDs|$i{vmf(lfET zIM(M83($9f(%BKgygw_+hWZjE)q}MDE%>VyGYiVk^N1S9Z?iO-vJsMJw%Wl!mE!Us5|mv z=%@%I$__CalYk@#_|CH;ag9lG00urQlJ(|6sqgF(iJ|5}DIV++$stBpnXmSU#B)|x z86NG4bd?!hdm~+dz5_H8f$uJI03mFz@CF(ofZ*;GgTnO#2wi){@DV18@2eL?;uRak z$H*5%a*!eVCQ1)SxgIqJ^qn3(d5avI!*49Y9^sWnBSGvDW!VTKM2{F)@RMXXc(PmO zrr1w%S5g{&@C8c{n9Y40=_V5i-u4N-=kJr_&3yVKFnnJePM85@;e6sL!tLYvbY@Z0hUKXkHh>Kt^ zi;7B9zH(o^DiW{T@|9!ct0EcdC^t3g6;$kwKomgV>D8TD4sF11jO-Q3&?g{#_Oee- zpxk7;pNZEPBF63)df?*ZK;64tI(ZB*rUISw-yhQn#XP{p9BAms4yZmmz@BiexwfT? z+uOpkp_~Yd<$&-iY;4Z zmj>rxv~1EQ??cf61?W46bj>5O;d=bW$U`FKnP7nMen|8WkA<|!`%NZ(8^Qs7=S}^< zBXZ#l_{~71$}EvHep93~7V><)#l+7UA~FW5$_~`mJt(VgZf#m(XESXk^Q~wy0paJZ zsB&rIRe6~GOf-J*@UU)uR8D|$2?2*iDvBuinW(C^0vr&JF!5$X!~`7CCmxj(L3BVo z5-WE=JQ6D}LiLXds&GddBHSF+Gai$}Kr90BsHhBA6Cj93MO}E>q)B1uF^)LR5aH&S z-u#%H459+@Se&B*@mQQ=F^I>Rc#9zx1L@LEIb~9sia|Uc=U5El@i@mMh$mtqHW^Sh z+Zf!w{62m6YT3}pt2a$acsUV!Ny5vC*h>mtPO=w1Q__?I(w95sSm;iHcv7UoGX)UD zlcGGTxC`RDOq^hdE|9+CaXAh|ZjkSaRCwA0g7~h;gu5wC9*C!yc$*=5K>F3k=)%tD!%T9{Yq@4cwUC7d1mHu|J6Ki=o$8 zH~XNsD$i3$PLrfb~ zmn{wEnv*bC+;mTFaa-Yt;M445Q4wA=(v*g?kHz4~cLvTb3aT-OdYUr6BQ9$BBRLfM zGhkj6wb7(xz`Q6%e$LKO1rom`NZC260Md8-NH*S>rV0=*iQ@jzNDwcHvama(sS+VC z3#xX<8U2+8U7M{BZr77m$|`;8DcOHEhQY~Yk&U8P!pUWh&X>H5uRaxthbg>Jvd&LM zG8~yPZT?Es<^g@@O4#P{8=9{~eHReKD^Z&VM2IU^a3yN<48t~mMc6i421(^ zq?i0y26+JZUP-pA1H$)8vK=@>5<*uIT4}3$pxWHx5B$_AOr<^q$Ae0uO+HB=j0a|lS_Xch4P3>_EZZm7h z3;Sipw3ang8Xk0jh_QyU;YQ04x0VjVO63j#Xwb0i1T1^~e_Q1c{p?m*(SQd~+CjBJ zD9!Yl4yq4tiy2bzvX;F}H(m_V|Fad12G77;OSR!$0TA)m67CA&WOAcf$JL)@m}oTX zbn`ZO3y9ok){$+dfFQ0T+e|aWjb=R)XBZ-;dA9OJdO1xB6UkBAOdWn z(cwErCPUnW9%5->1T>+CbnYoR7&&nhdMM6`o6tjXP9>10SsJ&5450~W-Sd=eybHgf zK$90u6!#=e^)@7NPtr8L!5kbFzIv1rPuhcnZ#Ioy=L!kiABWG}dYzSBwiaV_f` z05G(Z>=hLdPCKLhRbe*zW@hpY7Z5L3qZO;@kp5$HoR4ll6m{ z&28;1t;>Vf+`^XDd!sYG!d!B@qM8H3dl%L53sVuo^XBiOYe$c_ZU9 zbqgiKL$nI-qm_S}5&UeA{cwr4lOOgeJcXa_G&nHRR_&{2 zD6z*%t;Wb_2rrzRZncrRlSA-L3eb0U>eEllarfdkLhOt}0D`!a{O}3}h!8uYeF})3 zxs$Tf%zGBYT}kfXJE>->jl_y~qxhzCRddyM>+d}yM^DCY24q_vAYAXJGT%%=)_0zx z#BehMS&Vy*@bTjwmsG-6FA{$=IrEHM;J--83U{9Cs04CQFA=?}=RYgw=3gRZ_9xr1 zG+v_W@vMg-qP#>me?5X&M*GN_&I#~SXZN93>e%E>bD^YQf|Gp|Omzo@P8?tT8#zBg zT4ipr8T7*>o4lV;kz4AHOa%9NSy zAofy)Sy>Fh>ZQinRy6m}*T^wd=ciWmYvfI}qC*p$yhgzkD;g}dpPbhVqJ_hv_mlU! z5#7KN*#_EwkQ!x0vjyP~kh;~q-H0Z<0}{POGCLiwfXig1ZrLRp^9Mz#nmOo6&oQ9Au;o>mW&#-#UiyqBc8bQc^ zo18gz$w({zZSuZqs~?)+lo?OvJ7pN=*<7|pdHfPEEeIXk*LDPTp z#tvtREy(5^sm^GYl&{VcUDPi;C%-x6JSlTSLn#!P=c(#CJ2!k`I!`y<9zjU_keo?& zZ7I99KGbubm*x2nDY((5tswLQIe#crT^XGh$ooSUpOEvXLMe((DLx_ZPlZyj39SDmHPV)XEeQW9 zsX6W(v;J@v_7Sa-`rn_IU(WM2vkxD}tTtx%QMq|vLLyALN)ae5LeO%SLV^ymi1}|sFf%qm(|W0{ lxyk}r{~|k%y~uwK{)+IY@K=n#B>qzPb9;`x=-q$r{{d<}1&;s# delta 5846 zcmY*dYj9Q76~24zlYLLl2_!i;$%O>MB?J%^d4-~)A^|Br##hz0R?(_xX*;z(>Wn{Z zipVewLsiCM7kMN=aSz*52P* z-`bD0_DS3O!?$l4{)gwpbF^OmWD-qZ*LL?Ld6(bT`w_XI8$BPjZG2Kboo>7I8L36^ z&Er8jDoCaNOZw-l(q(%0{eIZi`Fpvyq9F*#3nFixNL2@6AiY2^@T-C%41|%IFH#GI zFhe1R<_o`9&@CwNLP~j&w?I&UnI1!fa`B*I7)CJ!b%DrK#ZWS=?h_O>AWBiB8bxZc zi&BKCjl!=nQ;STLrZ@^<dNPFo|@- zyrshLhk*w2x<}qCB2{Zfx?|)O;rBJ!7e{KjNUe0biZQf2)>UkDt%!92Mjp^06B!7) zR*0~73_)EXs%v8iT`R=Ei#W(IuOw2dMCx@Hr36z~3BTG*EiqBnaFh{PW5CE;qksD+ zIbD61=qt z-S;>C@L%w5myp2pmL!}o6H4udVie(8cthP}gliGGYh5_u!nKILW84gayLE#6pvr_J zAiZdw%-&K$1lQ|CVJ4ml*Xu+@)@(^>q}GenMz>g{n7Ll~HfpI^kyb(J;3D`0jJ#H% zuYA<+b2+Pm0n=NBZyf`|aVtBvqnzLdW)CoI%-taL>_`3HqujW$5e`GU2rFD1POn{L?ap8ne%eLfnqUeJX%wkVBK4L2_GS4{O@xV? z;-e6m>^Ad?U5*HVk+)etJ73m~z;DdlEDA#t0T3=Xi|)k^a$;MU_=q85?iT&|eEA@V zyo*~zVQD-Q#4Vz%+(F)>txUYc5RubX-LOCo1d)^28t)Mxh+E^uh=`BYHYQ$Sh#1_a z_b-qmL6jhF6NPaI$z!5NPZ!YxaR(ExHbkuH4n20EyaGfI#2txL55ygb)B>#WPC*sH zAVY+koqEke*?)9I1t9JeS$jwTLEI^7Y{`g7Vd^f9IL;8^2B=5n$lUeg_0&ajR2`Hc^_liPWv;jffE6VK!i6{hd9}{mf#1KgLZ;}&1k^>xJVARZL80~{Flj zIqGu!2JuiLwHU-hiPRDh4>R!^Lo6|%_M*(`XO_rv#OC6DI9a9=xHz0FQz={= zVHYU5RZwT@iJvVJeDj|8HmRPl?T;^SO%nfH_J*8%RoFX zD(oWx5X9r6Pwb~0#1n$5Oo@)D97zANS=NGB4&n*XE8dB65Ko9fm$;3oK#rY)l-rmJ zApLH$90g(ph@B$cJ)Q|-rzo{mKB6olo)pwG7-pnqf%GM>$iX*b2*i`3GLD!9@gzs& zmro{Ar$p+HWM4kK8mEMBXJ$-SJ{@;uz{opoyE1-5=jpgj0)lut?#h4&aXRkGfVl3b z$3kSMG|tG9V+sxQ!VJvQJn* zFfWLH_SKdl1?G3m9B-Hg=}9Z(m=PEQ^E=VY_H;lnzvG^6#dC|8N?6tF4HGS5s@}aq zUI!vKhpFV+As~oT$+g1_adVi)#0iFo?VF}2u9Wp4a&wr5s_#N@bC^cuwm@Wvo5OS_ za_0sF(r>Rs=f-akr;}^>fFMq%vY5!tVFnZJI-@zv(AigIUl6%D%pmtH0|apfRoDWY zp%7a#ldwVkOhhz?nfh0+%0BfN!cxto(3Su|_?byH_K^+>>O{h~_v1Ac)Nr+2;`;LNv!$5D=HHnJUMbFByg{KKImSs;YO9Sn)D!f@v^WUj1eI zleKd282n~Ht}_9`^)f1r%vSV>yp@z1XttsU=B*^ZHh3T)m5S7A;xF|ZTjc%GYVs?B z9|fLDAqTaVXuW>BMc&@9mXx`AY{y|(OFf6P9)^grmahJB3~_K;$Q#cI@Tm9N&bMmV z6pjm^ByWO~7RuEJ#ny=zsn^JR18J28X)|e#&!+GVDhNt~A-=PLwvJSPm|_dUzfS4_ zezReYh*T@lTl($SAADVoYuHB0 zlt9RraIua0O>lb6R~X&)yBI?LcJgj>M@BmN+bO)&t-dwE$#%-!;#MEMUhN?7gS>oc zVh&CsRZJ_;=RIR%Z zY(eae@Wg* zr#$VHe@S7TQ*KRg@+IX)IOS<5KS|!Hyz;bBev-mdRLAv`PY>Hb`-)Wc_bdqiHQx?< zl~KOV5M3ZW_)U3V13&uCkTT!ZaKP*{R9WYwa?)pL%-v3d4-H-9eUm>yzB@r(6n>LG zLDq;Q|4nMJ%gEYrg3cx => { return res.data.advisors; }; +export const getAdvisorCheckScript = async (name: string): Promise => { + const res = await api.get( + `/advisors/checks/${encodeURIComponent(name)}/script` + ); + return res.data.script; +}; + export const startAdvisorChecks = async (names: string[]): Promise => { const payload: StartAdvisorChecksRequest = { names }; const res = await api.post( diff --git a/ui/apps/pmm/src/hooks/api/useAdvisors.ts b/ui/apps/pmm/src/hooks/api/useAdvisors.ts index d35a3efabd3..064da4983b3 100644 --- a/ui/apps/pmm/src/hooks/api/useAdvisors.ts +++ b/ui/apps/pmm/src/hooks/api/useAdvisors.ts @@ -8,6 +8,7 @@ import { } from '@tanstack/react-query'; import { changeAdvisorChecks, + getAdvisorCheckScript, listAdvisors, listCheckResultsFilterValues, listCheckResultsHistory, @@ -26,6 +27,7 @@ import { PaginatedResponse } from 'types/util.types'; const KEYS = { LIST: 'advisors:list', + CHECK_SCRIPT: 'advisors:check-script', START_CHECKS: 'advisors:start-checks', CHANGE_CHECKS: 'advisors:change-checks', HISTORY: 'advisors:history', @@ -40,6 +42,18 @@ export const useAdvisors = (options?: Partial>) => ...options, }); +export const useAdvisorCheckScript = ( + name?: string, + options?: Partial> +) => + useQuery({ + queryKey: [KEYS.CHECK_SCRIPT, name], + queryFn: () => getAdvisorCheckScript(name!), + // only fetch once a check is selected (lazy, on overlay open) + enabled: !!name, + ...options, + }); + export const useStartAdvisorChecks = ( options?: Partial> ) => diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts index 8b3af75b953..5c98d7ae898 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts @@ -29,9 +29,26 @@ export const Messages = { addAdvisor: 'Add advisor', viewResults: 'View results', run: 'Run', + details: { + title: 'Advisor check details', + maximize: 'Maximize', + close: 'Close', + checkName: 'Check name', + advisor: 'Advisor', + category: 'Category', + vendor: 'Vendor', + interval: 'Interval', + status: 'Status', + summary: 'Summary', + description: 'Description', + code: 'Code', + copyCode: 'Copy', + codeCopied: 'Check code copied to clipboard', + codeError: 'Unable to load the check code', + noCode: 'No code available', + }, success: { - checksStarted: - 'Advisor checks started, batch ID copied to clipboard', + checksStarted: 'Advisor checks started, batch ID copied to clipboard', checkStarted: (summary: string) => `Check "${summary}" started, batch ID copied to clipboard`, checkEnabled: (summary: string) => `Check "${summary}" enabled`, diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx index 76853e91f9e..2bf79574268 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -98,6 +98,40 @@ describe('AdvisorsList', () => { vi.mocked(advisorsApi.listAdvisors).mockResolvedValue(TEST_ADVISORS); vi.mocked(advisorsApi.startAdvisorChecks).mockResolvedValue('run-123'); vi.mocked(advisorsApi.changeAdvisorChecks).mockResolvedValue(); + vi.mocked(advisorsApi.getAdvisorCheckScript).mockResolvedValue( + 'print("hi")' + ); + }); + + it('opens the check details overlay on row double-click and shows the code', async () => { + renderComponent(); + + await waitForRows(); + + fireEvent.dblClick(screen.getByTestId('advisor-row-mysql_version_check')); + + const pane = await screen.findByTestId('check-details-pane'); + // the check's fields are shown + expect( + within(screen.getByTestId('check-details-field-check-name')).getByText( + 'mysql_version_check' + ) + ).toBeInTheDocument(); + // double-click opens the pane maximized + expect( + within(pane).getByTestId('CloseFullscreenOutlinedIcon') + ).toBeInTheDocument(); + + // the code is fetched lazily and shown in the text area + await screen.findByTestId('check-code'); + expect(advisorsApi.getAdvisorCheckScript).toHaveBeenCalledWith( + 'mysql_version_check' + ); + expect(screen.getByTestId('check-code')).toHaveValue('print("hi")'); + + // Copy button copies the code + fireEvent.click(within(pane).getByTestId('check-code-copy')); + expect(navigator.clipboard.writeText).toHaveBeenCalledWith('print("hi")'); }); it('renders all checks', async () => { diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index f75ecb33568..76cbc39fb63 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -1,4 +1,4 @@ -import { FC, useCallback, useMemo } from 'react'; +import { FC, useCallback, useMemo, useState } from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import IconButton from '@mui/material/IconButton'; @@ -32,6 +32,7 @@ import { capitalize } from 'utils/text.utils'; import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; import { Messages } from './AdvisorsList.messages'; import { getAdvisorsColumns, INTERVAL_OPTIONS } from './AdvisorsList.constants'; +import { AdvisorCheckDetailsPane } from './details-pane'; interface CheckFilters { category: string; @@ -91,6 +92,16 @@ const AdvisorsList: FC = () => { useStartAdvisorChecks(); const { mutate: changeChecks } = useChangeAdvisorChecks(); + const [detailsCheck, setDetailsCheck] = useState( + null + ); + const [detailsMaximized, setDetailsMaximized] = useState(false); + + const openDetails = (check: AdvisorCheckRow, maximized = false) => { + setDetailsMaximized(maximized); + setDetailsCheck(check); + }; + const [searchParams, setSearchParams] = useSearchParams(); // the URL query string is the single source of truth for filters + @@ -447,6 +458,11 @@ const AdvisorsList: FC = () => { {Messages.run} )} + muiTableBodyRowProps={({ row }) => ({ + 'data-testid': `advisor-row-${row.original.checkName}`, + // double-click opens the check details overlay maximized + onDoubleClick: () => openDetails(row.original, true), + })} muiTableContainerProps={{ sx: { flex: 1, @@ -456,6 +472,11 @@ const AdvisorsList: FC = () => { }, }} /> + setDetailsCheck(null)} + /> ); diff --git a/ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx b/ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx new file mode 100644 index 00000000000..04baa7caef6 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx @@ -0,0 +1,255 @@ +import { FC, ReactNode, useEffect, useState } from 'react'; +import CloseIcon from '@mui/icons-material/Close'; +import CloseFullscreenOutlinedIcon from '@mui/icons-material/CloseFullscreenOutlined'; +import ContentCopyOutlinedIcon from '@mui/icons-material/ContentCopyOutlined'; +import OpenInFullOutlinedIcon from '@mui/icons-material/OpenInFullOutlined'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import CircularProgress from '@mui/material/CircularProgress'; +import Divider from '@mui/material/Divider'; +import Drawer from '@mui/material/Drawer'; +import IconButton from '@mui/material/IconButton'; +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import { enqueueSnackbar } from 'notistack'; +import { + DRAWER_CLOSED_WIDTH, + DRAWER_WIDTH, +} from 'components/sidebar/drawer/Drawer.constants'; +import { useNavigation } from 'contexts/navigation/navigation.hooks'; +import { useAdvisorCheckScript } from 'hooks/api/useAdvisors'; +import { AdvisorCheckRow } from 'types/advisors.types'; +import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; +import { capitalize } from 'utils/text.utils'; +import { Messages } from '../AdvisorsList.messages'; + +const EM_DASH = '—'; + +interface FieldProps { + label: string; + children: ReactNode; + // grid columns to span (out of 4) + span?: number; +} + +const Field: FC = ({ label, children, span = 1 }) => ( + + + {label} + + {children} + + +); + +interface AdvisorCheckDetailsPaneProps { + check: AdvisorCheckRow | null; + // open the pane already maximized (e.g. triggered by a row double-click) + initialMaximized?: boolean; + onClose: () => void; +} + +export const AdvisorCheckDetailsPane: FC = ({ + check, + initialMaximized = false, + onClose, +}) => { + const [maximized, setMaximized] = useState(false); + const { navOpen } = useNavigation(); + const open = !!check; + // the pane never covers the main navigation + const sidebarWidth = navOpen ? DRAWER_WIDTH : DRAWER_CLOSED_WIDTH; + + const { + data: script, + isLoading: isScriptLoading, + isError: isScriptError, + } = useAdvisorCheckScript(check?.checkName); + + // apply the requested height on each open, reset on close + useEffect(() => { + setMaximized(open ? initialMaximized : false); + }, [open, initialMaximized]); + + const m = Messages.details; + + const handleCopyCode = () => { + if (!script) { + return; + } + void navigator.clipboard.writeText(script); + enqueueSnackbar(m.codeCopied, { variant: 'success' }); + }; + + return ( + + theme.transitions.create(['height', 'left'], { + duration: theme.transitions.duration.short, + }), + }, + }, + }} + > + + {m.title} + + setMaximized((current) => !current)} + data-testid="check-details-maximize" + > + {maximized ? ( + + ) : ( + + )} + + + + + + + {check && ( + + + + {check.checkName} + + + {check.advisorName} + + + + {capitalize(check.category)} + + + + + {ADVISOR_FAMILY[check.family]} + + + + + {ADVISOR_INTERVAL[check.interval]} + + + + + {check.enabled + ? Messages.status.enabled + : Messages.status.disabled} + + + + + + {check.summary || EM_DASH} + + + + + {check.description || EM_DASH} + + + + + + + {m.code} + + + {isScriptLoading ? ( + + ) : isScriptError ? ( + + {m.codeError} + + ) : script ? ( + // fills the remaining height and scrolls internally, so the pane + // itself never scrolls + + ) : ( + + {m.noCode} + + )} + + + )} + + ); +}; diff --git a/ui/apps/pmm/src/pages/advisors/details-pane/index.ts b/ui/apps/pmm/src/pages/advisors/details-pane/index.ts new file mode 100644 index 00000000000..6a6be5101a0 --- /dev/null +++ b/ui/apps/pmm/src/pages/advisors/details-pane/index.ts @@ -0,0 +1 @@ +export { AdvisorCheckDetailsPane } from './AdvisorCheckDetailsPane'; diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index 8b1630b3497..f33ab796823 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -16,7 +16,7 @@ export const Messages = { enableCheck: 'Enable check', }, details: { - title: 'Details', + title: 'Advisor insight details', maximize: 'Maximize', close: 'Close', summary: 'Summary', diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index dd5cc5cafc5..676d00566d7 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -36,6 +36,10 @@ export interface ListAdvisorsResponse { advisors: Advisor[]; } +export interface GetAdvisorCheckScriptResponse { + script: string; +} + export interface StartAdvisorChecksRequest { names: string[]; } From 6196a665f9da4b3f2de1a2c91e2f1083ccf1f981 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Thu, 16 Jul 2026 14:06:55 +0300 Subject: [PATCH 036/120] PMM-14109 Revert advisor check link fixes (moved to PMM-15179) The broken read_more link fixes in managed/data/checks/*.yml are tracked separately in PMM-15179; revert them here to keep this PR focused on advisor output/UI changes. --- managed/data/checks/mongodb_authmech_scramsha256.yml | 2 +- managed/data/checks/mongodb_balancer.yml | 2 +- managed/data/checks/mongodb_bindip.yml | 2 +- managed/data/checks/mongodb_collection_fragmented.yml | 2 +- managed/data/checks/mongodb_connection_sudden_spike.yml | 2 +- managed/data/checks/mongodb_connections.yml | 2 +- managed/data/checks/mongodb_dbpath_mount.yml | 2 +- managed/data/checks/mongodb_fcv_check.yml | 2 +- managed/data/checks/mongodb_journal.yml | 2 +- managed/data/checks/mongodb_localhost_auth_bypass.yml | 2 +- managed/data/checks/mongodb_loglevel.yml | 2 +- managed/data/checks/mongodb_maxsessions.yml | 2 +- managed/data/checks/mongodb_multiple_services.yml | 2 +- managed/data/checks/mongodb_oplog_size_recommendation.yml | 2 +- managed/data/checks/mongodb_psa_architecture_check.yml | 2 +- managed/data/checks/mongodb_read_tickets.yml | 2 +- managed/data/checks/mongodb_replicaset_topology.yml | 2 +- managed/data/checks/mongodb_replication_lag.yml | 2 +- .../checks/mongodb_shard_collection_inconsistent_indexes.yml | 2 +- managed/data/checks/mongodb_swap_allocation.yml | 2 +- managed/data/checks/mongodb_taskexecutor.yml | 2 +- managed/data/checks/mongodb_unused_index.yml | 2 +- managed/data/checks/mongodb_version.yml | 2 +- managed/data/checks/mongodb_write_tickets.yml | 2 +- managed/data/checks/mongodb_xfs_ftype.yml | 2 +- managed/data/checks/mysql_32binary_on_64system.yml | 2 +- .../checks/mysql_ahi_efficiency_performance_basic_check.yml | 2 +- managed/data/checks/mysql_automatic_sp_privileges_enabled.yml | 2 +- managed/data/checks/mysql_config_binlog_retention_period.yml | 2 +- managed/data/checks/mysql_config_binlog_row_image.yml | 2 +- managed/data/checks/mysql_config_binlogs_checksummed.yml | 2 +- managed/data/checks/mysql_config_general_log.yml | 2 +- managed/data/checks/mysql_config_innodb_redolog_disabled.yml | 2 +- managed/data/checks/mysql_config_local_infile.yml | 2 +- managed/data/checks/mysql_config_log_bin.yml | 2 +- managed/data/checks/mysql_config_relay_log_purge.yml | 2 +- managed/data/checks/mysql_config_replication_bp1.yml | 2 +- managed/data/checks/mysql_config_slave_parallel_workers.yml | 2 +- managed/data/checks/mysql_config_sql_mode.yml | 2 +- managed/data/checks/mysql_config_sync_binlog.yml | 2 +- managed/data/checks/mysql_config_tmp_table_size_limit.yml | 2 +- .../data/checks/mysql_configuration_innodb_file_format.yml | 2 +- .../data/checks/mysql_configuration_innodb_file_maxlimit.yml | 2 +- .../mysql_configuration_innodb_file_per_table_not_enabled.yml | 2 +- .../data/checks/mysql_configuration_innodb_flush_method.yml | 2 +- .../data/checks/mysql_configuration_innodb_strict_mode.yml | 2 +- managed/data/checks/mysql_configuration_log_verbosity.yml | 2 +- .../data/checks/mysql_configuration_max_connections_usage.yml | 2 +- .../checks/mysql_configuration_secure_file_priv_empty.yml | 2 +- .../checks/mysql_innodb_redo_logs_not_sized_correctly.yml | 2 +- managed/data/checks/mysql_log_replica_updates.yml | 2 +- managed/data/checks/mysql_password_expiry.yml | 2 +- .../data/checks/mysql_performance_temp_ondisk_table_high.yml | 2 +- ...sql_replica_running_skipping_errors_or_idempotent_mode.yml | 2 +- managed/data/checks/mysql_replication_grants.yml | 2 +- managed/data/checks/mysql_require_secure_transport.yml | 2 +- managed/data/checks/mysql_security_anonymous_user.yml | 2 +- managed/data/checks/mysql_security_open_to_world_host.yml | 2 +- managed/data/checks/mysql_security_password_lifetime.yml | 2 +- managed/data/checks/mysql_security_password_policy.yml | 2 +- .../data/checks/mysql_security_replication_grants_mixed.yml | 2 +- managed/data/checks/mysql_security_root_not_local.yml | 2 +- managed/data/checks/mysql_security_user_ssl.yml | 2 +- managed/data/checks/mysql_security_user_super_not_local.yml | 2 +- managed/data/checks/mysql_security_user_without_password.yml | 2 +- managed/data/checks/mysql_tables_without_pk.yml | 2 +- managed/data/checks/mysql_test_database.yml | 2 +- managed/data/checks/mysql_timezone.yml | 2 +- managed/data/checks/mysql_unsupported_version_check.yml | 2 +- managed/data/checks/mysql_version_eol_57.yml | 2 +- managed/data/checks/postgresql_archiver_failing.yml | 2 +- managed/data/checks/postgresql_cache_hit_ratio.yml | 2 +- .../data/checks/postgresql_config_changes_need_restart.yml | 2 +- managed/data/checks/postgresql_cve_check.yml | 2 +- managed/data/checks/postgresql_eol_check.yml | 2 +- managed/data/checks/postgresql_expiring_passwd_check.yml | 2 +- managed/data/checks/postgresql_extension_check.yml | 2 +- managed/data/checks/postgresql_fsync.yml | 4 ++-- .../data/checks/postgresql_log_autovacuum_min_duration.yml | 2 +- managed/data/checks/postgresql_log_checkpoints.yml | 2 +- .../data/checks/postgresql_logging_recommendation_checks.yml | 2 +- managed/data/checks/postgresql_max_connections.yml | 2 +- managed/data/checks/postgresql_number_of_index_check.yml | 2 +- managed/data/checks/postgresql_sequential_scan_check.yml | 2 +- managed/data/checks/postgresql_stale_replication_slot.yml | 2 +- managed/data/checks/postgresql_table_autovac_settings.yml | 2 +- managed/data/checks/postgresql_table_bloat_bytes.yml | 2 +- managed/data/checks/postgresql_table_bloat_in_percentage.yml | 2 +- managed/data/checks/postgresql_tmpfiles_check.yml | 2 +- .../data/checks/postgresql_txid_wraparound_approaching.yml | 2 +- managed/data/checks/postgresql_unsupported_check.yml | 2 +- managed/data/checks/postgresql_unused_index_check.yml | 2 +- managed/data/checks/postgresql_vacuum_sanity_check.yml | 2 +- managed/data/checks/postgresql_version_check.yml | 2 +- managed/data/checks/postgresql_wal_retention_check.yml | 2 +- 95 files changed, 96 insertions(+), 96 deletions(-) diff --git a/managed/data/checks/mongodb_authmech_scramsha256.yml b/managed/data/checks/mongodb_authmech_scramsha256.yml index d0e48bbec97..5f17f8af54e 100644 --- a/managed/data/checks/mongodb_authmech_scramsha256.yml +++ b/managed/data/checks/mongodb_authmech_scramsha256.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETPARAMETER script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_balancer.yml b/managed/data/checks/mongodb_balancer.yml index 33de3a10a04..95a540374d4 100644 --- a/managed/data/checks/mongodb_balancer.yml +++ b/managed/data/checks/mongodb_balancer.yml @@ -12,7 +12,7 @@ checks: - type: METRICS_INSTANT query: avg by(cluster) (mongodb_mongos_sharding_chunks_is_balancer_running{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_bindip.yml b/managed/data/checks/mongodb_bindip.yml index c86a0ac61f4..28516650549 100644 --- a/managed/data/checks/mongodb_bindip.yml +++ b/managed/data/checks/mongodb_bindip.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_collection_fragmented.yml b/managed/data/checks/mongodb_collection_fragmented.yml index 030c86fc61b..2e9a82a62f5 100644 --- a/managed/data/checks/mongodb_collection_fragmented.yml +++ b/managed/data/checks/mongodb_collection_fragmented.yml @@ -19,7 +19,7 @@ checks: - type: METRICS_INSTANT query: avg by(collection,database) (mongodb_collstats_storageStats_size{database!="admin", database!="config", database!="local", collection!="system.profile", node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_connection_sudden_spike.yml b/managed/data/checks/mongodb_connection_sudden_spike.yml index 42814700dc5..029330b4ae6 100644 --- a/managed/data/checks/mongodb_connection_sudden_spike.yml +++ b/managed/data/checks/mongodb_connection_sudden_spike.yml @@ -15,7 +15,7 @@ checks: range: 24h step: 15m script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): #Gathering initial connection count. diff --git a/managed/data/checks/mongodb_connections.yml b/managed/data/checks/mongodb_connections.yml index 514c5d3c3b2..b25e850e2c8 100644 --- a/managed/data/checks/mongodb_connections.yml +++ b/managed/data/checks/mongodb_connections.yml @@ -13,7 +13,7 @@ checks: queries: - type: MONGODB_GETDIAGNOSTICDATA script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_dbpath_mount.yml b/managed/data/checks/mongodb_dbpath_mount.yml index 0b9443031db..1cf048549ad 100644 --- a/managed/data/checks/mongodb_dbpath_mount.yml +++ b/managed/data/checks/mongodb_dbpath_mount.yml @@ -13,7 +13,7 @@ checks: - type: METRICS_INSTANT query: avg by (fstype,mountpoint,node_name) (node_filesystem_files{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_fcv_check.yml b/managed/data/checks/mongodb_fcv_check.yml index 1e3da3cee46..e5cc0878024 100644 --- a/managed/data/checks/mongodb_fcv_check.yml +++ b/managed/data/checks/mongodb_fcv_check.yml @@ -13,7 +13,7 @@ checks: - type: MONGODB_BUILDINFO - type: MONGODB_GETPARAMETER script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_journal.yml b/managed/data/checks/mongodb_journal.yml index 8023befdca5..8455389ac56 100644 --- a/managed/data/checks/mongodb_journal.yml +++ b/managed/data/checks/mongodb_journal.yml @@ -12,7 +12,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_localhost_auth_bypass.yml b/managed/data/checks/mongodb_localhost_auth_bypass.yml index c1841a7c4b0..c23a22a9b8c 100644 --- a/managed/data/checks/mongodb_localhost_auth_bypass.yml +++ b/managed/data/checks/mongodb_localhost_auth_bypass.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_loglevel.yml b/managed/data/checks/mongodb_loglevel.yml index d3005e5ff4e..440f0cb119f 100644 --- a/managed/data/checks/mongodb_loglevel.yml +++ b/managed/data/checks/mongodb_loglevel.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_maxsessions.yml b/managed/data/checks/mongodb_maxsessions.yml index 4d9a7f1a701..4f884534831 100644 --- a/managed/data/checks/mongodb_maxsessions.yml +++ b/managed/data/checks/mongodb_maxsessions.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_multiple_services.yml b/managed/data/checks/mongodb_multiple_services.yml index 950579b1a72..716c4b81626 100644 --- a/managed/data/checks/mongodb_multiple_services.yml +++ b/managed/data/checks/mongodb_multiple_services.yml @@ -12,7 +12,7 @@ checks: - type: METRICS_INSTANT query: avg by(node_name,rs_nm,cluster) (mongodb_ss_pid{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_oplog_size_recommendation.yml b/managed/data/checks/mongodb_oplog_size_recommendation.yml index af6669ff730..0f9ef75f3f6 100644 --- a/managed/data/checks/mongodb_oplog_size_recommendation.yml +++ b/managed/data/checks/mongodb_oplog_size_recommendation.yml @@ -16,7 +16,7 @@ checks: range: 24h step: 15m script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_psa_architecture_check.yml b/managed/data/checks/mongodb_psa_architecture_check.yml index 1dab6793bf4..2b29c8375c3 100644 --- a/managed/data/checks/mongodb_psa_architecture_check.yml +++ b/managed/data/checks/mongodb_psa_architecture_check.yml @@ -14,7 +14,7 @@ checks: - type: METRICS_INSTANT query: avg by(cluster,node_name,set) (mongodb_mongod_replset_my_state{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_read_tickets.yml b/managed/data/checks/mongodb_read_tickets.yml index 07d2b72e126..2122108d721 100644 --- a/managed/data/checks/mongodb_read_tickets.yml +++ b/managed/data/checks/mongodb_read_tickets.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_replicaset_topology.yml b/managed/data/checks/mongodb_replicaset_topology.yml index 2447cdfc975..79ddb786a63 100644 --- a/managed/data/checks/mongodb_replicaset_topology.yml +++ b/managed/data/checks/mongodb_replicaset_topology.yml @@ -12,7 +12,7 @@ checks: queries: - type: MONGODB_REPLSETGETSTATUS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_replication_lag.yml b/managed/data/checks/mongodb_replication_lag.yml index 95880572c24..641ad0cbd90 100644 --- a/managed/data/checks/mongodb_replication_lag.yml +++ b/managed/data/checks/mongodb_replication_lag.yml @@ -12,7 +12,7 @@ checks: queries: - type: MONGODB_REPLSETGETSTATUS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml b/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml index d7959f6f4d4..f7b183c236e 100644 --- a/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml +++ b/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml @@ -12,7 +12,7 @@ checks: - type: METRICS_INSTANT query: avg by(cl_role,cluster,node_name,rs_state) (mongodb_ss_shardedIndexConsistency_numShardedCollectionsWithInconsistentIndexes{rs_state="1", node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_swap_allocation.yml b/managed/data/checks/mongodb_swap_allocation.yml index 2d4df98eba4..fd14436a05b 100644 --- a/managed/data/checks/mongodb_swap_allocation.yml +++ b/managed/data/checks/mongodb_swap_allocation.yml @@ -16,7 +16,7 @@ checks: - type: METRICS_INSTANT query: avg by(cluster,node_name,set) (mongodb_mongod_replset_my_state{node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): results = [] diff --git a/managed/data/checks/mongodb_taskexecutor.yml b/managed/data/checks/mongodb_taskexecutor.yml index 9b1ca226ff8..4812b01c0ac 100644 --- a/managed/data/checks/mongodb_taskexecutor.yml +++ b/managed/data/checks/mongodb_taskexecutor.yml @@ -13,7 +13,7 @@ checks: - type: METRICS_INSTANT query: mongodb_sys_cpu_num_cpus{node_name="{{.NodeName}}"} script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): info = docs[0] diff --git a/managed/data/checks/mongodb_unused_index.yml b/managed/data/checks/mongodb_unused_index.yml index 56b875651e6..f1607d7f541 100644 --- a/managed/data/checks/mongodb_unused_index.yml +++ b/managed/data/checks/mongodb_unused_index.yml @@ -14,7 +14,7 @@ checks: - type: METRICS_INSTANT query: avg by (cluster,collection,database,key_name) (mongodb_indexstats_accesses_ops{node_name=~"{{.NodeName}}"}) == 0 script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): threshold = 30 diff --git a/managed/data/checks/mongodb_version.yml b/managed/data/checks/mongodb_version.yml index 0b8cd356d4c..b46decde185 100644 --- a/managed/data/checks/mongodb_version.yml +++ b/managed/data/checks/mongodb_version.yml @@ -20,7 +20,7 @@ checks: "7.0": 70032, # https://www.percona.com/downloads/percona-server-mongodb-7.0/ "8.0": 80021, # https://www.percona.com/downloads/percona-server-mongodb-8.0/ }, - "read_url": "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html", + "read_url": "https://docs.percona.com/percona-platform/advisors/checks/{}.html", } def check_context(docs, context): diff --git a/managed/data/checks/mongodb_write_tickets.yml b/managed/data/checks/mongodb_write_tickets.yml index 51dbaf91465..1e5232721e8 100644 --- a/managed/data/checks/mongodb_write_tickets.yml +++ b/managed/data/checks/mongodb_write_tickets.yml @@ -11,7 +11,7 @@ checks: queries: - type: MONGODB_GETCMDLINEOPTS script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mongodb_xfs_ftype.yml b/managed/data/checks/mongodb_xfs_ftype.yml index ca78bcf7956..b68f877335b 100644 --- a/managed/data/checks/mongodb_xfs_ftype.yml +++ b/managed/data/checks/mongodb_xfs_ftype.yml @@ -14,7 +14,7 @@ checks: - type: METRICS_INSTANT query: avg by (fstype,mountpoint,node_name) (node_filesystem_files{fstype="xfs", node_name=~"{{.NodeName}}"}) script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mysql_32binary_on_64system.yml b/managed/data/checks/mysql_32binary_on_64system.yml index 173ac33d97a..92a2d49afa0 100644 --- a/managed/data/checks/mysql_32binary_on_64system.yml +++ b/managed/data/checks/mysql_32binary_on_64system.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version_compile_machine as version_compile_machine" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): """ diff --git a/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml b/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml index 30c889b5fb1..639c5630a5f 100644 --- a/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml +++ b/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml @@ -45,7 +45,7 @@ checks: results = [] ahi_parts = 0 - read_more = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/mysql-ahi-efficiency-performance-basic-check.html" + read_more = "https://docs.percona.com/percona-platform/advisors/checks/mysql-ahi-efficiency-performance-basic-check.html" # Check if AHI is enabled and partitioned for row in docs[0]: diff --git a/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml b/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml index 0b946f245fe..48a11aa0580 100644 --- a/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml +++ b/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service, @@automatic_sp_privileges as automatic_sp_privileges" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs,context): results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_config_binlog_retention_period.yml b/managed/data/checks/mysql_config_binlog_retention_period.yml index 5db27ef9bb2..a793a792ca2 100644 --- a/managed/data/checks/mysql_config_binlog_retention_period.yml +++ b/managed/data/checks/mysql_config_binlog_retention_period.yml @@ -46,7 +46,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] in_result = check_binlog_retention_period(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_binlog_row_image.yml b/managed/data/checks/mysql_config_binlog_row_image.yml index ec2c536e22e..4df2e1f2723 100644 --- a/managed/data/checks/mysql_config_binlog_row_image.yml +++ b/managed/data/checks/mysql_config_binlog_row_image.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] in_result = check_binlog_row_image(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_binlogs_checksummed.yml b/managed/data/checks/mysql_config_binlogs_checksummed.yml index 897f8ab5ac9..93e9d3c0b7d 100644 --- a/managed/data/checks/mysql_config_binlogs_checksummed.yml +++ b/managed/data/checks/mysql_config_binlogs_checksummed.yml @@ -31,7 +31,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] in_result = check_binlog_checksum(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_general_log.yml b/managed/data/checks/mysql_config_general_log.yml index b5f23fc8f3a..45b33017ed3 100644 --- a/managed/data/checks/mysql_config_general_log.yml +++ b/managed/data/checks/mysql_config_general_log.yml @@ -32,7 +32,7 @@ checks: } def check_context(docs, context): - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] in_result = check_general_log(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_innodb_redolog_disabled.yml b/managed/data/checks/mysql_config_innodb_redolog_disabled.yml index 99783f2365b..b61acf5e7c3 100644 --- a/managed/data/checks/mysql_config_innodb_redolog_disabled.yml +++ b/managed/data/checks/mysql_config_innodb_redolog_disabled.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = innodb_redolog_disabled(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_local_infile.yml b/managed/data/checks/mysql_config_local_infile.yml index fb4d89623b1..dc9f545df4c 100644 --- a/managed/data/checks/mysql_config_local_infile.yml +++ b/managed/data/checks/mysql_config_local_infile.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_local_infile(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_log_bin.yml b/managed/data/checks/mysql_config_log_bin.yml index 1841e1927c2..069fdcbed69 100644 --- a/managed/data/checks/mysql_config_log_bin.yml +++ b/managed/data/checks/mysql_config_log_bin.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] in_result = check_log_bin(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_relay_log_purge.yml b/managed/data/checks/mysql_config_relay_log_purge.yml index 7baddb726b6..e60c51e5e36 100644 --- a/managed/data/checks/mysql_config_relay_log_purge.yml +++ b/managed/data/checks/mysql_config_relay_log_purge.yml @@ -34,7 +34,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_relay_log_purge(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_replication_bp1.yml b/managed/data/checks/mysql_config_replication_bp1.yml index 4ca00d14847..a1de0c7bde3 100644 --- a/managed/data/checks/mysql_config_replication_bp1.yml +++ b/managed/data/checks/mysql_config_replication_bp1.yml @@ -49,7 +49,7 @@ checks: } } def check_context(docs, context): - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_replication_bp1_RO(docs[0],read_url) if result1: diff --git a/managed/data/checks/mysql_config_slave_parallel_workers.yml b/managed/data/checks/mysql_config_slave_parallel_workers.yml index c3b889a9625..c746c1f7c02 100644 --- a/managed/data/checks/mysql_config_slave_parallel_workers.yml +++ b/managed/data/checks/mysql_config_slave_parallel_workers.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_slave_parallel_workers(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_sql_mode.yml b/managed/data/checks/mysql_config_sql_mode.yml index fd2ccb95dbe..3d99abc725a 100644 --- a/managed/data/checks/mysql_config_sql_mode.yml +++ b/managed/data/checks/mysql_config_sql_mode.yml @@ -37,7 +37,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] in_result = check_sql_mode(docs[0],read_url) diff --git a/managed/data/checks/mysql_config_sync_binlog.yml b/managed/data/checks/mysql_config_sync_binlog.yml index abd44846340..76ed961ab29 100644 --- a/managed/data/checks/mysql_config_sync_binlog.yml +++ b/managed/data/checks/mysql_config_sync_binlog.yml @@ -27,7 +27,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_config_tmp_table_size_limit.yml b/managed/data/checks/mysql_config_tmp_table_size_limit.yml index ccc9179dc8a..6866e195427 100644 --- a/managed/data/checks/mysql_config_tmp_table_size_limit.yml +++ b/managed/data/checks/mysql_config_tmp_table_size_limit.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] in_result = check_tmp_table_size(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_file_format.yml b/managed/data/checks/mysql_configuration_innodb_file_format.yml index d2a8b688d9d..2950accc40e 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_format.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_format.yml @@ -45,7 +45,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_innodb_conf(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml b/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml index 48903921e76..a87b2fc5a9f 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_innodb_conf(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml index f055fcd04c6..3b1db1c88bc 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml @@ -14,7 +14,7 @@ checks: - type: MYSQL_SELECT query: "@@global.innodb_file_per_table as innodb_file_per_table, @@global.version as version, @@global.hostname as service" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_configuration_innodb_flush_method.yml b/managed/data/checks/mysql_configuration_innodb_flush_method.yml index 384dd6624d6..767f33529a1 100644 --- a/managed/data/checks/mysql_configuration_innodb_flush_method.yml +++ b/managed/data/checks/mysql_configuration_innodb_flush_method.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_innodb_conf(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_innodb_strict_mode.yml b/managed/data/checks/mysql_configuration_innodb_strict_mode.yml index e903066d4c6..9d8ac9a9590 100644 --- a/managed/data/checks/mysql_configuration_innodb_strict_mode.yml +++ b/managed/data/checks/mysql_configuration_innodb_strict_mode.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_innodb_strict_mode(docs[0],read_url) diff --git a/managed/data/checks/mysql_configuration_log_verbosity.yml b/managed/data/checks/mysql_configuration_log_verbosity.yml index 9bd92017bb2..d00ef20476c 100644 --- a/managed/data/checks/mysql_configuration_log_verbosity.yml +++ b/managed/data/checks/mysql_configuration_log_verbosity.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SHOW query: VARIABLES script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_log_error_verbosity(log_error_verbosity): if log_error_verbosity < 2: diff --git a/managed/data/checks/mysql_configuration_max_connections_usage.yml b/managed/data/checks/mysql_configuration_max_connections_usage.yml index 7ac40326fae..e8af9dd13a9 100644 --- a/managed/data/checks/mysql_configuration_max_connections_usage.yml +++ b/managed/data/checks/mysql_configuration_max_connections_usage.yml @@ -19,7 +19,7 @@ checks: query: mysql_global_status_max_used_connections_time{service_name=~"{{.ServiceName}}"} script: | def check_context(docs, context): - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] max_conn = "" max_used_conn = "" diff --git a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml index af21b536160..13eae93ebe8 100644 --- a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml +++ b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml @@ -14,7 +14,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service, @@global.secure_file_priv as secure_file_priv" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs, context): results = [] for row in docs[0]: diff --git a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml index 04090c4880d..4fd12b98a8a 100644 --- a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml +++ b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml @@ -28,7 +28,7 @@ checks: range: 168h step: 5m script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def redo_log_check(docs): for row in docs[0]: version = row["version"] diff --git a/managed/data/checks/mysql_log_replica_updates.yml b/managed/data/checks/mysql_log_replica_updates.yml index 92aeeee1316..b0805f592ec 100644 --- a/managed/data/checks/mysql_log_replica_updates.yml +++ b/managed/data/checks/mysql_log_replica_updates.yml @@ -27,7 +27,7 @@ checks: # (Starlark does not support Python exceptions); # it is recommended to use global function `fail` for that instead. results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" for row in docs[0]: name, value = row["Variable_name"], row["Value"] diff --git a/managed/data/checks/mysql_password_expiry.yml b/managed/data/checks/mysql_password_expiry.yml index 7fecf470552..5a9e033663a 100644 --- a/managed/data/checks/mysql_password_expiry.yml +++ b/managed/data/checks/mysql_password_expiry.yml @@ -15,7 +15,7 @@ checks: query: " user,host,password_expired,password_last_changed,password_lifetime,password_expire_days,CASE WHEN (password_expired='Y' OR password_expire_days <= 10) THEN 'ERROR' WHEN (password_expire_days > 10 AND password_expire_days<=30) THEN 'WARNING' ELSE 'OK' END AS pwdresult FROM ( SELECT user, host, password_expired, password_last_changed, password_lifetime, @@default_password_lifetime, IFNULL(password_lifetime, CASE WHEN @@default_password_lifetime=0 THEN 99999 WHEN @@default_password_lifetime>0 THEN datediff(password_last_changed, NOW()) ELSE 99999 END ) password_expire_days FROM mysql.user) X" script: | def check_context(docs, context): - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] for row in docs[0]: version = row["version"] diff --git a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml index ea2e0dacc1b..127b4fca02e 100644 --- a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml +++ b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml @@ -16,7 +16,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # This advisor check hints about creation of on-disk temp tables due to unoptimized query or low configuration value for tmp_table_size / max_heap_table_size. def check_tmp_table_ondisk(docs): diff --git a/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml b/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml index 2eced2e9ea0..f6cb25f8ce5 100644 --- a/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml +++ b/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml @@ -12,7 +12,7 @@ checks: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service /*!50700 , @@global.slave_exec_mode as slave_exec_mode */ /*!50700 , @@global.slave_skip_errors slave_skip_errors*/ /*!80026 , @@global.replica_exec_mode as replica_exec_mode */ /*!80026 , @@global.replica_skip_errors replica_skip_errors*/ " script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(docs,context): results = [] skip_errors = "" diff --git a/managed/data/checks/mysql_replication_grants.yml b/managed/data/checks/mysql_replication_grants.yml index 759ccc17db9..fcae87d7fad 100644 --- a/managed/data/checks/mysql_replication_grants.yml +++ b/managed/data/checks/mysql_replication_grants.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_rep_grants(docs[0],read_url) diff --git a/managed/data/checks/mysql_require_secure_transport.yml b/managed/data/checks/mysql_require_secure_transport.yml index da8911f74fd..e7fbd73c8c4 100644 --- a/managed/data/checks/mysql_require_secure_transport.yml +++ b/managed/data/checks/mysql_require_secure_transport.yml @@ -14,7 +14,7 @@ checks: script: | def check_context(docs, context): results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" for row in docs[0]: name, value = row["Variable_name"], row["Value"] diff --git a/managed/data/checks/mysql_security_anonymous_user.yml b/managed/data/checks/mysql_security_anonymous_user.yml index 5e37733b1c8..a4ac8a3edc6 100644 --- a/managed/data/checks/mysql_security_anonymous_user.yml +++ b/managed/data/checks/mysql_security_anonymous_user.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_anonym_user(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_open_to_world_host.yml b/managed/data/checks/mysql_security_open_to_world_host.yml index 40813729460..9128a9da330 100644 --- a/managed/data/checks/mysql_security_open_to_world_host.yml +++ b/managed/data/checks/mysql_security_open_to_world_host.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_open_host(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_password_lifetime.yml b/managed/data/checks/mysql_security_password_lifetime.yml index 4e07a9b16fd..13ff85e2fc2 100644 --- a/managed/data/checks/mysql_security_password_lifetime.yml +++ b/managed/data/checks/mysql_security_password_lifetime.yml @@ -32,7 +32,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_slave_parallel_workers(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_password_policy.yml b/managed/data/checks/mysql_security_password_policy.yml index 34a7f2fee14..8185ad484a3 100644 --- a/managed/data/checks/mysql_security_password_policy.yml +++ b/managed/data/checks/mysql_security_password_policy.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_pw_policy(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_replication_grants_mixed.yml b/managed/data/checks/mysql_security_replication_grants_mixed.yml index 697d37c429d..e14c1a01498 100644 --- a/managed/data/checks/mysql_security_replication_grants_mixed.yml +++ b/managed/data/checks/mysql_security_replication_grants_mixed.yml @@ -16,7 +16,7 @@ checks: script: | def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" whois = "This instance is a SOURCE" results = [] diff --git a/managed/data/checks/mysql_security_root_not_local.yml b/managed/data/checks/mysql_security_root_not_local.yml index 946494cbc65..b14845c3726 100644 --- a/managed/data/checks/mysql_security_root_not_local.yml +++ b/managed/data/checks/mysql_security_root_not_local.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_root_user(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_user_ssl.yml b/managed/data/checks/mysql_security_user_ssl.yml index 75402dc155c..0d53d77c1cc 100644 --- a/managed/data/checks/mysql_security_user_ssl.yml +++ b/managed/data/checks/mysql_security_user_ssl.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_ssl(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_user_super_not_local.yml b/managed/data/checks/mysql_security_user_super_not_local.yml index 4bad54d3b17..00a75012692 100644 --- a/managed/data/checks/mysql_security_user_super_not_local.yml +++ b/managed/data/checks/mysql_security_user_super_not_local.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_super(docs[0],read_url) diff --git a/managed/data/checks/mysql_security_user_without_password.yml b/managed/data/checks/mysql_security_user_without_password.yml index c6c6d78cae7..d2c77e2970c 100644 --- a/managed/data/checks/mysql_security_user_without_password.yml +++ b/managed/data/checks/mysql_security_user_without_password.yml @@ -33,7 +33,7 @@ checks: def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_user_without_password(docs[0],read_url) diff --git a/managed/data/checks/mysql_tables_without_pk.yml b/managed/data/checks/mysql_tables_without_pk.yml index 9bef4bf1191..c72bacf5e9a 100644 --- a/managed/data/checks/mysql_tables_without_pk.yml +++ b/managed/data/checks/mysql_tables_without_pk.yml @@ -42,7 +42,7 @@ checks: # (Starlark does not support Python exceptions); # it is recommended to use global function `fail` for that instead. results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" for row in docs[0]: TABLE_SCHEMA, TABLE_NAME, TABLE_ROWS = row["TABLE_SCHEMA"], row["TABLE_NAME"], row["TABLE_ROWS"] results.append({ diff --git a/managed/data/checks/mysql_test_database.yml b/managed/data/checks/mysql_test_database.yml index ba14d5fbc3c..3ffb1e64e46 100644 --- a/managed/data/checks/mysql_test_database.yml +++ b/managed/data/checks/mysql_test_database.yml @@ -29,7 +29,7 @@ checks: description = " is" return [{ "summary": "Test database{} detected: {}".format(description,dbs), - "description": "Improve MySQL Installation Security by running mysql_secure_installation", + "description": "Please Improve MySQL Installation Security by running program mysql_secure_installation", "severity": "notice" }] diff --git a/managed/data/checks/mysql_timezone.yml b/managed/data/checks/mysql_timezone.yml index ed8238a2f31..ecf9f55282c 100644 --- a/managed/data/checks/mysql_timezone.yml +++ b/managed/data/checks/mysql_timezone.yml @@ -27,7 +27,7 @@ checks: # (Starlark does not support Python exceptions); # it is recommended to use global function `fail` for that instead. results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" timezonecount = int(docs[0][0]["timezonecount"]) if timezonecount == 0: diff --git a/managed/data/checks/mysql_unsupported_version_check.yml b/managed/data/checks/mysql_unsupported_version_check.yml index 88381c26a17..1dd26ab70af 100644 --- a/managed/data/checks/mysql_unsupported_version_check.yml +++ b/managed/data/checks/mysql_unsupported_version_check.yml @@ -58,7 +58,7 @@ checks: } def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_unsupported_version(docs[0],read_url,context) if result1 : diff --git a/managed/data/checks/mysql_version_eol_57.yml b/managed/data/checks/mysql_version_eol_57.yml index 2813a056328..a9413999f05 100644 --- a/managed/data/checks/mysql_version_eol_57.yml +++ b/managed/data/checks/mysql_version_eol_57.yml @@ -57,7 +57,7 @@ checks: } def check_context(docs, context): # we first define some global variables - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" results = [] result1 = check_eol(docs[0],read_url,context) if result1 : diff --git a/managed/data/checks/postgresql_archiver_failing.yml b/managed/data/checks/postgresql_archiver_failing.yml index b7e48f2f61c..59d9c1e16d0 100644 --- a/managed/data/checks/postgresql_archiver_failing.yml +++ b/managed/data/checks/postgresql_archiver_failing.yml @@ -23,7 +23,7 @@ checks: trunc(extract(EPOCH FROM (now() - stats_reset))::numeric,0) AS sec_since_stats_reset FROM pg_stat_archiver script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor # threshold 24 hours = 86400 seconds diff --git a/managed/data/checks/postgresql_cache_hit_ratio.yml b/managed/data/checks/postgresql_cache_hit_ratio.yml index 0c72f1e4c12..a8d3a941b74 100644 --- a/managed/data/checks/postgresql_cache_hit_ratio.yml +++ b/managed/data/checks/postgresql_cache_hit_ratio.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: round(100. * sd.blks_hit /(sd.blks_read + sd.blks_hit),0) AS dhitratio, d.datname, r.rolname AS rolname FROM pg_stat_database sd JOIN pg_database d ON (d.oid = sd.datid) AND d.datname != 'postgres' AND d.datname NOT LIKE 'template%' JOIN pg_roles r ON (r.oid = d.datdba) WHERE sd.blks_read + sd.blks_hit <> 0 ORDER BY 1 DESC script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_config_changes_need_restart.yml b/managed/data/checks/postgresql_config_changes_need_restart.yml index 1e1e7fa8a35..70e9dae9eb1 100644 --- a/managed/data/checks/postgresql_config_changes_need_restart.yml +++ b/managed/data/checks/postgresql_config_changes_need_restart.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting, short_desc, reset_val FROM pg_settings WHERE pending_restart IS true script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_cve_check.yml b/managed/data/checks/postgresql_cve_check.yml index 0b13c79ba19..888704d7826 100644 --- a/managed/data/checks/postgresql_cve_check.yml +++ b/managed/data/checks/postgresql_cve_check.yml @@ -177,7 +177,7 @@ checks: def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" description = "" for row in rows[0]: ver, major = int(row["setting"]), int(row["major"]) diff --git a/managed/data/checks/postgresql_eol_check.yml b/managed/data/checks/postgresql_eol_check.yml index 3ea35730167..d3b41a1a5ba 100644 --- a/managed/data/checks/postgresql_eol_check.yml +++ b/managed/data/checks/postgresql_eol_check.yml @@ -30,7 +30,7 @@ checks: def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" description = "" iseol = False for row in rows[0]: diff --git a/managed/data/checks/postgresql_expiring_passwd_check.yml b/managed/data/checks/postgresql_expiring_passwd_check.yml index 47c4165b59f..41de4d13471 100644 --- a/managed/data/checks/postgresql_expiring_passwd_check.yml +++ b/managed/data/checks/postgresql_expiring_passwd_check.yml @@ -16,7 +16,7 @@ checks: script: | def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" description = "" sev="warning" for row in rows[0]: diff --git a/managed/data/checks/postgresql_extension_check.yml b/managed/data/checks/postgresql_extension_check.yml index d2f10ec8f96..e0a84c2a71d 100644 --- a/managed/data/checks/postgresql_extension_check.yml +++ b/managed/data/checks/postgresql_extension_check.yml @@ -13,7 +13,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_fsync.yml b/managed/data/checks/postgresql_fsync.yml index cb67418a6b4..b7ab42f0c2c 100644 --- a/managed/data/checks/postgresql_fsync.yml +++ b/managed/data/checks/postgresql_fsync.yml @@ -3,7 +3,7 @@ checks: - version: 2 name: postgresql_fsync summary: PostgreSQL fsync is set to off - description: This check returns an error if the fsync configuration option is off which can lead to database corruption. + description: This check returns a error if the fsync configuration option is set to off which can lead to database corruptions. family: POSTGRESQL #author: Jobin Augustine advisor: configuration_generic @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'fsync' script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_log_autovacuum_min_duration.yml b/managed/data/checks/postgresql_log_autovacuum_min_duration.yml index e644457b039..52a33992afd 100644 --- a/managed/data/checks/postgresql_log_autovacuum_min_duration.yml +++ b/managed/data/checks/postgresql_log_autovacuum_min_duration.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'log_autovacuum_min_duration' script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_log_checkpoints.yml b/managed/data/checks/postgresql_log_checkpoints.yml index 40ae11e2b34..7443a282eec 100644 --- a/managed/data/checks/postgresql_log_checkpoints.yml +++ b/managed/data/checks/postgresql_log_checkpoints.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'log_checkpoints' script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_logging_recommendation_checks.yml b/managed/data/checks/postgresql_logging_recommendation_checks.yml index 5ebec0771fb..a1d5d0397ec 100644 --- a/managed/data/checks/postgresql_logging_recommendation_checks.yml +++ b/managed/data/checks/postgresql_logging_recommendation_checks.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: " s1.setting AS logging_collector, s2.setting AS log_temp_files, s3.setting log_checkpoints, s4.setting log_min_duration_statement, s5.unit unit, s6.min_val AS minval, s7.setting AS log_autovacuum_min_duration FROM pg_settings s1 , pg_settings s2 , pg_settings s3 , pg_settings s4 , pg_settings s5 , pg_settings s6 , pg_settings s7 WHERE s1.name = 'logging_collector' and s2.name = 'log_temp_files' and s3.name = 'log_checkpoints' and s4.name = 'log_min_duration_statement' and s5.name = 'log_min_duration_statement' and s6.name = 'log_min_duration_statement' and s7.name = 'log_autovacuum_min_duration'" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(rows, context): results = [] diff --git a/managed/data/checks/postgresql_max_connections.yml b/managed/data/checks/postgresql_max_connections.yml index 8f36527908a..76ccbcbbd42 100644 --- a/managed/data/checks/postgresql_max_connections.yml +++ b/managed/data/checks/postgresql_max_connections.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: name, setting FROM pg_settings WHERE name = 'max_connections' script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_number_of_index_check.yml b/managed/data/checks/postgresql_number_of_index_check.yml index 26d8f289093..396d7a93cdc 100644 --- a/managed/data/checks/postgresql_number_of_index_check.yml +++ b/managed/data/checks/postgresql_number_of_index_check.yml @@ -13,7 +13,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_sequential_scan_check.yml b/managed/data/checks/postgresql_sequential_scan_check.yml index 8fbbe1528bb..1ad8f9acec5 100644 --- a/managed/data/checks/postgresql_sequential_scan_check.yml +++ b/managed/data/checks/postgresql_sequential_scan_check.yml @@ -13,7 +13,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_stale_replication_slot.yml b/managed/data/checks/postgresql_stale_replication_slot.yml index 3692a00ffa7..1b0a77ae58b 100644 --- a/managed/data/checks/postgresql_stale_replication_slot.yml +++ b/managed/data/checks/postgresql_stale_replication_slot.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: slot_name, pg_current_wal_insert_lsn()-restart_lsn stale_bytes, (SELECT setting FROM pg_settings WHERE name = 'max_wal_size') max_wal_size FROM pg_replication_slots WHERE active = FALSE AND temporary = FALSE AND restart_lsn IS NOT NULL script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_table_autovac_settings.yml b/managed/data/checks/postgresql_table_autovac_settings.yml index 43655d1abbc..c74fd6e8c4a 100644 --- a/managed/data/checks/postgresql_table_autovac_settings.yml +++ b/managed/data/checks/postgresql_table_autovac_settings.yml @@ -12,7 +12,7 @@ checks: - type: POSTGRESQL_SELECT query: " * FROM (SELECT c.relname, pg_catalog.array_to_string(c.reloptions || array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ') as opts FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid) ) AS tabopts WHERE opts like '%vacuum%'" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor # thresholds diff --git a/managed/data/checks/postgresql_table_bloat_bytes.yml b/managed/data/checks/postgresql_table_bloat_bytes.yml index 41834d0ba76..86a4deb0e87 100644 --- a/managed/data/checks/postgresql_table_bloat_bytes.yml +++ b/managed/data/checks/postgresql_table_bloat_bytes.yml @@ -13,7 +13,7 @@ checks: all_dbs: true query: " * FROM ( WITH a AS ( SELECT current_database(), schemaname, tblname, tblpages as pages,est_tblpages as est_pages ,est_tblpages_ff as est_pages_ff, bs*tblpages AS cur_size_byte, (tblpages-est_tblpages)*bs AS free_bytes, CASE WHEN tblpages - est_tblpages > 0 THEN 100 * (tblpages - est_tblpages)/tblpages::float ELSE 0 END AS extra_pages_pct, fillfactor, CASE WHEN tblpages - est_tblpages_ff > 0 THEN (tblpages-est_tblpages_ff)*bs ELSE 0 END AS bloatsize_byte, CASE WHEN tblpages - est_tblpages_ff > 0 THEN 100 * (tblpages - est_tblpages_ff)/tblpages::float ELSE 0 END AS bloat_pct, is_na AS stats_missing FROM ( SELECT ceil( reltuples / ( (bs-page_hdr)/tpl_size) ) + ceil( toasttuples / 4 ) AS est_tblpages, ceil( reltuples / ( (bs-page_hdr)*fillfactor/(tpl_size*100) ) ) + ceil( toasttuples / 4 ) AS est_tblpages_ff, tblpages, fillfactor, bs, tblid, schemaname, tblname, heappages, toastpages, is_na FROM ( SELECT ( 4 + tpl_hdr_size + tpl_data_size + (2*ma) - CASE WHEN tpl_hdr_size%ma = 0 THEN ma ELSE tpl_hdr_size%ma END - CASE WHEN ceil(tpl_data_size)::int%ma = 0 THEN ma ELSE ceil(tpl_data_size)::int%ma END) AS tpl_size, bs - page_hdr AS size_per_block, (heappages + toastpages) AS tblpages, heappages, toastpages, reltuples, toasttuples, bs, page_hdr, tblid, schemaname, tblname, fillfactor, is_na FROM ( SELECT tbl.oid AS tblid, ns.nspname AS schemaname, tbl.relname AS tblname, tbl.reltuples, tbl.relpages AS heappages, coalesce(toast.relpages, 0) AS toastpages, coalesce(toast.reltuples, 0) AS toasttuples, coalesce(substring( array_to_string(tbl.reloptions, ' ') FROM 'fillfactor=([0-9]+)')::smallint, 100) AS fillfactor, current_setting('block_size')::numeric AS bs, CASE WHEN version()~'mingw32' OR version()~'64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS ma, 24 AS page_hdr, 23 + CASE WHEN MAX(coalesce(s.null_frac,0)) > 0 THEN ( 7 + count(s.attname) ) / 8 ELSE 0::int END + CASE WHEN bool_or(att.attname = 'oid' and att.attnum < 0) THEN 4 ELSE 0 END AS tpl_hdr_size, sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 0) ) AS tpl_data_size, bool_or(att.atttypid = 'pg_catalog.name'::regtype) OR sum(CASE WHEN att.attnum > 0 THEN 1 ELSE 0 END) <> count(s.attname) AS is_na FROM pg_attribute AS att JOIN pg_class AS tbl ON att.attrelid = tbl.oid JOIN pg_namespace AS ns ON ns.oid = tbl.relnamespace AND ns.nspname NOT IN ('pg_catalog', 'information_schema') LEFT JOIN pg_stats AS s ON s.schemaname=ns.nspname AND s.tablename = tbl.relname AND s.inherited=false AND s.attname=att.attname LEFT JOIN pg_class AS toast ON tbl.reltoastrelid = toast.oid WHERE NOT att.attisdropped AND tbl.relkind in ('r','m') GROUP BY 1,2,3,4,5,6,7,8,9,10 ORDER BY 2,3) AS s) AS s2) AS s3 ORDER BY schemaname, tblname) SELECT current_database, schemaname, tblname, cur_size_byte real_size, pg_size_pretty(cur_size_byte::numeric) real_size_pretty, free_bytes, bloatsize_byte bloat_size_byte, pg_size_pretty(bloatsize_byte::numeric) bloat_size_byte_pretty FROM a WHERE schemaname != 'pg_catalog' AND bloatsize_byte > 250000000 ORDER BY cur_size_byte DESC) x" script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(tuples, context): results = [] diff --git a/managed/data/checks/postgresql_table_bloat_in_percentage.yml b/managed/data/checks/postgresql_table_bloat_in_percentage.yml index 71661f2393a..4dc8ae08192 100644 --- a/managed/data/checks/postgresql_table_bloat_in_percentage.yml +++ b/managed/data/checks/postgresql_table_bloat_in_percentage.yml @@ -83,7 +83,7 @@ checks: ORDER BY cur_size_byte DESC ) x script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor # threshold diff --git a/managed/data/checks/postgresql_tmpfiles_check.yml b/managed/data/checks/postgresql_tmpfiles_check.yml index 5f7ef851e93..32c744af476 100644 --- a/managed/data/checks/postgresql_tmpfiles_check.yml +++ b/managed/data/checks/postgresql_tmpfiles_check.yml @@ -15,7 +15,7 @@ checks: script: | def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" for row in rows[0]: db, tempfiles, tempbytes, age = row["datname"], row["temp_files"], row["temp_bytes"], row["age"] if tempfiles > 100: diff --git a/managed/data/checks/postgresql_txid_wraparound_approaching.yml b/managed/data/checks/postgresql_txid_wraparound_approaching.yml index f3877020d88..e7f39633c3c 100644 --- a/managed/data/checks/postgresql_txid_wraparound_approaching.yml +++ b/managed/data/checks/postgresql_txid_wraparound_approaching.yml @@ -16,7 +16,7 @@ checks: WHERE (age(datfrozenxid)::numeric/1000000000*100)::numeric(4,2) >= 20.0::numeric(4,2) ORDER BY 2 DESC script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" # pg_advisor def check_context(docs, context): diff --git a/managed/data/checks/postgresql_unsupported_check.yml b/managed/data/checks/postgresql_unsupported_check.yml index 5917cf5e979..126f37c5cc9 100644 --- a/managed/data/checks/postgresql_unsupported_check.yml +++ b/managed/data/checks/postgresql_unsupported_check.yml @@ -31,7 +31,7 @@ checks: def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" description = "" iseol = False for row in rows[0]: diff --git a/managed/data/checks/postgresql_unused_index_check.yml b/managed/data/checks/postgresql_unused_index_check.yml index 95c9b7f9167..f68fb28053c 100644 --- a/managed/data/checks/postgresql_unused_index_check.yml +++ b/managed/data/checks/postgresql_unused_index_check.yml @@ -14,7 +14,7 @@ checks: parameters: all_dbs: true script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(tuple, context): results = [] for checkedDB, rows in tuple[0].items(): diff --git a/managed/data/checks/postgresql_vacuum_sanity_check.yml b/managed/data/checks/postgresql_vacuum_sanity_check.yml index 08fc05401f6..2cdea7b84db 100644 --- a/managed/data/checks/postgresql_vacuum_sanity_check.yml +++ b/managed/data/checks/postgresql_vacuum_sanity_check.yml @@ -11,7 +11,7 @@ checks: - type: POSTGRESQL_SELECT query: "current_setting('autovacuum') AS autovacuum, current_setting('autovacuum_max_workers') AS autovacuum_max_workers, current_setting('autovacuum_vacuum_scale_factor') AS autovacuum_vacuum_scale_factor, current_setting('vacuum_cost_page_hit') AS vacuum_cost_page_hit, current_setting('vacuum_cost_delay') AS vacuum_cost_delay, current_setting('vacuum_cost_page_dirty') AS vacuum_cost_page_dirty , current_setting('vacuum_cost_page_miss') AS vacuum_cost_page_miss " script: | - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" def check_context(rows, context): results = [] diff --git a/managed/data/checks/postgresql_version_check.yml b/managed/data/checks/postgresql_version_check.yml index 8f8962dffab..a6f2d501869 100644 --- a/managed/data/checks/postgresql_version_check.yml +++ b/managed/data/checks/postgresql_version_check.yml @@ -84,7 +84,7 @@ checks: def check_context(rows, context): #fail(rows) results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" description = "" daysleft = "" minoroutdated = False diff --git a/managed/data/checks/postgresql_wal_retention_check.yml b/managed/data/checks/postgresql_wal_retention_check.yml index 4147811bd64..fc77d03813a 100644 --- a/managed/data/checks/postgresql_wal_retention_check.yml +++ b/managed/data/checks/postgresql_wal_retention_check.yml @@ -14,7 +14,7 @@ checks: script: | def check_context(rows, context): results = [] - read_url = "https://docs.percona.com/percona-monitoring-and-management/3/advisors/checks/{}.html" + read_url = "https://docs.percona.com/percona-platform/advisors/checks/{}.html" description = "" keeping = "" for row in rows[0]: From 4386087f611642b8cdbc92613e19ec8f9e3b53ae Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 19 Jul 2026 00:47:23 +0300 Subject: [PATCH 037/120] PMM-14109 Send advisor check summaries by email via Grafana SMTP Replace the Grafana alert-rule based advisor notifications with direct email delivery. When advisor notifications are enabled, PMM emails a summary of each completed check batch to the Grafana email contact point named "PMM Advisor Insights", reusing Grafana's SMTP configuration (the inherited GF_SMTP_* environment) instead of duplicating it. - Resolve and cache the contact point's recipients when settings change, since the batch-completion path runs in a background context with no Grafana credentials. - On batch completion, filter insights by the configured severity threshold, format each like the UI's "Copy to text", and send via SMTP. - Compose the email with an intro (batch id and how the batch was triggered), a per-severity summary and next steps, followed by the insights. - Drop the now-unused alert-rule helpers and Grafana client methods. - Center the "No advisor insights found" empty-state message. --- go.mod | 2 + go.sum | 4 + managed/models/settings.go | 6 +- managed/services/checks/checks.go | 3 + managed/services/checks/insight_text.go | 162 ++++++++++++++++++ managed/services/checks/insight_text_test.go | 120 +++++++++++++ managed/services/checks/notification.go | 125 ++++++++++++++ managed/services/checks/notification_test.go | 59 +++++++ managed/services/checks/smtp.go | 125 ++++++++++++++ managed/services/grafana/client.go | 60 ++++--- .../services/server/advisor_notifications.go | 128 +++++--------- .../server/advisor_notifications_test.go | 82 ++++----- managed/services/server/deps.go | 6 +- .../server/mock_grafana_client_test.go | 72 +------- managed/services/server/server.go | 13 +- managed/services/server/server_test.go | 5 +- .../advisors/insights/AdvisorInsights.tsx | 1 + .../src/pages/settings/Settings.messages.ts | 2 +- 18 files changed, 731 insertions(+), 244 deletions(-) create mode 100644 managed/services/checks/insight_text.go create mode 100644 managed/services/checks/insight_text_test.go create mode 100644 managed/services/checks/notification.go create mode 100644 managed/services/checks/notification_test.go create mode 100644 managed/services/checks/smtp.go diff --git a/go.mod b/go.mod index aeb2384cff4..ec1da434009 100644 --- a/go.mod +++ b/go.mod @@ -79,6 +79,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad google.golang.org/grpc v1.82.0 google.golang.org/protobuf v1.36.11 + gopkg.in/mail.v2 v2.3.1 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 gopkg.in/reform.v1 v1.5.1 gopkg.in/yaml.v3 v3.0.1 @@ -338,6 +339,7 @@ require ( golang.org/x/term v0.45.0 // indirect google.golang.org/appengine v1.6.8-0.20221117013220-504804fb50de // indirect google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.0 // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 188518d23cb..1bd025bd290 100644 --- a/go.sum +++ b/go.sum @@ -1079,6 +1079,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1087,6 +1089,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.2 h1:JtOSMb9OuaCZKr7h5D/h6iii14sK0hLbplTc6frx4Ss= gopkg.in/ini.v1 v1.67.2/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/reform.v1 v1.5.1 h1:7vhDFW1n1xAPC6oDSvIvVvpRkaRpXlxgJ4QB4s3aDdo= diff --git a/managed/models/settings.go b/managed/models/settings.go index 47ac8c05e6f..d76699fbc4c 100644 --- a/managed/models/settings.go +++ b/managed/models/settings.go @@ -102,11 +102,15 @@ type Settings struct { Enabled *bool `json:"enabled"` } `json:"alerting"` - // AdvisorNotifications controls email notifications for Advisor check results. + // AdvisorNotifications controls emailing Advisor check results to a Grafana email contact point. AdvisorNotifications struct { Enabled *bool `json:"enabled"` // SeverityThreshold is the least-severe level that triggers a notification. SeverityThreshold common.Severity `json:"severity_threshold"` + // EmailAddresses is the resolved recipient list of the Grafana email contact point. It is + // cached at enable time because the batch-completion path runs in a background context that + // has no Grafana credentials. + EmailAddresses []string `json:"email_addresses"` } `json:"advisor_notifications"` Azurediscover struct { diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index 45bdff7771d..6814be7cdb1 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -366,6 +366,9 @@ func (s *Service) run(ctx context.Context, intervalGroup check.Interval, checkNa s.alertsRegistry.set(res) + // Best-effort: email the completed batch to the configured Advisor contact point. + s.maybeSendAdvisorNotification(ctx, ri.batchID, ri.triggeredBy) + return nil } diff --git a/managed/services/checks/insight_text.go b/managed/services/checks/insight_text.go new file mode 100644 index 00000000000..eeb631f4da4 --- /dev/null +++ b/managed/services/checks/insight_text.go @@ -0,0 +1,162 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package checks + +import ( + "fmt" + "sort" + "strings" + "unicode" + + "github.com/percona/pmm/managed/models" +) + +// insightTimeFormat mirrors TIME_FORMAT in ui/apps/pmm/src/lib/constants.ts. +const insightTimeFormat = "2006-01-02 15:04:05" + +// The maps below mirror the display labels in ui/apps/pmm/src/lib/constants.ts so that the +// webhook payload reads identically to the UI's "Copy to text" output. + +var insightStatusText = map[models.CheckResultStatus]string{ + models.CheckResultOK: "OK", + models.CheckResultFailed: "Failed", + models.CheckResultError: "Error", +} + +var insightSeverityText = map[models.CheckSeverity]string{ + models.CheckSeverityEmergency: "Emergency", + models.CheckSeverityAlert: "Alert", + models.CheckSeverityCritical: "Critical", + models.CheckSeverityError: "Error", + models.CheckSeverityWarning: "Warning", + models.CheckSeverityNotice: "Notice", + models.CheckSeverityInfo: "Info", + models.CheckSeverityDebug: "Debug", +} + +var insightIntervalText = map[models.Interval]string{ + models.Standard: "Standard", + models.Rare: "Rare", + models.Frequent: "Frequent", +} + +var insightTriggeredByText = map[models.CheckTriggeredBy]string{ + models.CheckTriggeredByUser: "User", + models.CheckTriggeredByScheduler: "Scheduler", +} + +// insightToText renders an Advisor check result as a human-readable narrative, matching the +// UI's "Copy to text" command (insightToText in ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts). +func insightToText(r *models.CheckResult) (string, error) { + labelsMap, err := r.GetLabels() + if err != nil { + return "", fmt.Errorf("failed to decode labels for check result %q: %w", r.ID, err) + } + + keys := make([]string, 0, len(labelsMap)) + for k := range labelsMap { + keys = append(keys, k) + } + sort.Strings(keys) + labelPairs := make([]string, 0, len(keys)) + for _, k := range keys { + labelPairs = append(labelPairs, fmt.Sprintf("%s=%s", k, labelsMap[k])) + } + labels := strings.Join(labelPairs, ", ") + + var checkedAt string + if !r.CheckedAt.IsZero() { + checkedAt = r.CheckedAt.Format(insightTimeFormat) + } + + details := [][2]string{ + {"ID", r.ID}, + {"Batch ID", r.BatchID}, + {"Check Name", r.CheckName}, + {"Advisor", r.AdvisorName}, + {"Category", capitalize(r.Category)}, + {"Service Name", r.ServiceName}, + {"Service Type", string(r.ServiceType)}, + {"Node Name", r.NodeName}, + {"Environment", r.Environment}, + {"Cluster", r.Cluster}, + {"Replication Set", r.ReplicationSet}, + {"Interval", insightIntervalLabel(r.Interval)}, + {"Triggered By", insightTriggeredByText[r.TriggeredBy]}, + {"Read", insightReadLabel(r.IsRead)}, + {"Summary", r.Summary}, + {"Description", r.Description}, + {"Outcome", r.Outcome}, + {"Severity", insightSeverityLabel(r.Severity)}, + {"Read More", r.ReadMoreURL}, + {"Labels", labels}, + } + + var detailLines []string + for _, d := range details { + if d[1] == "" { + continue + } + detailLines = append(detailLines, fmt.Sprintf(" %s: %s", d[0], d[1])) + } + + return fmt.Sprintf( + "The Advisor Check %q completed at %s with status %q.\n\nCheck Details:\n%s", + r.Summary, checkedAt, insightStatusLabel(r.Status), strings.Join(detailLines, "\n"), + ), nil +} + +// insightIntervalLabel maps a stored interval to its display label; an empty interval means +// standard (see convertModelInterval in managed/services/management/checks.go). +func insightIntervalLabel(interval models.Interval) string { + if interval == "" { + return insightIntervalText[models.Standard] + } + if label, ok := insightIntervalText[interval]; ok { + return label + } + return "Unspecified" +} + +func insightStatusLabel(status models.CheckResultStatus) string { + if label, ok := insightStatusText[status]; ok { + return label + } + return "Unspecified" +} + +func insightSeverityLabel(severity models.CheckSeverity) string { + if label, ok := insightSeverityText[severity]; ok { + return label + } + return "Unspecified" +} + +func insightReadLabel(isRead bool) string { + if isRead { + return "Read" + } + return "Unread" +} + +func capitalize(s string) string { + if s == "" { + return "" + } + r := []rune(s) + r[0] = unicode.ToUpper(r[0]) + return string(r) +} diff --git a/managed/services/checks/insight_text_test.go b/managed/services/checks/insight_text_test.go new file mode 100644 index 00000000000..7da59c728ba --- /dev/null +++ b/managed/services/checks/insight_text_test.go @@ -0,0 +1,120 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package checks + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/percona/pmm/managed/models" +) + +// TestInsightToText locks the Go output to the UI's "Copy to text" format +// (insightToText in ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts). +func TestInsightToText(t *testing.T) { + t.Parallel() + + t.Run("all fields", func(t *testing.T) { + t.Parallel() + + r := &models.CheckResult{ + ID: "insight-1", + BatchID: "batch-1", + CheckName: "mysql_version", + AdvisorName: "version_advisor", + Category: "performance", + ServiceName: "mysql-prod", + ServiceType: "mysql", + NodeName: "node-a", + Environment: "prod", + Cluster: "cluster-1", + ReplicationSet: "rs0", + Interval: models.Standard, + TriggeredBy: models.CheckTriggeredByScheduler, + IsRead: false, + Summary: "Outdated MySQL version", + Description: "The MySQL version is old", + Outcome: "Upgrade recommended", + Severity: models.CheckSeverityWarning, + ReadMoreURL: "https://example.com/more", + Status: models.CheckResultFailed, + CheckedAt: time.Date(2026, 7, 16, 10, 30, 0, 0, time.UTC), + } + require.NoError(t, r.SetLabels(map[string]string{"tier": "db", "env": "prod"})) + + want := `The Advisor Check "Outdated MySQL version" completed at 2026-07-16 10:30:00 with status "Failed". + +Check Details: + ID: insight-1 + Batch ID: batch-1 + Check Name: mysql_version + Advisor: version_advisor + Category: Performance + Service Name: mysql-prod + Service Type: mysql + Node Name: node-a + Environment: prod + Cluster: cluster-1 + Replication Set: rs0 + Interval: Standard + Triggered By: Scheduler + Read: Unread + Summary: Outdated MySQL version + Description: The MySQL version is old + Outcome: Upgrade recommended + Severity: Warning + Read More: https://example.com/more + Labels: env=prod, tier=db` + + got, err := insightToText(r) + require.NoError(t, err) + require.Equal(t, want, got) + }) + + t.Run("empty fields are omitted", func(t *testing.T) { + t.Parallel() + + r := &models.CheckResult{ + ID: "insight-2", + BatchID: "batch-2", + CheckName: "pg_check", + Summary: "Issue found", + Severity: models.CheckSeverityError, + Status: models.CheckResultFailed, + TriggeredBy: models.CheckTriggeredByUser, + IsRead: true, + CheckedAt: time.Date(2026, 7, 16, 12, 0, 0, 0, time.UTC), + } + + want := `The Advisor Check "Issue found" completed at 2026-07-16 12:00:00 with status "Failed". + +Check Details: + ID: insight-2 + Batch ID: batch-2 + Check Name: pg_check + Interval: Standard + Triggered By: User + Read: Read + Summary: Issue found + Severity: Error` + + got, err := insightToText(r) + require.NoError(t, err) + require.Equal(t, want, got) + }) +} diff --git a/managed/services/checks/notification.go b/managed/services/checks/notification.go new file mode 100644 index 00000000000..c34924e2fe7 --- /dev/null +++ b/managed/services/checks/notification.go @@ -0,0 +1,125 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package checks + +import ( + "context" + "fmt" + "strings" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/pi/common" +) + +// maybeSendAdvisorNotification emails the completed batch's insights to the configured Advisor email +// contact point when notifications are enabled. It is best-effort: every failure is logged and +// swallowed so it never affects the check run. The recipients are read from settings (cached at +// enable time by the server service), because this runs in a background context that cannot reach +// Grafana. +func (s *Service) maybeSendAdvisorNotification(ctx context.Context, batchID string, triggeredBy models.CheckTriggeredBy) { + settings, err := models.GetSettings(s.db.Querier) + if err != nil { + s.l.Warnf("Advisor notification: failed to load settings: %v", err) + return + } + an := settings.AdvisorNotifications + if !settings.IsAdvisorNotificationsEnabled() || len(an.EmailAddresses) == 0 { + return + } + + results, _, err := s.GetCheckResultsHistory(ctx, models.CheckResultFilters{BatchID: batchID}, 0, 0) + if err != nil { + s.l.Warnf("Advisor notification: failed to load results for batch %s: %v", batchID, err) + return + } + + threshold := an.SeverityThreshold + if threshold == common.Unknown { + threshold = common.Error + } + + counts := make(map[common.Severity]int) + texts := make([]string, 0, len(results)) + for _, r := range results { + severity := common.ParseSeverity(string(r.Severity)) + // Keep only insights at least as severe as the threshold (a smaller value is more severe). + if severity < common.Emergency || severity > threshold { + continue + } + text, err := insightToText(r) + if err != nil { + s.l.Warnf("Advisor notification: failed to format insight %s: %v", r.ID, err) + continue + } + counts[severity]++ + texts = append(texts, text) + } + + if len(texts) == 0 { + return + } + + subject := fmt.Sprintf("PMM Advisor Insights: %d finding(s) for batch %s", len(texts), batchID) + body := buildAdvisorEmailReport(batchID, triggeredBy, threshold, counts, texts) + + err = s.sendAdvisorEmail(an.EmailAddresses, subject, body) + if err != nil { + s.l.Warnf("Advisor notification: failed to email batch %s: %v", batchID, err) + return + } + s.l.Infof("Advisor notification: emailed %d insight(s) for batch %s", len(texts), batchID) +} + +// buildAdvisorEmailReport composes the notification email body: a brief introduction, a per-severity +// summary, suggested next steps, and then the insights (formatted like the UI's "Copy to text") +// one after another. +func buildAdvisorEmailReport(batchID string, triggeredBy models.CheckTriggeredBy, threshold common.Severity, counts map[common.Severity]int, insights []string) string { + var b strings.Builder + + fmt.Fprintf(&b, "Percona Monitoring and Management runs Advisor checks against your monitored "+ + "databases to surface potential issues. This report covers batch %s, which was %s. It found %d "+ + "insight(s) at or above the %q severity level that may need your attention.\n\n", + batchID, triggerPhrase(triggeredBy), len(insights), capitalize(threshold.String())) + + b.WriteString("Findings by severity:\n") + // Iterate from the most severe level down to the configured threshold (Emergency=1 .. threshold). + for sev := common.Emergency; sev <= threshold; sev++ { + fmt.Fprintf(&b, " %s: %d\n", capitalize(sev.String()), counts[sev]) + } + + b.WriteString("\nNext steps:\n") + b.WriteString(" - Review the insights below, addressing the most severe findings first.\n") + b.WriteString(" - Follow each insight's \"Read More\" link for remediation guidance.\n") + b.WriteString(" - Prioritize issues affecting production services.\n") + b.WriteString(" - See full details in PMM under Advisors -> Insights.\n\n") + + fmt.Fprintf(&b, "Advisor Insights (%d):\n\n", len(insights)) + b.WriteString(strings.Join(insights, "\n\n")) + + return b.String() +} + +// triggerPhrase describes, in prose, how the batch run was initiated. +func triggerPhrase(triggeredBy models.CheckTriggeredBy) string { + switch triggeredBy { + case models.CheckTriggeredByScheduler: + return "run automatically on schedule" + case models.CheckTriggeredByUser: + return "triggered manually by an operator" + default: + return "run" + } +} diff --git a/managed/services/checks/notification_test.go b/managed/services/checks/notification_test.go new file mode 100644 index 00000000000..510523d0450 --- /dev/null +++ b/managed/services/checks/notification_test.go @@ -0,0 +1,59 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package checks + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/percona/pmm/managed/models" + "github.com/percona/pmm/managed/pi/common" +) + +func TestBuildAdvisorEmailReport(t *testing.T) { + t.Parallel() + + counts := map[common.Severity]int{ + common.Error: 1, + common.Warning: 1, + } + insights := []string{"Insight A", "Insight B"} + + want := `Percona Monitoring and Management runs Advisor checks against your monitored databases to surface potential issues. This report covers batch batch-123, which was triggered manually by an operator. It found 2 insight(s) at or above the "Warning" severity level that may need your attention. + +Findings by severity: + Emergency: 0 + Alert: 0 + Critical: 0 + Error: 1 + Warning: 1 + +Next steps: + - Review the insights below, addressing the most severe findings first. + - Follow each insight's "Read More" link for remediation guidance. + - Prioritize issues affecting production services. + - See full details in PMM under Advisors -> Insights. + +Advisor Insights (2): + +Insight A + +Insight B` + + got := buildAdvisorEmailReport("batch-123", models.CheckTriggeredByUser, common.Warning, counts, insights) + require.Equal(t, want, got) +} diff --git a/managed/services/checks/smtp.go b/managed/services/checks/smtp.go new file mode 100644 index 00000000000..fea8f6964e3 --- /dev/null +++ b/managed/services/checks/smtp.go @@ -0,0 +1,125 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package checks + +import ( + "crypto/tls" + "errors" + "fmt" + "net" + "os" + "strconv" + + gomail "gopkg.in/mail.v2" +) + +// smtpConfig holds the SMTP settings PMM reuses from the bundled Grafana. PMM Server configures +// Grafana's SMTP via GF_SMTP_* environment variables, and the pmm-managed process inherits them, +// so email delivery shares Grafana's single SMTP configuration instead of duplicating it. +type smtpConfig struct { + enabled bool + host string + user string + password string + fromAddress string + fromName string + skipVerify bool + startTLS string +} + +// smtpConfigFromEnv reads the Grafana SMTP settings from the inherited GF_SMTP_* environment. +func smtpConfigFromEnv() smtpConfig { + enabled, _ := strconv.ParseBool(os.Getenv("GF_SMTP_ENABLED")) + skipVerify, _ := strconv.ParseBool(os.Getenv("GF_SMTP_SKIP_VERIFY")) + return smtpConfig{ + enabled: enabled, + host: os.Getenv("GF_SMTP_HOST"), + user: os.Getenv("GF_SMTP_USER"), + password: os.Getenv("GF_SMTP_PASSWORD"), + fromAddress: os.Getenv("GF_SMTP_FROM_ADDRESS"), + fromName: os.Getenv("GF_SMTP_FROM_NAME"), + skipVerify: skipVerify, + startTLS: os.Getenv("GF_SMTP_STARTTLS_POLICY"), + } +} + +// dialer builds a gomail dialer from the config, mirroring Grafana's createDialer +// (grafana pkg/services/notifications/smtp.go). +func (c smtpConfig) dialer() (*gomail.Dialer, error) { + host, portStr, err := net.SplitHostPort(c.host) + if err != nil { + return nil, fmt.Errorf("invalid GF_SMTP_HOST %q: %w", c.host, err) + } + port, err := strconv.Atoi(portStr) + if err != nil { + return nil, fmt.Errorf("invalid SMTP port in %q: %w", c.host, err) + } + + d := gomail.NewDialer(host, port, c.user, c.password) + d.TLSConfig = &tls.Config{ + ServerName: host, + // Honors GF_SMTP_SKIP_VERIFY, matching Grafana's own SMTP behavior. + InsecureSkipVerify: c.skipVerify, //nolint:gosec + } + switch c.startTLS { + case "NoStartTLS": + d.StartTLSPolicy = gomail.NoStartTLS + case "MandatoryStartTLS": + d.StartTLSPolicy = gomail.MandatoryStartTLS + default: + d.StartTLSPolicy = gomail.OpportunisticStartTLS + } + + return d, nil +} + +// sendAdvisorEmail emails a pre-composed report to the recipients using the Grafana-configured +// SMTP server. +func (s *Service) sendAdvisorEmail(to []string, subject, body string) error { + if len(to) == 0 { + return errors.New("no recipient addresses configured") + } + + cfg := smtpConfigFromEnv() + if !cfg.enabled { + return errors.New("SMTP is not enabled (GF_SMTP_ENABLED)") + } + if cfg.fromAddress == "" { + return errors.New("no sender address configured (GF_SMTP_FROM_ADDRESS)") + } + + return s.sendEmail(cfg, to, subject, body) +} + +// sendEmail sends a plain-text email to the recipients using the Grafana-configured SMTP server. +func (s *Service) sendEmail(cfg smtpConfig, to []string, subject, body string) error { + dialer, err := cfg.dialer() + if err != nil { + return err + } + + m := gomail.NewMessage() + if cfg.fromName != "" { + m.SetAddressHeader("From", cfg.fromAddress, cfg.fromName) + } else { + m.SetHeader("From", cfg.fromAddress) + } + m.SetHeader("To", to...) + m.SetHeader("Subject", subject) + m.SetBody("text/plain", body) + + return dialer.DialAndSend(m) +} diff --git a/managed/services/grafana/client.go b/managed/services/grafana/client.go index 5cada1a75f7..e94f3248255 100644 --- a/managed/services/grafana/client.go +++ b/managed/services/grafana/client.go @@ -767,14 +767,48 @@ func (c *Client) CreateAlertRule(ctx context.Context, folderUID, groupName, inte return nil } -// DeleteAlertRuleGroup deletes a Grafana-managed alert rule group from the given folder. -func (c *Client) DeleteAlertRuleGroup(ctx context.Context, folderUID, groupName string) error { +// GetEmailContactPoint returns the recipient addresses of the Grafana email contact point with the +// given name. It returns nil when no contact point with that name exists or it is not an email type. +func (c *Client) GetEmailContactPoint(ctx context.Context, name string) ([]string, error) { authHeaders, err := auth.GetHeadersFromContext(ctx) if err != nil { - return err + return nil, err + } + + var contactPoints []struct { + Name string `json:"name"` + Type string `json:"type"` + Settings map[string]any `json:"settings"` + } + err = c.do(ctx, http.MethodGet, "/api/v1/provisioning/contact-points", "", authHeaders, nil, &contactPoints) + if err != nil { + return nil, err } - return c.do(ctx, http.MethodDelete, fmt.Sprintf("/api/ruler/grafana/api/v1/rules/%s/%s", folderUID, groupName), "", authHeaders, nil, nil) + for _, cp := range contactPoints { + if cp.Name != name || cp.Type != "email" { + continue + } + addresses, _ := cp.Settings["addresses"].(string) + return splitEmailAddresses(addresses), nil + } + + return nil, nil +} + +// splitEmailAddresses splits a Grafana email contact point address string, whose entries may be +// separated by ';', ',', whitespace, or newlines. +func splitEmailAddresses(s string) []string { + fields := strings.FieldsFunc(s, func(r rune) bool { + return r == ';' || r == ',' || r == '\n' || r == ' ' || r == '\t' + }) + addresses := make([]string, 0, len(fields)) + for _, f := range fields { + if f != "" { + addresses = append(addresses, f) + } + } + return addresses } func validateDurations(intervalD, forD string) error { @@ -824,24 +858,6 @@ func (c *Client) CreateFolder(ctx context.Context, title string) (*models.Folder return resp.Payload, nil } -// CreateFolderWithUID creates a grafana folder with a specific UID. -func (c *Client) CreateFolderWithUID(ctx context.Context, title, uid string) error { - authHeaders, err := auth.GetHeadersFromContext(ctx) - if err != nil { - return err - } - - body, err := json.Marshal(struct { - UID string `json:"uid"` - Title string `json:"title"` - }{UID: uid, Title: title}) - if err != nil { - return err - } - - return c.do(ctx, http.MethodPost, "/api/folders", "", authHeaders, body, nil) -} - // DeleteFolder deletes grafana folder. func (c *Client) DeleteFolder(ctx context.Context, id string, force bool) error { grafanaClient, err := c.createGrafanaClient(ctx) diff --git a/managed/services/server/advisor_notifications.go b/managed/services/server/advisor_notifications.go index 41265d324b9..31c0893015b 100644 --- a/managed/services/server/advisor_notifications.go +++ b/managed/services/server/advisor_notifications.go @@ -18,114 +18,70 @@ package server import ( "context" "fmt" - "strings" + + "gopkg.in/reform.v1" "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/pi/common" - "github.com/percona/pmm/managed/services" ) -const ( - advisorNotificationsFolderUID = "pmm-advisor-notifications" - advisorNotificationsFolderTitle = "PMM Advisor Notifications" - advisorNotificationsRuleGroup = "pmm_advisor_notifications" - advisorNotificationsRuleTitle = "Advisor check failing" - advisorNotificationsRuleInterval = "1m" - advisorNotificationsRuleFor = "5m" - advisorInsightsMetric = "pmm_managed_advisor_check_insights" - // Look-back window (seconds) for the instant query. - advisorNotificationsQueryRangeSeconds = 600 - // Added to fired alerts so operators can route them via a Grafana notification policy. - advisorNotificationLabel = "advisor_notification" -) +// advisorContactPointName is the fixed-convention Grafana email contact point that PMM delivers +// Advisor batch summaries to. The user creates and configures it in Grafana. +const advisorContactPointName = "PMM Advisor Insights" -// advisorNotificationSeverityRegex builds a label-value regex matching every severity at least as -// severe as the given threshold (e.g. Error -> "emergency|alert|critical|error"). -func advisorNotificationSeverityRegex(threshold common.Severity) string { - if threshold == common.Unknown { - threshold = common.Error +// syncAdvisorContactPoint resolves the Advisor email contact point and caches its recipients in +// settings when the notification enablement changes or notifications are enabled (to pick up +// changes). Failures are logged and swallowed - they must not fail the settings change. +func (s *Server) syncAdvisorContactPoint(ctx context.Context, oldSettings, newSettings *models.Settings) { + enabledNow := newSettings.IsAdvisorNotificationsEnabled() + if !enabledNow && oldSettings.IsAdvisorNotificationsEnabled() == enabledNow { + return } - var names []string - for s := common.Emergency; s <= threshold; s++ { - names = append(names, s.String()) + addresses, err := s.reconcileAdvisorContactPoint(ctx, newSettings) + if err != nil { + s.l.Errorf("Failed to reconcile Advisor contact point: %v", err) + return } - return strings.Join(names, "|") -} - -// buildAdvisorNotificationRule builds the Grafana alert rule that fires for advisor insights at or -// above the configured severity threshold. -func buildAdvisorNotificationRule(datasourceUID string, threshold common.Severity) *services.Rule { - expr := fmt.Sprintf(`%s{severity=~"%s"} > 0`, advisorInsightsMetric, advisorNotificationSeverityRegex(threshold)) - return &services.Rule{ - GrafanaAlert: services.GrafanaAlert{ - Title: advisorNotificationsRuleTitle, - Condition: "A", - NoDataState: "OK", - ExecErrState: "Alerting", - Data: []services.Data{ - { - RefID: "A", - DatasourceUID: datasourceUID, - RelativeTimeRange: services.RelativeTimeRange{From: advisorNotificationsQueryRangeSeconds, To: 0}, - Model: services.Model{ - RefID: "A", - Expr: expr, - Instant: true, - }, - }, - }, - }, - For: advisorNotificationsRuleFor, - Annotations: map[string]string{ - "summary": "Advisor check {{ $labels.check_name }} is failing on service {{ $labels.service_name }}", - "description": "Advisor {{ $labels.advisor }} check {{ $labels.check_name }} reported a {{ $labels.severity }} issue on service {{ $labels.service_name }}.", - }, - Labels: map[string]string{ - advisorNotificationLabel: "1", - }, + err = s.saveAdvisorContactPointCache(ctx, addresses) + if err != nil { + s.l.Errorf("Failed to cache Advisor contact point: %v", err) } } -// reconcileAdvisorNotifications creates or removes the Grafana alert rule that drives advisor email -// notifications, based on the current settings. +// reconcileAdvisorContactPoint resolves the Advisor email contact point's recipients from Grafana +// when notifications are enabled, returning them for the caller to cache in settings. // // It talks to Grafana on the caller's behalf, so it must be called within an authenticated request // context (e.g. ChangeSettings) - background contexts have no Grafana credentials. -func (s *Server) reconcileAdvisorNotifications(ctx context.Context, settings *models.Settings) error { +func (s *Server) reconcileAdvisorContactPoint(ctx context.Context, settings *models.Settings) ([]string, error) { if !settings.IsAdvisorNotificationsEnabled() { - err := s.grafanaClient.DeleteAlertRuleGroup(ctx, advisorNotificationsFolderUID, advisorNotificationsRuleGroup) - if err != nil { - s.l.Debugf("Failed to delete advisor notifications rule group (ignored): %v", err) - } - return nil + return nil, nil } - // Best-effort folder creation; an error here usually means the folder already exists. A genuine - // problem (auth, connectivity) surfaces below when creating the rule. - err := s.grafanaClient.CreateFolderWithUID(ctx, advisorNotificationsFolderTitle, advisorNotificationsFolderUID) + addresses, err := s.grafanaClient.GetEmailContactPoint(ctx, advisorContactPointName) if err != nil { - s.l.Debugf("Failed to create advisor notifications folder (ignored, may already exist): %v", err) + return nil, fmt.Errorf("failed to read advisor contact point: %w", err) } - - // Remove any existing rule so we always reflect the latest settings (idempotent replace). - err = s.grafanaClient.DeleteAlertRuleGroup(ctx, advisorNotificationsFolderUID, advisorNotificationsRuleGroup) - if err != nil { - s.l.Debugf("Failed to delete existing advisor notifications rule group (ignored): %v", err) + if len(addresses) == 0 { + s.l.Warnf("Advisor notifications are enabled but no email contact point named %q was found in "+ + "Grafana. Create one to start sending batch summaries.", advisorContactPointName) } - // "Metrics" is the VictoriaMetrics datasource provisioned by PMM. - datasourceUID, err := s.grafanaClient.GetDatasourceUIDByName(ctx, "Metrics") - if err != nil { - return fmt.Errorf("failed to get metrics datasource UID: %w", err) - } + return addresses, nil +} - rule := buildAdvisorNotificationRule(datasourceUID, settings.AdvisorNotifications.SeverityThreshold) - err = s.grafanaClient.CreateAlertRule(ctx, advisorNotificationsFolderUID, advisorNotificationsRuleGroup, advisorNotificationsRuleInterval, rule) - if err != nil { - return fmt.Errorf("failed to create advisor notifications rule: %w", err) - } +// saveAdvisorContactPointCache persists the resolved recipient addresses into settings so the +// background batch-completion path (which cannot reach Grafana) can email without further Grafana calls. +func (s *Server) saveAdvisorContactPointCache(ctx context.Context, addresses []string) error { + return s.db.InTransactionContext(ctx, nil, func(tx *reform.TX) error { + settings, err := models.GetSettings(tx) + if err != nil { + return err + } + + settings.AdvisorNotifications.EmailAddresses = addresses - return nil + return models.SaveSettings(tx, settings) + }) } diff --git a/managed/services/server/advisor_notifications_test.go b/managed/services/server/advisor_notifications_test.go index 47b4533c750..00d2b8223f3 100644 --- a/managed/services/server/advisor_notifications_test.go +++ b/managed/services/server/advisor_notifications_test.go @@ -20,39 +20,13 @@ import ( "testing" "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/pi/common" - "github.com/percona/pmm/managed/services" ) -func TestAdvisorNotificationSeverityRegex(t *testing.T) { - t.Parallel() - - assert.Equal(t, "emergency", advisorNotificationSeverityRegex(common.Emergency)) - assert.Equal(t, "emergency|alert|critical|error", advisorNotificationSeverityRegex(common.Error)) - assert.Equal(t, "emergency|alert|critical|error|warning|notice|info|debug", advisorNotificationSeverityRegex(common.Debug)) - // Unknown falls back to the Error threshold. - assert.Equal(t, "emergency|alert|critical|error", advisorNotificationSeverityRegex(common.Unknown)) -} - -func TestBuildAdvisorNotificationRule(t *testing.T) { - t.Parallel() - - rule := buildAdvisorNotificationRule("ds-uid", common.Error) - - require.Len(t, rule.GrafanaAlert.Data, 1) - assert.Equal(t, advisorNotificationsRuleTitle, rule.GrafanaAlert.Title) - assert.Equal(t, "ds-uid", rule.GrafanaAlert.Data[0].DatasourceUID) - assert.Equal(t, `pmm_managed_advisor_check_insights{severity=~"emergency|alert|critical|error"} > 0`, rule.GrafanaAlert.Data[0].Model.Expr) - assert.True(t, rule.GrafanaAlert.Data[0].Model.Instant) - assert.Equal(t, "1", rule.Labels[advisorNotificationLabel]) -} - -func TestReconcileAdvisorNotifications(t *testing.T) { +func TestReconcileAdvisorContactPoint(t *testing.T) { t.Parallel() newServer := func(t *testing.T) (*Server, *mockGrafanaClient) { @@ -66,53 +40,55 @@ func TestReconcileAdvisorNotifications(t *testing.T) { } enabledSettings := func() *models.Settings { + enabled := true s := &models.Settings{} - s.AdvisorNotifications.Enabled = new(true) - s.AdvisorNotifications.SeverityThreshold = common.Error + s.AdvisorNotifications.Enabled = &enabled return s } - t.Run("enabled creates folder and rule", func(t *testing.T) { + t.Run("enabled resolves the email contact point recipients", func(t *testing.T) { t.Parallel() s, gc := newServer(t) - gc.On("CreateFolderWithUID", mock.Anything, advisorNotificationsFolderTitle, advisorNotificationsFolderUID).Return(nil) - gc.On("DeleteAlertRuleGroup", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup).Return(nil) - gc.On("GetDatasourceUIDByName", mock.Anything, "Metrics").Return("ds-uid", nil) - gc.On( - "CreateAlertRule", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup, advisorNotificationsRuleInterval, - mock.MatchedBy(func(rule *services.Rule) bool { - return rule.GrafanaAlert.Data[0].Model.Expr == `pmm_managed_advisor_check_insights{severity=~"emergency|alert|critical|error"} > 0` && - rule.Labels[advisorNotificationLabel] == "1" - }), - ).Return(nil) - - err := s.reconcileAdvisorNotifications(t.Context(), enabledSettings()) + gc.On("GetEmailContactPoint", mock.Anything, advisorContactPointName). + Return([]string{"a@example.com", "b@example.com"}, nil) + + addresses, err := s.reconcileAdvisorContactPoint(t.Context(), enabledSettings()) + require.NoError(t, err) + require.Equal(t, []string{"a@example.com", "b@example.com"}, addresses) + }) + + t.Run("disabled returns nil without calling Grafana", func(t *testing.T) { + t.Parallel() + + s, gc := newServer(t) + + addresses, err := s.reconcileAdvisorContactPoint(t.Context(), &models.Settings{}) require.NoError(t, err) + require.Nil(t, addresses) + gc.AssertNotCalled(t, "GetEmailContactPoint") }) - t.Run("disabled deletes rule group only", func(t *testing.T) { + t.Run("enabled with no matching contact point returns nil", func(t *testing.T) { t.Parallel() s, gc := newServer(t) - gc.On("DeleteAlertRuleGroup", mock.Anything, advisorNotificationsFolderUID, advisorNotificationsRuleGroup).Return(nil) + gc.On("GetEmailContactPoint", mock.Anything, advisorContactPointName). + Return([]string(nil), nil) - err := s.reconcileAdvisorNotifications(t.Context(), &models.Settings{}) + addresses, err := s.reconcileAdvisorContactPoint(t.Context(), enabledSettings()) require.NoError(t, err) - gc.AssertNotCalled(t, "CreateFolderWithUID") - gc.AssertNotCalled(t, "CreateAlertRule") + require.Empty(t, addresses) }) - t.Run("enabled returns error when datasource lookup fails", func(t *testing.T) { + t.Run("enabled propagates a Grafana error", func(t *testing.T) { t.Parallel() s, gc := newServer(t) - gc.On("CreateFolderWithUID", mock.Anything, mock.Anything, mock.Anything).Return(nil) - gc.On("DeleteAlertRuleGroup", mock.Anything, mock.Anything, mock.Anything).Return(nil) - gc.On("GetDatasourceUIDByName", mock.Anything, "Metrics").Return("", errors.New("boom")) + gc.On("GetEmailContactPoint", mock.Anything, advisorContactPointName). + Return([]string(nil), errors.New("boom")) - err := s.reconcileAdvisorNotifications(t.Context(), enabledSettings()) + _, err := s.reconcileAdvisorContactPoint(t.Context(), enabledSettings()) require.Error(t, err) - gc.AssertNotCalled(t, "CreateAlertRule") }) } diff --git a/managed/services/server/deps.go b/managed/services/server/deps.go index bd485d00b81..5e49e2bd097 100644 --- a/managed/services/server/deps.go +++ b/managed/services/server/deps.go @@ -22,7 +22,6 @@ import ( serverv1 "github.com/percona/pmm/api/server/v1" "github.com/percona/pmm/managed/models" - "github.com/percona/pmm/managed/services" ) // healthChecker interface wraps all services that implements the IsReady method to report the @@ -35,10 +34,7 @@ type healthChecker interface { //nolint:iface // We use it instead of real type for testing and to avoid dependency cycle. type grafanaClient interface { //nolint:iface healthChecker - GetDatasourceUIDByName(ctx context.Context, name string) (string, error) - CreateFolderWithUID(ctx context.Context, title, uid string) error - CreateAlertRule(ctx context.Context, folderUID, groupName, interval string, rule *services.Rule) error - DeleteAlertRuleGroup(ctx context.Context, folderUID, groupName string) error + GetEmailContactPoint(ctx context.Context, name string) ([]string, error) } // prometheusService is a subset of methods of victoriametrics.Service used by this package. diff --git a/managed/services/server/mock_grafana_client_test.go b/managed/services/server/mock_grafana_client_test.go index 8c76377503e..fe3bcdc4a6a 100644 --- a/managed/services/server/mock_grafana_client_test.go +++ b/managed/services/server/mock_grafana_client_test.go @@ -6,8 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - - services "github.com/percona/pmm/managed/services" ) // mockGrafanaClient is an autogenerated mock type for the grafanaClient type @@ -15,77 +13,25 @@ type mockGrafanaClient struct { mock.Mock } -// CreateAlertRule provides a mock function with given fields: ctx, folderUID, groupName, interval, rule -func (_m *mockGrafanaClient) CreateAlertRule(ctx context.Context, folderUID string, groupName string, interval string, rule *services.Rule) error { - ret := _m.Called(ctx, folderUID, groupName, interval, rule) - - if len(ret) == 0 { - panic("no return value specified for CreateAlertRule") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, *services.Rule) error); ok { - r0 = rf(ctx, folderUID, groupName, interval, rule) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// CreateFolderWithUID provides a mock function with given fields: ctx, title, uid -func (_m *mockGrafanaClient) CreateFolderWithUID(ctx context.Context, title string, uid string) error { - ret := _m.Called(ctx, title, uid) - - if len(ret) == 0 { - panic("no return value specified for CreateFolderWithUID") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, title, uid) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DeleteAlertRuleGroup provides a mock function with given fields: ctx, folderUID, groupName -func (_m *mockGrafanaClient) DeleteAlertRuleGroup(ctx context.Context, folderUID string, groupName string) error { - ret := _m.Called(ctx, folderUID, groupName) - - if len(ret) == 0 { - panic("no return value specified for DeleteAlertRuleGroup") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { - r0 = rf(ctx, folderUID, groupName) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// GetDatasourceUIDByName provides a mock function with given fields: ctx, name -func (_m *mockGrafanaClient) GetDatasourceUIDByName(ctx context.Context, name string) (string, error) { +// GetEmailContactPoint provides a mock function with given fields: ctx, name +func (_m *mockGrafanaClient) GetEmailContactPoint(ctx context.Context, name string) ([]string, error) { ret := _m.Called(ctx, name) if len(ret) == 0 { - panic("no return value specified for GetDatasourceUIDByName") + panic("no return value specified for GetEmailContactPoint") } - var r0 string + var r0 []string var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string) (string, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, string) ([]string, error)); ok { return rf(ctx, name) } - if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + if rf, ok := ret.Get(0).(func(context.Context, string) []string); ok { r0 = rf(ctx, name) } else { - r0 = ret.Get(0).(string) + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } } if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { diff --git a/managed/services/server/server.go b/managed/services/server/server.go index 2d924a02316..b59df6e20e3 100644 --- a/managed/services/server/server.go +++ b/managed/services/server/server.go @@ -629,15 +629,10 @@ func (s *Server) ChangeSettings(ctx context.Context, req *serverv1.ChangeSetting } } - // When Advisor notification settings change, reconcile the Grafana alert rule that drives them. - // This runs in the request context, which carries the Grafana credentials needed to manage rules. - if oldSettings.IsAdvisorNotificationsEnabled() != newSettings.IsAdvisorNotificationsEnabled() || - oldSettings.AdvisorNotifications.SeverityThreshold != newSettings.AdvisorNotifications.SeverityThreshold { - err := s.reconcileAdvisorNotifications(ctx, newSettings) - if err != nil { - s.l.Errorf("Failed to reconcile Advisor notifications: %v", err) - } - } + // Resolve and cache the Advisor contact point while notifications are enabled (so the background + // batch-completion path can deliver without Grafana credentials), and clear it on disable. This + // runs in the request context, which carries the Grafana credentials needed to reach Grafana. + s.syncAdvisorContactPoint(ctx, oldSettings, newSettings) return &serverv1.ChangeSettingsResponse{ Settings: s.convertSettings(newSettings, disableInternalPgQan), diff --git a/managed/services/server/server_test.go b/managed/services/server/server_test.go index ca1af628686..f74a19b78fc 100644 --- a/managed/services/server/server_test.go +++ b/managed/services/server/server_test.go @@ -88,10 +88,7 @@ func TestServer(t *testing.T) { var mgrafana mockGrafanaClient mgrafana.Test(t) mgrafana.On("IsReady", mock.Anything).Return(nil) - mgrafana.On("CreateFolderWithUID", mock.Anything, mock.Anything, mock.Anything).Return(nil) - mgrafana.On("DeleteAlertRuleGroup", mock.Anything, mock.Anything, mock.Anything).Return(nil) - mgrafana.On("GetDatasourceUIDByName", mock.Anything, mock.Anything).Return("ds-uid", nil) - mgrafana.On("CreateAlertRule", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + mgrafana.On("GetEmailContactPoint", mock.Anything, mock.Anything).Return([]string(nil), nil) s, err := NewServer(&Params{ DB: reform.NewDB(sqlDB, postgresql.Dialect, reform.NewPrintfLogger(t.Logf)), diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 251b149296f..146ab73719a 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -464,6 +464,7 @@ const AdvisorInsights: FC = () => { data={data?.results ?? []} rowCount={data?.totalItems ?? 0} noDataMessage={Messages.noData} + noDataAlertProps={{ sx: { justifyContent: 'center' } }} manualPagination enablePagination enableTopToolbar={false} diff --git a/ui/apps/pmm/src/pages/settings/Settings.messages.ts b/ui/apps/pmm/src/pages/settings/Settings.messages.ts index af704a89aac..fface2ddfe4 100644 --- a/ui/apps/pmm/src/pages/settings/Settings.messages.ts +++ b/ui/apps/pmm/src/pages/settings/Settings.messages.ts @@ -43,7 +43,7 @@ export const Messages = { 'How long PMM keeps Advisor check results history. Older results are automatically deleted.', advisorNotificationsLabel: 'Advisor notifications', advisorNotificationsTooltip: - 'Send email notifications when Advisor checks detect issues.', + 'Email a summary of completed Advisor checks to a Grafana email contact point named "PMM Advisor Insights".', advisorSeverityThresholdLabel: 'Notification severity threshold', advisorSeverityThresholdTooltip: 'Least-severe level that triggers a notification.', From 807d89ec45dd59cdaaeffd5f7e2b12304ef9dea6 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 19 Jul 2026 01:46:22 +0300 Subject: [PATCH 038/120] PMM-14109 Restore managed/Makefile --- managed/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/managed/Makefile b/managed/Makefile index 02a3aea542c..8970e4a5e7e 100644 --- a/managed/Makefile +++ b/managed/Makefile @@ -20,7 +20,6 @@ PMM_LD_FLAGS = -ldflags " \ -X 'github.com/percona/pmm/version.Timestamp=$(PMM_RELEASE_TIMESTAMP)' \ -X 'github.com/percona/pmm/version.FullCommit=$(PMM_RELEASE_FULLCOMMIT)' \ -X 'github.com/percona/pmm/version.Branch=$(PMM_RELEASE_BRANCH)' \ - -w \ " IS_ARM := $(filter arm64,$(shell uname -m)) @@ -42,7 +41,6 @@ pi-validate: ## Validate Percona Intelligence advisors and checks release: ## Build pmm-managed release binaries env CGO_ENABLED=0 go build -v $(PMM_LD_FLAGS) -o $(PMM_RELEASE_PATH)/ ./cmd/... - release-encryption-rotation: ## Build PMM encryption rotation tool env CGO_ENABLED=0 go build -v $(PMM_LD_FLAGS) -o $(PMM_RELEASE_PATH)/ ./cmd/pmm-encryption-rotation/... From 105552b28fee7e2ac004423a63a5ea5f93133764 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 19 Jul 2026 02:30:04 +0300 Subject: [PATCH 039/120] PMM-14109 Update binary descriptor file --- api/descriptor.bin | Bin 828599 -> 830200 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/api/descriptor.bin b/api/descriptor.bin index cc221296811765fad61ebef146c377439e3faa98..b6601f04dcd9bf8c230376e769cfc630f5e3f86c 100644 GIT binary patch delta 26546 zcma)ld6XB`xo!8atE#(erex3-p#d3trn{ND8!;vh5j4?wbMKXSpF@&&b4}jOz3<(% zUJ^h>L<9km1B!rvgdhP4Vv8sO4hYC7GRP<)h)g1afFQoTPko2V`{S+k{%|dJRek$A zRdvoj`+RkNZS&fm=RfW_{IUGUa<3N5TW=lRTzW?-_=lwc4nMTmOGE*d4doZdY|@8>_V%+}-k;_x;BD zOU_zX==M-^^C|83oz|NpwBfBn7n2VvY|xh>V5Ev=R+8f6V` zzT*$pOvl<_;js@Wwc0kvBdv!uO<%U{> z=K?FS*0?#>?c!R5L~7VXx>sLgU=d+SliR{AW@OQ# zqAJ<#9x9bFFG2DM0ESOg%uS#z~-?)UX+Ly;`VjXUL8$VSzr2 zgnTtUas{}r9d7II33ow}=HB79xlt~#z`e`OIc|;S#!KJjs+v_+xvH9CJC(cKLf2dg z=3QanPzo zq=U%4ZgJYP01>&@P0ULxMCAVL#TF8&#e?m3_w>jWB65HB910P+pASBL4uyCQ`?Kdz zm_CR7*>flY^{1pxp93xj`kq?cZ1q5oECTtbZgDJZMIiswy{e^w`s!9U%0n(n$v<^l z50VRtLH<`aSLpso-*GXKy6*$~_Fg@5#i0JHTXeO#6x4rpuf0y7i^#w6DR7+Zph+ z>s>1;^Yyv5-3Dw&J<-l;>?b1~k z3hRGKn2;gb4vy4`s1CD%(O4F{3* zlAENX84wJY-0RvI28@MEZu{HySisqIEL?I+e<&B&AibQWz@xpaemBEz9C|rRLH)R# zrLd9Wa+bnIipyCFJ56ypOW`2Ja1VFEv0RqJV;JtK5v`nZyi1DDa8IT#Kx7*3#i_sm zBGYhBW`(j`A&4F!5j75wNS$is^iglm#JhYXBrK$CcoD#Or8YOc8h_Jmy`S4!5#gF&G{v1E(}VB6a&u?RF0V;FccG zh$twJdsp61F^C@bt}`twM)JqK(!uh6iqnVpxYyx!c|R^PJ&`>;C=SqIEriHLJ$fR` zMFD!kOVW{vv&i*?*Vgm}7rCDBuJi>r&Gm$Lr7w8M^(1pq7t3-`D4?z?-eKQ{SLGqs zlb)A~E+BF}>9t4|2N1cQ^sY}wdRfi~)l;ORng9~1jmPYcg8)GERQ9f@WKVhVl}Hdh zmK)}Qrr&cY2D$Sg2J5A#`QhJsj@ zgSr7#suq8F(EfofuQYtXxiYVoUfr#@vlO5sG$ zGu@Z!H_>aE&IdRPo{1jjgDR+BdEzK9Z-tlNvx6G(tld)WonyCdr@W%nwv}s@o9bZ( zq$2}Ntf{KSOZNBfnCgiY!$B}k^~8z+;ssCj#EKE7R&1&#R;)ZnEA~7|*>3@f)P0lf zcK-mNkvK9ya6fOx9w4}%_r#GArrgha;>gN#bYw4(oAUr*;sDK5*Uq*3KJLQOu)6AxCNqX(PgVe+J20TO8sRtEs;Ii8p>Kv2)|#DtaS zXu{?)k^%)tl$tOAM9%fZgaIOQt|um}Tf=0PK2!c@~d%)awH@nEj)=o1Z-g@nG|_=Rgm(fYj-8z~w;V!OFD< zTi}TY0|fa3Pdpf)zFIsOp?=5-VS|t~H;=uqDYax0fJs1Gmz0ea61_klwW>x*N-L10O z6W@k|2x<1jx0P!lTE-B{6kuX4!`pn`zC~?%8Qox+C+-cW5V*_}_g1czXSoq2z{Fba zY4?UcOBq`3iG2e^`hAR>H7L}Rqts-$& zdU<~p_f~-vD?M3FR%rLOnysOG15B*dUh3We@CsHNtp!BnYERr7AablW!=ggFw|7az zaSoVR?|Rz3-3Wk&zw3#81JozQz5#;hT~F*=MUJEReG<{W0TQVe)9nfnah$%NwTM~X z_r%5FEQsFs#Kl$Q=;A)`#Ki#;sSzOR1%Sv8JTY^C`lOh-iX6?{y6j$3G+13X*RHuA zXVHjtW+n#&)jH!E0713R6ITa_(Y4OZrLKUB9bvilAFFiSx} z`Y=mDLHaODL09)-mO@lPhH(001$1?h$v{Ajjh935N$TLt|CWUw>7(I+`v}ax;ngKO4-)z)@kmx z8gqxU;Mr=-U4=Gx+sMO75)g}jF?RqU+LjSfskUX$kV>`9m^)mICTuh2j!?g*ZN}VH zz?I{*-UlD#o1Z-dm&X6$6qvs>{;yK|zpofbDFaNbuTuY43xJ3CmGOUoi2TY-bd_2$ z&+>N4bR^XDtZIDSt{8IGD^3@kxCS9-z4oQr%K+jw&Uzh&=%pi}ene-zj)Ua_isw0U zvU*TSVLj)me_Lbs#w(?gp7V;+B9iAvi4IS27p)ilrNPRKtw*}iw^@tj;DNCo>XZcHjYGm-+)+K z`>78DK*PuR;==&-N%3KTAR6b353ABXY&?nR!vL|e_ER4QfEJCMN!zTLT!vL|g_O%bI1wiCPUwjy#J}Ew|O8c-$Yy#B?FtH}7J66~OhEDRmw5W!I zV3_1f(FPCXA3emqJRFwqKL86u7U+z8coasaNgaww8aB0Y&sKB)c_L< z=ojkOYw-1@a+U4eJ3UK9L7DC+X*m_wBGq)iS0BTKRMY*wKbKTu&!+qR9+C@a&t@`J z+Uub>GqIYt`!&tXQc!tj`cfyX(#kW_m$hnDj;3oC8ECoyHA+p_AV55rS-w=%06{g& zmx>x7T06@~N|iQUb4b-)Q$dR6s2^^zJA;RwYfjcAdagNsl4?87f@h9jk(QXNwC9>j z9!e7+$`I=EYP(0n+>C*qYp$P|cS5C_>zAjqLsgERYaSVB{{V^9%-`A_Zv;RWoaajg z3=l-~e5rr|f@q#EtMMvrz2=jM<_!?_2n-W`(*(dh&Cfa?o!5L{s(UyKqWQjj)2vRM zMSk99`lg!pi+ovyR%?Y@OcADA0!*yMzW%2969Din_N9;p2)@O>6w(0EGZy<&NFz)w z&0=2)Y1P^;Eg?782!JRg__~mGH-JWBmjJ=N#0)h+a4+$tkVcqtFY%?2R;_h#DY+?7 zfG8@c7Vp6>E%l{}hJzqo>Pt-v5Tr|esc8}FQM1&SnpU;8OU)T4qJdJogcegUn=^6> zW^+bPzto(Oi(hKa$my4s`Qn$Vsi@2Rv|t7R>SewZ%m6{X%$I^$wKh!48A;s%L}kL) z1v9nceN3>+eW{n>6atr<38`B9rMGxLlp8=)Ce)Yj+ZBV~^2IOVAVS{q#V-NkHs12Z zFA?fz^p-Dvsah{K-zF!O1u(JRR=-+fHx7B*7o&uO;C$N`qXY=fw|y~6gqrhhUyM?< z*1lEbq=Wz_)+z`z>Uy;Rcr>egDeM7)dX+DQy=rZg-tnbC2AEjysGogc-&OIBFO@MI zM94cvZK}0Hde4_q6<}h$rw)98PmJ&RQlr8_guLfVjjCEp&>Fq~4naU{6~L>*C&oGe zv~P_sr7A!~uJNT*Rjoy5J?~6=BjChZPj580V!g3NIEa|_M#HMLE!w~sY7byyZJ;f> z9uI?(v%#1nKm=|u=BQfB$|foW%@JT?ZK65qa?2)Ti*OJjn~W{0Nt~^I-dAFaYCyi# z*rFP3i?)%Cwg?cbbg@MM=!4sg?f@cko3TZJ$g$1z!WwOhwv&i&7Z6ME)E22z>uslD zyKzN0rO$~g0tC-?t^rAB+BeOW3z?tSWo4R*uOeOU^+qJ3Ekj{SXE3c8|w zSqgDQ`?3^tMF*IIuBe9Ma3FO>g8-25K=wRoiw+oDgtN$Wz-V=iwnYa?M0o<_iXOJ8 zuiC#6?&@GhLvM7@cq3d0nuEq0)o5>Yh%^){z{EO4Z&Y#Lq3o6^28WC*!ZlzxWLyy- zV~i^z)KB%0aYZ%S6&+>@Y8PN)0i~|!en8yx;Vc(z(P3kYa2B}^8(Rd3T!)Pp0C(*?{9&V`z(x8(V~Hz;N8yq8e?BPLhGr z1ejPSX^XDE5&uR@PG&q*s*}bX;VgJg8go>m&Cx0H&>R6K)+sSZ0O*OQj5z`X(J5n& z06}!hn4=nPj!u(^$_$9@5n_%2(4x~>@1r?7ZOjqQg6K5OQD3YNdnV2~KToOOY_>?-jNkgLhX?6rMjlA1FZ=SDk%x3o|IU}sj6Jn$dL%%yn{_f!J`$+k zZ?kV1@<WFcV#NS)3y%b1#RxU&BY{}4p1RWiSRif*5E~1E)GYzv={y#QTLJ|2 zV}ZD(p4u%v&Pd7;Ahr$!+AY-rAoB4*>=Ga%9}i^x-ZST*=RFaKGXMlq2R^ndtDgwO z8Q>s7o(N=t-BY`vCz*`>4-kcgAct?&v+edsN5OkC5N`m8*e3(AT0OPvd5W>DsRE*w zpvG^<_M@i)`GAFk2ze@y^$-D5jif9HC9ipIpg_~ z(%uF+8n4Ffusc_b55!yH8ib4wl5_`CPpvHz8PZ<256Ux99oS)a7(6k1tyGwaLCbVo z5khbi6N5H4>BS!Y0mNs0Rr8sB=Z*L`derlQl!O2g_X9rReBGlbub|598T5Wq?%2MFIfCj5!+w2=2 zz*&v2aJ{rET9yCh3Qv$G_SonSbNL`wqM2?mHnOR^p$!m}jnLELS= zl!@qKYAHNRRfm&yCv+fc($YXGJb*~FG>{4pAQCMNq{36H-B2@mIEetFkPxI59ssns zIeYDNL(PFycyJa(%>hhIKbV-h#CbEw+o#$du=}=uGbl=TV%KTGT0zaFi2+Qk6+v3z z0RZ2MKq@?d;9C($g$EE%U_~Gm9>UZOtO%sSQ>RVLN;9nhCe}(!NZcv~pplpuKya@# zqXrP%D+8(U5T@KK1F7)TX<1uM?jPuO!^8l+r+)vb{rz98Hd7ET1MliUJPaT_%<7=^ zd*WeuAZ30h5D&vcy3f2Dh=-}u9%c=5-K2AY66mIq-fF})ySv)^xqa2$xCl42CQD3t zT*JiNHG{Lbp*3cnBGft7n0cyBTbi}T(f}sbTCp?$pk8Y%4Irr38cS2Bg>SvFG=L}< zq?V=^03z2LO9P0=^=AI5(?Yhv7zRMp3xeErdb1*8scRdIWdKC%hCsG&)@kk9#H{Sz zfG8XUxsK^JZa~Ct3SmxiQmRbN1`H`_xfQbAkkWx#X)}oIYN%aIwtd9e|E2tI#ksljZ1&GLx z1KAc-r;W~ztP?|+cF-HOMp0(=#Z|x3;#youB@+6 zT6P(qgtK@cyNpjF)O}@_@kw=hHMN_})G$E&7J)vg6wK6;-Nr2ef_b-bOMqbBo%O;X zW!|0jLN2fN8qunw*x=_?hwbh+?=?ON2f?}5_@w&8IS}NH2veU_kL(A6qV!`yz4l25 z$wr?9$hALw(mf3ajb`B>LJk^-1PJnjria#RhjfSxbVz_$!iz%!KwA$PhXklkibDbf z(IMlI>a{~UOd>iYK&;QjApu~>9L`$AEQgIl!dVaCa@p+N$~3O+SRg8u9wpS?l~(0OC2a19vF8%tHMtH^xm7>VEc(aZ~lWGHr3BqnmwPW|DJV&ojE}-K zNO8&dC_tpRl=U-_q)S;p;GgW#gdgbs1=Q z2nNm?fcQZ~m^vr`yprLetk(e1*5RQzC_oSm587W3yvmi`=_XhyJQK2{}K=6$U#X$k$-baPvpa@ehGAa}Y)k{05(d6bU z1Wc^a&mM5v-i?3q-=Qpv0l_>vl)b}%U>+T|>ZgB`N0>5?4qNxthNPDky)k6w>;#xt zW7OMUVEsNOEKYwyh=U*<6PBdE?g0epn6T}wdi_qQd&8LUx?6;kTgt~~oQNK)Do@!R zhK$WPDT-q=PWqy;8K?N7u^FcYVR<@~vP&MwBZ?b`SwYL>ew?`2({{2 zhOmCxi#i5$y=ofmw(CO=h(k#EY$(+mK*T>AO7*6fF8C+uYAD4G97M>}P>LJ96K7hOw@4=K-XNbA z7NtL@>8&U2>15-i4Tul?YRhT+o&nR%Fu_5DOb?~30SNNxp;XFx>q&bi88~SJ@|*u= z+o`(||3*`1hEml4+JVY=ZM0FiS-scHb~lQL)b)^qk;Hi4rA5Fhcw++AwIh~k$2 zoi7!K(2%*IlpO#;H#bbu4N8EZn;UjYe;^2mw>mfM{9`?W2=xe>8+Q4T9znhJyge_= z2X3IdRLv>->W6Sv<14w?h393t*oEh1xj2E(%W}yCJ}=9~34A_tQ5Ji10tf1$?)cJf ze-j{b&Ceb%=kWPP7;zT4=7+N5q_>{K7m$j59}vG|2vM70-&f^d+it^xjESRQK`6Be zTnnZJq0}aN>q&eenb?;B@v{ZIs*X;_Isi0rVJORHKoBhqW!Ve}qJ<&W7-i7vK8dp= z%v-P4er@+?w>GwG4U5y?so@}qmWHy>0Yn>?hSv?! zQc9Rg>C&*>4f>_^(IVYUQqI(XSaqux&)Jhg>o(aS^ihZDkn z54-&GjGbM6dB#pfUY@awA}`O_+2h|L`(3*2=tV#+OTMrClg0Jw_6v5~o^ORxHtwTG zz+0hwlJBFt@Y@U?s)IoVR8n$>da8}xUv0l&m)5*(=1W|SroCSl+t63~%Y3&B}2gLH6B7f%~{2Pfj znc)hEz)eQ#0nw^WM(X=&soz2#N=TgZ#bI01jKSbMBT+bS=>);MyjS=St^SBu28C`xE85)8FA{HqlWJ$(`}jwj~u9z8b7jl z;P*K{;R>+t&geKic85v&dsdtU-R`hM`rEF)TF3X2j%zwVF8^nIXV*6E%^0ZPd&4CC zsTZyR!(Pg6nvOpp*-r*eDt+0*fqLjqUUh(I%>L|EQo;9|Nd;#?wV#tpH59yG;v5R| zzMbS$wLcUVr9WNhr#t6iDgeDUAeQFhwE@6(*k}hJ*bW=*07O#`8?Q~6%J^a9wfkuq zKSFMLZ9uH$;k7#sIbvKkj)C)taoK?2JYrlnVaj>Lxa@wq?;a&5{R1GD?dr~ar^Dc* zX1>8ekRCO!6cD6G!|QI-9)VEzo}*#ATlFLEr`7#9IXT?`a&5md-|0N~cqsd}aF9oh zHw6Ue@lf_{5o*rkq3ql0r(Mj+tetp?Clx+rbf`F)wUfR4WY$iaky8xmteZikM&z8X z)u+PZw0rf_z4esoUj1}mJe`H0w*qxk)0Y&N^k(9b# zSX~?auLH!*e`6*9K*WAyCV+l9{_TrP99eWmfJEsZm-xbRoLep#ua8p*ykxw7|HSz& z%$pRY1-kx7@m*My?n>>ir-2a>I5`afCf10Eo7;cVFd~vQF^(c;L?mV(5bPr&G5h`X z4Dcu^I0FD;4}ZjOn0*@_jl}2Us6H${9}pCeM&k4PYw;gR3W`4<_Vh=o&j&!i8kx0) z{39dr`8W%rk&&$U`fKqY6^YLW#OgZIKEDnCk)tB<`GESQh<|@A{-fChj#EIao+EX2 zp;J0^bR>QoM?o<Zr<1jXn`ibsIxIisU4cj<9UsK?mosOyjQxb3f1e++YQ+yY`T z9jVEM&h__>$#PKc$3(KT8y6wRm`Hp!Aaaa}WM?;_&M_vEo!$NQd@we<4|JKas!fs8 z;fAqU3XZX{*==x)jm>U@e<0#%GH_V;=NJPjFKMHymK3*EPZv3U)6*FjCxfS>B>npw zxEfqfM?KO%JkVd8`3V^p8V^*a$NLXB-f;zD6T*ZjN!1=_K{p}lp6o%l0l0E# z06ik6Fb78jAh!7H5phQy02({R^hH2KPBG&G5ILrBTy#f{hQxUx%6m^WxlXtCFGRAq zZqO7nA}AQ=FF<^JkJ7Jg0N|SuNv#MFd@~}c6#?Su&4{E{M3@TMj7Vxl4SN21k=*QG zfcRP;rC-|sG?LW_Ah=(Qq<{bj?iVBZ+C~WO);uI%+ZyyRoK0>PCjb)%Xs&wNb9y~A zJCcP8j)Ql0BwyPA;kIW-t>;Fmv*v-c)pH{G+Qvh=55E-2*R}>dzs+N=dYucDKsTu` zS~`_?<1FrEUY3#LcpfvdKjAFyWL_joBSK9+FOsEEgP!Q-M-Xi~96&5%qjcvG0I26j zvU3O!)bk_RInr=L{h>6MC>b(l&~7~(E1Bw(^rNE z^Os21lMu;q_LoTNNq~s_OV%B@Kj2l4f$!<87-z4dy?5G8YE$Sq170=bwLuTFSED3d zRRDtL)u?MayEN$8?zOB#VzzrtwTPU~m9IszJj68!c`cG%MGg96+v^OW4g)6E>qxx= zKj!>Hy1d=vD0pk zKE)#V8b7|JVBKVt;s-ErkQZpa4E%37f z{$?a)RY35+8I`2OJ$`I%mx;|S0WI9kE#~{+O#r~`XC@8S4OB0rjh)M2CJi7iQdfI zkc;uvJj%VRKE1}NQwNZA*y`xo^g{(sB6M|B-BT~I0r`nNs(m*~m)Jb8sHhc>)x8TL zNL&}sNFQV0eH*sT;5%YYEvm7_)+Fz_7uL?M7`@HW{-5$R+pzFjQ|cE(Hg9G!mE6s9nky zCgqR@OdOzXRN?AjfOrmD%-94(_AQaDQ2{}hjTmbOIgw}~|KKq}2!jWqL+ z?uj26X>QaOW;+`|X$Hg&{3tiLq-*I<)K@K?>U+0m=_!fZv-Fh2?M%=9g-G=I?U5{z z33aCJkt~rLwUOD$Ow?&W?9o@lTRF7@c4p6){by$+8?SH;QtUJ;)~MIApOAri4Tz2W z>WfxRQ^O}20~Pd>NOoM|8ZdkkNkzU<+m}6Lpbi3JSAL`x-(ol21b}PLSdk{wcw`orTvrl3*+;)8so zW}L9wKLCKX9?UZF`{Th#wn*VDG98R$ixeO-9n4;`X!61ACG#&_9bzU5XCpQFP^1R_ z54+z(0LXMG%S4Gj6iHnjXOZbpBtQHGM5aT=dlTw=I%K?eqyA2Ln3*V{fT#sTxz1|w zcI##+2nGCb)+;F2hqGQmxjr1pevn4JAL|II=t2Qe0!UpbdIh&n95F5w5JX3e3k3wx z5xUTH3{ahq8jWp)Iy*qesj>Zje$>b-jw9-*kyk(r+@n$LagkRZ(DHgTsyi<7D#tiH zj!|CIbo|o_C)sX#iAG2|Q2G@V01x0~_5k=77EVU;6%=RDf|C)xg7$#3ZAzT4qP$7! zw6eZst-@zH3DVgD;)nI(YyrS`);L>0@SQcz77#D*tZ}x4sSuqt&bCQA z+jHdR_yNQ(>r-cYH-JXsYyrW2&WHdYxX&49OPF$>GtRb2JKGE7<}U>Su`yq*y4D$R z=LO?6a1f*yjL8H9=>=m52z76}U<^T%cCZ&SPDBIgUkaA0hub>W47r$bQ{pdX+%&Kk zGj1`k7c*{t5B=7d$tD`uZ&Nc_3xH?wtud2;p#IiOI88Ylk>9Zca9jfdsp{*TE|uRI z8-Rld`7T1aoPDNA7i=Dl;XHn*LqPCotRB10xxMnySbQ=rLd>JF_~a(-Sw}L4x(kRE zdYt-X05ou9EIt_!kt1U%B{XSG9TnqM@HakySg^;c>2Nhefmiktc*4WXcX5|PFOZ7PSGyRKakW+F;$MOS3K#-4)<=4J|ARir957i5M zLQOt8uDMs961R1XAvrxo6EzvAmD)1JuBihA`IuM?FCfUr#A0}xw4jdV)8eQE#9BPo zJKE|25IHs$e-DVrv9Z*WnzTSpU{?L(L13(vV>R#rdxqLrio(@|SpKpCP9btaEW37_ z^!C$d;+(JliYg%1#wx#qQ+dlXabVs&Memsy(+*e60~2R*oVPemYe)mptjTdvCw=z= z(-m`!Zp9TdAXdR~`UesK@MNaMQb__tP#k~H3+L}E_B0fey{5C$;yWv%1 zM_9AxVksx#ls+fc3=lle#ZpchsIA#F@=%}w@pW4b@91=Im=;TY00+S^EtdKKAQ+~_ zQp6sZE5N9lP6lcMAd$Lrgr9Wu<`C+xGd&iY zGf+FanOP>}#oxu~xxV0~-+E&13n~q1WU6%*oy}XP!B+*eYBJ zo;k7Ds)5>=%_R?qIUqiXtNhMR#eH+Ld!|s#jin5RYrrr!mNFP1?s;x3WiUehSm(x4 z1{EiSrE%#CcrgdSYWhjp!RMH$-qC542Wt%oaY-wDS{*~Puv^Km({qjK%h&n)=8=#*A5C~t3rLF`B!q;M{ z@&MwUycW0auZ#MG>8$=*+@_zz^N)1CPFdxb;u|>Hfm)QPuev%leO`|X@t2|S#Bl<| zug6jBx@hSjeE5#@+UdUnGYBEeqG0yRJMA%~=_@&_<6CNmj-cP0UG%4znt@^dDx|@RfCMcH|*%09VIX z4uND?u+vuECMRE*b@5D}9_E$NA^zX(_Pj*lo z$xoaQ;@n0xqr204*axu_O0)72_(2@$6&f!?)CX~QyWo+suR*^s{7{nDqS!}vnbV@eySu}b}Y~3!6&gmBNkoQArbb1IRTjJ8&q|sbg zZ;h>wuQWQR8@)C5KF%7=V+i{wcG^p$c?9XV#ZIN$OF!v?#Mu?+4ys?4IrYPKWltLa zTLf!Y_M|yy?BbJ7Uo<8k=abmli}Y9NXI+ps8wb6;Xh7OU(u26a-Lcd0|2hUe-4i>} z-?8nBtxtb&{Q6j@Ce9{#m+yuRr+SIGe-dWw|c6lUt}i*?eG&)^k5=_YfHM9-Xu9nAO6pO z`)?2ad+DzqD%IIafBA6ffBfRX())k)pTGT&2mjrLm}?dW7PU6000=I>7#fRzcF4OL za$8`*Iu&$)mQs4Hq=(fhuS>o@0mD@XUvrP}I_d%RRyJUH%N)PhlXyqH|day9B7I~4aDR_6GO-w^ z-c*Zm#H*9`8g(wHE7e8^H$_RWxB8g&YH7CWy*{SBsV-kt(92=bkav*kazXD=?K&0X PKNtUb&Fwn*Q%C$C;5fe; delta 26008 zcmZvFdzcs1m2LO0tE#)}Z3zesb~hl;em{6MbT?>>!6<0d#EDnOnCMIgR*3e^txxwQB87^K;!|6}PsE zRo!FO{Z0S%1M9OSvplcq$B$cGbJW%cap3r=)?oFkpIZ;9){lXq?w3}prv8svTe9h& zH>!VCR!6n=E~{PBeLu78YzprF%l|jHY4OumbH=*hxII;2XRBw^-UqBFvzxm9yA@>X zJk9@M{nYL>)^WS5dvCJ3^MKT=71qe6hkk9j8EadvTSB4j)KmZ4y0Pi=2drOZtH=M{ zYNdw#HOFr1@LyJiFrEI5^&7j>4$Ez&?rnwsZ6#J|(?`Rs_npkQIZZE&vc_hs=YC_| zrY4WJN}BeKwtkhLY0hmLGQnzPOGMCv#tA2W`EFh{|okV z$E(JP^h})1Zq}FT*OTn3qRnnzcQ2f@b_V7VENFCZaPuiLZ(&}Tp{Di?azr+`w-I+|<_6m~SIwMj7yh_sCYw?Ijpk5r zZ*$w+WFWY=xozu(J6pK7x$OqX5gBlAC+-I3&Lj@dC$6PhX4<`m^~_|zzunEh!5j|$ z?QW~qZp3Gu$)n@jeB$OvhKyv`;ac6?*v-QUW%726Lex&zsuYqOV1iHPT zy!h^4-*@j_#ZUd@-~R1Cp8TIbD}F-#;}Y9bS7+KcJEYL;dU+5xt<4Bi~`iK5*VPAcEE~5Y9 z=3YM>(SLD^J4v*MOZ$bJY3-JBv`0t{+G=-0UJsF9xNSO{LlOCf+toa`KJp%+yj?lc zC!|__>E2wY^ZJNB;^uacXdlr>+@g*G14JLA=ph^(FzTWX%(3r4<^ZwB+}t8_Fk+9n zoo*2rV$3Jpj4Njx5>jWHtxh#PGa({RxSqN0AtFz>HyOo<5P6EuwvMw#Kx)`@d%)mR zZkw*c9wFqE+oQzwAzCGgbK1>%!OM0%H^(Xg`Dr(=gpVxAWZ_Zxn#S<}*Z>KsC-1cH zxfKBC_qFTkSqg~AuiaSBc0lC#+RXNnOg4zVAtIXXfIupqVAtM;e`CboxL$inNuu?Q z+o6Yn;Q7WaEfbgl&w1jhW*%tac~||Uty2aflB@ISfGEj%H`ezSy&yX8cI_raImr4~ zH`88-(D_$a?Eq0t39HFp-3}GzQ0}a*5olou-_j6Bp-N~#->T1N+6|9=>v~!W(TLpN zx`}?)0m1OCdvl>-z@zf5TXZ)+D(KaZ%C~OuU2=d8(#vTIoEOlLf^s!viQR!TuiaxL zJeSjiq&1h*gfx7rngbos3rG)hSmt=5luDa^L61!9l{DbWbxSC#7 z2Z^q_u@)m7i9}b;JEbI(3!Y~@@Q@q=0;!=(?S8mBBwNpT*QZM^c%JcMJ^#@Qo@cyH z=4R!A=UL*>(*?tS)>BVDWY=KckybtHUBA?%O3!+UmJalS=vlA5ekMyY`5=0Zi0JhQ z2&4wSZ5RDB{tcezQXZ0^=e+B;EFV12c{iK!bRp+hm-wudeqdiZnH6U`0_HNMP1c+Rty<4;*lw^ERjUg&hSU^Ul>Y@H_ zhdW5?&;+_M>Fp!w8{@^-<3TsZgQDnz1JI2nIug#345V+Yr=~w_cf{=@Ssa@Zkq(aa z;w~l$-WcwDFn~Bl!sJtoEK~9MlX2Ac_l_RBJhk) z&kw3N-cvvM!0uFAk|D($?|EiMM<5#SwbCyW^nz%-hnGnOw6ZjDUiPxyRqI~2%Zpz2 z^7N=nSqhbh*C!b~z{FA>8@vYqz^6Phc!1zjo)|np++^j6!6T>*p7O-tm1fA`O(t%d z!GJ(&#$3D04<~!#?9d3($(}enK#)%M#Mu$lq?0{ycBL$puMjD{B>)o#Xqsmg^i&;J zz*wK&XXmMZSz_Nf44p{%iYG1)5V>CQ#N`3P<-OvyndWJiM-4jLR8L$UHL=Tk)f1Oj znjx1rgYwh!4an&Bf}a0hmsg0ZNCt04ItVg&GiVSr-_VN_p5ckXBgpw?cw+EMGi2~) zd3YDo(+NmO8$19|&+^3J0fKs#CkC%HLpnQ~B1zEz39-Se0YKzzPYfO)B4>MI@Jcge z@aClFh*>sA4SLtEtwk3C=Xhf901-IH6N6XEN;x;Z;}Frgo_gjBtMGpGA#!ed9Y{9k zrq_Xd-rV#$h|imwUI)_7H;Gzb2OR#UIxx?!8TzItzOIxN^i5BE9UvX#iLWEb*Y-_M zd|fH)=v$unI>5ww%VS@s7QJOV(GVKzU7InD`hoYK$n(82QaY~cx>zX=(|et zxWE%zhkisapeIrHlD;jbv_I!)sNZ7MZ@&GDvc+DWet1h+KpzSI*7h(=^t>WKv`WwlyHV51tBMC3|OOkZgx z#)++>6Vs1#Oh`R5-R?CMeTZD;iT49UJL0|duXIqPuyNvhTPtV>EJaQ@_*}O>z|Oqd}v00Hq#eP~|o1o@fz(7f8qGGqWZr&+>>g40*e@dFtv?%#7{n$&$<4Zd@J$!L!}CyfSuq zJBf$hk$|Wukjv}x*v^!J{N2vBf-;Rd?FxtTIf|ng~0N}`NGQ@rP^<_3sm6>`=+8V zjINfmb{?U3FquU_6b-~I0)X_0F^hm8Jz~rvAg0U_V-^W&r**`b#d0=_$BcCVL{Wjv zV$p;6HvwZA0YQDtJj;NfK4vT-{IorWgDL0}|d1^*Sr;{q&WZ(Dz4#40~rTnDPr&4~h zf2UG@v45vheiG-e=w(b=S5EJduf+ZVfch(A{{TV#m9c;2Z2!(sBxxLAVx7_UuNDB2 zXN>&=MC2Ls)+=ZGcb3kngd?G^XFav!r*_vLp%0N~y?nh$1w`aouc(+G9YCDUS+CYhTkYT_2#x*ttQaL&uu%P2r3IOmm>n|LHR z=T$r`3B)Fz^D6&`96&bl0wtg)yqs>|1+uPng?q(#Gr+{UqP-cH z1<`=$E5@J!BKnFkXyq(})qMa#`$=Z2}E} zR0=S$CaAmC*#jP(;Cs3_hej|=@TJlN2!;v1cr!rE_6fd}T?q2iH^G;(O9gwgm(mnC zFQ6gn>W6mC&(O>GdM?t4m(pCM5ig~=$fUiL<`R?kQksiQ+C<7l!c{>gZKBV0Ioujr zUrtP~C~3+>U%VQ6k!hkYC4ma|YLkeFbPO=DCi&`~rFP$20YEe{d%~cDd|-v$2P@J^b>#sK{LhguFJZB6zKPSkR^y9 zU*#!&$&XlqD%jFZr97l@fQbe4&(}5X2{d8YQ`3ATGE@CTS836Ud{h12eGMJ*P4)Zz zljIYBH`T9uLJlB*H;wY?hX5)BRH&YQ$gaA*f|sh((p;oV(|oBpq8GWQ`LeF9$dGZH zK~!Yi02yiHhTBH#))~Ik-si|P+HjAiwFcmavmaoo~IJaO-wkewnUeSFmTBO+=(wfT&dXnF_V&J$&9N`~V(ncFIIvZML77TSZbf z+b`8GkBSU=wK>E@W)hIf8jpTp_b8v^OAQT;V3^}e4GjkQbVg`TeOh4 zX?*~gSPOmrNcsQ(BPpc;f_tHPZUDi((3esgLCw9;mr`0K3)^DiCdC1yI>gf-+5?6z z_N8WqMvyM{rCbFF(#5`%s|fPsU+hb{s*?TC(v%a?Oa1G9sNK+|DKp96(v+E;(9)Dy zoY2ygnVirvUz|`S>Ekk73Hs6rfGe@gmqHjIsF(Rt2&-gaYobU}5I~eJd@h8k!p-XuFtOJAT$p0>g9apA?@M(G5Yg*> zsZLe0c5I}RWb*@@SR2Xw%qiPwY!4a{v(ac#CEK1&6hjgMm{^<0_S}NABgNQc%nu*} zHyQI&$>wJZDF&Gzz{J`@=BMl6Eynhs5g}WQ?WszfZGP4%u{~8F-)3x272BTe#74FU z5QPA-Jph=M+s&H{5Ru!B?EyrN?Pgw9vF+JOM0BG8Q2@}kN8R(W?bPoyt_NM*C$0w& zJUfl+sbbf&i+ITO0Ag9MU5{EzJiF5IP>x;3^x#PF>@udOicQaMV|oCwgx97=Rc^PP z%H78Epo{y&^Hj0tX{G`6=K`7DMa_>=Bw%hfO>`7CQ<=K;_AT`*NrXb6+Cru%iXHS}fEYDs_ zL6)bA}dd?&aEynEN7%;RLvja#m#_SN}%i3bhP8FM- zgOq~g3^1{P{>JQ}31@yV%|~)_(3lu*Y*C8WaRcv++6BU^qz{CO)vjYgK!^Z3Yg6gm_JAj}%Yy_r? z&CXGxBC`XSSVzU|0D$OdIwmqZM~&G*FNlsBvs1-p=Qt6OQUN9wkTyHF0)pyzN=4dr z+_)X|g6g<&J5}sr;X&l=A|Q2Uaz#`9FO z=Q&5*?0GH__npj*&xb(Y`j)D6 z>_Pv6e(+x~CIt}u7s#a0#xOv9GQ8lo`PSE;45>k9_^U6U45^9d>_uNb8CJ6=x=cC0 z$2mcH*;j*_?ZHDYr1AVws`@ zX9IcX10wR-K$gYT?0TM~ob=8I#Fhkg?ay}i%I5-k(W4O|&jsS7s@ctqq7bTx0%A)+ zkhz67A*pG5;M+z8@;M5f2ptv3O0SwFXLKNT1`x#uwPTNcfBEP@d<+^9GCGizPc2^SK&%svMBtbp(VLj6StrI)U=a@!DgyLfHL!!zR;~HW zcJ3V;h?&N*2pt==(i@EcaZY1{n{MZo9YMawV}rKe;gwxAOUF3kCi?-1N<)Cc<+f4w z%?|+LijNEA<0l}<#|1a)56gfc9~X#IC&=XE0&(iqnEUT2)j(=GfVhpX22#@@$hYy;Kx#TQ>}#f{ zxxhVL{d&KB=fl&}6!cV2PgBrSJv~i9zGixwLVV5iGzIyZnUsQjO$|NvGgWa5zPHUx zuOU7DGXtsN;25Ns8AuJMh7HXhh=B|ZU}F72{l3L+Z2UvYKvw1tffR3W3>f}k9_bpk zGOrN>sR3YO0hO^D+zyD-el4XUPxD$JJ8IAis@H;&QkkQ)vFdfAqW69csRNK~J^}>Q z>wy$G073P7AVm&9P`w^VJ++42$QwjOZz{mV0xDDoe(bj8%|~bg-5cqhAV=~>AmtbI zg6<6?LN)A2<`G>n(?Lt-1?uimcKe^94@C1)BJv~i(pyT(GB1!lUpN@oXI>zCz6kQH znHR{OuNpQi^C=T43n0o6f!aFCE%XkQ$Pig@N9`1c0fuFp$~{ATlisr1k=cObY|}kUIE~+QfM~$l9&GbI9&j z^mdS^H(l4Vs4ORmBp(8pSjz)ldjSC7@<3`YfZ$smNbLm>BVQg!?S-IzlP?dX_EO6} zWQBPr04COoKyOe7U?e^S5Zo)wd_grm?mKwg@F75}14}jd zcEiun5B_(|n*$L1?*!sQ0O3R43EHd-|BlzmL zE|8)Oy1=|HkfKa2yO8z9g#coauU$wD08W0raUp<+TyI_twY-$tVBYS4iM2s3JYwHp zw!ysJ(TI=@f$XKMW&5#_lF=jtM0G$_9!2GEV<4M!(1?(YL9zaFQk%&G? zklt^to;ilg_>r+X=tSs8f$Y4gWm)(*ouiP9kHxoaI|kqKvGFZ95`iBZ-%`s@`3?#s z-vXFeK;m19kHfd@NGAn7^E-@h!Lhg)JB)83$dh7+@h!EyPWgnmNnHRF3rKtmAnxub z#Q9Yt>6JLmLDmKF zExmALbC9QN?!DNz>>*O}Er3|*i*EtI+}vYcE`W&KV|)uBa_ljavlsi8y+lO51rY0c z@h!zCX+MDRE$HGt@hyPh*=u}DFZM0_h=+U&AlCKdTgugVqS==Yhf?e_<^>0WW}lgi zz1Y0881n*16#$r*@`q51JPQL7prJ%?qLz8<<0BE^q@4QTHCU8-9jf#$uKLk?T;JieFbSKl1k+(S+$WCbVg6?D>JE42AxA~Ij zNR$8*>q{uh9D6WMkzCD}DG|AvFOASSO?@SV!KzBNw zP~>e+8;wWL>^aXA8;L*Ty8_U|j64jY%TN zGxKX>l6rA5<{QdHG6smBbBIX-K&EffOr&Yw7?XrvWctRKBtT^PCY_g}Y2T#tlDM~0tDX`W0C+d@+-z95!5#0iZMyO*(6;fZn_$en7)yv)_X1`VC=k1cp--c3QK_fzb8%l+xHw)A6D5MXE;Hm(%Rc9WzD{-QvQ@;yy z_3sh@5&OGP7K6Pr`555uLz(P=gt+jaq6@Y&`1hgI9ngiq--l9n=#w}T!mQUqU3ch% z6cfTc{Uet?{QiE4IO+Wjh|LKh*B#UXa1MAWl(GZ55cpCkWd}f{cqx<$S08?TPb40C zeFI`Af;xS{uB)FIO2Gk*)Edf*8xRZ=Ln%1);TQKLVxSi{AhsZcdM610F7%{yC`3Og zl)3|YK{UzChd%u3o)Svk0T8EIY@#Ch2E?udb@f{;FJ_0bxJ4rvW{0x41q8$F5UY(6=yu=4 zc_YkPryjUu_bhxP%+qU-zO38xNT3?Q3y4L%di9b$=$?6DzW&u18bLHKl$8!3lFtio zzLiClpcd76Vc{UYV|`h$=MyQtjsdZL$K&_DRagVSNLICg;GSObn zsD@p(ZymBQloBV7LCC^T){lS~&caZtkOX=DEDWUz*_YR(i&IWSFILeNa4t?cX?ibC zIZ1;Tr<|g}i&IXT;Y*40ejX>L%~Cb}iv7dtrJ+=D`|>PT~N)6RN6n`Q6l0>n%&|yJ|bb zn!P!`7WVgyumj?E z6`}g-al0CkG=<+YvJQyI_rf-2B9ggWOOblALe|%Y>gf)4-O#>VMOz!nX9Yk+t_|C@ z=beK65@&swwM%rpA9Ab@^R)i-V_n}sPZsGqAXfES*KY$r!VTsT1w`ZqBkX|4vB3y? zKNj|lL`1?4h_!yGcM1aFnr$@t4#=IN?|>lMX!N}w>-#1mB7FzM+F$e?03+Izj)<~s zGWw2Q5N$I0-jDTti_v#LR0OoX*8m`Li_v#L?i79R$NK&e4S}9RKokVjGa2XBhd(k} zi$*Yf6iQVY5DXuMQdI`Tef=nusxm=-EI$gRs@#ud{bNc&3qU}W4pdQ&b4TOHX$q3_ zk3*?t;uxg(*a%U-45{@FV)#BY;1UDjSNXrqAINHrBfz>Nr6aZ85hnUKr050RjraS|R&IbO5`>vfsd$+?fb&QJ6S#ISdCkVlim%0R4!QLI9-OcgtFlY zjnrz)BOo|iLfP;{kU3jI+3-}Ss|D#eF)a?N&bdy8f3x({RtxFkdgQ(TI?v#y|k#%#VgWhq4$G)VJtpSfY2k*KrN;xDjJO zEZ6m7KyAx&oU-Fah0z7-<3=0m^g^Aql&lUQ7Un8D-|1d{(wKNOBIIN!HN-l-Bsanh zh$XlPHvmrkOC#KXi2TwBcU^}5%EW1Uw8*^x64HKrf4<`kK5hIsx)6BU`0@UUb2iKx z9ce$_A1Tg;d3xt%f7b1D#7Vjhh|luk$A9BGPW?F}lITLxB z=BD&#!Mmmddz@I3vN zBLFzn=Ogj*fFOE45-$%3qUR&jVCaVr0}^LUl=VA#EC%4nF;SittpWU4jHMj(SODVt zf5gkwS^x}oY$WScKtzs>WSt6#9AhJ_Q+pssed4?jWvx^dk<-2Cg-BMx^-S?%1QDZm z7$82)NBSKG0KOL^v9N&PdodCV3y7=tVkGY{f?CU7jN~0w&+o98iJRsZAimbCnZ-`g zgZMXrNLCGipnf@$H!Xr}lSu)@f;Q4ylmS3JEt0QcfS{fh z$=9%YUVqG>NUA3TVx=1CJvjh~oDqq621MixnhAPPv?pg)Bn78>S{2WVbioM#k+UKx zH~}JZRwMiM~vLy`K1;j#ef>Q4=N z5j!W6>JK1d=cLntzP`_;N8mf06_43mHS9*`y94H$2eqD`uenj87Xg4^m>YG|@0NOg z)4iF_M7-(VRN1YZE|qUavb@7F2zfJ-O*-{lV1A22NPq$HWB$l|?D|zJ$GP{d^rq8G z?yX2R>EKwL-CL1t(jmw<{jEqg>C|)0c>!@#l^75|^`{xdn{)tiF&0GP@&G};Ad*cw zfFNIx&L}BCFGyz;m6;b2IW4N{sRX?!Qcu6(_Ex`a?YKi1MN<4k7nm1C1-j%52_w4Sy?XwY{}Q@~Lzx*R=OvLk@S%05irY9&`I2j!aP&t<-ZnZ} zPrp=sJ7T-g8vtkfb|m#XKt#SBp?;?$>9_vNqf7zs_N~vvi37Ak?I?6=)pjHuwmfRD zKN_GDq06JnYF;4&;$dGN)vSp03Yi)f=C!7_+7%Fh#C36XxQ*s~Q{=W{F>XklRZ-Rf z5#t7Qt%~yWlA?jdc(oB@z$C|7t=0H8AYAy>MvVaxy4t8QAV#;^JcAAFQq~X?xfDQr zGmrFUrNXw3Ghj_5wL^4qpI8+@@T`fXcG$pHWgYR5RRP2YbM%QhJyH69?!+Qs2s9fVd7D z%##U->>DCkRsw=*Lxg1|ZI1-RUD^;8eJGMl4O)^vFp^A7JQFt>Np4{0vY7@zk_?Dn z|3~qs=u^zDj(jQrY9-foTeu!+)U|dejyTbesd(NT7sNub0n+U2KFyoDHG{4 zV1hp!@Kk|=KOB%=Uz$H#BiYD=V~}F2QLhGGhHfJU(rG~Y!vXsX9Q@&cl!3H!TO=Eq za10o>MN&C$VAryp7)bvBv9Ui=zk1njyd41NzCAr#64LEP2GI+m?NK-VcY+$&uk0iu zdLaX1XMZGnkG`v~2UTQtrgY?5c1E&ZM*!${MzR62fj{@{B07>tKy2_=^&Om!5ARAD zXdSUDz5FDyyCT_igbDt@1jNq-)T$0n*GG1zDd^kZ z?nrhU;TWXY9m#GZK&056-eD2r-RT{szXsJzDM&9HNQ|2!b^2wy?g;=~j^;EIDRXlq zg>UpCQ*$Igdj&+M=1BZDK|Y!0Nc?t#{!;>!iS!c?HGl|vHtuP$z6bf>zafxL3Hm&^ zC!G?c)q5h@!_mMywf7PgIZr^W{I&DMl%U-XdyVr11kqmOJOM$pmz<}*;UvxbjKDTP znjN4P64<&2_Ze+PJEHa(Z3V@a7jjWtU=#@n#6c9iB7ZVBqf+NO+0%9OXj0pwAH9ulZC_ybAM~n$= zWD|OfxM|J<;+OwqLc9Fnn6aN|1nDvJ!~%l!n6aM(HR&;9KO5P8o*+{C85|&f@lP*s z{CR+4)wiS5ZpaB^4$ukm6UGq&g8YPee-q?ca>Bg78`*B2O1TkzN=@(R3>bPU~m zm2#5HJe6{a%RH5G(kI5RjN@x0m-&@;e7ym1Nxm|U4-nK}nYTk@#zy2B^8f-eYNraf z**Dh$BKC}Vc>^N$OoSRW&80J2>$CIb+W7t9;Ak(KZwT{rsW3LqBZ5&sE-2LKRxF_L-|AR;dsZwkoA zNd{l!422f(UolP<5d2q+Q*C6YdW|j_ znQ}m^$RqiyO_#Io)MMC6!Q z*1dqpF(#JP&OmlrV~L2aE+7`gF*~i>0Wc@W#$vSqxl^nbAc)4sVzmac)fz`cq`83D zEFYs@I5WpCz6}sm<6>Fw1A=N?EbDzhP>qYFbT}}RgC}r2QIUQC5>j`svwNv0yF1RK z<726fpbI?XV{uP_e5lwLKuoRivDg=aJhjHhVqXTbQ=5<`LRujC`96Aa9Veu@NC_sS zxkw2n#Mg6CIcY+gOHA2>G#C9DrvxQFVK*I_vI9* zg}=yet?n*&Zb%lydHnb5oGhG#vnb9iS5K8Y{e~@y9sV1p)DD4J6yLx`jUW;)ipv^l z90V~J7RMI|M1>~x^1C@o0;cI;Hs+(S!t;;e`>@2MYEIDLk#h@DV|m5sm^am33jIt)=O z;vT#?iy#KQGPb@)w}7D@^vc+~Lk68~Q4>g3#>L;2K_kj}C$?5!A9S`wgMKIWR;Poe zHiWH;odOv&wIKbw>7Y?1TpMRTPy;G4=(Q*<$e>Be*Ty$;kr%@vIbIuA-EMj@=ykDm zw+uSNBcvwpE*Z3L0?E3#`1>+wS`@z@TN|zqI>Up0KlV1HgQhlwt&g1|88o#Z{U2ke z-0jU*Iwx^9#hIO|W0liu*rxPK=OA!XdZp>bu!*j;zR`HWIGbbZBc#8PuXTT}ed^R*ms0m~GICgr<$xsW1 zwLNwoq)iey2BX>)XFgXQs-1_2?TQ`#BQ?~Hz+JJf-VsF9uDIe>Nsqru=zJPm&DT%H zl9Tx~_L{GsjBZ5a?${}nlhJKBnLni`Lu`MJt-a~VSbQ>nj=jCtPllQ>raiG!CMQEJ zApb0O9&#)AWU$+!CC(gHjWtgBu$J^>Yy`HXCqpl{7CIUI;L=<2Kx}y~V8hl|MRnAZjpZCe&8c1~vq zHW?it0QE)J`~e+0qwXq4fU`4p)eK?Xw7Ovc_1*G^#NG04peURdWWEP}(fmrc{JLR1 z9G~K-HIwA@2nq}WOOGx!23bi?Ppdbs0_jYazQ#E{yyyl-%(BJo?kPp3J;MU zFQhT2DlRq%kyRxF48nM;tzI%-ErMwAYGu4e7IUhL**xH+NK0$1-e$b4iB^r*+l*HW j;*B}A4wc&I474ET^m_gud*tIk7yo%p|JcKyJpBIvuN7;0 From 928fbd5a1a3f337141cc4273de99f4a7b3f6d0aa Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 19 Jul 2026 03:48:23 +0300 Subject: [PATCH 040/120] PMM-14109 Add Advisors settings page and functionality - Introduced new Advisors settings tab in the UI. - Created AdvisorsForm component for managing advisor settings. - Implemented validation and schema for advisor settings using Zod. - Added utility functions for converting intervals and handling advisor settings. - Updated Settings.messages.ts to include new messages related to advisors. - Refactored AdvancedSettingsForm to remove advisor-related fields. - Added tests for new AdvisorsForm and its utilities. --- .../src/pages/settings/Settings.messages.ts | 49 +++-- .../pmm/src/pages/settings/Settings.test.tsx | 13 ++ ui/apps/pmm/src/pages/settings/Settings.tsx | 7 + .../pmm/src/pages/settings/Settings.types.ts | 6 +- .../components/advanced/Advanced.constants.ts | 31 --- .../advanced/Advanced.utils.test.ts | 59 +----- .../components/advanced/Advanced.utils.ts | 28 --- .../advanced/AdvancedSettingsForm.schema.ts | 82 ++------ .../advanced/AdvancedSettingsForm.tsx | 122 +----------- .../advanced/AdvancedSettingsForm.utils.ts | 38 +--- .../components/advisors/Advisors.constants.ts | 32 +++ .../advisors/Advisors.utils.test.ts | 58 ++++++ .../components/advisors/Advisors.utils.ts | 28 +++ .../advisors/AdvisorsForm.schema.ts | 63 ++++++ .../components/advisors/AdvisorsForm.tsx | 188 ++++++++++++++++++ .../components/advisors/AdvisorsForm.types.ts | 5 + .../AdvisorsForm.utils.test.ts} | 2 +- .../components/advisors/AdvisorsForm.utils.ts | 46 +++++ 18 files changed, 493 insertions(+), 364 deletions(-) create mode 100644 ui/apps/pmm/src/pages/settings/components/advisors/Advisors.constants.ts create mode 100644 ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.test.ts create mode 100644 ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.ts create mode 100644 ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.schema.ts create mode 100644 ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.tsx create mode 100644 ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.types.ts rename ui/apps/pmm/src/pages/settings/components/{advanced/AdvancedSettingsForm.utils.test.ts => advisors/AdvisorsForm.utils.test.ts} (96%) create mode 100644 ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.utils.ts diff --git a/ui/apps/pmm/src/pages/settings/Settings.messages.ts b/ui/apps/pmm/src/pages/settings/Settings.messages.ts index fface2ddfe4..6389af8c7d2 100644 --- a/ui/apps/pmm/src/pages/settings/Settings.messages.ts +++ b/ui/apps/pmm/src/pages/settings/Settings.messages.ts @@ -4,13 +4,13 @@ export const Messages = { ssh: 'SSH key', metrics: 'Metrics resolution', advanced: 'Advanced settings', + advisors: 'Advisors', }, advanced: { validation: { required: 'Required field', retentionRange: (min: number, max: number) => `Value should be in the range from ${min} to ${max}`, - intervalMin: (min: number) => `Min ${min}`, }, retentionLabel: 'Data retention', retentionTooltip: @@ -28,25 +28,6 @@ export const Messages = { updatesLink: 'https://per.co.na/updates', updatesTooltip: 'Option to check new versions and ability to update PMM from UI.', - advisorsLabel: 'Advisors', - sttRareIntervalLabel: 'Rare', - sttStandardIntervalLabel: 'Standard', - sttFrequentIntervalLabel: 'Frequent', - sttCheckIntervalLabel: 'Check run interval', - sttCheckIntervalTooltip: - 'How often Advisor checks run. Lower values catch issues faster but increase resource usage.', - advisorsLink: 'https://per.co.na/advisors', - advisorsTooltip: - 'Run automated checks to identify potential database performance and configuration issues.', - advisorRetentionLabel: 'Advisor history retention', - advisorRetentionTooltip: - 'How long PMM keeps Advisor check results history. Older results are automatically deleted.', - advisorNotificationsLabel: 'Advisor notifications', - advisorNotificationsTooltip: - 'Email a summary of completed Advisor checks to a Grafana email contact point named "PMM Advisor Insights".', - advisorSeverityThresholdLabel: 'Notification severity threshold', - advisorSeverityThresholdTooltip: - 'Least-severe level that triggers a notification.', azureDiscoverLabel: 'Microsoft Azure monitoring', azureDiscoverTooltip: 'Option to enable/disable Microsoft Azure DB instances discovery and monitoring', @@ -81,6 +62,34 @@ export const Messages = { ' to be used in production environments. Read more about feature status', technicalPreviewLinkText: 'here.', }, + advisors: { + validation: { + required: 'Required field', + retentionRange: (min: number, max: number) => + `Value should be in the range from ${min} to ${max}`, + intervalMin: (min: number) => `Min ${min}`, + }, + advisorsLabel: 'Advisors', + advisorsLink: 'https://per.co.na/advisors', + advisorsTooltip: + 'Run automated checks to identify potential database performance and configuration issues.', + rareIntervalLabel: 'Rare', + standardIntervalLabel: 'Standard', + frequentIntervalLabel: 'Frequent', + checkIntervalLabel: 'Check run interval', + checkIntervalTooltip: + 'How often Advisor checks run. Lower values catch issues faster but increase resource usage.', + advisorRetentionLabel: 'Advisor history retention', + advisorRetentionTooltip: + 'How long PMM keeps Advisor check results history. Older results are automatically deleted.', + retentionUnits: 'days', + advisorNotificationsLabel: 'Advisor notifications', + advisorNotificationsTooltip: + 'Email a summary of completed Advisor checks to a Grafana email contact point named "PMM Advisor Insights".', + advisorSeverityThresholdLabel: 'Notification severity threshold', + advisorSeverityThresholdTooltip: + 'Least-severe level that triggers a notification.', + }, metrics: { label: 'Metrics resolution', link: 'https://per.co.na/metrics_resolution', diff --git a/ui/apps/pmm/src/pages/settings/Settings.test.tsx b/ui/apps/pmm/src/pages/settings/Settings.test.tsx index 32b5a2b836c..da16c2c95dd 100644 --- a/ui/apps/pmm/src/pages/settings/Settings.test.tsx +++ b/ui/apps/pmm/src/pages/settings/Settings.test.tsx @@ -13,6 +13,9 @@ vi.mock('./components/metrics-resolution/MetricsResolutionForm', () => ({ vi.mock('./components/advanced/AdvancedSettingsForm', () => ({ AdvancedSettingsForm: () => null, })); +vi.mock('./components/advisors/AdvisorsForm', () => ({ + AdvisorsForm: () => null, +})); vi.mock('./components/ssh-key/SshKeyForm', () => ({ SshKeyForm: () => null, })); @@ -67,6 +70,16 @@ describe('Settings', () => { ); }); + it('activates advisors tab for /settings/advisors', async () => { + renderWithRoute('/settings/advisors'); + await waitFor(() => + expect(screen.getByTestId('settings-tab-advisors')).toHaveAttribute( + 'aria-selected', + 'true' + ) + ); + }); + it('activates ssh tab for /settings/ssh', async () => { renderWithRoute('/settings/ssh-key'); await waitFor(() => diff --git a/ui/apps/pmm/src/pages/settings/Settings.tsx b/ui/apps/pmm/src/pages/settings/Settings.tsx index 2632aba112f..bc617e3b324 100644 --- a/ui/apps/pmm/src/pages/settings/Settings.tsx +++ b/ui/apps/pmm/src/pages/settings/Settings.tsx @@ -9,6 +9,7 @@ import { useSettings } from 'hooks/api/useSettings'; import { SshKeyForm } from './components/ssh-key/SshKeyForm'; import { MetricsResolutionForm } from './components/metrics-resolution/MetricsResolutionForm'; import { AdvancedSettingsForm } from './components/advanced/AdvancedSettingsForm'; +import { AdvisorsForm } from './components/advisors/AdvisorsForm'; import { Messages } from './Settings.messages'; import { TabValue } from './Settings.types'; import { useNavigate, useParams } from 'react-router-dom'; @@ -65,6 +66,11 @@ export const Settings: FC = () => { value="advanced-settings" label={Messages.tabs.advanced} /> + { {tab === 'advanced-settings' && ( )} + {tab === 'advisors' && } {tab === 'ssh-key' && } diff --git a/ui/apps/pmm/src/pages/settings/Settings.types.ts b/ui/apps/pmm/src/pages/settings/Settings.types.ts index 0b9329e0130..63febc0ea74 100644 --- a/ui/apps/pmm/src/pages/settings/Settings.types.ts +++ b/ui/apps/pmm/src/pages/settings/Settings.types.ts @@ -1 +1,5 @@ -export type TabValue = 'ssh-key' | 'metrics-resolution' | 'advanced-settings'; +export type TabValue = + | 'ssh-key' + | 'metrics-resolution' + | 'advanced-settings' + | 'advisors'; diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts index d0e9c68f125..d0568da049d 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.constants.ts @@ -1,4 +1,3 @@ -import { Severity } from 'types/severity.types'; import { Messages } from '../../Settings.messages'; export const SECONDS = 60; @@ -8,37 +7,7 @@ export const SECONDS_IN_DAY = SECONDS * MINUTES * HOURS; export const MINUTES_IN_DAY = MINUTES * HOURS; export const MIN_DAYS = 1; export const MAX_DAYS = 3650; -export const MIN_STT_CHECK_INTERVAL = 0.1; -export const STT_CHECK_INTERVAL_STEP = 0.1; export const DEFAULT_DATA_RETENTION = '86400s'; -// 30 days, matches the pmm-managed default -export const DEFAULT_ADVISOR_RETENTION = '2592000s'; - -export const ADVISOR_SEVERITY_OPTIONS = [ - Severity.emergency, - Severity.alert, - Severity.critical, - Severity.error, - Severity.warning, - Severity.notice, - Severity.info, - Severity.debug, -]; - -export const STT_CHECK_INTERVALS = [ - { - label: Messages.advanced.sttRareIntervalLabel, - name: 'rareInterval' as const, - }, - { - label: Messages.advanced.sttStandardIntervalLabel, - name: 'standardInterval' as const, - }, - { - label: Messages.advanced.sttFrequentIntervalLabel, - name: 'frequentInterval' as const, - }, -]; export const TECHNICAL_PREVIEW_DOC_URL = 'https://per.co.na/pmm-feature-status'; diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.test.ts b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.test.ts index ea7ed753942..96a8f7d2940 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.test.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.test.ts @@ -1,10 +1,5 @@ import { describe, it, expect } from 'vitest'; -import { - convertSecondsToDays, - convertSecondsStringToHour, - convertHoursStringToSeconds, - convertCheckIntervalsToHours, -} from './Advanced.utils'; +import { convertSecondsToDays } from './Advanced.utils'; describe('convertSecondsToDays', () => { it('converts seconds to days', () => { @@ -34,55 +29,3 @@ describe('convertSecondsToDays', () => { expect(convertSecondsToDays('')).toBe(''); }); }); - -describe('convertSecondsStringToHour', () => { - it('converts a seconds string to hours', () => { - expect(convertSecondsStringToHour('3600s')).toBe(1); - expect(convertSecondsStringToHour('7200s')).toBe(2); - expect(convertSecondsStringToHour('1800s')).toBe(0.5); - }); - - it('works without the s suffix', () => { - expect(convertSecondsStringToHour('3600')).toBe(1); - }); - - it('returns 0 for zero', () => { - expect(convertSecondsStringToHour('0s')).toBe(0); - }); -}); - -describe('convertHoursStringToSeconds', () => { - it('converts hours to seconds', () => { - expect(convertHoursStringToSeconds('1')).toBe(3600); - expect(convertHoursStringToSeconds(2)).toBe(7200); - }); - - it('rounds fractional hours correctly', () => { - expect(convertHoursStringToSeconds('0.5')).toBe(1800); - expect(convertHoursStringToSeconds('0.1')).toBe(360); - }); -}); - -describe('convertCheckIntervalsToHours', () => { - it('converts interval seconds strings to hour strings', () => { - const result = convertCheckIntervalsToHours({ - rareInterval: '86400s', - standardInterval: '3600s', - frequentInterval: '1800s', - }); - expect(result).toEqual({ - rareInterval: '24', - standardInterval: '1', - frequentInterval: '0.5', - }); - }); - - it('returns default 24-hour values when intervals are undefined', () => { - const result = convertCheckIntervalsToHours(undefined); - expect(result).toEqual({ - rareInterval: '24', - standardInterval: '24', - frequentInterval: '24', - }); - }); -}); diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.ts b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.ts index 5fa29375d8d..5b6cf89eabd 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/Advanced.utils.ts @@ -1,4 +1,3 @@ -import { AdvisorRunIntervals } from 'types/settings.types'; import { HOURS, MINUTES_IN_DAY, SECONDS_IN_DAY } from './Advanced.constants'; export const convertSecondsToDays = (dataRetention: string): number | '' => { @@ -19,30 +18,3 @@ export const convertSecondsToDays = (dataRetention: string): number | '' => { return ''; } }; - -const parseSeconds = (s: string): number => { - const match = String(s).match(/^(\d+)s?$/); - return match ? parseInt(match[1], 10) : 0; -}; - -export const convertSecondsStringToHour = (secondsStr: string): number => - parseSeconds(secondsStr) / 3600; - -export const convertHoursStringToSeconds = (hours: string | number): number => - Math.round(parseFloat(String(hours)) * 3600); - -export const convertCheckIntervalsToHours = ( - sttCheckIntervals: AdvisorRunIntervals | undefined -) => { - if (!sttCheckIntervals) - return { - rareInterval: '24', - standardInterval: '24', - frequentInterval: '24', - }; - return { - rareInterval: `${convertSecondsStringToHour(sttCheckIntervals.rareInterval)}`, - standardInterval: `${convertSecondsStringToHour(sttCheckIntervals.standardInterval)}`, - frequentInterval: `${convertSecondsStringToHour(sttCheckIntervals.frequentInterval)}`, - }; -}; diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts index cc4c59e7657..4eb018824ef 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts +++ b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.schema.ts @@ -1,13 +1,8 @@ import { z } from 'zod'; -import { Severity } from 'types/severity.types'; import { Messages } from '../../Settings.messages'; -import { - MAX_DAYS, - MIN_DAYS, - MIN_STT_CHECK_INTERVAL, -} from './Advanced.constants'; +import { MAX_DAYS, MIN_DAYS } from './Advanced.constants'; -const { required, retentionRange, intervalMin } = Messages.advanced.validation; +const { required, retentionRange } = Messages.advanced.validation; const retentionField = z .string() @@ -20,67 +15,16 @@ const retentionField = z { message: retentionRange(MIN_DAYS, MAX_DAYS) } ); -const intervalFields = [ - 'rareInterval', - 'standardInterval', - 'frequentInterval', -] as const; - -export const advancedSettingsSchema = z - .object({ - retention: retentionField, - telemetry: z.boolean(), - updates: z.boolean(), - alerting: z.boolean(), - backup: z.boolean(), - enableInternalPgQan: z.boolean(), - publicAddress: z.string(), - stt: z.boolean(), - rareInterval: z.string(), - standardInterval: z.string(), - frequentInterval: z.string(), - advisorRetention: z.string(), - advisorNotifications: z.boolean(), - advisorSeverityThreshold: z.nativeEnum(Severity), - azureDiscover: z.boolean(), - accessControl: z.boolean(), - }) - .superRefine((data, ctx) => { - if (!data.stt) return; - for (const field of intervalFields) { - const v = data[field]; - const n = parseFloat(v); - if (v === '' || isNaN(n)) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: required, - path: [field], - }); - } else if (n < MIN_STT_CHECK_INTERVAL) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: intervalMin(MIN_STT_CHECK_INTERVAL), - path: [field], - }); - } - } - - // the API requires a multiple of 24h, so whole days only - const retention = data.advisorRetention; - const days = parseFloat(retention); - if (retention === '' || isNaN(days) || !Number.isInteger(days)) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: required, - path: ['advisorRetention'], - }); - } else if (days < MIN_DAYS || days > MAX_DAYS) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: retentionRange(MIN_DAYS, MAX_DAYS), - path: ['advisorRetention'], - }); - } - }); +export const advancedSettingsSchema = z.object({ + retention: retentionField, + telemetry: z.boolean(), + updates: z.boolean(), + alerting: z.boolean(), + backup: z.boolean(), + enableInternalPgQan: z.boolean(), + publicAddress: z.string(), + azureDiscover: z.boolean(), + accessControl: z.boolean(), +}); export type AdvancedSettingsFormValues = z.infer; diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx index 89842a1b6e3..ce5e75b7f79 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx +++ b/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.tsx @@ -12,9 +12,7 @@ import CloseIcon from '@mui/icons-material/Close'; import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import WarningIcon from '@mui/icons-material/Warning'; -import MenuItem from '@mui/material/MenuItem'; -import { TextInput, SwitchInput, SelectInput } from '@percona/percona-ui'; -import { SEVERITY } from 'lib/constants'; +import { TextInput, SwitchInput } from '@percona/percona-ui'; import { zodResolver } from '@hookform/resolvers/zod'; import { FC, useEffect, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; @@ -22,12 +20,9 @@ import { enqueueSnackbar } from 'notistack'; import { useUpdateSettings } from 'hooks/api/useSettings'; import { Messages } from '../../Settings.messages'; import { - ADVISOR_SEVERITY_OPTIONS, FEATURE_MANAGEMENT_SETTINGS, MAX_DAYS, MIN_DAYS, - MIN_STT_CHECK_INTERVAL, - STT_CHECK_INTERVALS, TECHNICAL_PREVIEW_DOC_URL, } from './Advanced.constants'; import { AdvancedSettingsFormProps } from './AdvancedSettingsForm.types'; @@ -53,10 +48,8 @@ export const AdvancedSettingsForm: FC = ({ mode: 'onChange', }); - const { handleSubmit, reset, watch, setValue } = methods; + const { handleSubmit, reset, setValue } = methods; - const sttEnabled = watch('stt'); - const advisorNotificationsEnabled = watch('advisorNotifications'); const [telemetryDialogOpen, setTelemetryDialogOpen] = useState(false); useEffect(() => { @@ -273,117 +266,6 @@ export const AdvancedSettingsForm: FC = ({ - - - - - - {sttEnabled && ( - - - - {STT_CHECK_INTERVALS.map(({ name, label }) => ( - - ))} - - - - - - - - {m.retentionUnits} - - - - - - - - {advisorNotificationsEnabled && ( - - {ADVISOR_SEVERITY_OPTIONS.map((severity) => ( - - {SEVERITY[severity]} - - ))} - - )} - - - )} - - { const dataRetention = `${Math.round(parseFloat(values.retention) * SECONDS_IN_DAY)}s`; - const advisorRunIntervals = values.stt - ? { - rareInterval: `${convertHoursStringToSeconds(values.rareInterval)}s`, - standardInterval: `${convertHoursStringToSeconds(values.standardInterval)}s`, - frequentInterval: `${convertHoursStringToSeconds(values.frequentInterval)}s`, - } - : undefined; return { dataRetention, @@ -62,11 +33,6 @@ export const toPayload = ( enableAlerting: values.alerting, enableBackupManagement: values.backup, enableInternalPgQan: values.enableInternalPgQan, - enableAdvisor: values.stt, - advisorRunIntervals, - advisorHistoryRetention: `${Math.round(parseFloat(values.advisorRetention)) * SECONDS_IN_DAY}s`, - enableAdvisorNotifications: values.advisorNotifications, - advisorNotificationSeverityThreshold: values.advisorSeverityThreshold, enableAzurediscover: values.azureDiscover, enableAccessControl: values.accessControl, }; diff --git a/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.constants.ts b/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.constants.ts new file mode 100644 index 00000000000..88dab9985be --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.constants.ts @@ -0,0 +1,32 @@ +import { Severity } from 'types/severity.types'; +import { Messages } from '../../Settings.messages'; + +export const MIN_ADVISOR_CHECK_INTERVAL = 0.1; +// 30 days, matches the pmm-managed default +export const DEFAULT_ADVISOR_RETENTION = '2592000s'; + +export const ADVISOR_SEVERITY_OPTIONS = [ + Severity.emergency, + Severity.alert, + Severity.critical, + Severity.error, + Severity.warning, + Severity.notice, + Severity.info, + Severity.debug, +]; + +export const STT_CHECK_INTERVALS = [ + { + label: Messages.advisors.rareIntervalLabel, + name: 'rareInterval' as const, + }, + { + label: Messages.advisors.standardIntervalLabel, + name: 'standardInterval' as const, + }, + { + label: Messages.advisors.frequentIntervalLabel, + name: 'frequentInterval' as const, + }, +]; diff --git a/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.test.ts b/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.test.ts new file mode 100644 index 00000000000..ff1dafcd8a0 --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.test.ts @@ -0,0 +1,58 @@ +import { describe, it, expect } from 'vitest'; +import { + convertSecondsStringToHour, + convertHoursStringToSeconds, + convertCheckIntervalsToHours, +} from './Advisors.utils'; + +describe('convertSecondsStringToHour', () => { + it('converts a seconds string to hours', () => { + expect(convertSecondsStringToHour('3600s')).toBe(1); + expect(convertSecondsStringToHour('7200s')).toBe(2); + expect(convertSecondsStringToHour('1800s')).toBe(0.5); + }); + + it('works without the s suffix', () => { + expect(convertSecondsStringToHour('3600')).toBe(1); + }); + + it('returns 0 for zero', () => { + expect(convertSecondsStringToHour('0s')).toBe(0); + }); +}); + +describe('convertHoursStringToSeconds', () => { + it('converts hours to seconds', () => { + expect(convertHoursStringToSeconds('1')).toBe(3600); + expect(convertHoursStringToSeconds(2)).toBe(7200); + }); + + it('rounds fractional hours correctly', () => { + expect(convertHoursStringToSeconds('0.5')).toBe(1800); + expect(convertHoursStringToSeconds('0.1')).toBe(360); + }); +}); + +describe('convertCheckIntervalsToHours', () => { + it('converts interval seconds strings to hour strings', () => { + const result = convertCheckIntervalsToHours({ + rareInterval: '86400s', + standardInterval: '3600s', + frequentInterval: '1800s', + }); + expect(result).toEqual({ + rareInterval: '24', + standardInterval: '1', + frequentInterval: '0.5', + }); + }); + + it('returns default 24-hour values when intervals are undefined', () => { + const result = convertCheckIntervalsToHours(undefined); + expect(result).toEqual({ + rareInterval: '24', + standardInterval: '24', + frequentInterval: '24', + }); + }); +}); diff --git a/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.ts b/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.ts new file mode 100644 index 00000000000..5c899fce93c --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advisors/Advisors.utils.ts @@ -0,0 +1,28 @@ +import { AdvisorRunIntervals } from 'types/settings.types'; + +const parseSeconds = (s: string): number => { + const match = String(s).match(/^(\d+)s?$/); + return match ? parseInt(match[1], 10) : 0; +}; + +export const convertSecondsStringToHour = (secondsStr: string): number => + parseSeconds(secondsStr) / 3600; + +export const convertHoursStringToSeconds = (hours: string | number): number => + Math.round(parseFloat(String(hours)) * 3600); + +export const convertCheckIntervalsToHours = ( + sttCheckIntervals: AdvisorRunIntervals | undefined +) => { + if (!sttCheckIntervals) + return { + rareInterval: '24', + standardInterval: '24', + frequentInterval: '24', + }; + return { + rareInterval: `${convertSecondsStringToHour(sttCheckIntervals.rareInterval)}`, + standardInterval: `${convertSecondsStringToHour(sttCheckIntervals.standardInterval)}`, + frequentInterval: `${convertSecondsStringToHour(sttCheckIntervals.frequentInterval)}`, + }; +}; diff --git a/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.schema.ts b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.schema.ts new file mode 100644 index 00000000000..1d3da9453af --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.schema.ts @@ -0,0 +1,63 @@ +import { z } from 'zod'; +import { Severity } from 'types/severity.types'; +import { Messages } from '../../Settings.messages'; +import { MAX_DAYS, MIN_DAYS } from '../advanced/Advanced.constants'; +import { MIN_ADVISOR_CHECK_INTERVAL } from './Advisors.constants'; + +const { required, retentionRange, intervalMin } = Messages.advisors.validation; + +const intervalFields = [ + 'rareInterval', + 'standardInterval', + 'frequentInterval', +] as const; + +export const advisorsSchema = z + .object({ + stt: z.boolean(), + rareInterval: z.string(), + standardInterval: z.string(), + frequentInterval: z.string(), + advisorRetention: z.string(), + advisorNotifications: z.boolean(), + advisorSeverityThreshold: z.nativeEnum(Severity), + }) + .superRefine((data, ctx) => { + if (!data.stt) return; + for (const field of intervalFields) { + const v = data[field]; + const n = parseFloat(v); + if (v === '' || isNaN(n)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: required, + path: [field], + }); + } else if (n < MIN_ADVISOR_CHECK_INTERVAL) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: intervalMin(MIN_ADVISOR_CHECK_INTERVAL), + path: [field], + }); + } + } + + // the API requires a multiple of 24h, so whole days only + const retention = data.advisorRetention; + const days = parseFloat(retention); + if (retention === '' || isNaN(days) || !Number.isInteger(days)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: required, + path: ['advisorRetention'], + }); + } else if (days < MIN_DAYS || days > MAX_DAYS) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: retentionRange(MIN_DAYS, MAX_DAYS), + path: ['advisorRetention'], + }); + } + }); + +export type AdvisorsFormValues = z.infer; diff --git a/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.tsx b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.tsx new file mode 100644 index 00000000000..47710e10459 --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.tsx @@ -0,0 +1,188 @@ +import Stack from '@mui/material/Stack'; +import Typography from '@mui/material/Typography'; +import MenuItem from '@mui/material/MenuItem'; +import { TextInput, SwitchInput, SelectInput } from '@percona/percona-ui'; +import { SEVERITY } from 'lib/constants'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { FC, useEffect } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { enqueueSnackbar } from 'notistack'; +import { useUpdateSettings } from 'hooks/api/useSettings'; +import { Messages } from '../../Settings.messages'; +import { MAX_DAYS, MIN_DAYS } from '../advanced/Advanced.constants'; +import { + ADVISOR_SEVERITY_OPTIONS, + MIN_ADVISOR_CHECK_INTERVAL, + STT_CHECK_INTERVALS, +} from './Advisors.constants'; +import { AdvisorsFormProps } from './AdvisorsForm.types'; +import { AdvisorsFormValues, advisorsSchema } from './AdvisorsForm.schema'; +import { toFormValues, toPayload } from './AdvisorsForm.utils'; +import { SettingsFieldLabel } from '../settings-field-label'; +import { SettingsSubmitButton } from '../settings-submit-button'; +import { formControlClasses } from '@mui/material/FormControl'; +import { helperTextTestId } from 'utils/mui.utils'; + +export const AdvisorsForm: FC = ({ settings }) => { + const { mutateAsync: updateSettings } = useUpdateSettings(); + + const methods = useForm({ + resolver: zodResolver(advisorsSchema), + defaultValues: toFormValues(settings), + mode: 'onChange', + }); + + const { handleSubmit, reset, watch } = methods; + + const sttEnabled = watch('stt'); + const advisorNotificationsEnabled = watch('advisorNotifications'); + + useEffect(() => { + reset(toFormValues(settings)); + }, [settings, reset]); + + const onSubmit = async (values: AdvisorsFormValues) => { + await updateSettings(toPayload(values), { + onSuccess: () => { + enqueueSnackbar(Messages.service.success, { variant: 'success' }); + reset(values); + }, + onError: (error) => { + enqueueSnackbar( + error instanceof Error ? error.message : Messages.unauthorized, + { variant: 'error' } + ); + }, + }); + }; + + const m = Messages.advisors; + + return ( + + + + + + + + {sttEnabled && ( + + + + {STT_CHECK_INTERVALS.map(({ name, label }) => ( + + ))} + + + + + + + + {m.retentionUnits} + + + + + + + + {advisorNotificationsEnabled && ( + + {ADVISOR_SEVERITY_OPTIONS.map((severity) => ( + + {SEVERITY[severity]} + + ))} + + )} + + + )} + + + + + + ); +}; diff --git a/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.types.ts b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.types.ts new file mode 100644 index 00000000000..2257b1b4a66 --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.types.ts @@ -0,0 +1,5 @@ +import { Settings } from 'types/settings.types'; + +export interface AdvisorsFormProps { + settings: Settings; +} diff --git a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.utils.test.ts similarity index 96% rename from ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts rename to ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.utils.test.ts index a8edcd13d1a..96ed1588c73 100644 --- a/ui/apps/pmm/src/pages/settings/components/advanced/AdvancedSettingsForm.utils.test.ts +++ b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.utils.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect } from 'vitest'; import { Settings } from 'types/settings.types'; import { Severity } from 'types/severity.types'; -import { toFormValues, toPayload } from './AdvancedSettingsForm.utils'; +import { toFormValues, toPayload } from './AdvisorsForm.utils'; const TEST_SETTINGS: Settings = { updatesEnabled: true, diff --git a/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.utils.ts b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.utils.ts new file mode 100644 index 00000000000..fbb6a39a962 --- /dev/null +++ b/ui/apps/pmm/src/pages/settings/components/advisors/AdvisorsForm.utils.ts @@ -0,0 +1,46 @@ +import { Settings, UpdateSettingsPayload } from 'types/settings.types'; +import { Severity } from 'types/severity.types'; +import { AdvisorsFormValues } from './AdvisorsForm.schema'; +import { SECONDS_IN_DAY } from '../advanced/Advanced.constants'; +import { convertSecondsToDays } from '../advanced/Advanced.utils'; +import { DEFAULT_ADVISOR_RETENTION } from './Advisors.constants'; +import { + convertCheckIntervalsToHours, + convertHoursStringToSeconds, +} from './Advisors.utils'; + +export const toFormValues = (settings: Settings): AdvisorsFormValues => ({ + stt: settings.advisorEnabled, + ...convertCheckIntervalsToHours(settings.advisorRunIntervals), + advisorRetention: String( + convertSecondsToDays( + settings.advisorHistoryRetention ?? DEFAULT_ADVISOR_RETENTION + ) || '1' + ), + advisorNotifications: settings.advisorNotificationsEnabled ?? false, + advisorSeverityThreshold: + settings.advisorNotificationSeverityThreshold && + settings.advisorNotificationSeverityThreshold !== Severity.unspecified + ? settings.advisorNotificationSeverityThreshold + : Severity.error, +}); + +export const toPayload = ( + values: AdvisorsFormValues +): UpdateSettingsPayload => { + const advisorRunIntervals = values.stt + ? { + rareInterval: `${convertHoursStringToSeconds(values.rareInterval)}s`, + standardInterval: `${convertHoursStringToSeconds(values.standardInterval)}s`, + frequentInterval: `${convertHoursStringToSeconds(values.frequentInterval)}s`, + } + : undefined; + + return { + enableAdvisor: values.stt, + advisorRunIntervals, + advisorHistoryRetention: `${Math.round(parseFloat(values.advisorRetention)) * SECONDS_IN_DAY}s`, + enableAdvisorNotifications: values.advisorNotifications, + advisorNotificationSeverityThreshold: values.advisorSeverityThreshold, + }; +}; From 6e3187ed35b65445322b9a4fc94ec85e680c8ff5 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 19 Jul 2026 11:14:43 +0300 Subject: [PATCH 041/120] PMM-14109 Remove deprecated category field from advisor checks --- .../checks/mongodb_clickhouse.yml.example | 1 - ...tion_innodb_file_per_table_not_enabled.yml | 1 - ...ql_configuration_max_connections_usage.yml | 1 - ...l_configuration_secure_file_priv_empty.yml | 1 - ...l_innodb_redo_logs_not_sized_correctly.yml | 1 - ...sql_performance_temp_ondisk_table_high.yml | 1 - managed/data/checks/postgresql_cve_check.yml | 1 - .../postgresql_expiring_passwd_check.yml | 1 - .../data/checks/postgresql_tmpfiles_check.yml | 1 - managed/pi/check/advisor.go | 27 +--- managed/pi/check/check.go | 122 ++++-------------- managed/services/checks/checks.go | 54 +++----- managed/services/checks/checks_test.go | 81 +++++------- managed/services/management/checks.go | 6 +- managed/services/management/checks_test.go | 8 +- 15 files changed, 83 insertions(+), 224 deletions(-) diff --git a/managed/data/checks/mongodb_clickhouse.yml.example b/managed/data/checks/mongodb_clickhouse.yml.example index 9e1d1fd1988..ea24c3d9b73 100644 --- a/managed/data/checks/mongodb_clickhouse.yml.example +++ b/managed/data/checks/mongodb_clickhouse.yml.example @@ -7,7 +7,6 @@ checks: description: Sample Clickhouse advisor that checks if QAN is on a MongoDB instance interval: standard family: MONGODB - category: configuration queries: - type: CLICKHOUSE_SELECT query: service_id, service_name, COUNT(*) as count FROM metrics WHERE service_id='{{.ServiceID}}' GROUP BY (service_id,service_name); diff --git a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml index f055fcd04c6..30374b3d2ad 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml @@ -9,7 +9,6 @@ checks: #subcategory: performance #author:Kedar Vaijanapurkar family: MYSQL - category: configuration queries: - type: MYSQL_SELECT query: "@@global.innodb_file_per_table as innodb_file_per_table, @@global.version as version, @@global.hostname as service" diff --git a/managed/data/checks/mysql_configuration_max_connections_usage.yml b/managed/data/checks/mysql_configuration_max_connections_usage.yml index 7ac40326fae..955afc80e6d 100644 --- a/managed/data/checks/mysql_configuration_max_connections_usage.yml +++ b/managed/data/checks/mysql_configuration_max_connections_usage.yml @@ -9,7 +9,6 @@ checks: #subcategory: connection #author:Kedar Vaijanapurkar family: MYSQL - category: configuration queries: - type: MYSQL_SELECT query: "@@global.max_connections as max_connections, @@global.version as version, @@global.hostname as service" diff --git a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml index af21b536160..978b479e57e 100644 --- a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml +++ b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml @@ -9,7 +9,6 @@ checks: #subcategory: security #author:Kedar Vaijanapurkar family: MYSQL - category: configuration queries: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service, @@global.secure_file_priv as secure_file_priv" diff --git a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml index 04090c4880d..13503ad7ec0 100644 --- a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml +++ b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml @@ -5,7 +5,6 @@ checks: summary: Checks if InnoDB redo log size is not configured correctly. description: This check reviews InnoDB redo log size and suggests if it is configured too low. family: MYSQL - category: performance #subcategory: configuration #author: Kedar Vaijanapurkar advisor: configuration_innodb diff --git a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml index ea2e0dacc1b..a015b38b82a 100644 --- a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml +++ b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml @@ -5,7 +5,6 @@ checks: summary: Too many on disk temporary tables description: This check warns against too many ondisk temporary tables created due to unoptimized query execution. family: MYSQL - category: configuration advisor: query_index #subcategory: index #author: Kedar Vaijanapurkar diff --git a/managed/data/checks/postgresql_cve_check.yml b/managed/data/checks/postgresql_cve_check.yml index 0b13c79ba19..6bf501eb929 100644 --- a/managed/data/checks/postgresql_cve_check.yml +++ b/managed/data/checks/postgresql_cve_check.yml @@ -11,7 +11,6 @@ checks: advisor: security_cve interval: standard family: POSTGRESQL - category: configuration queries: - type: POSTGRESQL_SELECT query: "setting, (setting::int / 10000) major FROM pg_settings WHERE name = 'server_version_num' " diff --git a/managed/data/checks/postgresql_expiring_passwd_check.yml b/managed/data/checks/postgresql_expiring_passwd_check.yml index 47c4165b59f..98476a17f89 100644 --- a/managed/data/checks/postgresql_expiring_passwd_check.yml +++ b/managed/data/checks/postgresql_expiring_passwd_check.yml @@ -9,7 +9,6 @@ checks: advisor: security_configuration interval: standard family: POSTGRESQL - category: configuration queries: - type: POSTGRESQL_SELECT query: "rolname, rolvaliduntil::timestamp(0)::text, floor((extract(epoch from rolvaliduntil) - extract(epoch from now())) / 86400)::int AS expires FROM pg_roles WHERE rolvaliduntil IS NOT NULL" diff --git a/managed/data/checks/postgresql_tmpfiles_check.yml b/managed/data/checks/postgresql_tmpfiles_check.yml index 5f7ef851e93..29d9c28b05d 100644 --- a/managed/data/checks/postgresql_tmpfiles_check.yml +++ b/managed/data/checks/postgresql_tmpfiles_check.yml @@ -8,7 +8,6 @@ checks: advisor: performance_generic interval: standard family: POSTGRESQL - category: configuration queries: - type: POSTGRESQL_SELECT query: datname, temp_files, PG_SIZE_PRETTY(temp_bytes) AS temp_bytes, TO_CHAR( AGE(stats_reset), 'MM "Months" DD "Days"') AS age FROM pg_stat_database diff --git a/managed/pi/check/advisor.go b/managed/pi/check/advisor.go index ed81015b405..bfa3ca7d7d0 100644 --- a/managed/pi/check/advisor.go +++ b/managed/pi/check/advisor.go @@ -23,14 +23,16 @@ import ( "gopkg.in/yaml.v3" ) -// Advisor represents group of checks with the common idea. +// Advisor represents a group of checks with a common idea. +// Checks is populated at load time by linking checks via Check.Advisor; +// it is not authored in advisor files. type Advisor struct { Version uint32 `yaml:"version"` Name string `yaml:"name"` Summary string `yaml:"summary"` Description string `yaml:"description"` Category string `yaml:"category"` - Checks []Check `yaml:"checks"` + Checks []Check `yaml:"-"` } // ParseAdvisors returns a slice of validated advisors parsed from YAML passed via a reader. @@ -53,7 +55,7 @@ func ParseAdvisors(reader io.Reader, params *ParseParams) ([]Advisor, error) { for { var c advisors - err := d.Decode(&c) //nolint:musttag + err := d.Decode(&c) if err != nil { if errors.Is(err, io.EOF) { return res, nil @@ -99,24 +101,5 @@ func (a *Advisor) Validate() error { return errors.New("category is empty") } - checkNames := make(map[string]struct{}, len(a.Checks)) - for _, check := range a.Checks { - err := check.Validate() - if err != nil { - return err - } - - if check.Advisor != a.Name { - return fmt.Errorf("advisor name '%s' doesn't match name '%s' specified in corresponding check '%s'", - a.Name, check.Advisor, check.Name) - } - - if _, ok := checkNames[check.Name]; ok { - return fmt.Errorf("check name collision `%s` detected in '%s' advisor", check.Name, a.Name) - } - - checkNames[check.Name] = struct{}{} - } - return nil } diff --git a/managed/pi/check/check.go b/managed/pi/check/check.go index ca25b468a1a..9bb34493d65 100644 --- a/managed/pi/check/check.go +++ b/managed/pi/check/check.go @@ -179,16 +179,6 @@ func (t Type) Validate() error { } } -func isTypeSupportedByV1(t Type) bool { - switch t { - case MySQLShow, MySQLSelect, PostgreSQLShow, PostgreSQLSelect, MongoDBGetParameter, - MongoDBBuildInfo, MongoDBGetCmdLineOpts, MongoDBReplSetGetStatus, MongoDBGetDiagnosticData: - return true - default: - return false - } -} - // Supported DB families. const ( MySQL = Family("MYSQL") @@ -264,56 +254,44 @@ func (q Query) Validate() error { return validateQueryParameters(q.Type, q.Parameters) } -// Check represents advisor check structure. Fields marked with v1 should not be used for version 2, and vice versa. +// Supported advisor check format versions. Version 1 is deprecated and rejected. +const ( + // MinSupportedVersion is the minimum supported advisor check format version. + MinSupportedVersion uint32 = 2 + // MaxSupportedVersion is the maximum supported advisor check format version. + MaxSupportedVersion uint32 = 2 +) + +// Check represents an advisor check. type Check struct { Version uint32 `yaml:"version"` Name string `yaml:"name"` Summary string `yaml:"summary"` Description string `yaml:"description"` Advisor string `yaml:"advisor"` - Category string `yaml:"category,omitempty"` // deprecated - Type Type `yaml:"type,omitempty"` // for v1 - Family Family `yaml:"family,omitempty"` // for v2, emulated via GetFamily for v1 + Family Family `yaml:"family"` Interval Interval `yaml:"interval,omitempty"` - Query string `yaml:"query,omitempty"` // for v1 - Queries []Query `yaml:"queries,omitempty"` // for v2 + Queries []Query `yaml:"queries"` Script string `yaml:"script"` } -// GetFamily returns check family for both V1 and V2 check formats. -func (c *Check) GetFamily() Family { - switch c.Version { - case 1: - switch c.Type { - case MySQLSelect, MySQLShow: - return MySQL - - case PostgreSQLSelect, PostgreSQLShow: - return PostgreSQL - - case MongoDBGetParameter, MongoDBBuildInfo, MongoDBGetCmdLineOpts, - MongoDBReplSetGetStatus, MongoDBGetDiagnosticData: - return MongoDB - - case MetricsInstant, MetricsRange, ClickHouseSelect: - return "" // Unsupported query types for V1, check is invalid - } - case 2: //nolint:mnd - return c.Family - } - - return "" -} - // Validate validates check for minimal correctness. func (c *Check) Validate() error { - var err error - if !nameRE.MatchString(c.Name) { return errors.New("invalid check name") } - err = c.Interval.Validate() + if c.Version < MinSupportedVersion { + return fmt.Errorf("check %s: format version %d is no longer supported, minimum supported version is %d", + c.Name, c.Version, MinSupportedVersion) + } + + if c.Version > MaxSupportedVersion { + return fmt.Errorf("check %s: format version %d is not supported, maximum supported version is %d", + c.Name, c.Version, MaxSupportedVersion) + } + + err := c.Interval.Validate() if err != nil { return err } @@ -339,66 +317,12 @@ func (c *Check) Validate() error { return errors.New("advisor name is missing") } - switch c.Version { - case 1: - return c.validateV1() - case 2: //nolint:mnd - return c.validateV2() - default: - return fmt.Errorf("unexpected version %d", c.Version) - } -} - -func (c *Check) validateV1() error { - var err error - - err = c.Type.Validate() - if err != nil { - return err - } - - if !isTypeSupportedByV1(c.Type) { - return fmt.Errorf("check type '%s' is not supprted in V1", c.Type) - } - - err = validateQuery(c.Type, c.Query) - if err != nil { - return err - } - - if c.Family != "" { - return errors.New("field 'family' is part of check format version 2 and can't be used in version 1") - } - - if len(c.Queries) != 0 { - return errors.New("field 'queries' is part of check format version 2 and can't be used in version 1") - } - - return nil -} - -func (c *Check) validateV2() error { - var err error - err = c.Family.Validate() if err != nil { return err } - err = c.validateQueries() - if err != nil { - return err - } - - if c.Type != "" { - return errors.New("field 'type' is part of check format version 1 and can't be used in version 2") - } - - if c.Query != "" { - return errors.New("field 'query' is part of check format version 1 and can't be used in version 2") - } - - return nil + return c.validateQueries() } func (c *Check) validateScript() error { diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index 6814be7cdb1..4cdda940051 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -69,8 +69,6 @@ const ( prometheusNamespace = "pmm_managed" prometheusSubsystem = "advisor" - - maxSupportedVersion = 2 ) // pmm-agent versions with known changes in Query Actions. @@ -565,22 +563,15 @@ func (s *Service) waitForResult(ctx context.Context, resultID string) ([]byte, e } func (s *Service) minPMMAgentVersion(c check.Check) *version.Parsed { - switch c.Version { - case 1: - return s.minPMMAgentVersionForType(c.Type) - case 2: - res := pmmAgent2_6_0 // minimum version that can be used with advisors - for _, query := range c.Queries { - v := s.minPMMAgentVersionForType(query.Type) - if v != nil && res.Less(v) { - res = v - } + res := pmmAgent2_6_0 // minimum version that can be used with advisors + for _, query := range c.Queries { + v := s.minPMMAgentVersionForType(query.Type) + if v != nil && res.Less(v) { + res = v } - - return res - default: - return pmmAgentInvalid } + + return res } // minPMMAgentVersion returns the minimal version of pmm-agent that can handle the given check type. @@ -731,8 +722,8 @@ func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType mo pmmAgentVersion := s.minPMMAgentVersion(c) targets, err := s.findTargets(serviceType, pmmAgentVersion) if err != nil { - s.l.Warnf("Failed to find proper agents and services for check type: %s and "+ - "min version: %s, reason: %s.", c.Type, pmmAgentVersion, err) + s.l.Warnf("Failed to find proper agents and services for check family: %s and "+ + "min version: %s, reason: %s.", c.Family, pmmAgentVersion, err) continue } @@ -743,7 +734,7 @@ func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType mo // stamp each (check, target) outcome with its actual completion time checkedAt := models.Now() if err != nil { - s.l.Warnf("Failed to execute check %s of type %s on target %s: %+v", c.Name, c.Type, target.AgentID, err) + s.l.Warnf("Failed to execute check %s of family %s on target %s: %+v", c.Name, c.Family, target.AgentID, err) s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name, "error").Inc() history = append(history, newCheckResultRecord(c, target, category, models.CheckResultError, check.Result{Description: err.Error()}, checkedAt, ri)) continue @@ -888,11 +879,12 @@ func (s *Service) executeCheck(ctx context.Context, target services.Target, c ch s.mChecksExecutionTime.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name).Observe(time.Since(t).Seconds()) }(time.Now()) - queries := c.Queries - if c.Version == 1 { + if c.Version < check.MinSupportedVersion || c.Version > check.MaxSupportedVersion { return nil, fmt.Errorf("check %s has unsupported version %d", c.Name, c.Version) } + queries := c.Queries + eg, gCtx := errgroup.WithContext(ctx) resData := make([]any, len(queries)) @@ -1769,24 +1761,16 @@ func (s *Service) filterSupportedChecks(advisors []check.Advisor) []check.Adviso LOOP: for _, c := range advisor.Checks { - if c.Version > maxSupportedVersion { - s.l.Warnf("Unsupported checks version: %d, max supported version: %d.", c.Version, maxSupportedVersion) + if c.Version > check.MaxSupportedVersion { + s.l.Warnf("Unsupported checks version: %d, max supported version: %d.", c.Version, check.MaxSupportedVersion) continue LOOP } - switch c.Version { - case 1: - if ok := isQueryTypeSupported(c.Type); !ok { - s.l.Warnf("Unsupported check type: %s.", c.Type) + for _, query := range c.Queries { + if ok := isQueryTypeSupported(query.Type); !ok { + s.l.Warnf("Unsupported query type: %s.", query.Type) continue LOOP } - case 2: - for _, query := range c.Queries { - if ok := isQueryTypeSupported(query.Type); !ok { - s.l.Warnf("Unsupported query type: %s.", query.Type) - continue LOOP - } - } } checks = append(checks, c) @@ -1898,7 +1882,7 @@ func groupChecksByDB(l *logrus.Entry, checks map[string]check.Check) (mySQLCheck postgreSQLChecks = make(map[string]check.Check) mongoDBChecks = make(map[string]check.Check) for _, c := range checks { - switch c.GetFamily() { + switch c.Family { case check.MySQL: mySQLChecks[c.Name] = c case check.PostgreSQL: diff --git a/managed/services/checks/checks_test.go b/managed/services/checks/checks_test.go index 10dee71143d..b13362e89ef 100644 --- a/managed/services/checks/checks_test.go +++ b/managed/services/checks/checks_test.go @@ -364,8 +364,6 @@ func TestFilterChecks(t *testing.T) { Description: "Test mySQL advisor", Category: "test", Checks: []check.Check{ - {Name: "MySQLShow", Version: 1, Type: check.MySQLShow}, - {Name: "MySQLSelect", Version: 1, Type: check.MySQLSelect}, {Name: "MySQL check V2", Version: 2, Queries: []check.Query{{Type: check.MySQLShow}, {Type: check.MySQLSelect}}}, }, }, @@ -375,8 +373,6 @@ func TestFilterChecks(t *testing.T) { Description: "Test postgreSQL advisor", Category: "test", Checks: []check.Check{ - {Name: "PostgreSQLShow", Version: 1, Type: check.PostgreSQLShow}, - {Name: "PostgreSQLSelect", Version: 1, Type: check.PostgreSQLSelect}, {Name: "PostgreSQL check V2", Version: 2, Queries: []check.Query{{Type: check.PostgreSQLShow}, {Type: check.PostgreSQLSelect}}}, }, }, @@ -386,11 +382,6 @@ func TestFilterChecks(t *testing.T) { Description: "Test mongoDB advisor", Category: "test", Checks: []check.Check{ - {Name: "MongoDBGetParameter", Version: 1, Type: check.MongoDBGetParameter}, - {Name: "MongoDBBuildInfo", Version: 1, Type: check.MongoDBBuildInfo}, - {Name: "MongoDBGetCmdLineOpts", Version: 1, Type: check.MongoDBGetCmdLineOpts}, - {Name: "MongoDBReplSetGetStatus", Version: 1, Type: check.MongoDBReplSetGetStatus}, - {Name: "MongoDBGetDiagnosticData", Version: 1, Type: check.MongoDBGetDiagnosticData}, {Name: "MongoDB check V2", Version: 2, Queries: []check.Query{{Type: check.MongoDBBuildInfo}, {Type: check.MongoDBGetParameter}, {Type: check.MongoDBGetCmdLineOpts}}}, }, }, @@ -403,8 +394,8 @@ func TestFilterChecks(t *testing.T) { Description: "Test advisor that contains only unsupported checks", Category: "test", Checks: []check.Check{ - {Name: "unsupported version", Version: maxSupportedVersion + 1, Type: check.MySQLShow}, - {Name: "unsupported type", Version: 1, Type: check.Type("RedisInfo")}, + {Name: "unsupported version", Version: check.MaxSupportedVersion + 1, Queries: []check.Query{{Type: check.MySQLShow}}}, + {Name: "unsupported type", Version: 2, Queries: []check.Query{{Type: check.Type("RedisInfo")}}}, }, }, { @@ -413,8 +404,8 @@ func TestFilterChecks(t *testing.T) { Description: "Test advisor that contains some unsupported checks", Category: "test", Checks: []check.Check{ - {Name: "MySQLShow", Version: 1, Type: check.MySQLShow}, - {Name: "missing type", Version: 1}, + {Name: "MySQLShow", Version: 2, Queries: []check.Query{{Type: check.MySQLShow}}}, + {Name: "unsupported type", Version: 2, Queries: []check.Query{{Type: check.Type("RedisInfo")}}}, }, }, } @@ -438,13 +429,13 @@ func TestMinPMMAgents(t *testing.T) { check check.Check minVersion *version.Parsed }{ - {name: "MySQLShow", minVersion: pmmAgent2_6_0, check: check.Check{Version: 1, Type: check.MySQLShow}}, - {name: "MySQLSelect", minVersion: pmmAgent2_6_0, check: check.Check{Version: 1, Type: check.MySQLSelect}}, - {name: "PostgreSQLShow", minVersion: pmmAgent2_6_0, check: check.Check{Version: 1, Type: check.PostgreSQLShow}}, - {name: "PostgreSQLSelect", minVersion: pmmAgent2_6_0, check: check.Check{Version: 1, Type: check.PostgreSQLSelect}}, - {name: "MongoDBGetParameter", minVersion: pmmAgent2_6_0, check: check.Check{Version: 1, Type: check.MongoDBGetParameter}}, - {name: "MongoDBBuildInfo", minVersion: pmmAgent2_6_0, check: check.Check{Version: 1, Type: check.MongoDBBuildInfo}}, - {name: "MongoDBGetCmdLineOpts", minVersion: pmmAgent2_7_0, check: check.Check{Version: 1, Type: check.MongoDBGetCmdLineOpts}}, + {name: "MySQLShow", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.MySQLShow}}}}, + {name: "MySQLSelect", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.MySQLSelect}}}}, + {name: "PostgreSQLShow", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.PostgreSQLShow}}}}, + {name: "PostgreSQLSelect", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.PostgreSQLSelect}}}}, + {name: "MongoDBGetParameter", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.MongoDBGetParameter}}}}, + {name: "MongoDBBuildInfo", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.MongoDBBuildInfo}}}}, + {name: "MongoDBGetCmdLineOpts", minVersion: pmmAgent2_7_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.MongoDBGetCmdLineOpts}}}}, {name: "MySQL Family", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.MySQLShow}, {Type: check.MySQLSelect}}}}, {name: "MongoDB Family", minVersion: pmmAgent2_7_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.MongoDBBuildInfo}, {Type: check.MongoDBGetParameter}, {Type: check.MongoDBGetCmdLineOpts}}}}, {name: "PostgreSQL Family", minVersion: pmmAgent2_6_0, check: check.Check{Version: 2, Queries: []check.Query{{Type: check.PostgreSQLShow}, {Type: check.PostgreSQLSelect}}}}, @@ -829,45 +820,31 @@ func TestGroupChecksByDB(t *testing.T) { t.Parallel() checks := map[string]check.Check{ - "MySQLShow": {Name: "MySQLShow", Version: 1, Type: check.MySQLShow}, - "MySQLSelect": {Name: "MySQLSelect", Version: 1, Type: check.MySQLSelect}, - "PostgreSQLShow": {Name: "PostgreSQLShow", Version: 1, Type: check.PostgreSQLShow}, - "PostgreSQLSelect": {Name: "PostgreSQLSelect", Version: 1, Type: check.PostgreSQLSelect}, - "MongoDBGetParameter": {Name: "MongoDBGetParameter", Version: 1, Type: check.MongoDBGetParameter}, - "MongoDBBuildInfo": {Name: "MongoDBBuildInfo", Version: 1, Type: check.MongoDBBuildInfo}, - "MongoDBGetCmdLineOpts": {Name: "MongoDBGetCmdLineOpts", Version: 1, Type: check.MongoDBGetCmdLineOpts}, - "MongoDBReplSetGetStatus": {Name: "MongoDBReplSetGetStatus", Version: 1, Type: check.MongoDBReplSetGetStatus}, - "MongoDBGetDiagnosticData": {Name: "MongoDBGetDiagnosticData", Version: 1, Type: check.MongoDBGetDiagnosticData}, - "unsupported type": {Name: "unsupported type", Version: 1, Type: check.Type("RedisInfo")}, - "missing type": {Name: "missing type", Version: 1}, - "MySQL family V2": {Name: "MySQL family V2", Version: 2, Family: check.MySQL}, - "PostgreSQL family V2": {Name: "PostgreSQL family V2", Version: 2, Family: check.PostgreSQL}, - "MongoDB family V2": {Name: "MongoDB family V2", Version: 2, Family: check.MongoDB}, - "missing family": {Name: "missing family", Version: 2}, + "mysql_1": {Name: "mysql_1", Version: 2, Family: check.MySQL}, + "mysql_2": {Name: "mysql_2", Version: 2, Family: check.MySQL}, + "mysql_3": {Name: "mysql_3", Version: 2, Family: check.MySQL}, + "postgresql_1": {Name: "postgresql_1", Version: 2, Family: check.PostgreSQL}, + "postgresql_2": {Name: "postgresql_2", Version: 2, Family: check.PostgreSQL}, + "postgresql_3": {Name: "postgresql_3", Version: 2, Family: check.PostgreSQL}, + "mongodb_1": {Name: "mongodb_1", Version: 2, Family: check.MongoDB}, + "mongodb_2": {Name: "mongodb_2", Version: 2, Family: check.MongoDB}, + "mongodb_3": {Name: "mongodb_3", Version: 2, Family: check.MongoDB}, + "mongodb_4": {Name: "mongodb_4", Version: 2, Family: check.MongoDB}, + "mongodb_5": {Name: "mongodb_5", Version: 2, Family: check.MongoDB}, + "mongodb_6": {Name: "mongodb_6", Version: 2, Family: check.MongoDB}, + "missing family": {Name: "missing family", Version: 2}, + "unknown family": {Name: "unknown family", Version: 2, Family: check.Family("RedisFamily")}, } l := logrus.WithField("component", "tests") mySQLChecks, postgreSQLChecks, mongoDBChecks := groupChecksByDB(l, checks) + // checks with a missing or unknown family are skipped require.Len(t, mySQLChecks, 3) require.Len(t, postgreSQLChecks, 3) require.Len(t, mongoDBChecks, 6) - // V1 checks - assert.Equal(t, check.MySQLShow, mySQLChecks["MySQLShow"].Type) - assert.Equal(t, check.MySQLSelect, mySQLChecks["MySQLSelect"].Type) - - assert.Equal(t, check.PostgreSQLShow, postgreSQLChecks["PostgreSQLShow"].Type) - assert.Equal(t, check.PostgreSQLSelect, postgreSQLChecks["PostgreSQLSelect"].Type) - - assert.Equal(t, check.MongoDBGetParameter, mongoDBChecks["MongoDBGetParameter"].Type) - assert.Equal(t, check.MongoDBBuildInfo, mongoDBChecks["MongoDBBuildInfo"].Type) - assert.Equal(t, check.MongoDBGetCmdLineOpts, mongoDBChecks["MongoDBGetCmdLineOpts"].Type) - assert.Equal(t, check.MongoDBReplSetGetStatus, mongoDBChecks["MongoDBReplSetGetStatus"].Type) - assert.Equal(t, check.MongoDBGetDiagnosticData, mongoDBChecks["MongoDBGetDiagnosticData"].Type) - - // V2 checks - assert.Equal(t, check.MySQL, mySQLChecks["MySQL family V2"].Family) - assert.Equal(t, check.PostgreSQL, postgreSQLChecks["PostgreSQL family V2"].Family) - assert.Equal(t, check.MongoDB, mongoDBChecks["MongoDB family V2"].Family) + assert.Equal(t, check.MySQL, mySQLChecks["mysql_1"].Family) + assert.Equal(t, check.PostgreSQL, postgreSQLChecks["postgresql_1"].Family) + assert.Equal(t, check.MongoDB, mongoDBChecks["mongodb_1"].Family) } diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index 1e50318811e..a558f830063 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -345,7 +345,7 @@ func (s *ChecksAPIService) ListAdvisorChecks(_ context.Context, _ *advisorsv1.Li Name: c.Name, Enabled: !disabled, Summary: c.Summary, - Family: convertFamily(c.GetFamily()), + Family: convertFamily(c.Family), Description: c.Description, Interval: convertInterval(c.Interval), }) @@ -395,7 +395,7 @@ func (s *ChecksAPIService) ListAdvisors(_ context.Context, _ *advisorsv1.ListAdv Name: c.Name, Enabled: !disabled, Summary: c.Summary, - Family: convertFamily(c.GetFamily()), + Family: convertFamily(c.Family), Description: c.Description, Interval: convertInterval(c.Interval), }) @@ -417,7 +417,7 @@ func (s *ChecksAPIService) ListAdvisors(_ context.Context, _ *advisorsv1.ListAdv func createComment(checks []check.Check) string { var mySQL, postgreSQL, mongoDB bool for _, c := range checks { - switch c.GetFamily() { + switch c.Family { case check.MySQL: mySQL = true case check.PostgreSQL: diff --git a/managed/services/management/checks_test.go b/managed/services/management/checks_test.go index f0b0aa8c2d3..0aa2325927b 100644 --- a/managed/services/management/checks_test.go +++ b/managed/services/management/checks_test.go @@ -594,8 +594,8 @@ func TestCreateComment(t *testing.T) { Name: "all technologies", Comment: "All technologies supported", Checks: []check.Check{ - {Version: 1, Name: "a", Type: check.MySQLShow}, - {Version: 1, Name: "b", Type: check.PostgreSQLSelect}, + {Version: 2, Name: "a", Family: check.MySQL}, + {Version: 2, Name: "b", Family: check.PostgreSQL}, {Version: 2, Name: "c", Family: check.MongoDB}, }, }, @@ -603,7 +603,7 @@ func TestCreateComment(t *testing.T) { Name: "partial support", Comment: "Partial support (MySQL, MongoDB)", Checks: []check.Check{ - {Version: 1, Name: "a", Type: check.MySQLShow}, + {Version: 2, Name: "a", Family: check.MySQL}, {Version: 2, Name: "b", Family: check.MongoDB}, }, }, @@ -611,7 +611,7 @@ func TestCreateComment(t *testing.T) { Name: "partial support", Comment: "Partial support (MySQL)", Checks: []check.Check{ - {Version: 1, Name: "a", Type: check.MySQLShow}, + {Version: 2, Name: "a", Family: check.MySQL}, }, }, } From a5862b5d17f3b8fcbafa646e1cd4585f663900d2 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 19 Jul 2026 17:23:56 +0300 Subject: [PATCH 042/120] PMM-12345 Stop shipping advisors on-disk, update related tests and UI components - Changed AdvisorName to Subcategory in CheckResult and related structures. - Updated tests to reflect changes in advisor structure. - Modified UI components to display Subcategory instead of AdvisorName. - Adjusted filtering and sorting logic in AdvisorsList and AdvisorInsights. - Removed unused createComment function and related tests. - Updated YAML configuration for checks to include category and subcategory. --- .github/workflows/managed.yml | 1 - .github/workflows/percona-intelligence.yml | 1 - api/advisors/v1/advisors.pb.go | 66 +++++--- api/advisors/v1/advisors.pb.validate.go | 4 +- api/advisors/v1/advisors.proto | 28 ++-- .../list_advisors_responses.go | 13 +- .../list_check_results_history_responses.go | 6 +- api/advisors/v1/json/v1.json | 23 +-- api/descriptor.bin | Bin 830200 -> 830622 bytes api/swagger/swagger-dev.json | 23 +-- api/swagger/swagger.json | 23 +-- docker-compose.dev.yml | 3 +- managed/Makefile | 4 +- managed/cmd/pi-validator/main.go | 95 +----------- .../advisors/configuration_connection.yml | 7 - .../data/advisors/configuration_generic.yml | 7 - .../data/advisors/configuration_innodb.yml | 7 - .../advisors/configuration_replication.yml | 7 - .../data/advisors/configuration_resources.yml | 7 - .../data/advisors/configuration_vacuum.yml | 7 - .../data/advisors/configuration_version.yml | 7 - managed/data/advisors/example.yml.example | 7 - managed/data/advisors/performance_generic.yml | 7 - .../data/advisors/performance_replication.yml | 7 - managed/data/advisors/performance_vacuum.yml | 7 - managed/data/advisors/query_index.yml | 7 - managed/data/advisors/query_schema_design.yml | 7 - .../data/advisors/security_authentication.yml | 7 - .../data/advisors/security_configuration.yml | 7 - managed/data/advisors/security_connection.yml | 7 - managed/data/advisors/security_cve.yml | 7 - .../data/advisors/security_replication.yml | 7 - managed/data/checks/exampleV2.yml.example | 3 +- managed/data/checks/mongodb_EOL.yml | 3 +- ...ongodb_active_vs_available_connections.yml | 3 +- managed/data/checks/mongodb_auth.yml | 3 +- .../checks/mongodb_authmech_scramsha256.yml | 3 +- managed/data/checks/mongodb_balancer.yml | 3 +- managed/data/checks/mongodb_bindip.yml | 3 +- managed/data/checks/mongodb_cache_size.yml | 3 +- .../checks/mongodb_clickhouse.yml.example | 3 +- .../checks/mongodb_collection_fragmented.yml | 3 +- .../mongodb_connection_sudden_spike.yml | 3 +- managed/data/checks/mongodb_connections.yml | 3 +- managed/data/checks/mongodb_cpucores.yml | 3 +- .../checks/mongodb_cve_2025_14847_zlib.yml | 3 +- managed/data/checks/mongodb_cve_version.yml | 3 +- managed/data/checks/mongodb_dbpath_mount.yml | 3 +- managed/data/checks/mongodb_fcv_check.yml | 3 +- managed/data/checks/mongodb_journal.yml | 3 +- .../checks/mongodb_localhost_auth_bypass.yml | 3 +- managed/data/checks/mongodb_loglevel.yml | 3 +- managed/data/checks/mongodb_maxsessions.yml | 3 +- .../data/checks/mongodb_multiple_services.yml | 3 +- .../mongodb_oplog_size_recommendation.yml | 3 +- .../checks/mongodb_psa_architecture_check.yml | 3 +- managed/data/checks/mongodb_read_tickets.yml | 3 +- .../checks/mongodb_replicaset_topology.yml | 3 +- .../data/checks/mongodb_replication_lag.yml | 3 +- ..._shard_collection_inconsistent_indexes.yml | 3 +- .../data/checks/mongodb_swap_allocation.yml | 3 +- managed/data/checks/mongodb_taskexecutor.yml | 3 +- .../checks/mongodb_unsupported_version.yml | 3 +- managed/data/checks/mongodb_unused_index.yml | 3 +- managed/data/checks/mongodb_version.yml | 3 +- managed/data/checks/mongodb_write_tickets.yml | 3 +- .../checks/mongodb_write_tickets_runtime.yml | 3 +- managed/data/checks/mongodb_xfs_ftype.yml | 3 +- .../checks/mysql_32binary_on_64system.yml | 3 +- ...ahi_efficiency_performance_basic_check.yml | 3 +- .../mysql_automatic_expired_password.yml | 3 +- .../mysql_automatic_sp_privileges_enabled.yml | 3 +- .../mysql_config_binlog_retention_period.yml | 3 +- .../checks/mysql_config_binlog_row_image.yml | 3 +- .../mysql_config_binlogs_checksummed.yml | 3 +- .../data/checks/mysql_config_general_log.yml | 3 +- .../mysql_config_innodb_redolog_disabled.yml | 3 +- .../data/checks/mysql_config_local_infile.yml | 3 +- managed/data/checks/mysql_config_log_bin.yml | 3 +- .../checks/mysql_config_relay_log_purge.yml | 3 +- .../checks/mysql_config_replication_bp1.yml | 3 +- .../mysql_config_slave_parallel_workers.yml | 3 +- managed/data/checks/mysql_config_sql_mode.yml | 3 +- .../data/checks/mysql_config_sync_binlog.yml | 3 +- .../mysql_config_tmp_table_size_limit.yml | 3 +- ...mysql_configuration_innodb_file_format.yml | 3 +- ...sql_configuration_innodb_file_maxlimit.yml | 3 +- ...tion_innodb_file_per_table_not_enabled.yml | 3 +- ...ysql_configuration_innodb_flush_method.yml | 3 +- ...mysql_configuration_innodb_strict_mode.yml | 3 +- .../mysql_configuration_log_verbosity.yml | 3 +- ...ql_configuration_max_connections_usage.yml | 3 +- ...l_configuration_secure_file_priv_empty.yml | 3 +- managed/data/checks/mysql_indexes_larger.yml | 3 +- ...l_innodb_redo_logs_not_sized_correctly.yml | 3 +- .../data/checks/mysql_log_replica_updates.yml | 3 +- managed/data/checks/mysql_password_expiry.yml | 3 +- ...sql_performance_temp_ondisk_table_high.yml | 3 +- .../checks/mysql_private_networks_only.yml | 3 +- ...ing_skipping_errors_or_idempotent_mode.yml | 3 +- .../data/checks/mysql_replication_grants.yml | 3 +- .../checks/mysql_require_secure_transport.yml | 3 +- .../checks/mysql_security_anonymous_user.yml | 3 +- .../mysql_security_open_to_world_host.yml | 3 +- .../mysql_security_password_lifetime.yml | 3 +- .../checks/mysql_security_password_policy.yml | 3 +- ...ysql_security_replication_grants_mixed.yml | 3 +- .../checks/mysql_security_root_not_local.yml | 3 +- .../data/checks/mysql_security_user_ssl.yml | 3 +- .../mysql_security_user_super_not_local.yml | 3 +- .../mysql_security_user_without_password.yml | 3 +- .../data/checks/mysql_tables_without_pk.yml | 3 +- managed/data/checks/mysql_test_database.yml | 3 +- managed/data/checks/mysql_timezone.yml | 3 +- .../mysql_unsupported_version_check.yml | 3 +- managed/data/checks/mysql_version.yml | 3 +- managed/data/checks/mysql_version_eol_57.yml | 3 +- .../checks/postgresql_archiver_failing.yml | 3 +- .../checks/postgresql_cache_hit_ratio.yml | 3 +- ...postgresql_config_changes_need_restart.yml | 3 +- managed/data/checks/postgresql_cve_check.yml | 3 +- managed/data/checks/postgresql_eol_check.yml | 3 +- .../postgresql_expiring_passwd_check.yml | 4 +- .../checks/postgresql_extension_check.yml | 3 +- managed/data/checks/postgresql_fsync.yml | 3 +- ...postgresql_log_autovacuum_min_duration.yml | 3 +- .../checks/postgresql_log_checkpoints.yml | 3 +- ...stgresql_logging_recommendation_checks.yml | 3 +- .../checks/postgresql_max_connections.yml | 3 +- .../checks/postgresql_multidb.yml.example | 3 +- .../postgresql_number_of_index_check.yml | 3 +- .../postgresql_sequential_scan_check.yml | 3 +- .../postgresql_stale_replication_slot.yml | 3 +- managed/data/checks/postgresql_super_role.yml | 3 +- .../postgresql_table_autovac_settings.yml | 3 +- .../checks/postgresql_table_bloat_bytes.yml | 3 +- .../postgresql_table_bloat_in_percentage.yml | 3 +- .../data/checks/postgresql_tmpfiles_check.yml | 3 +- ...postgresql_txid_wraparound_approaching.yml | 3 +- .../checks/postgresql_unsupported_check.yml | 3 +- .../checks/postgresql_unused_index_check.yml | 3 +- .../checks/postgresql_vacuum_sanity_check.yml | 3 +- .../data/checks/postgresql_version_check.yml | 3 +- .../checks/postgresql_wal_retention_check.yml | 3 +- managed/models/check_result_helpers_test.go | 2 +- managed/models/check_result_model.go | 2 +- managed/models/check_result_model_reform.go | 12 +- managed/models/database.go | 2 +- managed/pi/check/advisor.go | 92 +---------- managed/pi/check/check.go | 15 +- .../checks/check_result_record_test.go | 12 +- managed/services/checks/checks.go | 143 +++++------------- managed/services/checks/checks_test.go | 43 ++---- managed/services/checks/insight_text.go | 4 +- managed/services/checks/insight_text_test.go | 6 +- managed/services/checks/registry.go | 2 +- managed/services/checks/registry_test.go | 2 +- managed/services/management/checks.go | 39 +---- managed/services/management/checks_test.go | 45 +----- managed/services/types.go | 2 +- managed/testdata/checks/good_check_pg.yml | 3 +- .../pages/advisors/AdvisorsList.constants.tsx | 9 +- .../pages/advisors/AdvisorsList.messages.ts | 4 +- .../src/pages/advisors/AdvisorsList.test.tsx | 14 +- .../pmm/src/pages/advisors/AdvisorsList.tsx | 55 +++++-- .../details-pane/AdvisorCheckDetailsPane.tsx | 33 ++-- .../insights/AdvisorInsights.constants.tsx | 3 +- .../insights/AdvisorInsights.messages.ts | 1 + .../insights/AdvisorInsights.test.tsx | 15 +- .../advisors/insights/AdvisorInsights.tsx | 21 ++- .../insights/AdvisorInsights.utils.ts | 5 +- .../details-pane/InsightDetailsPane.tsx | 24 ++- ui/apps/pmm/src/types/advisors.types.ts | 9 +- ui/apps/pmm/src/utils/advisors.utils.ts | 2 +- 174 files changed, 568 insertions(+), 806 deletions(-) delete mode 100644 managed/data/advisors/configuration_connection.yml delete mode 100644 managed/data/advisors/configuration_generic.yml delete mode 100644 managed/data/advisors/configuration_innodb.yml delete mode 100644 managed/data/advisors/configuration_replication.yml delete mode 100644 managed/data/advisors/configuration_resources.yml delete mode 100644 managed/data/advisors/configuration_vacuum.yml delete mode 100644 managed/data/advisors/configuration_version.yml delete mode 100644 managed/data/advisors/example.yml.example delete mode 100644 managed/data/advisors/performance_generic.yml delete mode 100644 managed/data/advisors/performance_replication.yml delete mode 100644 managed/data/advisors/performance_vacuum.yml delete mode 100644 managed/data/advisors/query_index.yml delete mode 100644 managed/data/advisors/query_schema_design.yml delete mode 100644 managed/data/advisors/security_authentication.yml delete mode 100644 managed/data/advisors/security_configuration.yml delete mode 100644 managed/data/advisors/security_connection.yml delete mode 100644 managed/data/advisors/security_cve.yml delete mode 100644 managed/data/advisors/security_replication.yml diff --git a/.github/workflows/managed.yml b/.github/workflows/managed.yml index 8498fd12e77..d2143bbc6fc 100644 --- a/.github/workflows/managed.yml +++ b/.github/workflows/managed.yml @@ -64,7 +64,6 @@ jobs: -v ./:/root/go/src/github.com/percona/pmm \ -v ~/go-mod-cache:/home/pmm/.cache/go/mod \ -v ~/go-build-cache:/home/pmm/.cache/go-build \ - -v ./managed/data/advisors/:/usr/local/percona/advisors/ \ -v ./managed/data/checks/:/usr/local/percona/checks/ \ -v ./managed/data/alerting-templates/:/usr/local/percona/alerting-templates/ \ -v ./Makefile.devcontainer:/root/go/src/github.com/percona/pmm/Makefile:ro \ diff --git a/.github/workflows/percona-intelligence.yml b/.github/workflows/percona-intelligence.yml index 017858bb408..c4f891c580e 100644 --- a/.github/workflows/percona-intelligence.yml +++ b/.github/workflows/percona-intelligence.yml @@ -4,7 +4,6 @@ on: pull_request: paths: - 'managed/data/alerting-templates/**' - - 'managed/data/advisors/**' - 'managed/data/checks/**' permissions: diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index fa940ef9f16..8e723a7eb9d 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -660,18 +660,28 @@ func (x *AdvisorCheck) GetFamily() AdvisorCheckFamily { type Advisor struct { state protoimpl.MessageState `protogen:"open.v1"` - // Machine-readable name (ID) that is used in expression. + // Deprecated: no longer populated; an advisor is identified by its category/subcategory pair. + // + // Deprecated: Marked as deprecated in advisors/v1/advisors.proto. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // Long human-readable description. + // Deprecated: advisor descriptions were removed. + // + // Deprecated: Marked as deprecated in advisors/v1/advisors.proto. Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // Short human-readable summary. + // Deprecated: use subcategory instead. + // + // Deprecated: Marked as deprecated in advisors/v1/advisors.proto. Summary string `protobuf:"bytes,3,opt,name=summary,proto3" json:"summary,omitempty"` - // Comment. + // Deprecated: no longer populated. + // + // Deprecated: Marked as deprecated in advisors/v1/advisors.proto. Comment string `protobuf:"bytes,4,opt,name=comment,proto3" json:"comment,omitempty"` - // Category. + // Category (top-level grouping). Category string `protobuf:"bytes,5,opt,name=category,proto3" json:"category,omitempty"` + // Subcategory (second-level grouping within a category). + Subcategory string `protobuf:"bytes,6,opt,name=subcategory,proto3" json:"subcategory,omitempty"` // Advisor checks. - Checks []*AdvisorCheck `protobuf:"bytes,6,rep,name=checks,proto3" json:"checks,omitempty"` + Checks []*AdvisorCheck `protobuf:"bytes,7,rep,name=checks,proto3" json:"checks,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -706,6 +716,7 @@ func (*Advisor) Descriptor() ([]byte, []int) { return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{4} } +// Deprecated: Marked as deprecated in advisors/v1/advisors.proto. func (x *Advisor) GetName() string { if x != nil { return x.Name @@ -713,6 +724,7 @@ func (x *Advisor) GetName() string { return "" } +// Deprecated: Marked as deprecated in advisors/v1/advisors.proto. func (x *Advisor) GetDescription() string { if x != nil { return x.Description @@ -720,6 +732,7 @@ func (x *Advisor) GetDescription() string { return "" } +// Deprecated: Marked as deprecated in advisors/v1/advisors.proto. func (x *Advisor) GetSummary() string { if x != nil { return x.Summary @@ -727,6 +740,7 @@ func (x *Advisor) GetSummary() string { return "" } +// Deprecated: Marked as deprecated in advisors/v1/advisors.proto. func (x *Advisor) GetComment() string { if x != nil { return x.Comment @@ -741,6 +755,13 @@ func (x *Advisor) GetCategory() string { return "" } +func (x *Advisor) GetSubcategory() string { + if x != nil { + return x.Subcategory + } + return "" +} + func (x *Advisor) GetChecks() []*AdvisorCheck { if x != nil { return x.Checks @@ -1446,9 +1467,9 @@ type CheckResultHistoryItem struct { BatchId string `protobuf:"bytes,2,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` // Name of the check that ran. CheckName string `protobuf:"bytes,3,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` - // Name of the advisor the check belongs to. - AdvisorName string `protobuf:"bytes,4,opt,name=advisor_name,json=advisorName,proto3" json:"advisor_name,omitempty"` - // Category of the advisor the check belongs to. + // Subcategory the check belongs to (second-level grouping within a category). + Subcategory string `protobuf:"bytes,4,opt,name=subcategory,proto3" json:"subcategory,omitempty"` + // Category the check belongs to (top-level grouping). Category string `protobuf:"bytes,5,opt,name=category,proto3" json:"category,omitempty"` // Check execution interval. Interval AdvisorCheckInterval `protobuf:"varint,6,opt,name=interval,proto3,enum=advisors.v1.AdvisorCheckInterval" json:"interval,omitempty"` @@ -1543,9 +1564,9 @@ func (x *CheckResultHistoryItem) GetCheckName() string { return "" } -func (x *CheckResultHistoryItem) GetAdvisorName() string { +func (x *CheckResultHistoryItem) GetSubcategory() string { if x != nil { - return x.AdvisorName + return x.Subcategory } return "" } @@ -2149,14 +2170,15 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\vdescription\x18\x03 \x01(\tR\vdescription\x12\x18\n" + "\asummary\x18\x04 \x01(\tR\asummary\x12=\n" + "\binterval\x18\x05 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\binterval\x127\n" + - "\x06family\x18\x06 \x01(\x0e2\x1f.advisors.v1.AdvisorCheckFamilyR\x06family\"\xc2\x01\n" + - "\aAdvisor\x12\x12\n" + - "\x04name\x18\x01 \x01(\tR\x04name\x12 \n" + - "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x18\n" + - "\asummary\x18\x03 \x01(\tR\asummary\x12\x18\n" + - "\acomment\x18\x04 \x01(\tR\acomment\x12\x1a\n" + - "\bcategory\x18\x05 \x01(\tR\bcategory\x121\n" + - "\x06checks\x18\x06 \x03(\v2\x19.advisors.v1.AdvisorCheckR\x06checks\"\x95\x01\n" + + "\x06family\x18\x06 \x01(\x0e2\x1f.advisors.v1.AdvisorCheckFamilyR\x06family\"\xf4\x01\n" + + "\aAdvisor\x12\x16\n" + + "\x04name\x18\x01 \x01(\tB\x02\x18\x01R\x04name\x12$\n" + + "\vdescription\x18\x02 \x01(\tB\x02\x18\x01R\vdescription\x12\x1c\n" + + "\asummary\x18\x03 \x01(\tB\x02\x18\x01R\asummary\x12\x1c\n" + + "\acomment\x18\x04 \x01(\tB\x02\x18\x01R\acomment\x12\x1a\n" + + "\bcategory\x18\x05 \x01(\tR\bcategory\x12 \n" + + "\vsubcategory\x18\x06 \x01(\tR\vsubcategory\x121\n" + + "\x06checks\x18\a \x03(\v2\x19.advisors.v1.AdvisorCheckR\x06checks\"\x95\x01\n" + "\x18ChangeAdvisorCheckParams\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1b\n" + "\x06enable\x18\x02 \x01(\bH\x00R\x06enable\x88\x01\x01\x12=\n" + @@ -2196,13 +2218,13 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "totalItems\x12\x1f\n" + "\vtotal_pages\x18\x02 \x01(\x05R\n" + "totalPages\x122\n" + - "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\xef\a\n" + + "\aresults\x18\x03 \x03(\v2\x18.advisors.v1.CheckResultR\aresults\"\xee\a\n" + "\x16CheckResultHistoryItem\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x19\n" + "\bbatch_id\x18\x02 \x01(\tR\abatchId\x12\x1d\n" + "\n" + - "check_name\x18\x03 \x01(\tR\tcheckName\x12!\n" + - "\fadvisor_name\x18\x04 \x01(\tR\vadvisorName\x12\x1a\n" + + "check_name\x18\x03 \x01(\tR\tcheckName\x12 \n" + + "\vsubcategory\x18\x04 \x01(\tR\vsubcategory\x12\x1a\n" + "\bcategory\x18\x05 \x01(\tR\bcategory\x12=\n" + "\binterval\x18\x06 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\binterval\x12\x1d\n" + "\n" + diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 6320643d0bb..2d8a37474c4 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -538,6 +538,8 @@ func (m *Advisor) validate(all bool) error { // no validation rules for Category + // no validation rules for Subcategory + for idx, item := range m.GetChecks() { _, _ = idx, item @@ -2442,7 +2444,7 @@ func (m *CheckResultHistoryItem) validate(all bool) error { // no validation rules for CheckName - // no validation rules for AdvisorName + // no validation rules for Subcategory // no validation rules for Category diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index db2735a5f31..d3c7527a1fc 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -112,18 +112,20 @@ message AdvisorCheck { } message Advisor { - // Machine-readable name (ID) that is used in expression. - string name = 1; - // Long human-readable description. - string description = 2; - // Short human-readable summary. - string summary = 3; - // Comment. - string comment = 4; - // Category. + // Deprecated: no longer populated; an advisor is identified by its category/subcategory pair. + string name = 1 [deprecated = true]; + // Deprecated: advisor descriptions were removed. + string description = 2 [deprecated = true]; + // Deprecated: use subcategory instead. + string summary = 3 [deprecated = true]; + // Deprecated: no longer populated. + string comment = 4 [deprecated = true]; + // Category (top-level grouping). string category = 5; + // Subcategory (second-level grouping within a category). + string subcategory = 6; // Advisor checks. - repeated AdvisorCheck checks = 6; + repeated AdvisorCheck checks = 7; } // ChangeAdvisorCheckParams specifies a single check parameters. @@ -205,9 +207,9 @@ message CheckResultHistoryItem { string batch_id = 2; // Name of the check that ran. string check_name = 3; - // Name of the advisor the check belongs to. - string advisor_name = 4; - // Category of the advisor the check belongs to. + // Subcategory the check belongs to (second-level grouping within a category). + string subcategory = 4; + // Category the check belongs to (top-level grouping). string category = 5; // Check execution interval. AdvisorCheckInterval interval = 6; diff --git a/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go b/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go index 63df558b915..de970fd7aaa 100644 --- a/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go @@ -529,21 +529,24 @@ ListAdvisorsOKBodyAdvisorsItems0 list advisors OK body advisors items0 swagger:model ListAdvisorsOKBodyAdvisorsItems0 */ type ListAdvisorsOKBodyAdvisorsItems0 struct { - // Machine-readable name (ID) that is used in expression. + // Deprecated: no longer populated; an advisor is identified by its category/subcategory pair. Name string `json:"name,omitempty"` - // Long human-readable description. + // Deprecated: advisor descriptions were removed. Description string `json:"description,omitempty"` - // Short human-readable summary. + // Deprecated: use subcategory instead. Summary string `json:"summary,omitempty"` - // Comment. + // Deprecated: no longer populated. Comment string `json:"comment,omitempty"` - // Category. + // Category (top-level grouping). Category string `json:"category,omitempty"` + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + // Advisor checks. Checks []*ListAdvisorsOKBodyAdvisorsItems0ChecksItems0 `json:"checks"` } diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go index 5b420a830d8..20d508f604b 100644 --- a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go @@ -544,10 +544,10 @@ type ListCheckResultsHistoryOKBodyResultsItems0 struct { // Name of the check that ran. CheckName string `json:"check_name,omitempty"` - // Name of the advisor the check belongs to. - AdvisorName string `json:"advisor_name,omitempty"` + // Subcategory the check belongs to (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` - // Category of the advisor the check belongs to. + // Category the check belongs to (top-level grouping). Category string `json:"category,omitempty"` // AdvisorCheckInterval represents possible execution interval values for checks. diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index 087a082ec6c..f6486a9276f 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -35,30 +35,35 @@ "type": "object", "properties": { "name": { - "description": "Machine-readable name (ID) that is used in expression.", + "description": "Deprecated: no longer populated; an advisor is identified by its category/subcategory pair.", "type": "string", "x-order": 0 }, "description": { - "description": "Long human-readable description.", + "description": "Deprecated: advisor descriptions were removed.", "type": "string", "x-order": 1 }, "summary": { - "description": "Short human-readable summary.", + "description": "Deprecated: use subcategory instead.", "type": "string", "x-order": 2 }, "comment": { - "description": "Comment.", + "description": "Deprecated: no longer populated.", "type": "string", "x-order": 3 }, "category": { - "description": "Category.", + "description": "Category (top-level grouping).", "type": "string", "x-order": 4 }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 5 + }, "checks": { "description": "Advisor checks.", "type": "array", @@ -111,7 +116,7 @@ } } }, - "x-order": 5 + "x-order": 6 } } }, @@ -574,13 +579,13 @@ "type": "string", "x-order": 2 }, - "advisor_name": { - "description": "Name of the advisor the check belongs to.", + "subcategory": { + "description": "Subcategory the check belongs to (second-level grouping within a category).", "type": "string", "x-order": 3 }, "category": { - "description": "Category of the advisor the check belongs to.", + "description": "Category the check belongs to (top-level grouping).", "type": "string", "x-order": 4 }, diff --git a/api/descriptor.bin b/api/descriptor.bin index b6601f04dcd9bf8c230376e769cfc630f5e3f86c..a417471fcfecdad9dce139d4db1a76f034f6c241 100644 GIT binary patch delta 7446 zcmb7IYm`;RmAboIUG@aog|_T%z8&^*N}Z$X6^c^JYNBbY=-M`6SAI8O?SBsV>C@tA+94mDKx_8wd}xB~qH>pnTYOjb%$oYT>3*5( z)J~k5tq_6el^8)4V!XkAH`lAq)=!>ZGp(VfuC{{m!`GYr4sLP%jHy#6PM=*N^D`n7 zk4~qC9bAuOsp;~s_dH>^bS~78Ewp;8M#bV3#k{XrT z`GVukU6rtwPnrwA2X?9T4P#;8z zm-M}^3c<9AHPiLwC9?a(SRA4J?rv*Waoo5BEbV4R35c2jQNxWW=$%2CbiW%!MZvFI z#QI=Xc6v6Lo}F4ZGh404EtTCL5C}7)@@5-GaF`kCJ~j*?%q)Z%Xu=SK-sv7UgqcyF z4X#h1rnbHzJF!}Cg7f6)lfGr^F(%L_K9H1^tu_-YHFwS*8P^r z9yt)70&%n<8c>-Y8r)ylr9rRy?Bu%I>c64~vuYY1tHFZjSGD&ou1&KDtMgPM86hZr zs=UG?1#vlY-A*Q;x|dN^x+Jh?GYEHo-j!0A;FU*YIL=jciVz&Z3N9|yRrzv(|l2xwvd$XJR_*g?QJ}fLEX~rk)-yQ$jb4dMuL-PM0w|k z1t-slu2qOnj`Gza5qlQL)Wb1Vn7K&AyO^1ZVo=(|O7DPwKp;Kz=W_T1O~MPaff1A@ z;g?4gIByc^_QrX!ua=0|a_hVpGna^XS2MHNRBjnp?#FNr=sU~wp`Xi1xn&{|I)@S7 zmWgBvJ%pUN@2n89DkC%wUn_VOIERFdJcrHh{$lzfxcaa1_^9Yea0VjpAbJ8WHbiX1XSs7dV-rNCwb%fc*4L`t2pM zgHAmsE62PLZ3qm*?+d&k*stfSbt3kX_3Od!IuYj{RpfZaZ!`P76@CGIr&-T@P7cjA zi$u6bV1&13;g^~swep?yBG$$MiSDBG^zVo_>;hM!> zZij)_c^`0*OMJCm#NM#FN-(rN(p6$~?TB;%`VLTU6B!7)b_lOy1VP;)I*kq&9>Wl} zL-g!rqWHerDPq5}QG86@DdOQ~@=cUo9ECeSpzrL`(^ksC6Ltx&o$(GMD7!>Sc)kJQ ze3$5$_ka_yOLV@|EpZduTBgmIJ~IJ8UU&%?^n2 zu;hU7aDY2N4N^$@>Y#{yrT@HIKGx}Aw6aN~{!n!I0e$C?p0h^Yo;f5Eo{JKwz3Zww~&SCxe8d;M$95p`}K{?FLj}uN3SNsT5`WOn-AJMtzWhQqdsyOC= zawJMPNxVCbGUZ`I!5~m&`g=EAzYULN!%H!kl;tN^eb7+%x7^7&t4|_{qXM^bC|8g!pD1-|((L6R32zjhfup*q?~DQrf^G1QUXZ-<1ggk%qfuwTMCSzoD!u`P#2VsnKIZ=Tp<0k%rZ4Z>wqCCo_6)2xDWsITVQu;)%TPMe6 zJ}C%m1E2C zWuMGvqJ8*;ff1C?M7JKc$ZZkjEJxu6nIzmKXZ86P9Vq9R@-0Kb z6$6w`_tX8C%0NHWEZb+!6$;S~EFxWbe#HQ5hAY6qJjF zLL@=CBq(Lx$w^8A>5ebUAahBSg|7k_LAfM4M;=n3To%;cH0dOzfb`=pqe)*D9isZC zK)Eb>_p#+JLoQbYDO>I`ApOqEa(L#7C~gzY0p*G)3EO;<$`R!%x|G}BdA( z$6OWZC`vgfS2+q_EGb`oEn=%Fe8Hx0#=aKuaAwL}y4Rvh7tnXE@uk~0i~phRT67@- zf_N>udI1sQT6FaS;y7N5u3m=W)q5?vdQ-$#ZzI{O7m$&@{S`TELL=Gx9adwuw=N)p zG?Kk_0THB;?5)c%4AMyU)=il^U@l>AbVqRjeP^yd_KNJ8nM?N8g%M8YlD#KWB%x~_ z>*{JK7@VhjZIIoD%_IBR!W_t&NA|G=$dd?l(evfn9~ z0}l(RUDz@J;b8&cDQ(=Wz2+aVK7=zt|v0XBJY2@RbQ8C=017d{?Ci-(}7s zri?NaM*5MB^6tzc>JVPem;=fp!sQ%B;qKeS#rdwGp!+uIBOB%4WtzzL+!S%oZ6e!1 zQ^Y-YF;ng~6x4sQ9m%EC^UA`eww!8NZkQP6W&=%4&jb|1Eayzo3? z4r;!Fx`t0=KzLX|neaWGB5uK&gN7c^g0(&b4;fw1$t_qHbhbv&RfR2#7Q9M#+AN1Z zxQe`}$o%23imIY0+>uw&fI;RYmig*=ioIk{Vi{&WPw}3njAiDyttI=!1N5D>q@C5W zY7hXXt|j}@1BBDH(GD&%Z>4q2m(fyocPW=<$DOdOYH zJznV1N`J5<6r1caJdrk#DrYN?>W?F%v z4HV}ee2Sb3({na))X9hn=sQ5&(mxDF)zmlC)J|>)^tCPWN5eLe{fNdKc-TaK_#6g= zh)rZ)B^9Q%Y-Wf2r3{FVD!ueoIq8AT1rJ<^&4gbELk(Pr&D1&kKCblDYZTjV)mCEW zYlIIbo>^(swy<-45CHm4iyr%$95SILatC-~(N7xwr?Xit;4RBAdtBFJtU z{y+q=KlYF_ik0)I({k{wu59u~x)72#!O0#9M!0Q5CyuY)BIno0r^GEbla|HVqc@>*KG>A-RL3%(Dz$_*yzhorYPxe4-B0cOH!( zrqC$(6(|6ugP z(Fvme(TBIohjS-LnV$+kcECJA?QgX*`2s#ccRga`;|f>*Mb0V2FEv};33bEhoq~dJ zvxi0`c#_nB8*I2s|C?0X>%4tL&gn7vbR3h;N93J0>9BS-LDR>i`q^yQf^7akYL0Lp zHQC@-)lZ4e>kB(%Huq`a*cO5LY2n!N+u&0^w&4N9FBIwwIiKgVDYDs|A@B2iHlY#O z{4c4VHk;6fY(6Vw!`{x4^T$FqMJAiGQG8)*MWs+&C!Y(e--r0%pE3ct}_A-bl!@01VUb%m69 zvq5w*h*zk?P^*$3PFHB;k0S`tSIHS`MHgGqSM@tPW$8m#DHvmQ7DMM(t*2BzP1_ssOb&jVFZ3Qw{H@-eh zY8HtWJ?h8u_PS<~D*EN%mrGO~%h65qMY=qiBY93m#zBE1E)Y=I z!%&1lwb3B_Ef7Jk2%6D~d<5ZXfv71sNGkN65|sCc8c$@9rTVrNaz@iq zk+#lZgtw(4n=@N56?)4=qQ4QEg0E$~7@R{oRLey|yD(`CEst_Yn;cd|MF$K$p#DY! z5bC%>U>9(q06|@GyTCqh7~xk4Yy^(thw3?zSmmPlnEISZ4KOo(lgvs^W*m|M3_YN* zFih`$Bvq@Q)v_>oWwb9a48JRRU$EaGRI5c|jq@A8?`n}6X#57oZ#(X%TBFH9D!j?wGdWBxoW|0_VlI(?vn?8L0@pEg~_% z3{+rX3-1Fiawb$Si^O)PD}$kzBV8GzYg?oXF!X?in#e%VwM_(lA_(d>QFn`7cnm|> zHZgdJi4unD6_I$=MF}zW6_K)=DKt?!Im#F;C1B`v>T}P@Yo~RJpu%{E5tL4mvBw+` z&O1e)ZVxyCoucmze#TF;ht!r7dM8Z9FE~DTm|Yx$4{XTiewS{3UQU>{D~=)9Dl&HY zFb6Sq@$&JO2SkirqWDD@L%0~bM86x{4D@nuH*d*W69c_xx9+`C_L;m}q${I2aJpOM zxx12A8LHPs;!RhTN`!x1q-?xOv%&WWO8P_K4KVcf=;oDj*oZwMWxc@&Z+qAqOROZ^ zG~QmO3^Ek>+bi_e&9dJZj2YC;>lkh4k$qvi)AC4?4m&)Q; zTZl5Sk4D!S#=$zID=C-RokvA9eMlw)z3lAs)C3O{VJlmya! z+U1u@$KwJdK{+nE3y=ckL`=bj8?!0{XM2%Yv?|Zp1DSjExjkwwl!zT2jxAHvj-(h0Vt=K za=W1fK>F=9@{ZCekKb5zY-j9X#0OkEySUD)C znR2J0lmqG4ek!MwPK$K4i&75CX;EvNXqI|nRX)T{G|v}6AU%Gq96tI(QET5GFoN=- z7%<3r=!Ga}I0|>REa3_O$`?vH^JuD%-mzBJmd?Zydx3l=mRJGuStftMka0_#)&H|r zez9~mE<^<=XX8R-K>3&{cNj_rNPqWd^3Kx7B5hkmmNKAxENW~g%~A-;Ii`HWP(mPm z=4bMr(z#ez2+FxwSS1Q^K~S|n*ib5g^z3zVXwwBz6BVKolnZeovY>n-C}*CzS;`tz zU#KWfX`K7mgY$|HPM^{E;N0$`mc^#}MC9#7kLhssiRc^o&cWG5LA9p)W+`XTRfU4i zt(OB!7e()={5kM0ilM{ZYUGjXB|*xqMjlAdTrVe-E{SB%XbvcsM8-DpEL9=YWkEIm z)h5*{ApOpIIcD-@QHY{cfpVFn@U@W()n_8{_hetDIppz~NZFY=bD3U=E>pnJyTX_0 z$oud=v|Wj=J3tVxL{};xLR^WiR6v~EE76t8&|axmqAN8=e5H0pS1KS7U#Vjei7%qA zI1=AIUD3sgQAFyBE>=K9>WVH_hBi`Hbg|}4gKsA6pMj_lVCXgLAN*VnE;W<8SYd?I zW^z|yjwHm*CtPUthJwNQ`q0nifbsLmy`(S)vgVU}NdfXC!b^(VWzKxqEo2WiDEuwd zBR0yx;}??q7Qq~NSV$GNtpLKqLc$Z@df;~5LfAvxaC6+QTXfq-G~5>IZJ&@Zg3?0$ z?V~A23Y0}mx!F({X}L*GDlMYk_Tt4HP!)V za^EB{g0h6N5rzA5TfA!M%We9#7qMz>@v3oOZlk>IhB*pQg zZCdMnFX3BGQxFxIzX~+jcl>i|7xEhR>nuY)QCTuUk2YO3*VM2Sr z1GyJUwdp7u*&%=U0^%D7}gPAW8 zzJK_f)EKoL?3|wofT7o+FKm%xr*%ZmVFaavLi@4+g!7K**Z|_7bWmZU`2t|LCB$#s7i;dCoyLR0uc=xwLOU{m-4rf(;FIM47& zB|^1>5^egzRyjS~L8-j|HQ!SS$W}XvUe^sT%PCDeNtu(wcC7hMsu|5f7$V3{nlLqj z*dM#dyP1{qsJHdNtMzOOCi)Q4ZGw|sRJ_UWWu17T`XzapZ*`V9(ha-yvXPTrv6jZQRJYA<9;e#t zoJ_u6kJF9ccJc8YuYOD3NyM)-+uF0bVGK?}f!)~Fhy+iN8vSQB+?4-9s@MPV_B--U zP3}&|GwJ+}f>S0P*3KqqdXLm7mknEx&A*cRq44iF+2D844~Rb2D|X1nrVrvHS_b9^ z@e$>l{{udv_ORh626dXe-*;zI=CV0W!SB1Xu|{O`@1zF1Y^)90d>CiL-p-KsQJhVg z$>t0NA9ZKLCTRKtA6>gPY(X|>Nv(?320w$IBf6;fc4BSLkuq-`ltO`dj;cqwwc$s} zIlBJt2twj{^2WOzrQD7>Pr>z0wKc)Xc`AP1)j&b@1@ivby#&gLzCghrjcC(w*aq5v zkQ(5Q0b3CM6H+(04TYaqFA-hQZ|{WYOQg(;45E`DUZURPoJxKcU80HiMi8PelXsgF zophovQ*f&jZB1};nTnI0=p;mcO5UHkMJJ8uPbv6QEShbg{WqzhPBdE({xec{`FELp zgD%xYv``=2CGTwN!VlR_78ARu(me2y1GBp5>RX~wh<;Lf*E-QDC;CYlT;oJr6P!FL zi({PV6ht>mZ-I+BW z{&%wb=(4w`rMKj|?rhQ~o2O;4#AL%qmrc;LSgJuT8MZ*yGc6zOmiY7VSB5`@za;)r Q_)Fu@@BCHdS0!7%ug8%>k diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index d82cd5c0f6e..89234356fe7 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -1348,30 +1348,35 @@ "type": "object", "properties": { "name": { - "description": "Machine-readable name (ID) that is used in expression.", + "description": "Deprecated: no longer populated; an advisor is identified by its category/subcategory pair.", "type": "string", "x-order": 0 }, "description": { - "description": "Long human-readable description.", + "description": "Deprecated: advisor descriptions were removed.", "type": "string", "x-order": 1 }, "summary": { - "description": "Short human-readable summary.", + "description": "Deprecated: use subcategory instead.", "type": "string", "x-order": 2 }, "comment": { - "description": "Comment.", + "description": "Deprecated: no longer populated.", "type": "string", "x-order": 3 }, "category": { - "description": "Category.", + "description": "Category (top-level grouping).", "type": "string", "x-order": 4 }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 5 + }, "checks": { "description": "Advisor checks.", "type": "array", @@ -1424,7 +1429,7 @@ } } }, - "x-order": 5 + "x-order": 6 } } }, @@ -1887,13 +1892,13 @@ "type": "string", "x-order": 2 }, - "advisor_name": { - "description": "Name of the advisor the check belongs to.", + "subcategory": { + "description": "Subcategory the check belongs to (second-level grouping within a category).", "type": "string", "x-order": 3 }, "category": { - "description": "Category of the advisor the check belongs to.", + "description": "Category the check belongs to (top-level grouping).", "type": "string", "x-order": 4 }, diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index c72fc7a7056..7f5c2a6d446 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -831,30 +831,35 @@ "type": "object", "properties": { "name": { - "description": "Machine-readable name (ID) that is used in expression.", + "description": "Deprecated: no longer populated; an advisor is identified by its category/subcategory pair.", "type": "string", "x-order": 0 }, "description": { - "description": "Long human-readable description.", + "description": "Deprecated: advisor descriptions were removed.", "type": "string", "x-order": 1 }, "summary": { - "description": "Short human-readable summary.", + "description": "Deprecated: use subcategory instead.", "type": "string", "x-order": 2 }, "comment": { - "description": "Comment.", + "description": "Deprecated: no longer populated.", "type": "string", "x-order": 3 }, "category": { - "description": "Category.", + "description": "Category (top-level grouping).", "type": "string", "x-order": 4 }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 5 + }, "checks": { "description": "Advisor checks.", "type": "array", @@ -907,7 +912,7 @@ } } }, - "x-order": 5 + "x-order": 6 } } }, @@ -1370,13 +1375,13 @@ "type": "string", "x-order": 2 }, - "advisor_name": { - "description": "Name of the advisor the check belongs to.", + "subcategory": { + "description": "Subcategory the check belongs to (second-level grouping within a category).", "type": "string", "x-order": 3 }, "category": { - "description": "Category of the advisor the check belongs to.", + "description": "Category the check belongs to (top-level grouping).", "type": "string", "x-order": 4 }, diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 9674f9530f5..a7d77126c93 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -47,8 +47,7 @@ services: - go-modules:/root/go/pkg/mod - go-cache:/root/.cache - pmm-data:/srv - # custom advisor files - - ./managed/data/advisors/:/usr/local/percona/advisors/ + # custom advisor checks - ./managed/data/checks/:/usr/local/percona/checks/ - ./managed/data/alerting-templates/:/usr/local/percona/alerting-templates/ # nginx config overrides diff --git a/managed/Makefile b/managed/Makefile index 8970e4a5e7e..bbbbebc5932 100644 --- a/managed/Makefile +++ b/managed/Makefile @@ -35,8 +35,8 @@ gen: clean ## Generate files clean: ## Remove generated files find . -name *_reform.go -delete -pi-validate: ## Validate Percona Intelligence advisors and checks - go run ./cmd/pi-validator/main.go advisors --advisors.dir ./data/advisors/ --checks.dir ./data/checks/ +pi-validate: ## Validate Percona Intelligence advisor checks + go run ./cmd/pi-validator/main.go advisors --checks.dir ./data/checks/ release: ## Build pmm-managed release binaries env CGO_ENABLED=0 go build -v $(PMM_LD_FLAGS) -o $(PMM_RELEASE_PATH)/ ./cmd/... diff --git a/managed/cmd/pi-validator/main.go b/managed/cmd/pi-validator/main.go index 2123b9eb333..2d161625bd3 100644 --- a/managed/cmd/pi-validator/main.go +++ b/managed/cmd/pi-validator/main.go @@ -33,8 +33,7 @@ import ( ) type advisorsCommand struct { - AdvisorsDir string `name:"advisors.dir" help:"Advisors directory" default:"data/advisors"` - ChecksDir string `name:"checks.dir" help:"Checks directory" default:"data/checks"` + ChecksDir string `name:"checks.dir" help:"Checks directory" default:"data/checks"` } type templatesCommand struct { @@ -42,7 +41,8 @@ type templatesCommand struct { } func (a *advisorsCommand) Run() error { - return validateAdvisorsAndChecks(a.AdvisorsDir, a.ChecksDir) + _, err := loadAndValidateChecks(a.ChecksDir) + return err } func (t *templatesCommand) Run() error { @@ -60,95 +60,6 @@ func main() { kongCtx.FatalIfErrorf(err) } -func validateAdvisorsAndChecks(advisorsDir, checksDir string) error { - advisors, err := loadAndValidateAdvisors(advisorsDir) - if err != nil { - return err - } - checks, err := loadAndValidateChecks(checksDir) - if err != nil { - return err - } - - for _, c := range checks { - a, ok := advisors[c.Advisor] - if !ok { - log.Fatalf("check '%s' refers unknown advisor '%s'", c.Name, c.Advisor) - } - - a.Checks = append(a.Checks, c) - } - return nil -} - -func loadAndValidateAdvisors(dir string) (map[string]*check.Advisor, error) { - patterns := []string{ - filepath.Join(dir, "*.yml"), - filepath.Join(dir, "*.yml.example"), - } - - var matches []string - - for _, pattern := range patterns { - files, err := filepath.Glob(pattern) - if err != nil { - log.Printf("failed to find advisor files matching '%s': %+v", pattern, err) - } - matches = append(matches, files...) - } - if len(matches) == 0 { - return nil, fmt.Errorf("no advisor files found in %s", dir) - } - - res := make(map[string]*check.Advisor, len(matches)) - for _, file := range matches { - log.Printf("Loading advisor file: %s", file) - _, fileName := filepath.Split(file) - - var validationErrors []error - b, err := os.ReadFile(file) //nolint:gosec - if err != nil { - validationErrors = append(validationErrors, fmt.Errorf("failed to read check file %s: %w", fileName, err)) - } - body := strings.TrimSpace(string(b)) - if !strings.HasPrefix(body, "---") { - validationErrors = append(validationErrors, fmt.Errorf("file %s should start with '---' separator", fileName)) - } - - if len(validationErrors) != 0 { - return nil, errors.Join(validationErrors...) - } - advisors, err := check.ParseAdvisors(strings.NewReader(body), &check.ParseParams{ - DisallowUnknownFields: true, - DisallowInvalidChecks: true, - }) - if err != nil { - validationErrors = append(validationErrors, fmt.Errorf("failed to parse advisors file %s: %w", fileName, err)) - } - - if len(advisors) != 1 { - validationErrors = append(validationErrors, fmt.Errorf("expected exactly one advisor in %s", fileName)) - } - a := advisors[0] - - if a.Name != strings.TrimSuffix(strings.TrimSuffix(fileName, ".example"), ".yml") { - validationErrors = append(validationErrors, fmt.Errorf("advisor name does not match file name %s", file)) - } - - if _, ok := res[a.Name]; ok { - validationErrors = append(validationErrors, fmt.Errorf("advisor name collision detected for: %s", a.Name)) - } - - res[a.Name] = &a - - if len(validationErrors) != 0 { - return nil, errors.Join(validationErrors...) - } - } - - return res, nil -} - func loadAndValidateChecks(dir string) (map[string]check.Check, error) { patterns := []string{ filepath.Join(dir, "*.yml"), diff --git a/managed/data/advisors/configuration_connection.yml b/managed/data/advisors/configuration_connection.yml deleted file mode 100644 index 14f92053cc6..00000000000 --- a/managed/data/advisors/configuration_connection.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: configuration_connection - summary: Connection Configuration - description: Provides recommendations on configuring database connection parameters for improving database performance. - category: configuration diff --git a/managed/data/advisors/configuration_generic.yml b/managed/data/advisors/configuration_generic.yml deleted file mode 100644 index 6d59052d67a..00000000000 --- a/managed/data/advisors/configuration_generic.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: configuration_generic - summary: Generic Configuration - description: Provides basic recommendations for improving your database configuration. - category: configuration diff --git a/managed/data/advisors/configuration_innodb.yml b/managed/data/advisors/configuration_innodb.yml deleted file mode 100644 index 92b6598b1a7..00000000000 --- a/managed/data/advisors/configuration_innodb.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: configuration_innodb - summary: InnoDB Configuration - description: Advises on configuring InnoDB optimization for high performance. - category: configuration diff --git a/managed/data/advisors/configuration_replication.yml b/managed/data/advisors/configuration_replication.yml deleted file mode 100644 index 98480494b8b..00000000000 --- a/managed/data/advisors/configuration_replication.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: configuration_replication - summary: Replication Configuration - description: Provides recommendations for scalable replication in database clusters. - category: configuration diff --git a/managed/data/advisors/configuration_resources.yml b/managed/data/advisors/configuration_resources.yml deleted file mode 100644 index 3007b3a52f6..00000000000 --- a/managed/data/advisors/configuration_resources.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: configuration_resources - summary: Resources Configuration - description: Watches your database and gives you recommendations for efficient management of resources like binaries architecture, CPU number versus DB Configuration, etc. - category: configuration diff --git a/managed/data/advisors/configuration_vacuum.yml b/managed/data/advisors/configuration_vacuum.yml deleted file mode 100644 index e864e21b0f9..00000000000 --- a/managed/data/advisors/configuration_vacuum.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: configuration_vacuum - summary: Vacuum Configuration - description: Provides recommendations on optimizing Vacuum configuration. - category: configuration diff --git a/managed/data/advisors/configuration_version.yml b/managed/data/advisors/configuration_version.yml deleted file mode 100644 index ed0f0bf7f28..00000000000 --- a/managed/data/advisors/configuration_version.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: configuration_version - summary: Version Configuration - description: Notifies of newly released database versions to streamline database maintenance and ensure the most up-to-date performance. - category: configuration diff --git a/managed/data/advisors/example.yml.example b/managed/data/advisors/example.yml.example deleted file mode 100644 index f2e531670e6..00000000000 --- a/managed/data/advisors/example.yml.example +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: example - summary: Example advisor - description: Advisor that gives awesome advises. - category: security diff --git a/managed/data/advisors/performance_generic.yml b/managed/data/advisors/performance_generic.yml deleted file mode 100644 index 190490b5f16..00000000000 --- a/managed/data/advisors/performance_generic.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: performance_generic - summary: Generic Performance - description: Provides basic database configuration recommendations for high-performance query execution. - category: performance diff --git a/managed/data/advisors/performance_replication.yml b/managed/data/advisors/performance_replication.yml deleted file mode 100644 index 63b04784575..00000000000 --- a/managed/data/advisors/performance_replication.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: performance_replication - summary: Replication Performance - description: Checks efficient replication usage of your database. - category: performance diff --git a/managed/data/advisors/performance_vacuum.yml b/managed/data/advisors/performance_vacuum.yml deleted file mode 100644 index f90f9865099..00000000000 --- a/managed/data/advisors/performance_vacuum.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: performance_vacuum - summary: Vacuum Performance - description: Helps improve the efficiency and execution speed of database Vacuum operations. - category: configuration diff --git a/managed/data/advisors/query_index.yml b/managed/data/advisors/query_index.yml deleted file mode 100644 index 129167e6caa..00000000000 --- a/managed/data/advisors/query_index.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: query_index - summary: Index Query - description: Provides query and index optimization strategies for peak database performance. - category: query diff --git a/managed/data/advisors/query_schema_design.yml b/managed/data/advisors/query_schema_design.yml deleted file mode 100644 index c31d78e5529..00000000000 --- a/managed/data/advisors/query_schema_design.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: query_schema_design - summary: Schema Design Query - description: Helps create efficient database schemas by analyzing queries and offering suggestions for optimization. - category: query diff --git a/managed/data/advisors/security_authentication.yml b/managed/data/advisors/security_authentication.yml deleted file mode 100644 index 5d40ee528ba..00000000000 --- a/managed/data/advisors/security_authentication.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: security_authentication - summary: Authentication Security - description: Ensures that all database authentication parameters are configured securely. - category: security diff --git a/managed/data/advisors/security_configuration.yml b/managed/data/advisors/security_configuration.yml deleted file mode 100644 index 0be2be5db20..00000000000 --- a/managed/data/advisors/security_configuration.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: security_configuration - summary: Configuration Security - description: Checks your database configuration to ensure that security best practices are correctly implemented. - category: security diff --git a/managed/data/advisors/security_connection.yml b/managed/data/advisors/security_connection.yml deleted file mode 100644 index e62766ac507..00000000000 --- a/managed/data/advisors/security_connection.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: security_connection - summary: Connection Security - description: Helps identify security issues on network connections and provides recommendations for enhancing security. - category: security diff --git a/managed/data/advisors/security_cve.yml b/managed/data/advisors/security_cve.yml deleted file mode 100644 index f63cad0a2e7..00000000000 --- a/managed/data/advisors/security_cve.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: security_cve - summary: CVE Security - description: Informs you of any database versions affected by CVE. - category: security diff --git a/managed/data/advisors/security_replication.yml b/managed/data/advisors/security_replication.yml deleted file mode 100644 index bd4f40e3995..00000000000 --- a/managed/data/advisors/security_replication.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -advisors: - - version: 1 - name: security_replication - summary: Replication Security - description: Helps safeguard data replication by assessing security risks and providing recommendations for improving protection. - category: security diff --git a/managed/data/checks/exampleV2.yml.example b/managed/data/checks/exampleV2.yml.example index 481ac1e0a0f..59a408b48de 100644 --- a/managed/data/checks/exampleV2.yml.example +++ b/managed/data/checks/exampleV2.yml.example @@ -5,7 +5,8 @@ checks: summary: Check format V2 description: Checks something important interval: standard - advisor: example + category: Security + subcategory: Example family: MYSQL queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mongodb_EOL.yml b/managed/data/checks/mongodb_EOL.yml index 0ac7a132f82..6ece94ec410 100644 --- a/managed/data/checks/mongodb_EOL.yml +++ b/managed/data/checks/mongodb_EOL.yml @@ -6,7 +6,8 @@ checks: description: This check returns errors or warnings if your current PSMDB or MongoDB version has reached or is about to reach End-of-Life. interval: standard family: MONGODB - advisor: configuration_version + category: Configuration + subcategory: Version #category: configuration #subcategory: version configuration #author: Parag Bhayani diff --git a/managed/data/checks/mongodb_active_vs_available_connections.yml b/managed/data/checks/mongodb_active_vs_available_connections.yml index 6cf2cf53496..1ca831299c2 100644 --- a/managed/data/checks/mongodb_active_vs_available_connections.yml +++ b/managed/data/checks/mongodb_active_vs_available_connections.yml @@ -7,7 +7,8 @@ checks: description: This check returns warnings if the ratio between active and available connections is higher than 75% family: MONGODB #author: Corrado Pandiani - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: MONGODB_GETDIAGNOSTICDATA diff --git a/managed/data/checks/mongodb_auth.yml b/managed/data/checks/mongodb_auth.yml index 3b7e6332930..9d2d1146d48 100644 --- a/managed/data/checks/mongodb_auth.yml +++ b/managed/data/checks/mongodb_auth.yml @@ -5,7 +5,8 @@ checks: summary: MongoDB authentication description: Warns if MongoDB authentication is disabled. family: MONGODB - advisor: security_authentication + category: Security + subcategory: Authentication interval: standard queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_authmech_scramsha256.yml b/managed/data/checks/mongodb_authmech_scramsha256.yml index d0e48bbec97..30156fd4744 100644 --- a/managed/data/checks/mongodb_authmech_scramsha256.yml +++ b/managed/data/checks/mongodb_authmech_scramsha256.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if MongoDB is not using the default SHA-256 hashing function as its SCRAM authentication method. family: MONGODB #author: Kimberly Wilkins - advisor: security_configuration + category: Security + subcategory: Configuration interval: standard queries: - type: MONGODB_GETPARAMETER diff --git a/managed/data/checks/mongodb_balancer.yml b/managed/data/checks/mongodb_balancer.yml index 33de3a10a04..7bea075701d 100644 --- a/managed/data/checks/mongodb_balancer.yml +++ b/managed/data/checks/mongodb_balancer.yml @@ -6,7 +6,8 @@ checks: description: This check warns if the balancer process is disabled interval: standard family: MONGODB - advisor: performance_replication + category: Performance + subcategory: Replication #author: Parag bhayani queries: - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_bindip.yml b/managed/data/checks/mongodb_bindip.yml index c86a0ac61f4..720f4e59984 100644 --- a/managed/data/checks/mongodb_bindip.yml +++ b/managed/data/checks/mongodb_bindip.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if the MongoDB network binding is not set as recommended. family: MONGODB #author: Divyanshu Soni - advisor: security_connection + category: Security + subcategory: Connection interval: standard queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_cache_size.yml b/managed/data/checks/mongodb_cache_size.yml index 5a4893abe95..eeb075a112b 100644 --- a/managed/data/checks/mongodb_cache_size.yml +++ b/managed/data/checks/mongodb_cache_size.yml @@ -6,7 +6,8 @@ checks: description: Mongo wiredtiger cache size is greater then default 50% interval: standard family: MONGODB - advisor: configuration_generic + category: Configuration + subcategory: Generic queries: - type: METRICS_INSTANT query: mongodb_sys_memory_MemTotal_kb{node_name="{{.NodeName}}"} diff --git a/managed/data/checks/mongodb_clickhouse.yml.example b/managed/data/checks/mongodb_clickhouse.yml.example index ea24c3d9b73..6569dff14e1 100644 --- a/managed/data/checks/mongodb_clickhouse.yml.example +++ b/managed/data/checks/mongodb_clickhouse.yml.example @@ -3,7 +3,8 @@ checks: - version: 2 name: mongodb_clickhouse summary: Sample Clickhouse advisor that checks if QAN is on a MongoDB instance - advisor: example + category: Security + subcategory: Example description: Sample Clickhouse advisor that checks if QAN is on a MongoDB instance interval: standard family: MONGODB diff --git a/managed/data/checks/mongodb_collection_fragmented.yml b/managed/data/checks/mongodb_collection_fragmented.yml index 030c86fc61b..e3c44dfdfe3 100644 --- a/managed/data/checks/mongodb_collection_fragmented.yml +++ b/managed/data/checks/mongodb_collection_fragmented.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if the Storage size is greater than the Data size of a collection. That condition indicates that the collection is fragmented and needs a Compaction or Initial sync to reclaim disk space. interval: rare family: MONGODB - advisor: configuration_resources + category: Configuration + subcategory: Resources #author: Parag Bhayani queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_connection_sudden_spike.yml b/managed/data/checks/mongodb_connection_sudden_spike.yml index 42814700dc5..73c9d029cf9 100644 --- a/managed/data/checks/mongodb_connection_sudden_spike.yml +++ b/managed/data/checks/mongodb_connection_sudden_spike.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if there is an increase in the number of connections that is higher than 50% of the most recent or normal number of connections. interval: standard family: MONGODB - advisor: configuration_connection + category: Configuration + subcategory: Connection #author: Parag Bhayani queries: - type: METRICS_RANGE diff --git a/managed/data/checks/mongodb_connections.yml b/managed/data/checks/mongodb_connections.yml index 514c5d3c3b2..a31a1fab0bf 100644 --- a/managed/data/checks/mongodb_connections.yml +++ b/managed/data/checks/mongodb_connections.yml @@ -6,7 +6,8 @@ checks: description: This check returns the current number of connections as an informational notice when connection counts are above 5000. interval: standard family: MONGODB - advisor: configuration_connection + category: Configuration + subcategory: Connection #category: configuration #subcategory: connection #author: Parag Bhayani diff --git a/managed/data/checks/mongodb_cpucores.yml b/managed/data/checks/mongodb_cpucores.yml index f904f1d9e69..f1fc4b6bcea 100644 --- a/managed/data/checks/mongodb_cpucores.yml +++ b/managed/data/checks/mongodb_cpucores.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if the number of CPU cores does not meet the minimum recommended requirements according to best practices. family: MONGODB #author: Parag Bhayani - advisor: configuration_resources + category: Configuration + subcategory: Resources interval: standard queries: - type: MONGODB_GETDIAGNOSTICDATA diff --git a/managed/data/checks/mongodb_cve_2025_14847_zlib.yml b/managed/data/checks/mongodb_cve_2025_14847_zlib.yml index 0ea40c81fc6..0248770a5d9 100644 --- a/managed/data/checks/mongodb_cve_2025_14847_zlib.yml +++ b/managed/data/checks/mongodb_cve_2025_14847_zlib.yml @@ -9,7 +9,8 @@ checks: EOL (no fix): 3.6.x, 4.0.x, 4.2.x interval: frequent family: MONGODB - advisor: security_cve + category: Security + subcategory: Vulnerabilities queries: - type: MONGODB_BUILDINFO - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_cve_version.yml b/managed/data/checks/mongodb_cve_version.yml index 9be698c76e0..0771b7af6a2 100644 --- a/managed/data/checks/mongodb_cve_version.yml +++ b/managed/data/checks/mongodb_cve_version.yml @@ -5,7 +5,8 @@ checks: summary: MongoDB CVE Version description: This check returns errors if MongoDB or Percona Server for MongoDB version is less than the latest one with CVE fixes. family: MONGODB - advisor: security_cve + category: Security + subcategory: Vulnerabilities interval: standard queries: - type: MONGODB_BUILDINFO diff --git a/managed/data/checks/mongodb_dbpath_mount.yml b/managed/data/checks/mongodb_dbpath_mount.yml index 0b9443031db..b20809d120f 100644 --- a/managed/data/checks/mongodb_dbpath_mount.yml +++ b/managed/data/checks/mongodb_dbpath_mount.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if dbpath does not have a dedicated mount point. interval: rare family: MONGODB - advisor: configuration_resources + category: Configuration + subcategory: Resources #author: Parag Bhayani queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_fcv_check.yml b/managed/data/checks/mongodb_fcv_check.yml index 1e3da3cee46..50175e5718c 100644 --- a/managed/data/checks/mongodb_fcv_check.yml +++ b/managed/data/checks/mongodb_fcv_check.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if there is a mismatch between the MongoDB version and the internal FCV parameter setting. interval: standard family: MONGODB - advisor: configuration_resources + category: Configuration + subcategory: Resources #category: configuration #author: Parag Bhayani queries: diff --git a/managed/data/checks/mongodb_journal.yml b/managed/data/checks/mongodb_journal.yml index 8023befdca5..2ee48537320 100644 --- a/managed/data/checks/mongodb_journal.yml +++ b/managed/data/checks/mongodb_journal.yml @@ -7,7 +7,8 @@ checks: description: This check returns warnings if journal is disabled. family: MONGODB #author: Corrado Pandiani - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_localhost_auth_bypass.yml b/managed/data/checks/mongodb_localhost_auth_bypass.yml index c1841a7c4b0..73bd164b224 100644 --- a/managed/data/checks/mongodb_localhost_auth_bypass.yml +++ b/managed/data/checks/mongodb_localhost_auth_bypass.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if MongoDB localhost bypass is enabled. family: MONGODB #author: Divyanshu Soni - advisor: security_authentication + category: Security + subcategory: Authentication interval: standard queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_loglevel.yml b/managed/data/checks/mongodb_loglevel.yml index d3005e5ff4e..7a147bbe2e3 100644 --- a/managed/data/checks/mongodb_loglevel.yml +++ b/managed/data/checks/mongodb_loglevel.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if MongoDB is not using the default log level. family: MONGODB #author: Vinicius Grippa - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_maxsessions.yml b/managed/data/checks/mongodb_maxsessions.yml index 4d9a7f1a701..11dd51fd59f 100644 --- a/managed/data/checks/mongodb_maxsessions.yml +++ b/managed/data/checks/mongodb_maxsessions.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if MongoDB is using more maxSessions value other than the default one 1000000 2 interval: standard family: MONGODB - advisor: configuration_resources + category: Configuration + subcategory: Resources #author: Vinodh Krishnaswamy/Parag Bhayani queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_multiple_services.yml b/managed/data/checks/mongodb_multiple_services.yml index 950579b1a72..9d2ed789736 100644 --- a/managed/data/checks/mongodb_multiple_services.yml +++ b/managed/data/checks/mongodb_multiple_services.yml @@ -6,7 +6,8 @@ checks: description: This check returns a notice if multiple mongod services are running in a single node. interval: standard family: MONGODB - advisor: performance_generic + category: Performance + subcategory: Generic #author: Parag Bhayani queries: - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_oplog_size_recommendation.yml b/managed/data/checks/mongodb_oplog_size_recommendation.yml index af6669ff730..bd950c77631 100644 --- a/managed/data/checks/mongodb_oplog_size_recommendation.yml +++ b/managed/data/checks/mongodb_oplog_size_recommendation.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if the oplog window is below a 24 hour period and offers a recommended oplog size based on your instance. interval: standard family: MONGODB - advisor: performance_replication + category: Performance + subcategory: Replication #author: Parag Bhayani queries: - type: MONGODB_GETDIAGNOSTICDATA diff --git a/managed/data/checks/mongodb_psa_architecture_check.yml b/managed/data/checks/mongodb_psa_architecture_check.yml index 1dab6793bf4..e47c1b44a85 100644 --- a/managed/data/checks/mongodb_psa_architecture_check.yml +++ b/managed/data/checks/mongodb_psa_architecture_check.yml @@ -6,7 +6,8 @@ checks: description: This check returns an error if the replicaSet is using a PSA architecture. interval: standard family: MONGODB - advisor: configuration_replication + category: Configuration + subcategory: Replication #author: Parag Bhayani queries: - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_read_tickets.yml b/managed/data/checks/mongodb_read_tickets.yml index 07d2b72e126..485d45b77d7 100644 --- a/managed/data/checks/mongodb_read_tickets.yml +++ b/managed/data/checks/mongodb_read_tickets.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if MongoDB is using more than 128 read tickets. interval: standard family: MONGODB - advisor: configuration_generic + category: Configuration + subcategory: Generic #author: Vinicius Grippa/Parag Bhayani queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_replicaset_topology.yml b/managed/data/checks/mongodb_replicaset_topology.yml index 2447cdfc975..935930d6774 100644 --- a/managed/data/checks/mongodb_replicaset_topology.yml +++ b/managed/data/checks/mongodb_replicaset_topology.yml @@ -7,7 +7,8 @@ checks: description: This check returns warnings if the Replica Set has less than 3 data bearing nodes family: MONGODB #author: Corrado Pandiani - advisor: configuration_replication + category: Configuration + subcategory: Replication interval: standard queries: - type: MONGODB_REPLSETGETSTATUS diff --git a/managed/data/checks/mongodb_replication_lag.yml b/managed/data/checks/mongodb_replication_lag.yml index 95880572c24..9d4a33413d0 100644 --- a/managed/data/checks/mongodb_replication_lag.yml +++ b/managed/data/checks/mongodb_replication_lag.yml @@ -5,7 +5,8 @@ checks: name: mongodb_replication_lag summary: MongoDB Replication Lag description: This check returns warnings if the Replica Set member is more than 10 sec behind the primary - advisor: performance_replication + category: Performance + subcategory: Replication family: MONGODB #author: Ivan Groenewold interval: standard diff --git a/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml b/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml index d7959f6f4d4..847bcf8048c 100644 --- a/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml +++ b/managed/data/checks/mongodb_shard_collection_inconsistent_indexes.yml @@ -6,7 +6,8 @@ checks: description: This check warns if there are inconsistent indexes across shards for sharded collections. Missing or inconsistent indexes across the shards can have a negative impact on performance. interval: standard family: MONGODB - advisor: query_index + category: Query + subcategory: Index #author: Parag Bhayani queries: - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_swap_allocation.yml b/managed/data/checks/mongodb_swap_allocation.yml index 2d4df98eba4..e233c264cd2 100644 --- a/managed/data/checks/mongodb_swap_allocation.yml +++ b/managed/data/checks/mongodb_swap_allocation.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if there is no swap memory allocated to your instance. interval: standard family: MONGODB - advisor: configuration_resources + category: Configuration + subcategory: Resources #author: Parag Bhayani queries: - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_taskexecutor.yml b/managed/data/checks/mongodb_taskexecutor.yml index 9b1ca226ff8..9cb98504b60 100644 --- a/managed/data/checks/mongodb_taskexecutor.yml +++ b/managed/data/checks/mongodb_taskexecutor.yml @@ -7,7 +7,8 @@ checks: interval: standard family: MONGODB #author: Divyanshu Soni/Parag Bhayani - advisor: configuration_resources + category: Configuration + subcategory: Resources queries: - type: MONGODB_GETPARAMETER - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_unsupported_version.yml b/managed/data/checks/mongodb_unsupported_version.yml index 7acc8a07551..08c492ea1e7 100644 --- a/managed/data/checks/mongodb_unsupported_version.yml +++ b/managed/data/checks/mongodb_unsupported_version.yml @@ -6,7 +6,8 @@ checks: description: This check returns errors if your current PSMDB or MongoDB version is not supported. interval: standard family: MONGODB - advisor: configuration_version + category: Configuration + subcategory: Version #category: configuration #subcategory: version configuration #author: Parag Bhayani diff --git a/managed/data/checks/mongodb_unused_index.yml b/managed/data/checks/mongodb_unused_index.yml index 56b875651e6..ce3416fb659 100644 --- a/managed/data/checks/mongodb_unused_index.yml +++ b/managed/data/checks/mongodb_unused_index.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if there are unused indexes on any database collection in your instance (Need to enable "indexStats" collector). interval: standard family: MONGODB - advisor: query_index + category: Query + subcategory: Index #author: Parag Bhayani queries: - type: METRICS_INSTANT diff --git a/managed/data/checks/mongodb_version.yml b/managed/data/checks/mongodb_version.yml index 0b8cd356d4c..30c10bb606b 100644 --- a/managed/data/checks/mongodb_version.yml +++ b/managed/data/checks/mongodb_version.yml @@ -5,7 +5,8 @@ checks: summary: MongoDB version check description: This check returns information on current MongoDB or Percona Server for MongoDB versions used in your environment. It also provides information on other available minor or major versions to consider for upgrades. family: MONGODB - advisor: configuration_version + category: Configuration + subcategory: Version #category: configuration #author: Parag Bhayani interval: standard diff --git a/managed/data/checks/mongodb_write_tickets.yml b/managed/data/checks/mongodb_write_tickets.yml index 51dbaf91465..a20de9dfe4e 100644 --- a/managed/data/checks/mongodb_write_tickets.yml +++ b/managed/data/checks/mongodb_write_tickets.yml @@ -6,7 +6,8 @@ checks: description: This check returns warnings if MongoDB is using more than 128 write tickets. interval: standard family: MONGODB - advisor: configuration_generic + category: Configuration + subcategory: Generic #author: Vinicius Grippa/Parag Bhayani queries: - type: MONGODB_GETCMDLINEOPTS diff --git a/managed/data/checks/mongodb_write_tickets_runtime.yml b/managed/data/checks/mongodb_write_tickets_runtime.yml index a3177994648..39c7cdcb12a 100644 --- a/managed/data/checks/mongodb_write_tickets_runtime.yml +++ b/managed/data/checks/mongodb_write_tickets_runtime.yml @@ -7,7 +7,8 @@ checks: description: This check returns warnings if MongoDB is using more than 128 write tickets during runtime. family: MONGODB #author: Vinicius Grippa - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: MONGODB_GETPARAMETER diff --git a/managed/data/checks/mongodb_xfs_ftype.yml b/managed/data/checks/mongodb_xfs_ftype.yml index ca78bcf7956..74d149c73f3 100644 --- a/managed/data/checks/mongodb_xfs_ftype.yml +++ b/managed/data/checks/mongodb_xfs_ftype.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if dbpath is not using xfs filesystem type. interval: standard family: MONGODB - advisor: configuration_resources + category: Configuration + subcategory: Resources #category: configuration #author: Parag Bhayani queries: diff --git a/managed/data/checks/mysql_32binary_on_64system.yml b/managed/data/checks/mysql_32binary_on_64system.yml index 173ac33d97a..8c6cbebad3e 100644 --- a/managed/data/checks/mysql_32binary_on_64system.yml +++ b/managed/data/checks/mysql_32binary_on_64system.yml @@ -6,7 +6,8 @@ checks: description: This check returns a notice if version_compile_machine equals i686. family: MYSQL #author: Carlos Tutte - advisor: configuration_resources + category: Configuration + subcategory: Resources interval: standard queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml b/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml index 30c889b5fb1..356c59e0443 100644 --- a/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml +++ b/managed/data/checks/mysql_ahi_efficiency_performance_basic_check.yml @@ -5,7 +5,8 @@ checks: summary: InnoDB Adaptive Hash Index (AHI) efficiency checker description: Check the efficiency and effectiveness of InnoDB's Adaptive Hash Index (AHI). interval: standard - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB family: MYSQL queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mysql_automatic_expired_password.yml b/managed/data/checks/mysql_automatic_expired_password.yml index 337debe2f85..f727322a108 100644 --- a/managed/data/checks/mysql_automatic_expired_password.yml +++ b/managed/data/checks/mysql_automatic_expired_password.yml @@ -5,7 +5,8 @@ checks: summary: MySQL Automatic User Expired Password description: This check warns if MySQL parameter automatic password expiry is not active. family: MYSQL - advisor: security_authentication + category: Security + subcategory: Authentication interval: standard queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml b/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml index 0b946f245fe..76b5bd22c6a 100644 --- a/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml +++ b/managed/data/checks/mysql_automatic_sp_privileges_enabled.yml @@ -6,7 +6,8 @@ checks: description: This check reviews the automatic_sp_privileges configuration is ON. family: MYSQL #author: Kedar Vaijanapurkar - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_config_binlog_retention_period.yml b/managed/data/checks/mysql_config_binlog_retention_period.yml index 5db27ef9bb2..93d8cec8e8b 100644 --- a/managed/data/checks/mysql_config_binlog_retention_period.yml +++ b/managed/data/checks/mysql_config_binlog_retention_period.yml @@ -5,7 +5,8 @@ checks: summary: Binlogs retention check description: Binlogs should not be rotated too often, except very specific cases. interval: standard - advisor: configuration_generic + category: Configuration + subcategory: Generic family: MYSQL queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_config_binlog_row_image.yml b/managed/data/checks/mysql_config_binlog_row_image.yml index ec2c536e22e..74f2b44767e 100644 --- a/managed/data/checks/mysql_config_binlog_row_image.yml +++ b/managed/data/checks/mysql_config_binlog_row_image.yml @@ -5,7 +5,8 @@ checks: summary: Binlogs raw image is not set to FULL description: Please consider setting binlog_row_image=FULL. interval: standard - advisor: configuration_generic + category: Configuration + subcategory: Generic #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_binlogs_checksummed.yml b/managed/data/checks/mysql_config_binlogs_checksummed.yml index 897f8ab5ac9..ac90d0a420c 100644 --- a/managed/data/checks/mysql_config_binlogs_checksummed.yml +++ b/managed/data/checks/mysql_config_binlogs_checksummed.yml @@ -5,7 +5,8 @@ checks: summary: Server is not configured to enforce data integrity description: Please consider setting binlog_checksum=CRC32 to improve consistency and reliability. interval: standard - advisor: configuration_generic + category: Configuration + subcategory: Generic #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_general_log.yml b/managed/data/checks/mysql_config_general_log.yml index b5f23fc8f3a..6de92d3accd 100644 --- a/managed/data/checks/mysql_config_general_log.yml +++ b/managed/data/checks/mysql_config_general_log.yml @@ -5,7 +5,8 @@ checks: summary: General Log is enabled description: Check if the general log is enabled. interval: standard - advisor: configuration_generic + category: Configuration + subcategory: Generic #subcategory: generic #author: The Grinch family: MYSQL diff --git a/managed/data/checks/mysql_config_innodb_redolog_disabled.yml b/managed/data/checks/mysql_config_innodb_redolog_disabled.yml index 99783f2365b..da183db9b47 100644 --- a/managed/data/checks/mysql_config_innodb_redolog_disabled.yml +++ b/managed/data/checks/mysql_config_innodb_redolog_disabled.yml @@ -5,7 +5,8 @@ checks: summary: Redo log is disabled in this instance description: The MySQL InnoDB Redo log, is one of the core components to fulfil the ACID paradigm in MySQL. This element is currently OFF, the setting is highly insecure. interval: standard - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_local_infile.yml b/managed/data/checks/mysql_config_local_infile.yml index fb4d89623b1..4108b53d7ad 100644 --- a/managed/data/checks/mysql_config_local_infile.yml +++ b/managed/data/checks/mysql_config_local_infile.yml @@ -5,7 +5,8 @@ checks: summary: Load data in file active description: Identify if a load data in file is active. interval: standard - advisor: security_configuration + category: Security + subcategory: Configuration #subcategory: generic #author: The Grinch family: MYSQL diff --git a/managed/data/checks/mysql_config_log_bin.yml b/managed/data/checks/mysql_config_log_bin.yml index 1841e1927c2..a2668ea6c01 100644 --- a/managed/data/checks/mysql_config_log_bin.yml +++ b/managed/data/checks/mysql_config_log_bin.yml @@ -5,7 +5,8 @@ checks: summary: Binary Log is disabled description: Check if the binlog is enabled or disabled. interval: standard - advisor: configuration_generic + category: Configuration + subcategory: Generic #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_relay_log_purge.yml b/managed/data/checks/mysql_config_relay_log_purge.yml index 7baddb726b6..83d2597b896 100644 --- a/managed/data/checks/mysql_config_relay_log_purge.yml +++ b/managed/data/checks/mysql_config_relay_log_purge.yml @@ -5,7 +5,8 @@ checks: summary: Automatic relay log purging is off description: Identify if a replica node has relay-logs purge set. interval: standard - advisor: configuration_replication + category: Configuration + subcategory: Replication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_replication_bp1.yml b/managed/data/checks/mysql_config_replication_bp1.yml index 4ca00d14847..1ac337eda2d 100644 --- a/managed/data/checks/mysql_config_replication_bp1.yml +++ b/managed/data/checks/mysql_config_replication_bp1.yml @@ -5,7 +5,8 @@ checks: summary: Checks for basic best practices when setting a replica node. description: Identify if a replica node is in read-only mode and if checksum. interval: standard - advisor: configuration_replication + category: Configuration + subcategory: Replication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_slave_parallel_workers.yml b/managed/data/checks/mysql_config_slave_parallel_workers.yml index c3b889a9625..0ef4c5ecace 100644 --- a/managed/data/checks/mysql_config_slave_parallel_workers.yml +++ b/managed/data/checks/mysql_config_slave_parallel_workers.yml @@ -5,7 +5,8 @@ checks: summary: Replication is single threaded description: Identify if a replication is single threaded. interval: standard - advisor: configuration_replication + category: Configuration + subcategory: Replication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_sql_mode.yml b/managed/data/checks/mysql_config_sql_mode.yml index fd2ccb95dbe..031d0ee11d6 100644 --- a/managed/data/checks/mysql_config_sql_mode.yml +++ b/managed/data/checks/mysql_config_sql_mode.yml @@ -5,7 +5,8 @@ checks: summary: Server is not configured to enforce data integrity description: In order for maximum data integrity to be set, the server should have specific values configured in sql_mode. interval: standard - advisor: configuration_generic + category: Configuration + subcategory: Generic #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_sync_binlog.yml b/managed/data/checks/mysql_config_sync_binlog.yml index abd44846340..7fb199250fc 100644 --- a/managed/data/checks/mysql_config_sync_binlog.yml +++ b/managed/data/checks/mysql_config_sync_binlog.yml @@ -5,7 +5,8 @@ checks: summary: Sync binlog is disabled description: Check if the binlog synchronized before transaction is committed. interval: standard - advisor: configuration_replication + category: Configuration + subcategory: Replication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_config_tmp_table_size_limit.yml b/managed/data/checks/mysql_config_tmp_table_size_limit.yml index ccc9179dc8a..f5d66a5b670 100644 --- a/managed/data/checks/mysql_config_tmp_table_size_limit.yml +++ b/managed/data/checks/mysql_config_tmp_table_size_limit.yml @@ -5,7 +5,8 @@ checks: summary: Temp table size is larger than Heap Table size description: Check if the Temporary table size exceeds the heap table size. interval: standard - advisor: configuration_generic + category: Configuration + subcategory: Generic #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_configuration_innodb_file_format.yml b/managed/data/checks/mysql_configuration_innodb_file_format.yml index d2a8b688d9d..9f03d9ac76e 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_format.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_format.yml @@ -5,7 +5,8 @@ checks: summary: MySQL InnoDB file format description: Check if InnoDB is configured with recommended file format interval: standard - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml b/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml index 48903921e76..6636eca6568 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_maxlimit.yml @@ -5,7 +5,8 @@ checks: summary: InnoDB Tablespace size has a maximum limit. description: Check if InnoDB is configured with recommended auto-extend interval: standard - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml index 30374b3d2ad..6b28bb4ede1 100644 --- a/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml +++ b/managed/data/checks/mysql_configuration_innodb_file_per_table_not_enabled.yml @@ -5,7 +5,8 @@ checks: summary: innodb_file_per_table not enabled description: innodb_file_per_table not enabled interval: standard - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB #subcategory: performance #author:Kedar Vaijanapurkar family: MYSQL diff --git a/managed/data/checks/mysql_configuration_innodb_flush_method.yml b/managed/data/checks/mysql_configuration_innodb_flush_method.yml index 384dd6624d6..794aac8c847 100644 --- a/managed/data/checks/mysql_configuration_innodb_flush_method.yml +++ b/managed/data/checks/mysql_configuration_innodb_flush_method.yml @@ -5,7 +5,8 @@ checks: summary: MySQL InnoDB flush method description: Check if InnoDB is configured with recommended flush method interval: standard - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_configuration_innodb_strict_mode.yml b/managed/data/checks/mysql_configuration_innodb_strict_mode.yml index e903066d4c6..573e17b2e42 100644 --- a/managed/data/checks/mysql_configuration_innodb_strict_mode.yml +++ b/managed/data/checks/mysql_configuration_innodb_strict_mode.yml @@ -5,7 +5,8 @@ checks: summary: InnoDB strict mode description: This check warns about password lifetime. interval: standard - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_configuration_log_verbosity.yml b/managed/data/checks/mysql_configuration_log_verbosity.yml index 9bd92017bb2..8e039f0497c 100644 --- a/managed/data/checks/mysql_configuration_log_verbosity.yml +++ b/managed/data/checks/mysql_configuration_log_verbosity.yml @@ -6,7 +6,8 @@ checks: description: Checks that warnings are being printed on the log family: MYSQL #author: Carlos - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mysql_configuration_max_connections_usage.yml b/managed/data/checks/mysql_configuration_max_connections_usage.yml index 955afc80e6d..6b535ae39d3 100644 --- a/managed/data/checks/mysql_configuration_max_connections_usage.yml +++ b/managed/data/checks/mysql_configuration_max_connections_usage.yml @@ -5,7 +5,8 @@ checks: summary: Check max connections usage description: Checks for MySQL max_connections configuration option for maximum utilization interval: standard - advisor: configuration_connection + category: Configuration + subcategory: Connection #subcategory: connection #author:Kedar Vaijanapurkar family: MYSQL diff --git a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml index 978b479e57e..6bcb94f7f55 100644 --- a/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml +++ b/managed/data/checks/mysql_configuration_secure_file_priv_empty.yml @@ -5,7 +5,8 @@ checks: summary: secure_file_priv is empty description: The secure_file_priv when empty allows users with FILE privilege to create files at any location where MySQL server has write permission. interval: standard - advisor: security_configuration + category: Security + subcategory: Configuration #subcategory: security #author:Kedar Vaijanapurkar family: MYSQL diff --git a/managed/data/checks/mysql_indexes_larger.yml b/managed/data/checks/mysql_indexes_larger.yml index c72d6216c04..74fd6704348 100644 --- a/managed/data/checks/mysql_indexes_larger.yml +++ b/managed/data/checks/mysql_indexes_larger.yml @@ -5,7 +5,8 @@ checks: summary: Are there tables with index sizes larger than data? description: Check all the tables to see if any have indexes larger than data. This indicates sub-optimial schema and should be reviewed. interval: standard - advisor: query_schema_design + category: Query + subcategory: Schema family: MYSQL queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml index 13503ad7ec0..3ffd563ba0f 100644 --- a/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml +++ b/managed/data/checks/mysql_innodb_redo_logs_not_sized_correctly.yml @@ -7,7 +7,8 @@ checks: family: MYSQL #subcategory: configuration #author: Kedar Vaijanapurkar - advisor: configuration_innodb + category: Configuration + subcategory: InnoDB interval: standard queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_log_replica_updates.yml b/managed/data/checks/mysql_log_replica_updates.yml index 92aeeee1316..cc49fa20420 100644 --- a/managed/data/checks/mysql_log_replica_updates.yml +++ b/managed/data/checks/mysql_log_replica_updates.yml @@ -6,7 +6,8 @@ checks: description: Checks if a replica is safely logging replicated transactions. interval: standard family: MYSQL - advisor: configuration_replication + category: Configuration + subcategory: Replication #author: tibi/the grinch queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mysql_password_expiry.yml b/managed/data/checks/mysql_password_expiry.yml index 7fecf470552..0b1d4825e8e 100644 --- a/managed/data/checks/mysql_password_expiry.yml +++ b/managed/data/checks/mysql_password_expiry.yml @@ -7,7 +7,8 @@ checks: interval: standard #author: Kedar Vaijanapurkar family: MYSQL - advisor: security_configuration + category: Security + subcategory: Configuration queries: - type: MYSQL_SELECT query: "@@global.version as version, @@global.hostname as service, @@global.default_password_lifetime as default_password_lifetime" diff --git a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml index a015b38b82a..426adf8dcb7 100644 --- a/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml +++ b/managed/data/checks/mysql_performance_temp_ondisk_table_high.yml @@ -5,7 +5,8 @@ checks: summary: Too many on disk temporary tables description: This check warns against too many ondisk temporary tables created due to unoptimized query execution. family: MYSQL - advisor: query_index + category: Query + subcategory: Index #subcategory: index #author: Kedar Vaijanapurkar interval: standard diff --git a/managed/data/checks/mysql_private_networks_only.yml b/managed/data/checks/mysql_private_networks_only.yml index bbbbe585184..74529a87e53 100644 --- a/managed/data/checks/mysql_private_networks_only.yml +++ b/managed/data/checks/mysql_private_networks_only.yml @@ -5,7 +5,8 @@ checks: summary: MySQL Users With Granted Public Networks Access description: Notifies about MySQL accounts currently allowed to connect from public networks. family: MYSQL - advisor: security_connection + category: Security + subcategory: Connection interval: standard queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml b/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml index 2eced2e9ea0..cf7f4b57f9e 100644 --- a/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml +++ b/managed/data/checks/mysql_replica_running_skipping_errors_or_idempotent_mode.yml @@ -6,7 +6,8 @@ checks: description: This check reviews replication status to review if it is configured to skip errors or if the slave_exec_mode is configured to be idempotent. family: MYSQL #author: Kedar Vaijanapurkar - advisor: configuration_replication + category: Configuration + subcategory: Replication interval: standard queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_replication_grants.yml b/managed/data/checks/mysql_replication_grants.yml index 759ccc17db9..829a45f23a2 100644 --- a/managed/data/checks/mysql_replication_grants.yml +++ b/managed/data/checks/mysql_replication_grants.yml @@ -5,7 +5,8 @@ checks: summary: MySQL security check for replication user description: This check if node has replication configured without a user grants interval: standard - advisor: security_replication + category: Security + subcategory: Replication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_require_secure_transport.yml b/managed/data/checks/mysql_require_secure_transport.yml index da8911f74fd..ff785fefe01 100644 --- a/managed/data/checks/mysql_require_secure_transport.yml +++ b/managed/data/checks/mysql_require_secure_transport.yml @@ -6,7 +6,8 @@ checks: description: Checks mysql_secure_transport_only. interval: standard family: MYSQL - advisor: security_configuration + category: Security + subcategory: Configuration #author:tibi/the grinch queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mysql_security_anonymous_user.yml b/managed/data/checks/mysql_security_anonymous_user.yml index 5e37733b1c8..3d813446f3e 100644 --- a/managed/data/checks/mysql_security_anonymous_user.yml +++ b/managed/data/checks/mysql_security_anonymous_user.yml @@ -5,7 +5,8 @@ checks: summary: Anonymous user (you must remove any anonymous user) description: Anonymous user should never be present, that is a security safe best practices. interval: standard - advisor: security_authentication + category: Security + subcategory: Authentication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_security_open_to_world_host.yml b/managed/data/checks/mysql_security_open_to_world_host.yml index 40813729460..b2cf09523fb 100644 --- a/managed/data/checks/mysql_security_open_to_world_host.yml +++ b/managed/data/checks/mysql_security_open_to_world_host.yml @@ -5,7 +5,8 @@ checks: summary: User(s) has/have host definition '%' which is too open description: Host definition should never be '%' given it is too open . interval: standard - advisor: security_authentication + category: Security + subcategory: Authentication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_security_password_lifetime.yml b/managed/data/checks/mysql_security_password_lifetime.yml index 4e07a9b16fd..2c3c537fd39 100644 --- a/managed/data/checks/mysql_security_password_lifetime.yml +++ b/managed/data/checks/mysql_security_password_lifetime.yml @@ -5,7 +5,8 @@ checks: summary: InnoDB password lifetime description: This check warns about password lifetime. interval: standard - advisor: security_configuration + category: Security + subcategory: Configuration #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_security_password_policy.yml b/managed/data/checks/mysql_security_password_policy.yml index 34a7f2fee14..f71d1439da3 100644 --- a/managed/data/checks/mysql_security_password_policy.yml +++ b/managed/data/checks/mysql_security_password_policy.yml @@ -5,7 +5,8 @@ checks: summary: MySQL security check for password description: This check for password policy. interval: standard - advisor: security_configuration + category: Security + subcategory: Configuration #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_security_replication_grants_mixed.yml b/managed/data/checks/mysql_security_replication_grants_mixed.yml index 697d37c429d..b06e1a8bb7c 100644 --- a/managed/data/checks/mysql_security_replication_grants_mixed.yml +++ b/managed/data/checks/mysql_security_replication_grants_mixed.yml @@ -6,7 +6,8 @@ checks: description: Check if replication privileges is mixed with more elevated privileges interval: standard #author: The Grinch - advisor: security_replication + category: Security + subcategory: Replication family: MYSQL queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_security_root_not_local.yml b/managed/data/checks/mysql_security_root_not_local.yml index 946494cbc65..f0b91596f5b 100644 --- a/managed/data/checks/mysql_security_root_not_local.yml +++ b/managed/data/checks/mysql_security_root_not_local.yml @@ -5,7 +5,8 @@ checks: summary: Root user can connect from non local location description: Root user has host definition that is not 127.0.0.1 or localhost. interval: standard - advisor: security_authentication + category: Security + subcategory: Authentication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_security_user_ssl.yml b/managed/data/checks/mysql_security_user_ssl.yml index 75402dc155c..7333fd9f79a 100644 --- a/managed/data/checks/mysql_security_user_ssl.yml +++ b/managed/data/checks/mysql_security_user_ssl.yml @@ -5,7 +5,8 @@ checks: summary: User(s) not using secure SSL protocol to connect description: User(s) not using secure SSL protocol to connect. interval: standard - advisor: security_authentication + category: Security + subcategory: Authentication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_security_user_super_not_local.yml b/managed/data/checks/mysql_security_user_super_not_local.yml index 4bad54d3b17..e251b7520c1 100644 --- a/managed/data/checks/mysql_security_user_super_not_local.yml +++ b/managed/data/checks/mysql_security_user_super_not_local.yml @@ -5,7 +5,8 @@ checks: summary: User(s) has/have Super privileges with remote and too open access description: User has Super privileges but is not connecting from local or the host is not fully restricted (ie 192.168.%). interval: standard - advisor: security_authentication + category: Security + subcategory: Authentication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_security_user_without_password.yml b/managed/data/checks/mysql_security_user_without_password.yml index c6c6d78cae7..4a855cfc646 100644 --- a/managed/data/checks/mysql_security_user_without_password.yml +++ b/managed/data/checks/mysql_security_user_without_password.yml @@ -5,7 +5,8 @@ checks: summary: User(s) without password description: There is/are user(s) without password . interval: standard - advisor: security_authentication + category: Security + subcategory: Authentication #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/mysql_tables_without_pk.yml b/managed/data/checks/mysql_tables_without_pk.yml index 9bef4bf1191..2be0436383b 100644 --- a/managed/data/checks/mysql_tables_without_pk.yml +++ b/managed/data/checks/mysql_tables_without_pk.yml @@ -7,7 +7,8 @@ checks: interval: standard family: MYSQL #author:tibi/the grinch - advisor: query_index + category: Query + subcategory: Index queries: - type: MYSQL_SELECT query: | diff --git a/managed/data/checks/mysql_test_database.yml b/managed/data/checks/mysql_test_database.yml index ba14d5fbc3c..f6e49bfe5aa 100644 --- a/managed/data/checks/mysql_test_database.yml +++ b/managed/data/checks/mysql_test_database.yml @@ -5,7 +5,8 @@ checks: summary: MySQL test Database description: This check returns a notice if there are databases with name 'test' or 'test_%'. family: MYSQL - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mysql_timezone.yml b/managed/data/checks/mysql_timezone.yml index ed8238a2f31..462dfbbc3ff 100644 --- a/managed/data/checks/mysql_timezone.yml +++ b/managed/data/checks/mysql_timezone.yml @@ -7,7 +7,8 @@ checks: interval: standard family: MYSQL #author:tibi/the grinch - advisor: configuration_generic + category: Configuration + subcategory: Generic queries: - type: MYSQL_SELECT query: count(*) as timezonecount from mysql.time_zone_name diff --git a/managed/data/checks/mysql_unsupported_version_check.yml b/managed/data/checks/mysql_unsupported_version_check.yml index 88381c26a17..8223e0bd3b6 100644 --- a/managed/data/checks/mysql_unsupported_version_check.yml +++ b/managed/data/checks/mysql_unsupported_version_check.yml @@ -6,7 +6,8 @@ checks: description: This check warns against an unsupported mysql version family: MYSQL #author: Kedar Vaijanapurkar - advisor: configuration_version + category: Configuration + subcategory: Version interval: standard queries: - type: MYSQL_SELECT diff --git a/managed/data/checks/mysql_version.yml b/managed/data/checks/mysql_version.yml index 57f790739ce..e39de1ded7d 100644 --- a/managed/data/checks/mysql_version.yml +++ b/managed/data/checks/mysql_version.yml @@ -5,7 +5,8 @@ checks: summary: MySQL Version description: This check returns warnings if MySQL, Percona Server for MySQL, or MariaDB version is not the latest one. family: MYSQL - advisor: configuration_version + category: Configuration + subcategory: Version interval: standard queries: - type: MYSQL_SHOW diff --git a/managed/data/checks/mysql_version_eol_57.yml b/managed/data/checks/mysql_version_eol_57.yml index 2813a056328..e5e60faed85 100644 --- a/managed/data/checks/mysql_version_eol_57.yml +++ b/managed/data/checks/mysql_version_eol_57.yml @@ -5,7 +5,8 @@ checks: summary: End Of Life server version (5.7). description: Check if server version is EOL interval: standard - advisor: configuration_version + category: Configuration + subcategory: Version #author: The Grinch family: MYSQL queries: diff --git a/managed/data/checks/postgresql_archiver_failing.yml b/managed/data/checks/postgresql_archiver_failing.yml index b7e48f2f61c..b78457da916 100644 --- a/managed/data/checks/postgresql_archiver_failing.yml +++ b/managed/data/checks/postgresql_archiver_failing.yml @@ -6,7 +6,8 @@ checks: description: This check verifies if the archiver has failed. family: POSTGRESQL #author: David Gonzales - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_cache_hit_ratio.yml b/managed/data/checks/postgresql_cache_hit_ratio.yml index 0c72f1e4c12..44148f9423b 100644 --- a/managed/data/checks/postgresql_cache_hit_ratio.yml +++ b/managed/data/checks/postgresql_cache_hit_ratio.yml @@ -6,7 +6,8 @@ checks: description: This check the hitratio of one or more databases and complains when they are too low. family: POSTGRESQL #author: David Gonzales - advisor: performance_generic + category: Performance + subcategory: Generic interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_config_changes_need_restart.yml b/managed/data/checks/postgresql_config_changes_need_restart.yml index 1e1e7fa8a35..a30a699e9cc 100644 --- a/managed/data/checks/postgresql_config_changes_need_restart.yml +++ b/managed/data/checks/postgresql_config_changes_need_restart.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if there is any setting/configuration that was changed and needs a server restart/reload. family: POSTGRESQL #author: Charly Batista - advisor: performance_generic + category: Performance + subcategory: Generic interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_cve_check.yml b/managed/data/checks/postgresql_cve_check.yml index 6bf501eb929..4226f38e145 100644 --- a/managed/data/checks/postgresql_cve_check.yml +++ b/managed/data/checks/postgresql_cve_check.yml @@ -8,7 +8,8 @@ checks: # This dictionary is based on the CVE list on the postgresql.org security website https://www.postgresql.org/support/security/ # The key is the CVE reference. # The values are a space separated list of postgresql versions where the CVE has been addressed - advisor: security_cve + category: Security + subcategory: Vulnerabilities interval: standard family: POSTGRESQL queries: diff --git a/managed/data/checks/postgresql_eol_check.yml b/managed/data/checks/postgresql_eol_check.yml index 3ea35730167..bf9d2a944a3 100644 --- a/managed/data/checks/postgresql_eol_check.yml +++ b/managed/data/checks/postgresql_eol_check.yml @@ -5,7 +5,8 @@ checks: summary: Check if PostgreSQL version is EOL description: Checks to see if the currently installed PostgreSQL version is end of life and no longer supported #author: Jorge Torralba - advisor: configuration_version + category: Configuration + subcategory: Version interval: standard family: POSTGRESQL queries: diff --git a/managed/data/checks/postgresql_expiring_passwd_check.yml b/managed/data/checks/postgresql_expiring_passwd_check.yml index 98476a17f89..f07b14b63fb 100644 --- a/managed/data/checks/postgresql_expiring_passwd_check.yml +++ b/managed/data/checks/postgresql_expiring_passwd_check.yml @@ -5,8 +5,8 @@ checks: summary: Check for password expiration description: Check for passwords which are expiring and displays the time left before it expires #author: Jorge Torralba - #advisor: version_check - advisor: security_configuration + category: Security + subcategory: Configuration interval: standard family: POSTGRESQL queries: diff --git a/managed/data/checks/postgresql_extension_check.yml b/managed/data/checks/postgresql_extension_check.yml index d2f10ec8f96..e18e915bb40 100644 --- a/managed/data/checks/postgresql_extension_check.yml +++ b/managed/data/checks/postgresql_extension_check.yml @@ -6,7 +6,8 @@ checks: description: This check will list outdated extensions with newer versions available interval: standard family: POSTGRESQL - advisor: configuration_version + category: Configuration + subcategory: Version queries: - type: POSTGRESQL_SELECT query: "current_database() AS db, name, installed_version, default_version FROM pg_available_extensions WHERE installed_version IS NOT NULL AND default_version IS NOT NULL AND installed_version != default_version" diff --git a/managed/data/checks/postgresql_fsync.yml b/managed/data/checks/postgresql_fsync.yml index cb67418a6b4..ddb9f183f1f 100644 --- a/managed/data/checks/postgresql_fsync.yml +++ b/managed/data/checks/postgresql_fsync.yml @@ -6,7 +6,8 @@ checks: description: This check returns an error if the fsync configuration option is off which can lead to database corruption. family: POSTGRESQL #author: Jobin Augustine - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_log_autovacuum_min_duration.yml b/managed/data/checks/postgresql_log_autovacuum_min_duration.yml index e644457b039..8fa5985f02c 100644 --- a/managed/data/checks/postgresql_log_autovacuum_min_duration.yml +++ b/managed/data/checks/postgresql_log_autovacuum_min_duration.yml @@ -6,7 +6,8 @@ checks: description: This check returns a notice if the log_autovacuum_min_duration configuration option is set to -1 (disabled). It is recommended to enable the logging of autovacuum run information, as that provides a lot of useful information with almost no drawbacks. family: POSTGRESQL #author: Sergey Kuzmichev - advisor: configuration_vacuum + category: Configuration + subcategory: Vacuum interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_log_checkpoints.yml b/managed/data/checks/postgresql_log_checkpoints.yml index 40ae11e2b34..c2dcb83c928 100644 --- a/managed/data/checks/postgresql_log_checkpoints.yml +++ b/managed/data/checks/postgresql_log_checkpoints.yml @@ -6,7 +6,8 @@ checks: description: This check returns a notice if the log_checkpoints configuration option is not enabled. It is recommended to enable the logging of checkpoint information, as that provides a lot of useful information with almost no drawbacks. family: POSTGRESQL #author: Sergey Kuzmichev - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_logging_recommendation_checks.yml b/managed/data/checks/postgresql_logging_recommendation_checks.yml index 5ebec0771fb..c350cc6f1ee 100644 --- a/managed/data/checks/postgresql_logging_recommendation_checks.yml +++ b/managed/data/checks/postgresql_logging_recommendation_checks.yml @@ -4,7 +4,8 @@ checks: name: postgresql_logging_recommendation_checks summary: Check for minimal logging description: Checks to see if recommended minimum logging features are enabled. - advisor: configuration_generic + category: Configuration + subcategory: Generic #Author: Jorge Torralba interval: standard family: POSTGRESQL diff --git a/managed/data/checks/postgresql_max_connections.yml b/managed/data/checks/postgresql_max_connections.yml index 8f36527908a..bda0d63d22a 100644 --- a/managed/data/checks/postgresql_max_connections.yml +++ b/managed/data/checks/postgresql_max_connections.yml @@ -6,7 +6,8 @@ checks: description: This check returns a notice if the max_connections configuration option is set to a high value (above 300). PostgreSQL doesn't cope well with having many connections even if they are idle. Recommended value is below 300. family: POSTGRESQL #author: Sergey Kuzmichev - advisor: configuration_connection + category: Configuration + subcategory: Connection interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_multidb.yml.example b/managed/data/checks/postgresql_multidb.yml.example index 8eb745ede6f..7d065078704 100644 --- a/managed/data/checks/postgresql_multidb.yml.example +++ b/managed/data/checks/postgresql_multidb.yml.example @@ -6,7 +6,8 @@ checks: description: This check demonstrates all_dbs option for PostgreSQL check queries interval: standard family: POSTGRESQL - advisor: example + category: Security + subcategory: Example queries: - type: POSTGRESQL_SELECT query: current_database() diff --git a/managed/data/checks/postgresql_number_of_index_check.yml b/managed/data/checks/postgresql_number_of_index_check.yml index 26d8f289093..63c1010443f 100644 --- a/managed/data/checks/postgresql_number_of_index_check.yml +++ b/managed/data/checks/postgresql_number_of_index_check.yml @@ -6,7 +6,8 @@ checks: description: This check will list relations with more than 10 indexes interval: standard family: POSTGRESQL - advisor: query_index + category: Query + subcategory: Index queries: - type: POSTGRESQL_SELECT query: " current_database() AS datname, relname, count(*) AS idxcount FROM pg_stat_user_indexes GROUP BY 1,2 ORDER BY 3 DESC " diff --git a/managed/data/checks/postgresql_sequential_scan_check.yml b/managed/data/checks/postgresql_sequential_scan_check.yml index 8fbbe1528bb..4e88d422166 100644 --- a/managed/data/checks/postgresql_sequential_scan_check.yml +++ b/managed/data/checks/postgresql_sequential_scan_check.yml @@ -6,7 +6,8 @@ checks: description: This check for tables with excessive sequential scans interval: standard family: POSTGRESQL - advisor: query_index + category: Query + subcategory: Index queries: - type: POSTGRESQL_SELECT query: " schemaname, relname, n_live_tup, seq_scan, COALESCE(idx_scan,0) AS idx_scan, ROUND(seq_scan / ( seq_scan + COALESCE(idx_scan,0))::numeric * 100)::int AS percent_seq_scan FROM pg_stat_user_tables WHERE seq_scan > 0 AND n_live_tup >= 50000" diff --git a/managed/data/checks/postgresql_stale_replication_slot.yml b/managed/data/checks/postgresql_stale_replication_slot.yml index 3692a00ffa7..26ea0af4058 100644 --- a/managed/data/checks/postgresql_stale_replication_slot.yml +++ b/managed/data/checks/postgresql_stale_replication_slot.yml @@ -6,7 +6,8 @@ checks: description: This check returns a warning if there is a stale replication slot. Stale replication slots will lead to WAL file accumulation and can result in a DB server outage. family: POSTGRESQL #author: Sergey Kuzmichev - advisor: performance_replication + category: Performance + subcategory: Replication interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_super_role.yml b/managed/data/checks/postgresql_super_role.yml index 1950c44911f..a5de2d86a7d 100644 --- a/managed/data/checks/postgresql_super_role.yml +++ b/managed/data/checks/postgresql_super_role.yml @@ -5,7 +5,8 @@ checks: summary: PostgreSQL Super Role description: This check returns a notice if there are users with superuser role. family: POSTGRESQL - advisor: security_authentication + category: Security + subcategory: Authentication interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_table_autovac_settings.yml b/managed/data/checks/postgresql_table_autovac_settings.yml index 43655d1abbc..a860ad734d0 100644 --- a/managed/data/checks/postgresql_table_autovac_settings.yml +++ b/managed/data/checks/postgresql_table_autovac_settings.yml @@ -6,7 +6,8 @@ checks: description: This check returns those tables where autovacuum parameters are specified along with autovacuum settings specified family: POSTGRESQL #author: Jobin Augustine - advisor: configuration_vacuum + category: Configuration + subcategory: Vacuum interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_table_bloat_bytes.yml b/managed/data/checks/postgresql_table_bloat_bytes.yml index 41834d0ba76..a2bcb9ee01d 100644 --- a/managed/data/checks/postgresql_table_bloat_bytes.yml +++ b/managed/data/checks/postgresql_table_bloat_bytes.yml @@ -4,7 +4,8 @@ checks: name: postgresql_table_bloat_bytes summary: Check amount of bloat in tables if greater than 250MB description: Checks check verifies the size of the table bloat in bytes accross all databases and alert accordingly - advisor: performance_vacuum + category: Performance + subcategory: Vacuum interval: standard family: POSTGRESQL queries: diff --git a/managed/data/checks/postgresql_table_bloat_in_percentage.yml b/managed/data/checks/postgresql_table_bloat_in_percentage.yml index 71661f2393a..37eb0563a83 100644 --- a/managed/data/checks/postgresql_table_bloat_in_percentage.yml +++ b/managed/data/checks/postgresql_table_bloat_in_percentage.yml @@ -6,7 +6,8 @@ checks: description: This check verifies the size of the table bloat in percentage of the total table size and alert accordingly family: POSTGRESQL #author: David Gonzalez - advisor: performance_vacuum + category: Performance + subcategory: Vacuum interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_tmpfiles_check.yml b/managed/data/checks/postgresql_tmpfiles_check.yml index 29d9c28b05d..4b692787071 100644 --- a/managed/data/checks/postgresql_tmpfiles_check.yml +++ b/managed/data/checks/postgresql_tmpfiles_check.yml @@ -5,7 +5,8 @@ checks: summary: PostgreSQL temporary file statistics description: This check reports the number of temporary files and number of bytes written to disk since last stats reset. #author: Jorge Torralba - advisor: performance_generic + category: Performance + subcategory: Generic interval: standard family: POSTGRESQL queries: diff --git a/managed/data/checks/postgresql_txid_wraparound_approaching.yml b/managed/data/checks/postgresql_txid_wraparound_approaching.yml index f3877020d88..eceb38b7c40 100644 --- a/managed/data/checks/postgresql_txid_wraparound_approaching.yml +++ b/managed/data/checks/postgresql_txid_wraparound_approaching.yml @@ -6,7 +6,8 @@ checks: description: This check verifies databases age and alert if the transaction ID wraparound issue is near family: POSTGRESQL #author: David Gonzalez - advisor: configuration_vacuum + category: Configuration + subcategory: Vacuum interval: standard queries: - type: POSTGRESQL_SELECT diff --git a/managed/data/checks/postgresql_unsupported_check.yml b/managed/data/checks/postgresql_unsupported_check.yml index 5917cf5e979..c483826fc8c 100644 --- a/managed/data/checks/postgresql_unsupported_check.yml +++ b/managed/data/checks/postgresql_unsupported_check.yml @@ -5,7 +5,8 @@ checks: summary: Check for unsupported PostgreSQL description: Checks to see if the currently installed version is supported by percona #author: Jorge Torralba - advisor: configuration_version + category: Configuration + subcategory: Version interval: standard family: POSTGRESQL queries: diff --git a/managed/data/checks/postgresql_unused_index_check.yml b/managed/data/checks/postgresql_unused_index_check.yml index 95c9b7f9167..1574f300f7c 100644 --- a/managed/data/checks/postgresql_unused_index_check.yml +++ b/managed/data/checks/postgresql_unused_index_check.yml @@ -6,7 +6,8 @@ checks: description: This check will list relations with indexes that have not been used since statistics where last reset interval: standard family: POSTGRESQL - advisor: query_index + category: Query + subcategory: Index queries: - type: POSTGRESQL_SELECT # Using this syntax (CURRENT_TIMESTAMP(0)::TIMESTAMP WITHOUT TIME ZONE)::text since PMM does not respect date formatting. Thus converting to a string diff --git a/managed/data/checks/postgresql_vacuum_sanity_check.yml b/managed/data/checks/postgresql_vacuum_sanity_check.yml index 08fc05401f6..3e1ddf7f64b 100644 --- a/managed/data/checks/postgresql_vacuum_sanity_check.yml +++ b/managed/data/checks/postgresql_vacuum_sanity_check.yml @@ -6,7 +6,8 @@ checks: description: This performs a quick check of some vacuum parameters interval: standard family: POSTGRESQL - advisor: configuration_vacuum + category: Configuration + subcategory: Vacuum queries: - type: POSTGRESQL_SELECT query: "current_setting('autovacuum') AS autovacuum, current_setting('autovacuum_max_workers') AS autovacuum_max_workers, current_setting('autovacuum_vacuum_scale_factor') AS autovacuum_vacuum_scale_factor, current_setting('vacuum_cost_page_hit') AS vacuum_cost_page_hit, current_setting('vacuum_cost_delay') AS vacuum_cost_delay, current_setting('vacuum_cost_page_dirty') AS vacuum_cost_page_dirty , current_setting('vacuum_cost_page_miss') AS vacuum_cost_page_miss " diff --git a/managed/data/checks/postgresql_version_check.yml b/managed/data/checks/postgresql_version_check.yml index 8f8962dffab..e0802ed47ad 100644 --- a/managed/data/checks/postgresql_version_check.yml +++ b/managed/data/checks/postgresql_version_check.yml @@ -5,7 +5,8 @@ checks: summary: Check for newer version of PostgreSQL description: Checks to see if the currently installed version is outdated for it's release level #author: Jorge Torralba - advisor: configuration_version + category: Configuration + subcategory: Version interval: standard family: POSTGRESQL queries: diff --git a/managed/data/checks/postgresql_wal_retention_check.yml b/managed/data/checks/postgresql_wal_retention_check.yml index 4147811bd64..466f416810a 100644 --- a/managed/data/checks/postgresql_wal_retention_check.yml +++ b/managed/data/checks/postgresql_wal_retention_check.yml @@ -5,7 +5,8 @@ checks: summary: Check for WAL file accumulation description: Checks to see if there are too many WAL files retained in the WAL directory #author: Jorge Torralba - advisor: configuration_generic + category: Configuration + subcategory: Generic interval: standard family: POSTGRESQL queries: diff --git a/managed/models/check_result_helpers_test.go b/managed/models/check_result_helpers_test.go index bf4991b53ec..160cb46484d 100644 --- a/managed/models/check_result_helpers_test.go +++ b/managed/models/check_result_helpers_test.go @@ -50,8 +50,8 @@ func TestCheckResults(t *testing.T) { labels := map[string]string{"k": "v"} cr := &models.CheckResult{ CheckName: "c1", - AdvisorName: "advisor", Category: "performance", + Subcategory: "advisor", Interval: models.Standard, ServiceID: svc, ServiceName: "find-me", diff --git a/managed/models/check_result_model.go b/managed/models/check_result_model.go index b5376f29506..9d59a0cf027 100644 --- a/managed/models/check_result_model.go +++ b/managed/models/check_result_model.go @@ -70,8 +70,8 @@ const ( type CheckResult struct { ID string `reform:"id,pk"` CheckName string `reform:"check_name"` - AdvisorName string `reform:"advisor_name"` Category string `reform:"category"` + Subcategory string `reform:"subcategory"` Interval Interval `reform:"interval"` ServiceID string `reform:"service_id"` ServiceName string `reform:"service_name"` diff --git a/managed/models/check_result_model_reform.go b/managed/models/check_result_model_reform.go index 645139bc5c0..03251d62ea5 100644 --- a/managed/models/check_result_model_reform.go +++ b/managed/models/check_result_model_reform.go @@ -30,8 +30,8 @@ func (v *checkResultTableType) Columns() []string { return []string{ "id", "check_name", - "advisor_name", "category", + "subcategory", "interval", "service_id", "service_name", @@ -78,8 +78,8 @@ var CheckResultTable = &checkResultTableType{ Fields: []parse.FieldInfo{ {Name: "ID", Type: "string", Column: "id"}, {Name: "CheckName", Type: "string", Column: "check_name"}, - {Name: "AdvisorName", Type: "string", Column: "advisor_name"}, {Name: "Category", Type: "string", Column: "category"}, + {Name: "Subcategory", Type: "string", Column: "subcategory"}, {Name: "Interval", Type: "Interval", Column: "interval"}, {Name: "ServiceID", Type: "string", Column: "service_id"}, {Name: "ServiceName", Type: "string", Column: "service_name"}, @@ -111,8 +111,8 @@ func (s CheckResult) String() string { res := make([]string, 24) res[0] = "ID: " + reform.Inspect(s.ID, true) res[1] = "CheckName: " + reform.Inspect(s.CheckName, true) - res[2] = "AdvisorName: " + reform.Inspect(s.AdvisorName, true) - res[3] = "Category: " + reform.Inspect(s.Category, true) + res[2] = "Category: " + reform.Inspect(s.Category, true) + res[3] = "Subcategory: " + reform.Inspect(s.Subcategory, true) res[4] = "Interval: " + reform.Inspect(s.Interval, true) res[5] = "ServiceID: " + reform.Inspect(s.ServiceID, true) res[6] = "ServiceName: " + reform.Inspect(s.ServiceName, true) @@ -142,8 +142,8 @@ func (s *CheckResult) Values() []interface{} { return []interface{}{ s.ID, s.CheckName, - s.AdvisorName, s.Category, + s.Subcategory, s.Interval, s.ServiceID, s.ServiceName, @@ -173,8 +173,8 @@ func (s *CheckResult) Pointers() []interface{} { return []interface{}{ &s.ID, &s.CheckName, - &s.AdvisorName, &s.Category, + &s.Subcategory, &s.Interval, &s.ServiceID, &s.ServiceName, diff --git a/managed/models/database.go b/managed/models/database.go index 37317d0a89a..869a8094a6e 100644 --- a/managed/models/database.go +++ b/managed/models/database.go @@ -1190,8 +1190,8 @@ var databaseSchema = [][]string{ id VARCHAR NOT NULL, batch_id VARCHAR NOT NULL, check_name VARCHAR NOT NULL CHECK (check_name <> ''), - advisor_name VARCHAR NOT NULL, category VARCHAR NOT NULL, + subcategory VARCHAR NOT NULL, interval VARCHAR NOT NULL, service_id VARCHAR NOT NULL, service_name VARCHAR NOT NULL, diff --git a/managed/pi/check/advisor.go b/managed/pi/check/advisor.go index bfa3ca7d7d0..6c4944ecce3 100644 --- a/managed/pi/check/advisor.go +++ b/managed/pi/check/advisor.go @@ -15,91 +15,11 @@ package check -import ( - "errors" - "fmt" - "io" - - "gopkg.in/yaml.v3" -) - -// Advisor represents a group of checks with a common idea. -// Checks is populated at load time by linking checks via Check.Advisor; -// it is not authored in advisor files. +// Advisor is an in-memory grouping of checks that share the same +// (Category, Subcategory) pair. It is synthesized at load time from the checks +// themselves and is not authored anywhere. type Advisor struct { - Version uint32 `yaml:"version"` - Name string `yaml:"name"` - Summary string `yaml:"summary"` - Description string `yaml:"description"` - Category string `yaml:"category"` - Checks []Check `yaml:"-"` -} - -// ParseAdvisors returns a slice of validated advisors parsed from YAML passed via a reader. -// It can handle multi-document YAMLs: parsing result will be a single slice -// that contains advisors from every parsed document. -func ParseAdvisors(reader io.Reader, params *ParseParams) ([]Advisor, error) { - if params == nil { - params = &ParseParams{} - } - - d := yaml.NewDecoder(reader) - d.KnownFields(params.DisallowUnknownFields) - - type advisors struct { - Advisors []Advisor `yaml:"advisors"` - } - - var res []Advisor - - for { - var c advisors - - err := d.Decode(&c) - if err != nil { - if errors.Is(err, io.EOF) { - return res, nil - } - - return nil, fmt.Errorf("failed to parse advisors: %w", err) - } - - for _, advisor := range c.Advisors { - err := advisor.Validate() - if err != nil { - if params.DisallowInvalidChecks { - return nil, err - } - - continue // skip invalid advisors - } - - res = append(res, advisor) - } - } -} - -// Validate validates an advisor. -func (a *Advisor) Validate() error { - if a.Version != 1 { - return fmt.Errorf("unexpected version %d", a.Version) - } - - if !nameRE.MatchString(a.Name) { - return errors.New("invalid advisor name") - } - - if a.Summary == "" { - return errors.New("summary is empty") - } - - if a.Description == "" { - return errors.New("description is empty") - } - - if a.Category == "" { - return errors.New("category is empty") - } - - return nil + Category string + Subcategory string + Checks []Check } diff --git a/managed/pi/check/check.go b/managed/pi/check/check.go index 9bb34493d65..0e0779af971 100644 --- a/managed/pi/check/check.go +++ b/managed/pi/check/check.go @@ -262,13 +262,16 @@ const ( MaxSupportedVersion uint32 = 2 ) -// Check represents an advisor check. +// Check represents a self-contained advisor check. Category and Subcategory are +// authored as exact display strings; the advisor "group" is the set of distinct +// (Category, Subcategory) pairs across all loaded checks. type Check struct { Version uint32 `yaml:"version"` Name string `yaml:"name"` Summary string `yaml:"summary"` Description string `yaml:"description"` - Advisor string `yaml:"advisor"` + Category string `yaml:"category"` + Subcategory string `yaml:"subcategory"` Family Family `yaml:"family"` Interval Interval `yaml:"interval,omitempty"` Queries []Query `yaml:"queries"` @@ -313,8 +316,12 @@ func (c *Check) Validate() error { return errors.New("description is empty") } - if c.Advisor == "" { - return errors.New("advisor name is missing") + if c.Category == "" { + return errors.New("category is empty") + } + + if c.Subcategory == "" { + return errors.New("subcategory is empty") } err = c.Family.Validate() diff --git a/managed/services/checks/check_result_record_test.go b/managed/services/checks/check_result_record_test.go index 33eb0c42882..906bd9c4331 100644 --- a/managed/services/checks/check_result_record_test.go +++ b/managed/services/checks/check_result_record_test.go @@ -30,7 +30,7 @@ import ( func TestNewCheckResultRecord(t *testing.T) { t.Parallel() - c := check.Check{Name: "chk", Summary: "Check title", Description: "Check description", Advisor: "adv", Interval: check.Standard} + c := check.Check{Name: "chk", Summary: "Check title", Description: "Check description", Category: "Performance", Subcategory: "Adv", Interval: check.Standard} target := services.Target{ ServiceID: "sid", ServiceName: "sname", @@ -55,11 +55,11 @@ func TestNewCheckResultRecord(t *testing.T) { Labels: map[string]string{"k": "v"}, } - rec := newCheckResultRecord(c, target, "performance", models.CheckResultFailed, result, checkedAt, ri) + rec := newCheckResultRecord(c, target, models.CheckResultFailed, result, checkedAt, ri) assert.Equal(t, "chk", rec.CheckName) - assert.Equal(t, "adv", rec.AdvisorName) - assert.Equal(t, "performance", rec.Category) + assert.Equal(t, "Performance", rec.Category) + assert.Equal(t, "Adv", rec.Subcategory) assert.Equal(t, models.Interval(check.Standard), rec.Interval) assert.Equal(t, "sid", rec.ServiceID) assert.Equal(t, "sname", rec.ServiceName) @@ -87,7 +87,7 @@ func TestNewCheckResultRecord(t *testing.T) { t.Run("ok outcome falls back to check summary and info severity", func(t *testing.T) { t.Parallel() - rec := newCheckResultRecord(c, target, "performance", models.CheckResultOK, check.Result{}, checkedAt, ri) + rec := newCheckResultRecord(c, target, models.CheckResultOK, check.Result{}, checkedAt, ri) assert.Equal(t, models.CheckResultOK, rec.Status) assert.Equal(t, "Check title", rec.Summary) @@ -104,7 +104,7 @@ func TestNewCheckResultRecord(t *testing.T) { result := check.Result{Description: "execution failed"} - rec := newCheckResultRecord(c, target, "performance", models.CheckResultError, result, checkedAt, ri) + rec := newCheckResultRecord(c, target, models.CheckResultError, result, checkedAt, ri) assert.Equal(t, models.CheckResultError, rec.Status) assert.Equal(t, "Check title", rec.Summary) diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index 4cdda940051..08ac51943a4 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -59,7 +59,6 @@ const ( // Environment variables that affect checks service; only for testing. envCheckFile = "PMM_DEV_ADVISOR_CHECKS_FILE" envDisableStartDelay = "PMM_ADVISORS_CHECKS_DISABLE_START_DELAY" - builtinAdvisorsPath = "/usr/local/percona/advisors" builtinChecksPath = "/usr/local/percona/checks" checkExecutionTimeout = 5 * time.Minute // limits execution time for every single check @@ -715,7 +714,6 @@ func (s *Service) executeChecks(ctx context.Context, intervalGroup check.Interva func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType models.ServiceType, checks map[string]check.Check, ri runInfo) []services.CheckResult { var res []services.CheckResult var history []*models.CheckResult - categories := s.advisorCategories() for _, c := range checks { s.l.Infof("Executing check: %s with interval: %s", c.Name, c.Interval) @@ -727,30 +725,28 @@ func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType mo continue } - category := categories[c.Advisor] - for _, target := range targets { results, err := s.executeCheck(ctx, target, c) // stamp each (check, target) outcome with its actual completion time checkedAt := models.Now() if err != nil { s.l.Warnf("Failed to execute check %s of family %s on target %s: %+v", c.Name, c.Family, target.AgentID, err) - s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name, "error").Inc() - history = append(history, newCheckResultRecord(c, target, category, models.CheckResultError, check.Result{Description: err.Error()}, checkedAt, ri)) + s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Subcategory, c.Name, "error").Inc() + history = append(history, newCheckResultRecord(c, target, models.CheckResultError, check.Result{Description: err.Error()}, checkedAt, ri)) continue } res = append(res, results...) - s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name, "ok").Inc() + s.mChecksExecuted.WithLabelValues(string(target.ServiceType), c.Subcategory, c.Name, "ok").Inc() if len(results) == 0 { - history = append(history, newCheckResultRecord(c, target, category, models.CheckResultOK, check.Result{}, checkedAt, ri)) + history = append(history, newCheckResultRecord(c, target, models.CheckResultOK, check.Result{}, checkedAt, ri)) continue } for _, finding := range results { - history = append(history, newCheckResultRecord(c, target, category, models.CheckResultFailed, finding.Result, checkedAt, ri)) + history = append(history, newCheckResultRecord(c, target, models.CheckResultFailed, finding.Result, checkedAt, ri)) } } } @@ -763,23 +759,10 @@ func (s *Service) executeChecksForTargetType(ctx context.Context, serviceType mo return res } -// advisorCategories returns a map of advisor name to its category. -func (s *Service) advisorCategories() map[string]string { - s.am.Lock() - defer s.am.Unlock() - - categories := make(map[string]string, len(s.advisors)) - for _, a := range s.advisors { - categories[a.Name] = a.Category - } - return categories -} - // newCheckResultRecord builds a history record for a single executed (check, target) outcome. func newCheckResultRecord( c check.Check, target services.Target, - category string, status models.CheckResultStatus, result check.Result, checkedAt time.Time, @@ -787,8 +770,8 @@ func newCheckResultRecord( ) *models.CheckResult { r := &models.CheckResult{ CheckName: c.Name, - AdvisorName: c.Advisor, - Category: category, + Category: c.Category, + Subcategory: c.Subcategory, Interval: models.Interval(c.Interval), ServiceID: target.ServiceID, ServiceName: target.ServiceName, @@ -876,7 +859,7 @@ func (s *Service) executeCheck(ctx context.Context, target services.Target, c ch defer cancel() defer func(t time.Time) { - s.mChecksExecutionTime.WithLabelValues(string(target.ServiceType), c.Advisor, c.Name).Observe(time.Since(t).Seconds()) + s.mChecksExecutionTime.WithLabelValues(string(target.ServiceType), c.Subcategory, c.Name).Observe(time.Since(t).Seconds()) }(time.Now()) if c.Version < check.MinSupportedVersion || c.Version > check.MaxSupportedVersion { @@ -1524,7 +1507,7 @@ func (s *Service) processResults(ctx context.Context, aCheck check.Check, target for i, result := range results { checkResults[i] = services.CheckResult{ CheckName: aCheck.Name, - AdvisorName: aCheck.Advisor, + Subcategory: aCheck.Subcategory, Interval: aCheck.Interval, Target: target, Result: result, @@ -1604,54 +1587,32 @@ func (s *Service) findTargets(serviceType models.ServiceType, minPMMAgentVersion return targets, nil } -// UpdateAdvisorsList loads advisors from built-in advisors directory or user-defined file, and stores versions supported by this pmm-managed version. +// UpdateAdvisorsList loads built-in checks (plus an optional user-defined file), +// groups them into advisors, and stores versions supported by this pmm-managed version. func (s *Service) UpdateAdvisorsList(ctx context.Context) { - var advisors []check.Advisor - var err error - defer s.refreshChecksInMemoryMetric() - s.l.Infof("Using builtin test checks file: %s", builtinAdvisorsPath) - advisors, err = s.loadBuiltinAdvisors(ctx) + checks, err := s.loadBuiltinChecks(ctx) if err != nil { - s.l.Errorf("Failed to load built-in advisors: %s.", err) + s.l.Errorf("Failed to load built-in checks: %s.", err) return // keep previously loaded advisors } - // if custom check file is provided, load it and append to the list of advisors + // if custom check file is provided, load it and append to the list of checks if s.customCheckFile != "" { s.l.Infof("Using local test checks file: %s.", s.customCheckFile) - checks, err := s.loadChecksFromFiles([]string{s.customCheckFile}) + devChecks, err := s.loadChecksFromFiles([]string{s.customCheckFile}) if err != nil { s.l.Errorf("Failed to load local checks file: %s.", err) return // keep previously loaded advisors } - - advisors = append(advisors, check.Advisor{ - Version: 2, - Name: "dev", - Summary: "Dev Advisor", - Description: "Advisor used for developing checks", - Category: "development", - Checks: checks, - }) + checks = append(checks, devChecks...) } - s.updateAdvisors(s.filterSupportedChecks(advisors)) + s.updateAdvisors(s.filterSupportedChecks(groupChecksIntoAdvisors(checks))) } -// loadBuiltinAdvisors loads builtin advisors. -func (s *Service) loadBuiltinAdvisors(_ context.Context) ([]check.Advisor, error) { - s.l.Infof("Loading advisors from dir=%s", builtinAdvisorsPath) - advisorFiles, err := filepath.Glob(filepath.Join(builtinAdvisorsPath, "*.yml")) - if err != nil { - return nil, fmt.Errorf("failed to find advisor files: %w", err) - } - - advisors, err := s.loadAdvisorsFromFiles(advisorFiles) - if err != nil { - return nil, err - } - +// loadBuiltinChecks loads builtin checks from the checks directory. +func (s *Service) loadBuiltinChecks(_ context.Context) ([]check.Check, error) { s.l.Infof("Loading checks from dir=%s", builtinChecksPath) checkFiles, err := filepath.Glob(filepath.Join(builtinChecksPath, "*.yml")) @@ -1659,25 +1620,26 @@ func (s *Service) loadBuiltinAdvisors(_ context.Context) ([]check.Advisor, error return nil, fmt.Errorf("failed to find check files: %w", err) } - checks, err := s.loadChecksFromFiles(checkFiles) - if err != nil { - return nil, err - } + return s.loadChecksFromFiles(checkFiles) +} - // Link checks to advisors +// groupChecksIntoAdvisors groups checks into advisors by their (Category, Subcategory) +// pair, preserving first-seen order. +func groupChecksIntoAdvisors(checks []check.Check) []check.Advisor { + index := make(map[string]int, len(checks)) + advisors := make([]check.Advisor, 0, len(checks)) for _, c := range checks { - a, ok := advisors[c.Advisor] + key := c.Category + "\x00" + c.Subcategory + i, ok := index[key] if !ok { - return nil, fmt.Errorf("check '%s' refers to an unknown advisor '%s'", c.Name, c.Advisor) + i = len(advisors) + index[key] = i + advisors = append(advisors, check.Advisor{Category: c.Category, Subcategory: c.Subcategory}) } - a.Checks = append(a.Checks, c) + advisors[i].Checks = append(advisors[i].Checks, c) } - advisorsSlice := make([]check.Advisor, 0, len(advisors)) - for _, a := range advisors { - advisorsSlice = append(advisorsSlice, *a) - } - return advisorsSlice, nil + return advisors } // loadChecksFromFiles loads Advisor checks from a list of given files. @@ -1715,43 +1677,6 @@ func (s *Service) loadChecksFromFiles(files []string) ([]check.Check, error) { } // loadAdvisorsFromFiles loads Advisors from a list of given files. -func (s *Service) loadAdvisorsFromFiles(files []string) (map[string]*check.Advisor, error) { - res := make(map[string]*check.Advisor, len(files)) - for _, file := range files { - s.l.Debugf("Loading advisor file=%s", file) - - b, err := os.ReadFile(file) //nolint:gosec - if err != nil { - return nil, fmt.Errorf("failed to read advisor file %s: %w", file, err) - } - advisors, err := check.ParseAdvisors(bytes.NewReader(b), &check.ParseParams{ - DisallowUnknownFields: true, - DisallowInvalidChecks: true, - }) - if err != nil { - return nil, fmt.Errorf("failed to parse advisor from file %s: %w", file, err) - } - - if len(advisors) != 1 { - return nil, fmt.Errorf("expected exactly one advisor in %s", file) - } - a := advisors[0] - - _, fileName := filepath.Split(file) - if a.Name != strings.TrimSuffix(fileName, ".yml") { - return nil, fmt.Errorf("advisor name does not match file name %s", file) - } - - if _, ok := res[a.Name]; ok { - return nil, fmt.Errorf("advisor name collision detected: %s", a.Name) - } - - res[a.Name] = &a - } - - return res, nil -} - // filterSupportedChecks returns supported advisor checks and prints warning log messages about unsupported. func (s *Service) filterSupportedChecks(advisors []check.Advisor) []check.Advisor { res := make([]check.Advisor, 0, len(advisors)) @@ -1872,7 +1797,7 @@ func (s *Service) refreshChecksInMemoryMetric() { func (s *Service) incChecksInMemoryMetric(serviceType models.ServiceType, checks map[string]check.Check) { for _, c := range checks { - s.mChecksAvailable.WithLabelValues(string(serviceType), c.Advisor, c.Name).Inc() + s.mChecksAvailable.WithLabelValues(string(serviceType), c.Subcategory, c.Name).Inc() } } diff --git a/managed/services/checks/checks_test.go b/managed/services/checks/checks_test.go index b13362e89ef..60cda69a9cb 100644 --- a/managed/services/checks/checks_test.go +++ b/managed/services/checks/checks_test.go @@ -66,7 +66,7 @@ func TestLoadBuiltinAdvisors(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) defer cancel() - dChecks, err := s.loadBuiltinAdvisors(ctx) + dChecks, err := s.loadBuiltinChecks(ctx) require.NoError(t, err) assert.NotEmpty(t, dChecks) @@ -86,7 +86,7 @@ func TestLoadBuiltinAdvisors(t *testing.T) { ctx, cancel := context.WithTimeout(t.Context(), 10*time.Second) defer cancel() - dChecks, err := s.loadBuiltinAdvisors(ctx) + dChecks, err := s.loadBuiltinChecks(ctx) require.NoError(t, err) assert.NotEmpty(t, dChecks) @@ -114,12 +114,11 @@ func TestUpdateAdvisorsList(t *testing.T) { require.NoError(t, err) require.GreaterOrEqual(t, len(advisors), 1) - // custom checks are loaded last, so we check the last advisor in the list. + // the custom check carries a unique (category, subcategory), so it forms + // its own advisor group loaded last. advisor := advisors[len(advisors)-1] - require.Equal(t, "dev", advisor.Name) - require.Equal(t, "Dev Advisor", advisor.Summary) - require.Equal(t, "Advisor used for developing checks", advisor.Description) - require.Equal(t, "development", advisor.Category) + require.Equal(t, "Development", advisor.Category) + require.Equal(t, "Dev", advisor.Subcategory) require.Len(t, advisor.Checks, 1) checkNames := make([]string, 0, len(advisor.Checks)) @@ -359,28 +358,22 @@ func TestFilterChecks(t *testing.T) { valid := []check.Advisor{ { - Name: "mysql_advisor", - Summary: "MySQL advisor", - Description: "Test mySQL advisor", - Category: "test", + Category: "Test", + Subcategory: "MySQL", Checks: []check.Check{ {Name: "MySQL check V2", Version: 2, Queries: []check.Query{{Type: check.MySQLShow}, {Type: check.MySQLSelect}}}, }, }, { - Name: "postgresql_advisor", - Summary: "PostgreSQL advisor", - Description: "Test postgreSQL advisor", - Category: "test", + Category: "Test", + Subcategory: "PostgreSQL", Checks: []check.Check{ {Name: "PostgreSQL check V2", Version: 2, Queries: []check.Query{{Type: check.PostgreSQLShow}, {Type: check.PostgreSQLSelect}}}, }, }, { - Name: "mongodb_advisor", - Summary: "MongoDB advisor", - Description: "Test mongoDB advisor", - Category: "test", + Category: "Test", + Subcategory: "MongoDB", Checks: []check.Check{ {Name: "MongoDB check V2", Version: 2, Queries: []check.Query{{Type: check.MongoDBBuildInfo}, {Type: check.MongoDBGetParameter}, {Type: check.MongoDBGetCmdLineOpts}}}, }, @@ -389,20 +382,16 @@ func TestFilterChecks(t *testing.T) { invalid := []check.Advisor{ { - Name: "completely_invalid_advisor", - Summary: "Completely invalid advisor", - Description: "Test advisor that contains only unsupported checks", - Category: "test", + Category: "Test", + Subcategory: "CompletelyInvalid", Checks: []check.Check{ {Name: "unsupported version", Version: check.MaxSupportedVersion + 1, Queries: []check.Query{{Type: check.MySQLShow}}}, {Name: "unsupported type", Version: 2, Queries: []check.Query{{Type: check.Type("RedisInfo")}}}, }, }, { - Name: "partially_invalid_advisor", - Summary: "Partially invalid advisor", - Description: "Test advisor that contains some unsupported checks", - Category: "test", + Category: "Test", + Subcategory: "PartiallyInvalid", Checks: []check.Check{ {Name: "MySQLShow", Version: 2, Queries: []check.Query{{Type: check.MySQLShow}}}, {Name: "unsupported type", Version: 2, Queries: []check.Query{{Type: check.Type("RedisInfo")}}}, diff --git a/managed/services/checks/insight_text.go b/managed/services/checks/insight_text.go index eeb631f4da4..ccf19d81e8c 100644 --- a/managed/services/checks/insight_text.go +++ b/managed/services/checks/insight_text.go @@ -86,8 +86,8 @@ func insightToText(r *models.CheckResult) (string, error) { {"ID", r.ID}, {"Batch ID", r.BatchID}, {"Check Name", r.CheckName}, - {"Advisor", r.AdvisorName}, - {"Category", capitalize(r.Category)}, + {"Category", r.Category}, + {"Sub category", r.Subcategory}, {"Service Name", r.ServiceName}, {"Service Type", string(r.ServiceType)}, {"Node Name", r.NodeName}, diff --git a/managed/services/checks/insight_text_test.go b/managed/services/checks/insight_text_test.go index 7da59c728ba..eb5483a2da2 100644 --- a/managed/services/checks/insight_text_test.go +++ b/managed/services/checks/insight_text_test.go @@ -36,8 +36,8 @@ func TestInsightToText(t *testing.T) { ID: "insight-1", BatchID: "batch-1", CheckName: "mysql_version", - AdvisorName: "version_advisor", - Category: "performance", + Subcategory: "version_advisor", + Category: "Performance", ServiceName: "mysql-prod", ServiceType: "mysql", NodeName: "node-a", @@ -63,8 +63,8 @@ Check Details: ID: insight-1 Batch ID: batch-1 Check Name: mysql_version - Advisor: version_advisor Category: Performance + Sub category: version_advisor Service Name: mysql-prod Service Type: mysql Node Name: node-a diff --git a/managed/services/checks/registry.go b/managed/services/checks/registry.go index fb626e27380..62295f1cda9 100644 --- a/managed/services/checks/registry.go +++ b/managed/services/checks/registry.go @@ -120,7 +120,7 @@ func (r *registry) Collect(ch chan<- prom.Metric) { r.mInsights.Reset() res := r.getCheckResults("") for _, re := range res { - r.mInsights.WithLabelValues(string(re.Target.ServiceType), re.Target.ServiceName, re.AdvisorName, re.CheckName, re.Result.Severity.String()).Inc() + r.mInsights.WithLabelValues(string(re.Target.ServiceType), re.Target.ServiceName, re.Subcategory, re.CheckName, re.Result.Severity.String()).Inc() } r.mInsights.Collect(ch) } diff --git a/managed/services/checks/registry_test.go b/managed/services/checks/registry_test.go index 178687fa086..0ac7ca7d44e 100644 --- a/managed/services/checks/registry_test.go +++ b/managed/services/checks/registry_test.go @@ -246,7 +246,7 @@ func TestRegistryInsightsMetric(t *testing.T) { r.set([]services.CheckResult{ { CheckName: "mysql_version", - AdvisorName: "adv", + Subcategory: "adv", Interval: check.Standard, Target: services.Target{ ServiceID: "svc-id", diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index a558f830063..ac21816aa7e 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -20,7 +20,6 @@ import ( "errors" "fmt" "maps" - "strings" "github.com/AlekSi/pointer" "github.com/sirupsen/logrus" @@ -238,8 +237,8 @@ func (s *ChecksAPIService) ListCheckResultsHistory( Id: r.ID, CheckName: r.CheckName, BatchId: r.BatchID, - AdvisorName: r.AdvisorName, Category: r.Category, + Subcategory: r.Subcategory, Severity: convertModelSeverity(r.Severity), Interval: convertModelInterval(r.Interval), ServiceId: r.ServiceID, @@ -402,11 +401,8 @@ func (s *ChecksAPIService) ListAdvisors(_ context.Context, _ *advisorsv1.ListAdv } res = append(res, &advisorsv1.Advisor{ - Name: a.Name, - Description: a.Description, - Summary: a.Summary, - Comment: createComment(a.Checks), Category: a.Category, + Subcategory: a.Subcategory, Checks: checks, }) } @@ -414,37 +410,6 @@ func (s *ChecksAPIService) ListAdvisors(_ context.Context, _ *advisorsv1.ListAdv return &advisorsv1.ListAdvisorsResponse{Advisors: res}, nil } -func createComment(checks []check.Check) string { - var mySQL, postgreSQL, mongoDB bool - for _, c := range checks { - switch c.Family { - case check.MySQL: - mySQL = true - case check.PostgreSQL: - postgreSQL = true - case check.MongoDB: - mongoDB = true - } - } - - b := make([]string, 0, 3) - if mySQL { - b = append(b, "MySQL") - } - if postgreSQL { - b = append(b, "PostgreSQL") - } - if mongoDB { - b = append(b, "MongoDB") - } - - if len(b) == 3 { - return "All technologies supported" - } - - return "Partial support (" + strings.Join(b, ", ") + ")" -} - // ChangeAdvisorChecks enables/disables advisor checks by names or changes its execution interval. func (s *ChecksAPIService) ChangeAdvisorChecks(_ context.Context, req *advisorsv1.ChangeAdvisorChecksRequest) (*advisorsv1.ChangeAdvisorChecksResponse, error) { var enableChecks, disableChecks []string diff --git a/managed/services/management/checks_test.go b/managed/services/management/checks_test.go index 0aa2325927b..d69afcdfcd3 100644 --- a/managed/services/management/checks_test.go +++ b/managed/services/management/checks_test.go @@ -293,7 +293,7 @@ func TestListCheckResultsHistory(t *testing.T) { record := &models.CheckResult{ ID: "id1", CheckName: "test_check", - AdvisorName: "test_advisor", + Subcategory: "test_advisor", Category: "configuration", Interval: models.Standard, ServiceID: "test_svc", @@ -328,7 +328,7 @@ func TestListCheckResultsHistory(t *testing.T) { { Id: "id1", CheckName: "test_check", - AdvisorName: "test_advisor", + Subcategory: "test_advisor", Category: "configuration", Interval: advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_STANDARD, ServiceId: "test_svc", @@ -581,44 +581,3 @@ func TestUpdateAdvisorChecks(t *testing.T) { assert.Equal(t, &advisorsv1.ChangeAdvisorChecksResponse{}, resp) }) } - -func TestCreateComment(t *testing.T) { - t.Parallel() - - testCases := []struct { - Name string - Comment string - Checks []check.Check - }{ - { - Name: "all technologies", - Comment: "All technologies supported", - Checks: []check.Check{ - {Version: 2, Name: "a", Family: check.MySQL}, - {Version: 2, Name: "b", Family: check.PostgreSQL}, - {Version: 2, Name: "c", Family: check.MongoDB}, - }, - }, - { - Name: "partial support", - Comment: "Partial support (MySQL, MongoDB)", - Checks: []check.Check{ - {Version: 2, Name: "a", Family: check.MySQL}, - {Version: 2, Name: "b", Family: check.MongoDB}, - }, - }, - { - Name: "partial support", - Comment: "Partial support (MySQL)", - Checks: []check.Check{ - {Version: 2, Name: "a", Family: check.MySQL}, - }, - }, - } - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - t.Parallel() - assert.Equal(t, tc.Comment, createComment(tc.Checks)) - }) - } -} diff --git a/managed/services/types.go b/managed/services/types.go index 3660666cb36..b80e8901a44 100644 --- a/managed/services/types.go +++ b/managed/services/types.go @@ -66,7 +66,7 @@ func (t *Target) Copy() Target { // CheckResult contains the output from the check file and other information. type CheckResult struct { CheckName string - AdvisorName string + Subcategory string Interval check.Interval Target Target Result check.Result diff --git a/managed/testdata/checks/good_check_pg.yml b/managed/testdata/checks/good_check_pg.yml index 35e95307732..54aa0f14f80 100644 --- a/managed/testdata/checks/good_check_pg.yml +++ b/managed/testdata/checks/good_check_pg.yml @@ -4,7 +4,8 @@ checks: name: good_check_pg summary: Good Check PG description: Good check for PostgreSQL. - advisor: dev + category: Development + subcategory: Dev family: POSTGRESQL queries: - type: POSTGRESQL_SELECT diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx index 23b438e8acd..8344d20d7df 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx @@ -4,7 +4,6 @@ import MenuItem from '@mui/material/MenuItem'; import Switch from '@mui/material/Switch'; import { AdvisorCheckRow, AdvisorInterval } from 'types/advisors.types'; import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; -import { capitalize } from 'utils/text.utils'; import { Messages } from './AdvisorsList.messages'; export const INTERVAL_OPTIONS = [ @@ -35,7 +34,13 @@ export const getAdvisorsColumns = ({ { id: 'category', header: Messages.columns.category, - accessorFn: (row) => capitalize(row.category), + accessorFn: (row) => row.category, + size: 150, + }, + { + id: 'subcategory', + header: Messages.columns.subcategory, + accessorFn: (row) => row.subcategory, size: 150, }, { diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts index 5c98d7ae898..02aa1a4a71f 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.messages.ts @@ -7,6 +7,7 @@ export const Messages = { check: 'Check', description: 'Description', category: 'Category', + subcategory: 'Sub category', vendor: 'Vendor', interval: 'Interval', status: 'Status', @@ -19,6 +20,7 @@ export const Messages = { filters: { all: 'All', category: 'Category', + subcategory: 'Sub category', vendor: 'Vendor', interval: 'Interval', status: 'Status', @@ -34,8 +36,8 @@ export const Messages = { maximize: 'Maximize', close: 'Close', checkName: 'Check name', - advisor: 'Advisor', category: 'Category', + subcategory: 'Sub category', vendor: 'Vendor', interval: 'Interval', status: 'Status', diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx index 2bf79574268..8ddd9d48561 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.test.tsx @@ -21,11 +21,8 @@ vi.mock('api/advisors'); const TEST_ADVISORS: Advisor[] = [ { - name: 'mysql_version', - summary: 'MySQL Version', - description: 'Advisor for MySQL versions', - comment: '', - category: 'version_configuration', + category: 'Configuration', + subcategory: 'Version', checks: [ { name: 'mysql_version_check', @@ -38,11 +35,8 @@ const TEST_ADVISORS: Advisor[] = [ ], }, { - name: 'postgresql_security', - summary: 'PostgreSQL Security', - description: 'Advisor for PostgreSQL security', - comment: '', - category: 'security', + category: 'Security', + subcategory: 'Authentication', checks: [ { name: 'postgresql_super_role', diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx index 76cbc39fb63..53e67128b47 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.tsx @@ -28,7 +28,6 @@ import { import { AdvisorCheckRow, AdvisorInterval } from 'types/advisors.types'; import { OrgRole } from 'types/user.types'; import { flattenAdvisorChecks } from 'utils/advisors.utils'; -import { capitalize } from 'utils/text.utils'; import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; import { Messages } from './AdvisorsList.messages'; import { getAdvisorsColumns, INTERVAL_OPTIONS } from './AdvisorsList.constants'; @@ -36,6 +35,7 @@ import { AdvisorCheckDetailsPane } from './details-pane'; interface CheckFilters { category: string; + subcategory: string; vendor: string; interval: string; status: string; @@ -92,16 +92,8 @@ const AdvisorsList: FC = () => { useStartAdvisorChecks(); const { mutate: changeChecks } = useChangeAdvisorChecks(); - const [detailsCheck, setDetailsCheck] = useState( - null - ); const [detailsMaximized, setDetailsMaximized] = useState(false); - const openDetails = (check: AdvisorCheckRow, maximized = false) => { - setDetailsMaximized(maximized); - setDetailsCheck(check); - }; - const [searchParams, setSearchParams] = useSearchParams(); // the URL query string is the single source of truth for filters + @@ -110,6 +102,7 @@ const AdvisorsList: FC = () => { const filters = useMemo( () => ({ category: searchParams.get('category') || '', + subcategory: searchParams.get('subcategory') || '', vendor: searchParams.get('vendor') || '', interval: searchParams.get('interval') || '', status: searchParams.get('status') || '', @@ -134,6 +127,11 @@ const AdvisorsList: FC = () => { setSearchParams(next, { replace: true }); }; + const openDetails = (check: AdvisorCheckRow, maximized = false) => { + setDetailsMaximized(maximized); + patchParams((p) => p.set('details', check.checkName), { resetPage: false }); + }; + const setSearch = (value: string) => patchParams((p) => { if (value) { @@ -178,14 +176,32 @@ const AdvisorsList: FC = () => { const rows = useMemo(() => flattenAdvisorChecks(advisors), [advisors]); + // the open details overlay is driven by the ?details= URL param, + // so the overlay is deep-linkable and reproduced by a shared URL + const detailsCheck = useMemo( + () => + rows.find( + (row) => row.checkName === (searchParams.get('details') || '') + ) ?? null, + [rows, searchParams] + ); + const categoryOptions = useMemo( () => - [...new Set(rows.map((row) => capitalize(row.category)))] + [...new Set(rows.map((row) => row.category))] .sort() .map((category) => ({ label: category, value: category })), [rows] ); + const subcategoryOptions = useMemo( + () => + [...new Set(rows.map((row) => row.subcategory))] + .sort() + .map((subcategory) => ({ label: subcategory, value: subcategory })), + [rows] + ); + const vendorOptions = useMemo( () => [...new Set(rows.map((row) => ADVISOR_FAMILY[row.family]))] @@ -211,7 +227,10 @@ const AdvisorsList: FC = () => { const filteredRows = useMemo(() => { const term = search.trim().toLowerCase(); return rows.filter((row) => { - if (filters.category && capitalize(row.category) !== filters.category) { + if (filters.category && row.category !== filters.category) { + return false; + } + if (filters.subcategory && row.subcategory !== filters.subcategory) { return false; } if (filters.vendor && ADVISOR_FAMILY[row.family] !== filters.vendor) { @@ -233,7 +252,7 @@ const AdvisorsList: FC = () => { } if (term) { const haystack = - `${row.summary} ${row.description} ${capitalize(row.category)} ${ADVISOR_FAMILY[row.family]}`.toLowerCase(); + `${row.summary} ${row.description} ${row.category} ${row.subcategory} ${ADVISOR_FAMILY[row.family]}`.toLowerCase(); if (!haystack.includes(term)) { return false; } @@ -357,6 +376,13 @@ const AdvisorsList: FC = () => { value={filters.category} onChange={(value) => updateFilter('category', value)} /> + updateFilter('subcategory', value)} + /> { - { setDetailsCheck(null)} + onClose={() => + patchParams((p) => p.delete('details'), { resetPage: false }) + } /> diff --git a/ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx b/ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx index 04baa7caef6..6e528015932 100644 --- a/ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx +++ b/ui/apps/pmm/src/pages/advisors/details-pane/AdvisorCheckDetailsPane.tsx @@ -11,6 +11,7 @@ import Drawer from '@mui/material/Drawer'; import IconButton from '@mui/material/IconButton'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; +import { CopyToClipboardButton } from '@percona/percona-ui'; import { enqueueSnackbar } from 'notistack'; import { DRAWER_CLOSED_WIDTH, @@ -20,7 +21,6 @@ import { useNavigation } from 'contexts/navigation/navigation.hooks'; import { useAdvisorCheckScript } from 'hooks/api/useAdvisors'; import { AdvisorCheckRow } from 'types/advisors.types'; import { ADVISOR_FAMILY, ADVISOR_INTERVAL } from 'lib/constants'; -import { capitalize } from 'utils/text.utils'; import { Messages } from '../AdvisorsList.messages'; const EM_DASH = '—'; @@ -41,7 +41,21 @@ const Field: FC = ({ label, children, span = 1 }) => ( {label} - {children} + + {children} + ); @@ -155,15 +169,16 @@ export const AdvisorCheckDetailsPane: FC = ({ }} > - {check.checkName} - - - {check.advisorName} + + {check.checkName} + + - - {capitalize(check.category)} - + {check.category} + + + {check.subcategory} diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx index 8dc4cf9d38e..192a288affa 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.constants.tsx @@ -5,7 +5,6 @@ import { format } from 'date-fns'; import { CheckResultHistoryItem } from 'types/advisors.types'; import { Severity } from 'types/severity.types'; import { ADVISOR_RESULT_STATUS, SEVERITY, TIME_FORMAT } from 'lib/constants'; -import { capitalize } from 'utils/text.utils'; import { Messages } from './AdvisorInsights.messages'; const SEVERITY_ORDER: Record = { @@ -55,7 +54,7 @@ export const getInsightsColumns = { id: 'category', header: Messages.columns.category, - accessorFn: (row) => capitalize(row.category), + accessorFn: (row) => row.category, size: 140, }, { diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts index f33ab796823..7c966a4e8d5 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.messages.ts @@ -31,6 +31,7 @@ export const Messages = { service: 'Service', node: 'Node', category: 'Category', + subcategory: 'Sub category', environment: 'Environment', cluster: 'Cluster', replicationSet: 'Replication set', diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx index ae4e7b5711e..501dc419b9a 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.test.tsx @@ -31,11 +31,8 @@ vi.mock('api/advisors'); const TEST_ADVISORS: Advisor[] = [ { - name: 'test_advisor', - summary: 'Test advisor', - description: '', - comment: '', - category: 'configuration', + category: 'Configuration', + subcategory: 'Version', checks: [ { name: 'mysql_version_check', @@ -60,8 +57,8 @@ const TEST_ADVISORS: Advisor[] = [ const TEST_ITEM: CheckResultHistoryItem = { id: 'result-1', checkName: 'mysql_version_check', - advisorName: 'MySQL Version', - category: 'version_configuration', + subcategory: 'Version', + category: 'Configuration', interval: AdvisorInterval.standard, serviceId: 'service-1', serviceName: 'mysql-prod', @@ -456,8 +453,8 @@ describe('AdvisorInsights', () => { ' ID: result-1\n' + ' Batch ID: batch-1\n' + ' Check Name: mysql_version_check\n' + - ' Advisor: MySQL Version\n' + - ' Category: Version_configuration\n' + + ' Category: Configuration\n' + + ' Sub category: Version\n' + ' Service Name: mysql-prod\n' + ' Service Type: mysql\n' + ' Node Name: node-1\n' + diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx index 146ab73719a..b72d0265757 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.tsx @@ -44,7 +44,6 @@ import { } from 'types/advisors.types'; import { Severity } from 'types/severity.types'; import { OrgRole } from 'types/user.types'; -import { capitalize } from 'utils/text.utils'; import { getInsightsColumns } from './AdvisorInsights.constants'; import { insightToText } from './AdvisorInsights.utils'; import { InsightDetailsPane } from './details-pane'; @@ -196,17 +195,25 @@ const AdvisorInsights: FC = () => { }; const [actionMenu, setActionMenu] = useState(null); - const [detailsInsight, setDetailsInsight] = - useState(null); const [detailsMaximized, setDetailsMaximized] = useState(false); const openDetails = (insight: CheckResultHistoryItem, maximized = false) => { setDetailsMaximized(maximized); - setDetailsInsight(insight); + patchParams((p) => p.set('insight', insight.id), { resetPage: false }); }; const { data, isLoading, isFetching, refetch } = useCheckResultsHistory(params); + + // the open details overlay is driven by the ?insight= URL param (the + // result's Check ID), so the overlay is deep-linkable via a shared URL + const detailsInsight = useMemo( + () => + (data?.results ?? []).find( + (item) => item.id === (searchParams.get('insight') || '') + ) ?? null, + [data, searchParams] + ); const { data: advisors = [], refetch: refetchAdvisors } = useAdvisors(); const { data: filterValues, refetch: refetchFilterValues } = useCheckResultsFilterValues(); @@ -312,7 +319,7 @@ const AdvisorInsights: FC = () => { () => [...new Set(advisors.map((advisor) => advisor.category))] .sort() - .map((category) => ({ label: capitalize(category), value: category })), + .map((category) => ({ label: category, value: category })), [advisors] ); @@ -642,7 +649,9 @@ const AdvisorInsights: FC = () => { ? checksByName.get(detailsInsight.checkName)?.enabled : undefined } - onClose={() => setDetailsInsight(null)} + onClose={() => + patchParams((p) => p.delete('insight'), { resetPage: false }) + } /> diff --git a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts index 5bd0b859a05..35856f54e1c 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts +++ b/ui/apps/pmm/src/pages/advisors/insights/AdvisorInsights.utils.ts @@ -9,7 +9,6 @@ import { SEVERITY, TIME_FORMAT, } from 'lib/constants'; -import { capitalize } from 'utils/text.utils'; const TRIGGERED_BY_LABEL: Record = { [AdvisorCheckTriggeredBy.user]: 'User', @@ -30,8 +29,8 @@ export const insightToText = (item: CheckResultHistoryItem): string => { ['ID', item.id], ['Batch ID', item.batchId], ['Check Name', item.checkName], - ['Advisor', item.advisorName], - ['Category', capitalize(item.category)], + ['Category', item.category], + ['Sub category', item.subcategory], ['Service Name', item.serviceName], ['Service Type', item.serviceType], ['Node Name', item.nodeName], diff --git a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx index 7da8d5608ab..1d7c693955f 100644 --- a/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx +++ b/ui/apps/pmm/src/pages/advisors/insights/details-pane/InsightDetailsPane.tsx @@ -25,7 +25,6 @@ import { SEVERITY, TIME_FORMAT, } from 'lib/constants'; -import { capitalize } from 'utils/text.utils'; import { Messages } from '../AdvisorInsights.messages'; const EM_DASH = '—'; @@ -61,7 +60,21 @@ const Field: FC = ({ label, children, span = 1 }) => ( {label} - {children} + + {children} + ); @@ -239,9 +252,10 @@ export const InsightDetailsPane: FC = ({ - - {capitalize(insight.category)} - + {insight.category} + + + {insight.subcategory} diff --git a/ui/apps/pmm/src/types/advisors.types.ts b/ui/apps/pmm/src/types/advisors.types.ts index 676d00566d7..7217f6ca73e 100644 --- a/ui/apps/pmm/src/types/advisors.types.ts +++ b/ui/apps/pmm/src/types/advisors.types.ts @@ -24,11 +24,8 @@ export interface AdvisorCheck { } export interface Advisor { - name: string; - description: string; - summary: string; - comment: string; category: string; + subcategory: string; checks: AdvisorCheck[]; } @@ -74,7 +71,7 @@ export interface StartAdvisorChecksResponse { export interface CheckResultHistoryItem { id: string; checkName: string; - advisorName: string; + subcategory: string; category: string; interval: AdvisorInterval; serviceId: string; @@ -129,7 +126,7 @@ export interface AdvisorCheckRow { checkName: string; summary: string; description: string; - advisorName: string; + subcategory: string; category: string; family: AdvisorFamily; interval: AdvisorInterval; diff --git a/ui/apps/pmm/src/utils/advisors.utils.ts b/ui/apps/pmm/src/utils/advisors.utils.ts index 4e914beaf66..135705564bd 100644 --- a/ui/apps/pmm/src/utils/advisors.utils.ts +++ b/ui/apps/pmm/src/utils/advisors.utils.ts @@ -6,7 +6,7 @@ export const flattenAdvisorChecks = (advisors: Advisor[]): AdvisorCheckRow[] => checkName: check.name, summary: check.summary, description: check.description, - advisorName: advisor.summary, + subcategory: advisor.subcategory, category: advisor.category, family: check.family, interval: check.interval, From c209631bd7b21da29bac71c02cf52e2ff7f94ee9 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Sun, 19 Jul 2026 21:37:08 +0300 Subject: [PATCH 043/120] PMM-14109 Rearrange category and subcategory fields in CheckResultHistoryItem and update related validation and JSON responses --- api/advisors/v1/advisors.pb.go | 20 +++++++++--------- api/advisors/v1/advisors.pb.validate.go | 4 ++-- api/advisors/v1/advisors.proto | 6 +++--- .../list_check_results_history_responses.go | 6 +++--- api/advisors/v1/json/v1.json | 8 +++---- api/alerting/v1/alerting.proto | 2 +- api/descriptor.bin | Bin 830622 -> 830622 bytes api/swagger/swagger-dev.json | 8 +++---- api/swagger/swagger.json | 8 +++---- .../rpm/server/SPECS/pmm-managed.spec | 1 - 10 files changed, 31 insertions(+), 32 deletions(-) diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index 8e723a7eb9d..28784d300f2 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -1467,10 +1467,10 @@ type CheckResultHistoryItem struct { BatchId string `protobuf:"bytes,2,opt,name=batch_id,json=batchId,proto3" json:"batch_id,omitempty"` // Name of the check that ran. CheckName string `protobuf:"bytes,3,opt,name=check_name,json=checkName,proto3" json:"check_name,omitempty"` - // Subcategory the check belongs to (second-level grouping within a category). - Subcategory string `protobuf:"bytes,4,opt,name=subcategory,proto3" json:"subcategory,omitempty"` // Category the check belongs to (top-level grouping). - Category string `protobuf:"bytes,5,opt,name=category,proto3" json:"category,omitempty"` + Category string `protobuf:"bytes,4,opt,name=category,proto3" json:"category,omitempty"` + // Subcategory the check belongs to (second-level grouping within a category). + Subcategory string `protobuf:"bytes,5,opt,name=subcategory,proto3" json:"subcategory,omitempty"` // Check execution interval. Interval AdvisorCheckInterval `protobuf:"varint,6,opt,name=interval,proto3,enum=advisors.v1.AdvisorCheckInterval" json:"interval,omitempty"` // ID of the monitored service on which the check ran. @@ -1564,16 +1564,16 @@ func (x *CheckResultHistoryItem) GetCheckName() string { return "" } -func (x *CheckResultHistoryItem) GetSubcategory() string { +func (x *CheckResultHistoryItem) GetCategory() string { if x != nil { - return x.Subcategory + return x.Category } return "" } -func (x *CheckResultHistoryItem) GetCategory() string { +func (x *CheckResultHistoryItem) GetSubcategory() string { if x != nil { - return x.Category + return x.Subcategory } return "" } @@ -2223,9 +2223,9 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x19\n" + "\bbatch_id\x18\x02 \x01(\tR\abatchId\x12\x1d\n" + "\n" + - "check_name\x18\x03 \x01(\tR\tcheckName\x12 \n" + - "\vsubcategory\x18\x04 \x01(\tR\vsubcategory\x12\x1a\n" + - "\bcategory\x18\x05 \x01(\tR\bcategory\x12=\n" + + "check_name\x18\x03 \x01(\tR\tcheckName\x12\x1a\n" + + "\bcategory\x18\x04 \x01(\tR\bcategory\x12 \n" + + "\vsubcategory\x18\x05 \x01(\tR\vsubcategory\x12=\n" + "\binterval\x18\x06 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\binterval\x12\x1d\n" + "\n" + "service_id\x18\a \x01(\tR\tserviceId\x12!\n" + diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index 2d8a37474c4..ad38d7e448a 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -2444,10 +2444,10 @@ func (m *CheckResultHistoryItem) validate(all bool) error { // no validation rules for CheckName - // no validation rules for Subcategory - // no validation rules for Category + // no validation rules for Subcategory + // no validation rules for Interval // no validation rules for ServiceId diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index d3c7527a1fc..9eafa926907 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -207,10 +207,10 @@ message CheckResultHistoryItem { string batch_id = 2; // Name of the check that ran. string check_name = 3; - // Subcategory the check belongs to (second-level grouping within a category). - string subcategory = 4; // Category the check belongs to (top-level grouping). - string category = 5; + string category = 4; + // Subcategory the check belongs to (second-level grouping within a category). + string subcategory = 5; // Check execution interval. AdvisorCheckInterval interval = 6; // ID of the monitored service on which the check ran. diff --git a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go index 20d508f604b..98cea5711ae 100644 --- a/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_check_results_history_responses.go @@ -544,12 +544,12 @@ type ListCheckResultsHistoryOKBodyResultsItems0 struct { // Name of the check that ran. CheckName string `json:"check_name,omitempty"` - // Subcategory the check belongs to (second-level grouping within a category). - Subcategory string `json:"subcategory,omitempty"` - // Category the check belongs to (top-level grouping). Category string `json:"category,omitempty"` + // Subcategory the check belongs to (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + // AdvisorCheckInterval represents possible execution interval values for checks. // Enum: ["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"] Interval *string `json:"interval,omitempty"` diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index f6486a9276f..8568f2a4539 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -579,13 +579,13 @@ "type": "string", "x-order": 2 }, - "subcategory": { - "description": "Subcategory the check belongs to (second-level grouping within a category).", + "category": { + "description": "Category the check belongs to (top-level grouping).", "type": "string", "x-order": 3 }, - "category": { - "description": "Category the check belongs to (top-level grouping).", + "subcategory": { + "description": "Subcategory the check belongs to (second-level grouping within a category).", "type": "string", "x-order": 4 }, diff --git a/api/alerting/v1/alerting.proto b/api/alerting/v1/alerting.proto index 86ccb3cf7a1..04163099c25 100644 --- a/api/alerting/v1/alerting.proto +++ b/api/alerting/v1/alerting.proto @@ -56,7 +56,7 @@ enum TemplateSource { TEMPLATE_SOURCE_UNSPECIFIED = 0; // Template that is shipped with PMM Server releases. TEMPLATE_SOURCE_BUILT_IN = 1; - // Template that is downloaded from check.percona.com. + // Template that is downloaded from check.percona.com. Deprecated. TEMPLATE_SOURCE_SAAS = 2; // Templated loaded from user-suplied file. TEMPLATE_SOURCE_USER_FILE = 3; diff --git a/api/descriptor.bin b/api/descriptor.bin index a417471fcfecdad9dce139d4db1a76f034f6c241..46037448203d467f1a37b88711815305ab1697f2 100644 GIT binary patch delta 188 zcmbPt(`epJqlOm77N#xCZdtriTpY=XC8_E8MU@gP)A>@F<+xZC7&SP9xQk1ZwpV8{ zUoz%$=3-$HVPY0yxitOZJZ48jW=0^BkyDV1mx~o70g_=95ruMDScO=wFfws)MT51m z0D05H=P^f$vjDYSVdNBnsRL@e!YD4$ZaJSBh*^M`6^Pk@m>q~YfS41Axqz5^yXAbI GR9*l}MJwU} delta 196 zcmbPt(`epJqlOm77N#xCZdr;7T-?Q_Ny&*Nsph~SgtTKad0_ Date: Mon, 20 Jul 2026 23:43:00 +0300 Subject: [PATCH 044/120] PMM-14109 Add CRUD for user-authored advisor checks User-authored advisor checks are now stored in the database with full create/read/update/delete support in the API and UI. Percona-shipped checks stay on disk and immutable; users can copy their code or clone them into new editable checks. The filesystem injection env var (PMM_DEV_ADVISOR_CHECKS_FILE) is removed in favor of DB storage. API: extend AdvisorCheck with category, subcategory, user_defined, queries and script; add CreateAdvisorCheck, UpdateAdvisorCheck, DeleteAdvisorCheck and GetAdvisorCheck. managed: add migration 120 (advisor_checks table), reform model and helpers; merge DB checks into the in-memory list (built-in wins on name collision); add CRUD service methods and API handlers. ui: add the authoring overlay (create/edit/clone) with structured fields and a script textarea; add Edit/Delete row actions and Clone from the details pane; add an Author column and drop the Description column. --- agent/docker-compose.yml | 2 - api-tests/docker-compose.yml | 2 - api/advisors/v1/advisors.pb.go | 854 +++++++++--- api/advisors/v1/advisors.pb.gw.go | 306 +++++ api/advisors/v1/advisors.pb.validate.go | 1150 +++++++++++++++- api/advisors/v1/advisors.proto | 100 +- api/advisors/v1/advisors_grpc.pb.go | 164 +++ .../advisor_service/advisor_service_client.go | 184 +++ .../create_advisor_check_parameters.go | 141 ++ .../create_advisor_check_responses.go | 1198 +++++++++++++++++ .../delete_advisor_check_parameters.go | 146 ++ .../delete_advisor_check_responses.go | 411 ++++++ .../get_advisor_check_parameters.go | 146 ++ .../get_advisor_check_responses.go | 806 +++++++++++ .../list_advisor_checks_responses.go | 129 +- .../list_advisors_responses.go | 129 +- .../update_advisor_check_parameters.go | 163 +++ .../update_advisor_check_responses.go | 1198 +++++++++++++++++ api/advisors/v1/json/v1.json | 840 ++++++++++++ api/alerting/v1/alerting.pb.go | 2 +- .../list_templates_responses.go | 2 +- api/alerting/v1/json/v1.json | 2 +- api/descriptor.bin | Bin 830622 -> 835836 bytes api/swagger/swagger-dev.json | 842 +++++++++++- api/swagger/swagger.json | 842 +++++++++++- managed/models/advisor_check_helpers.go | 97 ++ managed/models/advisor_check_model.go | 71 + managed/models/advisor_check_model_reform.go | 181 +++ managed/models/database.go | 17 + managed/pi/check/check.go | 10 +- managed/services/checks/checks.go | 229 +++- managed/services/checks/checks_test.go | 116 +- managed/services/management/checks.go | 210 +++ managed/services/management/deps.go | 3 + .../management/mock_checks_service_test.go | 54 + ui/apps/pmm/src/api/advisors.ts | 43 + ui/apps/pmm/src/hooks/api/useAdvisors.ts | 79 ++ .../pages/advisors/AdvisorsList.constants.tsx | 16 +- .../pages/advisors/AdvisorsList.messages.ts | 18 +- .../src/pages/advisors/AdvisorsList.test.tsx | 41 + .../pmm/src/pages/advisors/AdvisorsList.tsx | 164 ++- .../check-form/AdvisorCheckForm.constants.ts | 39 + .../check-form/AdvisorCheckForm.messages.ts | 39 + .../AdvisorCheckForm.schema.test.ts | 115 ++ .../check-form/AdvisorCheckForm.schema.ts | 84 ++ .../advisors/check-form/AdvisorCheckForm.tsx | 409 ++++++ .../src/pages/advisors/check-form/index.ts | 2 + .../details-pane/AdvisorCheckDetailsPane.tsx | 36 +- .../insights/AdvisorInsights.test.tsx | 6 + ui/apps/pmm/src/types/advisors.types.ts | 46 + ui/apps/pmm/src/utils/advisors.utils.ts | 1 + 51 files changed, 11651 insertions(+), 234 deletions(-) create mode 100644 api/advisors/v1/json/client/advisor_service/create_advisor_check_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/create_advisor_check_responses.go create mode 100644 api/advisors/v1/json/client/advisor_service/delete_advisor_check_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/delete_advisor_check_responses.go create mode 100644 api/advisors/v1/json/client/advisor_service/get_advisor_check_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/get_advisor_check_responses.go create mode 100644 api/advisors/v1/json/client/advisor_service/update_advisor_check_parameters.go create mode 100644 api/advisors/v1/json/client/advisor_service/update_advisor_check_responses.go create mode 100644 managed/models/advisor_check_helpers.go create mode 100644 managed/models/advisor_check_model.go create mode 100644 managed/models/advisor_check_model_reform.go create mode 100644 ui/apps/pmm/src/pages/advisors/check-form/AdvisorCheckForm.constants.ts create mode 100644 ui/apps/pmm/src/pages/advisors/check-form/AdvisorCheckForm.messages.ts create mode 100644 ui/apps/pmm/src/pages/advisors/check-form/AdvisorCheckForm.schema.test.ts create mode 100644 ui/apps/pmm/src/pages/advisors/check-form/AdvisorCheckForm.schema.ts create mode 100644 ui/apps/pmm/src/pages/advisors/check-form/AdvisorCheckForm.tsx create mode 100644 ui/apps/pmm/src/pages/advisors/check-form/index.ts diff --git a/agent/docker-compose.yml b/agent/docker-compose.yml index ed92c986127..965d783ebb3 100644 --- a/agent/docker-compose.yml +++ b/agent/docker-compose.yml @@ -8,8 +8,6 @@ services: - "127.0.0.1:443:8443" environment: - PMM_DEBUG=1 - # for local development - - PMM_DEV_ADVISOR_CHECKS_FILE=/srv/checks/custom-checks.yml volumes: - ./testdata/checks:/srv/checks diff --git a/api-tests/docker-compose.yml b/api-tests/docker-compose.yml index 181a50f4d59..54a877d6441 100644 --- a/api-tests/docker-compose.yml +++ b/api-tests/docker-compose.yml @@ -7,8 +7,6 @@ services: - 127.0.0.1:443:8443 environment: - PMM_DEBUG=1 - # for local development - # - PMM_DEV_ADVISOR_CHECKS_FILE=/srv/checks/custom-checks.yml volumes: - ./testdata/checks:/srv/checks diff --git a/api/advisors/v1/advisors.pb.go b/api/advisors/v1/advisors.pb.go index 28784d300f2..57341698316 100644 --- a/api/advisors/v1/advisors.pb.go +++ b/api/advisors/v1/advisors.pb.go @@ -567,6 +567,70 @@ func (x *CheckResult) GetSilenced() bool { return false } +// AdvisorCheckQuery is a single data-collection query of an advisor check. +type AdvisorCheckQuery struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `protobuf:"bytes,2,opt,name=query,proto3" json:"query,omitempty"` + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `protobuf:"bytes,3,rep,name=parameters,proto3" json:"parameters,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AdvisorCheckQuery) Reset() { + *x = AdvisorCheckQuery{} + mi := &file_advisors_v1_advisors_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AdvisorCheckQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdvisorCheckQuery) ProtoMessage() {} + +func (x *AdvisorCheckQuery) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdvisorCheckQuery.ProtoReflect.Descriptor instead. +func (*AdvisorCheckQuery) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{3} +} + +func (x *AdvisorCheckQuery) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *AdvisorCheckQuery) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *AdvisorCheckQuery) GetParameters() map[string]string { + if x != nil { + return x.Parameters + } + return nil +} + // AdvisorCheck contains check name and status. type AdvisorCheck struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -581,14 +645,24 @@ type AdvisorCheck struct { // Check execution interval. Interval AdvisorCheckInterval `protobuf:"varint,5,opt,name=interval,proto3,enum=advisors.v1.AdvisorCheckInterval" json:"interval,omitempty"` // DB family. - Family AdvisorCheckFamily `protobuf:"varint,6,opt,name=family,proto3,enum=advisors.v1.AdvisorCheckFamily" json:"family,omitempty"` + Family AdvisorCheckFamily `protobuf:"varint,6,opt,name=family,proto3,enum=advisors.v1.AdvisorCheckFamily" json:"family,omitempty"` + // Category (top-level grouping). + Category string `protobuf:"bytes,7,opt,name=category,proto3" json:"category,omitempty"` + // Subcategory (second-level grouping within a category). + Subcategory string `protobuf:"bytes,8,opt,name=subcategory,proto3" json:"subcategory,omitempty"` + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `protobuf:"varint,9,opt,name=user_defined,json=userDefined,proto3" json:"user_defined,omitempty"` + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*AdvisorCheckQuery `protobuf:"bytes,10,rep,name=queries,proto3" json:"queries,omitempty"` + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `protobuf:"bytes,11,opt,name=script,proto3" json:"script,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *AdvisorCheck) Reset() { *x = AdvisorCheck{} - mi := &file_advisors_v1_advisors_proto_msgTypes[3] + mi := &file_advisors_v1_advisors_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -600,7 +674,7 @@ func (x *AdvisorCheck) String() string { func (*AdvisorCheck) ProtoMessage() {} func (x *AdvisorCheck) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[3] + mi := &file_advisors_v1_advisors_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -613,7 +687,7 @@ func (x *AdvisorCheck) ProtoReflect() protoreflect.Message { // Deprecated: Use AdvisorCheck.ProtoReflect.Descriptor instead. func (*AdvisorCheck) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{3} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{4} } func (x *AdvisorCheck) GetName() string { @@ -658,6 +732,41 @@ func (x *AdvisorCheck) GetFamily() AdvisorCheckFamily { return AdvisorCheckFamily_ADVISOR_CHECK_FAMILY_UNSPECIFIED } +func (x *AdvisorCheck) GetCategory() string { + if x != nil { + return x.Category + } + return "" +} + +func (x *AdvisorCheck) GetSubcategory() string { + if x != nil { + return x.Subcategory + } + return "" +} + +func (x *AdvisorCheck) GetUserDefined() bool { + if x != nil { + return x.UserDefined + } + return false +} + +func (x *AdvisorCheck) GetQueries() []*AdvisorCheckQuery { + if x != nil { + return x.Queries + } + return nil +} + +func (x *AdvisorCheck) GetScript() string { + if x != nil { + return x.Script + } + return "" +} + type Advisor struct { state protoimpl.MessageState `protogen:"open.v1"` // Deprecated: no longer populated; an advisor is identified by its category/subcategory pair. @@ -688,7 +797,7 @@ type Advisor struct { func (x *Advisor) Reset() { *x = Advisor{} - mi := &file_advisors_v1_advisors_proto_msgTypes[4] + mi := &file_advisors_v1_advisors_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -700,7 +809,7 @@ func (x *Advisor) String() string { func (*Advisor) ProtoMessage() {} func (x *Advisor) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[4] + mi := &file_advisors_v1_advisors_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -713,7 +822,7 @@ func (x *Advisor) ProtoReflect() protoreflect.Message { // Deprecated: Use Advisor.ProtoReflect.Descriptor instead. func (*Advisor) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{4} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{5} } // Deprecated: Marked as deprecated in advisors/v1/advisors.proto. @@ -783,7 +892,7 @@ type ChangeAdvisorCheckParams struct { func (x *ChangeAdvisorCheckParams) Reset() { *x = ChangeAdvisorCheckParams{} - mi := &file_advisors_v1_advisors_proto_msgTypes[5] + mi := &file_advisors_v1_advisors_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -795,7 +904,7 @@ func (x *ChangeAdvisorCheckParams) String() string { func (*ChangeAdvisorCheckParams) ProtoMessage() {} func (x *ChangeAdvisorCheckParams) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[5] + mi := &file_advisors_v1_advisors_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -808,7 +917,7 @@ func (x *ChangeAdvisorCheckParams) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeAdvisorCheckParams.ProtoReflect.Descriptor instead. func (*ChangeAdvisorCheckParams) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{5} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{6} } func (x *ChangeAdvisorCheckParams) GetName() string { @@ -842,7 +951,7 @@ type StartAdvisorChecksRequest struct { func (x *StartAdvisorChecksRequest) Reset() { *x = StartAdvisorChecksRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[6] + mi := &file_advisors_v1_advisors_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -854,7 +963,7 @@ func (x *StartAdvisorChecksRequest) String() string { func (*StartAdvisorChecksRequest) ProtoMessage() {} func (x *StartAdvisorChecksRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[6] + mi := &file_advisors_v1_advisors_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -867,7 +976,7 @@ func (x *StartAdvisorChecksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartAdvisorChecksRequest.ProtoReflect.Descriptor instead. func (*StartAdvisorChecksRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{6} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{7} } func (x *StartAdvisorChecksRequest) GetNames() []string { @@ -887,7 +996,7 @@ type StartAdvisorChecksResponse struct { func (x *StartAdvisorChecksResponse) Reset() { *x = StartAdvisorChecksResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[7] + mi := &file_advisors_v1_advisors_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -899,7 +1008,7 @@ func (x *StartAdvisorChecksResponse) String() string { func (*StartAdvisorChecksResponse) ProtoMessage() {} func (x *StartAdvisorChecksResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[7] + mi := &file_advisors_v1_advisors_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -912,7 +1021,7 @@ func (x *StartAdvisorChecksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use StartAdvisorChecksResponse.ProtoReflect.Descriptor instead. func (*StartAdvisorChecksResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{7} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{8} } func (x *StartAdvisorChecksResponse) GetBatchId() string { @@ -930,7 +1039,7 @@ type ListAdvisorChecksRequest struct { func (x *ListAdvisorChecksRequest) Reset() { *x = ListAdvisorChecksRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[8] + mi := &file_advisors_v1_advisors_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -942,7 +1051,7 @@ func (x *ListAdvisorChecksRequest) String() string { func (*ListAdvisorChecksRequest) ProtoMessage() {} func (x *ListAdvisorChecksRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[8] + mi := &file_advisors_v1_advisors_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -955,7 +1064,7 @@ func (x *ListAdvisorChecksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAdvisorChecksRequest.ProtoReflect.Descriptor instead. func (*ListAdvisorChecksRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{8} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{9} } type ListAdvisorChecksResponse struct { @@ -967,7 +1076,7 @@ type ListAdvisorChecksResponse struct { func (x *ListAdvisorChecksResponse) Reset() { *x = ListAdvisorChecksResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[9] + mi := &file_advisors_v1_advisors_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -979,7 +1088,7 @@ func (x *ListAdvisorChecksResponse) String() string { func (*ListAdvisorChecksResponse) ProtoMessage() {} func (x *ListAdvisorChecksResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[9] + mi := &file_advisors_v1_advisors_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -992,7 +1101,7 @@ func (x *ListAdvisorChecksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAdvisorChecksResponse.ProtoReflect.Descriptor instead. func (*ListAdvisorChecksResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{9} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{10} } func (x *ListAdvisorChecksResponse) GetChecks() []*AdvisorCheck { @@ -1012,7 +1121,7 @@ type GetAdvisorCheckScriptRequest struct { func (x *GetAdvisorCheckScriptRequest) Reset() { *x = GetAdvisorCheckScriptRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[10] + mi := &file_advisors_v1_advisors_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1024,7 +1133,7 @@ func (x *GetAdvisorCheckScriptRequest) String() string { func (*GetAdvisorCheckScriptRequest) ProtoMessage() {} func (x *GetAdvisorCheckScriptRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[10] + mi := &file_advisors_v1_advisors_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1037,7 +1146,7 @@ func (x *GetAdvisorCheckScriptRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAdvisorCheckScriptRequest.ProtoReflect.Descriptor instead. func (*GetAdvisorCheckScriptRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{10} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{11} } func (x *GetAdvisorCheckScriptRequest) GetName() string { @@ -1057,7 +1166,7 @@ type GetAdvisorCheckScriptResponse struct { func (x *GetAdvisorCheckScriptResponse) Reset() { *x = GetAdvisorCheckScriptResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[11] + mi := &file_advisors_v1_advisors_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1069,7 +1178,7 @@ func (x *GetAdvisorCheckScriptResponse) String() string { func (*GetAdvisorCheckScriptResponse) ProtoMessage() {} func (x *GetAdvisorCheckScriptResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[11] + mi := &file_advisors_v1_advisors_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1082,7 +1191,7 @@ func (x *GetAdvisorCheckScriptResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAdvisorCheckScriptResponse.ProtoReflect.Descriptor instead. func (*GetAdvisorCheckScriptResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{11} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{12} } func (x *GetAdvisorCheckScriptResponse) GetScript() string { @@ -1092,6 +1201,363 @@ func (x *GetAdvisorCheckScriptResponse) GetScript() string { return "" } +type GetAdvisorCheckRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Machine-readable name (ID) of the check. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAdvisorCheckRequest) Reset() { + *x = GetAdvisorCheckRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAdvisorCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAdvisorCheckRequest) ProtoMessage() {} + +func (x *GetAdvisorCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAdvisorCheckRequest.ProtoReflect.Descriptor instead. +func (*GetAdvisorCheckRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{13} +} + +func (x *GetAdvisorCheckRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type GetAdvisorCheckResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Check *AdvisorCheck `protobuf:"bytes,1,opt,name=check,proto3" json:"check,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetAdvisorCheckResponse) Reset() { + *x = GetAdvisorCheckResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetAdvisorCheckResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAdvisorCheckResponse) ProtoMessage() {} + +func (x *GetAdvisorCheckResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAdvisorCheckResponse.ProtoReflect.Descriptor instead. +func (*GetAdvisorCheckResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{14} +} + +func (x *GetAdvisorCheckResponse) GetCheck() *AdvisorCheck { + if x != nil { + return x.Check + } + return nil +} + +type CreateAdvisorCheckRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The check to create. Its name must be unique across all checks. + Check *AdvisorCheck `protobuf:"bytes,1,opt,name=check,proto3" json:"check,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAdvisorCheckRequest) Reset() { + *x = CreateAdvisorCheckRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAdvisorCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAdvisorCheckRequest) ProtoMessage() {} + +func (x *CreateAdvisorCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAdvisorCheckRequest.ProtoReflect.Descriptor instead. +func (*CreateAdvisorCheckRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{15} +} + +func (x *CreateAdvisorCheckRequest) GetCheck() *AdvisorCheck { + if x != nil { + return x.Check + } + return nil +} + +type CreateAdvisorCheckResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Check *AdvisorCheck `protobuf:"bytes,1,opt,name=check,proto3" json:"check,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAdvisorCheckResponse) Reset() { + *x = CreateAdvisorCheckResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAdvisorCheckResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAdvisorCheckResponse) ProtoMessage() {} + +func (x *CreateAdvisorCheckResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAdvisorCheckResponse.ProtoReflect.Descriptor instead. +func (*CreateAdvisorCheckResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{16} +} + +func (x *CreateAdvisorCheckResponse) GetCheck() *AdvisorCheck { + if x != nil { + return x.Check + } + return nil +} + +type UpdateAdvisorCheckRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Machine-readable name (ID) of the check to update. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The updated check definition. + Check *AdvisorCheck `protobuf:"bytes,2,opt,name=check,proto3" json:"check,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateAdvisorCheckRequest) Reset() { + *x = UpdateAdvisorCheckRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateAdvisorCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAdvisorCheckRequest) ProtoMessage() {} + +func (x *UpdateAdvisorCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAdvisorCheckRequest.ProtoReflect.Descriptor instead. +func (*UpdateAdvisorCheckRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{17} +} + +func (x *UpdateAdvisorCheckRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UpdateAdvisorCheckRequest) GetCheck() *AdvisorCheck { + if x != nil { + return x.Check + } + return nil +} + +type UpdateAdvisorCheckResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Check *AdvisorCheck `protobuf:"bytes,1,opt,name=check,proto3" json:"check,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateAdvisorCheckResponse) Reset() { + *x = UpdateAdvisorCheckResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateAdvisorCheckResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAdvisorCheckResponse) ProtoMessage() {} + +func (x *UpdateAdvisorCheckResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAdvisorCheckResponse.ProtoReflect.Descriptor instead. +func (*UpdateAdvisorCheckResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{18} +} + +func (x *UpdateAdvisorCheckResponse) GetCheck() *AdvisorCheck { + if x != nil { + return x.Check + } + return nil +} + +type DeleteAdvisorCheckRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Machine-readable name (ID) of the check to delete. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteAdvisorCheckRequest) Reset() { + *x = DeleteAdvisorCheckRequest{} + mi := &file_advisors_v1_advisors_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteAdvisorCheckRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAdvisorCheckRequest) ProtoMessage() {} + +func (x *DeleteAdvisorCheckRequest) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAdvisorCheckRequest.ProtoReflect.Descriptor instead. +func (*DeleteAdvisorCheckRequest) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{19} +} + +func (x *DeleteAdvisorCheckRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type DeleteAdvisorCheckResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteAdvisorCheckResponse) Reset() { + *x = DeleteAdvisorCheckResponse{} + mi := &file_advisors_v1_advisors_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteAdvisorCheckResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAdvisorCheckResponse) ProtoMessage() {} + +func (x *DeleteAdvisorCheckResponse) ProtoReflect() protoreflect.Message { + mi := &file_advisors_v1_advisors_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAdvisorCheckResponse.ProtoReflect.Descriptor instead. +func (*DeleteAdvisorCheckResponse) Descriptor() ([]byte, []int) { + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{20} +} + type ListAdvisorsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -1100,7 +1566,7 @@ type ListAdvisorsRequest struct { func (x *ListAdvisorsRequest) Reset() { *x = ListAdvisorsRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[12] + mi := &file_advisors_v1_advisors_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1112,7 +1578,7 @@ func (x *ListAdvisorsRequest) String() string { func (*ListAdvisorsRequest) ProtoMessage() {} func (x *ListAdvisorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[12] + mi := &file_advisors_v1_advisors_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1125,7 +1591,7 @@ func (x *ListAdvisorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAdvisorsRequest.ProtoReflect.Descriptor instead. func (*ListAdvisorsRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{12} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{21} } type ListAdvisorsResponse struct { @@ -1137,7 +1603,7 @@ type ListAdvisorsResponse struct { func (x *ListAdvisorsResponse) Reset() { *x = ListAdvisorsResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[13] + mi := &file_advisors_v1_advisors_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1149,7 +1615,7 @@ func (x *ListAdvisorsResponse) String() string { func (*ListAdvisorsResponse) ProtoMessage() {} func (x *ListAdvisorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[13] + mi := &file_advisors_v1_advisors_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1162,7 +1628,7 @@ func (x *ListAdvisorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAdvisorsResponse.ProtoReflect.Descriptor instead. func (*ListAdvisorsResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{13} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{22} } func (x *ListAdvisorsResponse) GetAdvisors() []*Advisor { @@ -1181,7 +1647,7 @@ type ChangeAdvisorChecksRequest struct { func (x *ChangeAdvisorChecksRequest) Reset() { *x = ChangeAdvisorChecksRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[14] + mi := &file_advisors_v1_advisors_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1193,7 +1659,7 @@ func (x *ChangeAdvisorChecksRequest) String() string { func (*ChangeAdvisorChecksRequest) ProtoMessage() {} func (x *ChangeAdvisorChecksRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[14] + mi := &file_advisors_v1_advisors_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1206,7 +1672,7 @@ func (x *ChangeAdvisorChecksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeAdvisorChecksRequest.ProtoReflect.Descriptor instead. func (*ChangeAdvisorChecksRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{14} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{23} } func (x *ChangeAdvisorChecksRequest) GetParams() []*ChangeAdvisorCheckParams { @@ -1224,7 +1690,7 @@ type ChangeAdvisorChecksResponse struct { func (x *ChangeAdvisorChecksResponse) Reset() { *x = ChangeAdvisorChecksResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[15] + mi := &file_advisors_v1_advisors_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1236,7 +1702,7 @@ func (x *ChangeAdvisorChecksResponse) String() string { func (*ChangeAdvisorChecksResponse) ProtoMessage() {} func (x *ChangeAdvisorChecksResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[15] + mi := &file_advisors_v1_advisors_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1249,7 +1715,7 @@ func (x *ChangeAdvisorChecksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ChangeAdvisorChecksResponse.ProtoReflect.Descriptor instead. func (*ChangeAdvisorChecksResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{15} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{24} } type ListFailedServicesRequest struct { @@ -1260,7 +1726,7 @@ type ListFailedServicesRequest struct { func (x *ListFailedServicesRequest) Reset() { *x = ListFailedServicesRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[16] + mi := &file_advisors_v1_advisors_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1272,7 +1738,7 @@ func (x *ListFailedServicesRequest) String() string { func (*ListFailedServicesRequest) ProtoMessage() {} func (x *ListFailedServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[16] + mi := &file_advisors_v1_advisors_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1285,7 +1751,7 @@ func (x *ListFailedServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListFailedServicesRequest.ProtoReflect.Descriptor instead. func (*ListFailedServicesRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{16} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{25} } type ListFailedServicesResponse struct { @@ -1297,7 +1763,7 @@ type ListFailedServicesResponse struct { func (x *ListFailedServicesResponse) Reset() { *x = ListFailedServicesResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[17] + mi := &file_advisors_v1_advisors_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1309,7 +1775,7 @@ func (x *ListFailedServicesResponse) String() string { func (*ListFailedServicesResponse) ProtoMessage() {} func (x *ListFailedServicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[17] + mi := &file_advisors_v1_advisors_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1322,7 +1788,7 @@ func (x *ListFailedServicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListFailedServicesResponse.ProtoReflect.Descriptor instead. func (*ListFailedServicesResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{17} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{26} } func (x *ListFailedServicesResponse) GetResult() []*CheckResultSummary { @@ -1346,7 +1812,7 @@ type GetFailedChecksRequest struct { func (x *GetFailedChecksRequest) Reset() { *x = GetFailedChecksRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[18] + mi := &file_advisors_v1_advisors_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1358,7 +1824,7 @@ func (x *GetFailedChecksRequest) String() string { func (*GetFailedChecksRequest) ProtoMessage() {} func (x *GetFailedChecksRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[18] + mi := &file_advisors_v1_advisors_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1371,7 +1837,7 @@ func (x *GetFailedChecksRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFailedChecksRequest.ProtoReflect.Descriptor instead. func (*GetFailedChecksRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{18} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{27} } func (x *GetFailedChecksRequest) GetPageSize() int32 { @@ -1409,7 +1875,7 @@ type GetFailedChecksResponse struct { func (x *GetFailedChecksResponse) Reset() { *x = GetFailedChecksResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[19] + mi := &file_advisors_v1_advisors_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1421,7 +1887,7 @@ func (x *GetFailedChecksResponse) String() string { func (*GetFailedChecksResponse) ProtoMessage() {} func (x *GetFailedChecksResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[19] + mi := &file_advisors_v1_advisors_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1434,7 +1900,7 @@ func (x *GetFailedChecksResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetFailedChecksResponse.ProtoReflect.Descriptor instead. func (*GetFailedChecksResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{19} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{28} } func (x *GetFailedChecksResponse) GetTotalItems() int32 { @@ -1515,7 +1981,7 @@ type CheckResultHistoryItem struct { func (x *CheckResultHistoryItem) Reset() { *x = CheckResultHistoryItem{} - mi := &file_advisors_v1_advisors_proto_msgTypes[20] + mi := &file_advisors_v1_advisors_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1527,7 +1993,7 @@ func (x *CheckResultHistoryItem) String() string { func (*CheckResultHistoryItem) ProtoMessage() {} func (x *CheckResultHistoryItem) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[20] + mi := &file_advisors_v1_advisors_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1540,7 +2006,7 @@ func (x *CheckResultHistoryItem) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckResultHistoryItem.ProtoReflect.Descriptor instead. func (*CheckResultHistoryItem) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{20} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{29} } func (x *CheckResultHistoryItem) GetId() string { @@ -1747,7 +2213,7 @@ type ListCheckResultsHistoryRequest struct { func (x *ListCheckResultsHistoryRequest) Reset() { *x = ListCheckResultsHistoryRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[21] + mi := &file_advisors_v1_advisors_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1759,7 +2225,7 @@ func (x *ListCheckResultsHistoryRequest) String() string { func (*ListCheckResultsHistoryRequest) ProtoMessage() {} func (x *ListCheckResultsHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[21] + mi := &file_advisors_v1_advisors_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1772,7 +2238,7 @@ func (x *ListCheckResultsHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListCheckResultsHistoryRequest.ProtoReflect.Descriptor instead. func (*ListCheckResultsHistoryRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{21} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{30} } func (x *ListCheckResultsHistoryRequest) GetPageSize() int32 { @@ -1887,7 +2353,7 @@ type ListCheckResultsHistoryResponse struct { func (x *ListCheckResultsHistoryResponse) Reset() { *x = ListCheckResultsHistoryResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[22] + mi := &file_advisors_v1_advisors_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1899,7 +2365,7 @@ func (x *ListCheckResultsHistoryResponse) String() string { func (*ListCheckResultsHistoryResponse) ProtoMessage() {} func (x *ListCheckResultsHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[22] + mi := &file_advisors_v1_advisors_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1912,7 +2378,7 @@ func (x *ListCheckResultsHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListCheckResultsHistoryResponse.ProtoReflect.Descriptor instead. func (*ListCheckResultsHistoryResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{22} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{31} } func (x *ListCheckResultsHistoryResponse) GetTotalItems() int32 { @@ -1944,7 +2410,7 @@ type ListCheckResultsFilterValuesRequest struct { func (x *ListCheckResultsFilterValuesRequest) Reset() { *x = ListCheckResultsFilterValuesRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[23] + mi := &file_advisors_v1_advisors_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1956,7 +2422,7 @@ func (x *ListCheckResultsFilterValuesRequest) String() string { func (*ListCheckResultsFilterValuesRequest) ProtoMessage() {} func (x *ListCheckResultsFilterValuesRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[23] + mi := &file_advisors_v1_advisors_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1969,7 +2435,7 @@ func (x *ListCheckResultsFilterValuesRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use ListCheckResultsFilterValuesRequest.ProtoReflect.Descriptor instead. func (*ListCheckResultsFilterValuesRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{23} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{32} } type ListCheckResultsFilterValuesResponse struct { @@ -1984,7 +2450,7 @@ type ListCheckResultsFilterValuesResponse struct { func (x *ListCheckResultsFilterValuesResponse) Reset() { *x = ListCheckResultsFilterValuesResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[24] + mi := &file_advisors_v1_advisors_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1996,7 +2462,7 @@ func (x *ListCheckResultsFilterValuesResponse) String() string { func (*ListCheckResultsFilterValuesResponse) ProtoMessage() {} func (x *ListCheckResultsFilterValuesResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[24] + mi := &file_advisors_v1_advisors_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2009,7 +2475,7 @@ func (x *ListCheckResultsFilterValuesResponse) ProtoReflect() protoreflect.Messa // Deprecated: Use ListCheckResultsFilterValuesResponse.ProtoReflect.Descriptor instead. func (*ListCheckResultsFilterValuesResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{24} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{33} } func (x *ListCheckResultsFilterValuesResponse) GetServiceNames() []string { @@ -2038,7 +2504,7 @@ type MarkCheckResultsReadRequest struct { func (x *MarkCheckResultsReadRequest) Reset() { *x = MarkCheckResultsReadRequest{} - mi := &file_advisors_v1_advisors_proto_msgTypes[25] + mi := &file_advisors_v1_advisors_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2050,7 +2516,7 @@ func (x *MarkCheckResultsReadRequest) String() string { func (*MarkCheckResultsReadRequest) ProtoMessage() {} func (x *MarkCheckResultsReadRequest) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[25] + mi := &file_advisors_v1_advisors_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2063,7 +2529,7 @@ func (x *MarkCheckResultsReadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkCheckResultsReadRequest.ProtoReflect.Descriptor instead. func (*MarkCheckResultsReadRequest) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{25} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{34} } func (x *MarkCheckResultsReadRequest) GetIds() []string { @@ -2088,7 +2554,7 @@ type MarkCheckResultsReadResponse struct { func (x *MarkCheckResultsReadResponse) Reset() { *x = MarkCheckResultsReadResponse{} - mi := &file_advisors_v1_advisors_proto_msgTypes[26] + mi := &file_advisors_v1_advisors_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2100,7 +2566,7 @@ func (x *MarkCheckResultsReadResponse) String() string { func (*MarkCheckResultsReadResponse) ProtoMessage() {} func (x *MarkCheckResultsReadResponse) ProtoReflect() protoreflect.Message { - mi := &file_advisors_v1_advisors_proto_msgTypes[26] + mi := &file_advisors_v1_advisors_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2113,7 +2579,7 @@ func (x *MarkCheckResultsReadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MarkCheckResultsReadResponse.ProtoReflect.Descriptor instead. func (*MarkCheckResultsReadResponse) Descriptor() ([]byte, []int) { - return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{26} + return file_advisors_v1_advisors_proto_rawDescGZIP(), []int{35} } var File_advisors_v1_advisors_proto protoreflect.FileDescriptor @@ -2163,14 +2629,29 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + " \x01(\bR\bsilenced\x1a9\n" + "\vLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xf0\x01\n" + - "\fAdvisorCheck\x12\x12\n" + - "\x04name\x18\x01 \x01(\tR\x04name\x12\x18\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xcc\x01\n" + + "\x11AdvisorCheckQuery\x12\x12\n" + + "\x04type\x18\x01 \x01(\tR\x04type\x12\x14\n" + + "\x05query\x18\x02 \x01(\tR\x05query\x12N\n" + + "\n" + + "parameters\x18\x03 \x03(\v2..advisors.v1.AdvisorCheckQuery.ParametersEntryR\n" + + "parameters\x1a=\n" + + "\x0fParametersEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc7\x03\n" + + "\fAdvisorCheck\x126\n" + + "\x04name\x18\x01 \x01(\tB\"\xfaB\x1fr\x1d\x18\x80\x012\x18^[a-zA-Z_][a-zA-Z0-9_]*$R\x04name\x12\x18\n" + "\aenabled\x18\x02 \x01(\bR\aenabled\x12 \n" + "\vdescription\x18\x03 \x01(\tR\vdescription\x12\x18\n" + "\asummary\x18\x04 \x01(\tR\asummary\x12=\n" + "\binterval\x18\x05 \x01(\x0e2!.advisors.v1.AdvisorCheckIntervalR\binterval\x127\n" + - "\x06family\x18\x06 \x01(\x0e2\x1f.advisors.v1.AdvisorCheckFamilyR\x06family\"\xf4\x01\n" + + "\x06family\x18\x06 \x01(\x0e2\x1f.advisors.v1.AdvisorCheckFamilyR\x06family\x12\x1a\n" + + "\bcategory\x18\a \x01(\tR\bcategory\x12 \n" + + "\vsubcategory\x18\b \x01(\tR\vsubcategory\x12!\n" + + "\fuser_defined\x18\t \x01(\bR\vuserDefined\x128\n" + + "\aqueries\x18\n" + + " \x03(\v2\x1e.advisors.v1.AdvisorCheckQueryR\aqueries\x12\x16\n" + + "\x06script\x18\v \x01(\tR\x06script\"\xf4\x01\n" + "\aAdvisor\x12\x16\n" + "\x04name\x18\x01 \x01(\tB\x02\x18\x01R\x04name\x12$\n" + "\vdescription\x18\x02 \x01(\tB\x02\x18\x01R\vdescription\x12\x1c\n" + @@ -2194,7 +2675,23 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\x1cGetAdvisorCheckScriptRequest\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\"7\n" + "\x1dGetAdvisorCheckScriptResponse\x12\x16\n" + - "\x06script\x18\x01 \x01(\tR\x06script\"\x15\n" + + "\x06script\x18\x01 \x01(\tR\x06script\",\n" + + "\x16GetAdvisorCheckRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"J\n" + + "\x17GetAdvisorCheckResponse\x12/\n" + + "\x05check\x18\x01 \x01(\v2\x19.advisors.v1.AdvisorCheckR\x05check\"L\n" + + "\x19CreateAdvisorCheckRequest\x12/\n" + + "\x05check\x18\x01 \x01(\v2\x19.advisors.v1.AdvisorCheckR\x05check\"M\n" + + "\x1aCreateAdvisorCheckResponse\x12/\n" + + "\x05check\x18\x01 \x01(\v2\x19.advisors.v1.AdvisorCheckR\x05check\"`\n" + + "\x19UpdateAdvisorCheckRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12/\n" + + "\x05check\x18\x02 \x01(\v2\x19.advisors.v1.AdvisorCheckR\x05check\"M\n" + + "\x1aUpdateAdvisorCheckResponse\x12/\n" + + "\x05check\x18\x01 \x01(\v2\x19.advisors.v1.AdvisorCheckR\x05check\"/\n" + + "\x19DeleteAdvisorCheckRequest\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"\x1c\n" + + "\x1aDeleteAdvisorCheckResponse\"\x15\n" + "\x13ListAdvisorsRequest\"H\n" + "\x14ListAdvisorsResponse\x120\n" + "\badvisors\x18\x01 \x03(\v2\x14.advisors.v1.AdvisorR\badvisors\"[\n" + @@ -2311,7 +2808,7 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\x17AdvisorCheckTriggeredBy\x12*\n" + "&ADVISOR_CHECK_TRIGGERED_BY_UNSPECIFIED\x10\x00\x12#\n" + "\x1fADVISOR_CHECK_TRIGGERED_BY_USER\x10\x01\x12(\n" + - "$ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER\x10\x022\x87\x14\n" + + "$ADVISOR_CHECK_TRIGGERED_BY_SCHEDULER\x10\x022\xc2\x1b\n" + "\x0eAdvisorService\x12\xf3\x01\n" + "\x12ListFailedServices\x12&.advisors.v1.ListFailedServicesRequest\x1a'.advisors.v1.ListFailedServicesResponse\"\x8b\x01\x92Ae\x12\x14List Failed Services\x1aMReturns a list of services with failed checks and a summary of check results.\x82\xd3\xe4\x93\x02\x1d\x12\x1b/v1/advisors/failedServices\x12\xd5\x01\n" + "\x0fGetFailedChecks\x12#.advisors.v1.GetFailedChecksRequest\x1a$.advisors.v1.GetFailedChecksResponse\"w\x92AR\x12\x19Get Failed Advisor Checks\x1a5Returns the latest check results for a given service.\x82\xd3\xe4\x93\x02\x1c\x12\x1a/v1/advisors/checks/failed\x12\x87\x02\n" + @@ -2322,7 +2819,11 @@ const file_advisors_v1_advisors_proto_rawDesc = "" + "\x11ListAdvisorChecks\x12%.advisors.v1.ListAdvisorChecksRequest\x1a&.advisors.v1.ListAdvisorChecksResponse\"_\x92AA\x12\x13List Advisor Checks\x1a*List advisor checks available to the user.\x82\xd3\xe4\x93\x02\x15\x12\x13/v1/advisors/checks\x12\xf5\x01\n" + "\x15GetAdvisorCheckScript\x12).advisors.v1.GetAdvisorCheckScriptRequest\x1a*.advisors.v1.GetAdvisorCheckScriptResponse\"\x84\x01\x92AX\x12\x18Get Advisor Check Script\x1a management.v1.Severity - 31, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry - 34, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity - 32, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry - 0, // 4: advisors.v1.AdvisorCheck.interval:type_name -> advisors.v1.AdvisorCheckInterval - 1, // 5: advisors.v1.AdvisorCheck.family:type_name -> advisors.v1.AdvisorCheckFamily - 7, // 6: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck - 0, // 7: advisors.v1.ChangeAdvisorCheckParams.interval:type_name -> advisors.v1.AdvisorCheckInterval - 7, // 8: advisors.v1.ListAdvisorChecksResponse.checks:type_name -> advisors.v1.AdvisorCheck - 8, // 9: advisors.v1.ListAdvisorsResponse.advisors:type_name -> advisors.v1.Advisor - 9, // 10: advisors.v1.ChangeAdvisorChecksRequest.params:type_name -> advisors.v1.ChangeAdvisorCheckParams - 5, // 11: advisors.v1.ListFailedServicesResponse.result:type_name -> advisors.v1.CheckResultSummary - 6, // 12: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult - 0, // 13: advisors.v1.CheckResultHistoryItem.interval:type_name -> advisors.v1.AdvisorCheckInterval - 2, // 14: advisors.v1.CheckResultHistoryItem.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 34, // 15: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity - 33, // 16: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry - 35, // 17: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp - 3, // 18: advisors.v1.CheckResultHistoryItem.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy - 2, // 19: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus - 35, // 20: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp - 35, // 21: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp - 34, // 22: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity - 3, // 23: advisors.v1.ListCheckResultsHistoryRequest.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy - 24, // 24: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem - 20, // 25: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest - 22, // 26: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest - 25, // 27: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest - 27, // 28: advisors.v1.AdvisorService.ListCheckResultsFilterValues:input_type -> advisors.v1.ListCheckResultsFilterValuesRequest - 29, // 29: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest - 10, // 30: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest - 12, // 31: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest - 14, // 32: advisors.v1.AdvisorService.GetAdvisorCheckScript:input_type -> advisors.v1.GetAdvisorCheckScriptRequest - 16, // 33: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest - 18, // 34: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest - 21, // 35: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse - 23, // 36: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse - 26, // 37: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse - 28, // 38: advisors.v1.AdvisorService.ListCheckResultsFilterValues:output_type -> advisors.v1.ListCheckResultsFilterValuesResponse - 30, // 39: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse - 11, // 40: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse - 13, // 41: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse - 15, // 42: advisors.v1.AdvisorService.GetAdvisorCheckScript:output_type -> advisors.v1.GetAdvisorCheckScriptResponse - 17, // 43: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse - 19, // 44: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse - 35, // [35:45] is the sub-list for method output_type - 25, // [25:35] is the sub-list for method input_type - 25, // [25:25] is the sub-list for extension type_name - 25, // [25:25] is the sub-list for extension extendee - 0, // [0:25] is the sub-list for field type_name + 44, // 0: advisors.v1.AdvisorCheckResult.severity:type_name -> management.v1.Severity + 40, // 1: advisors.v1.AdvisorCheckResult.labels:type_name -> advisors.v1.AdvisorCheckResult.LabelsEntry + 44, // 2: advisors.v1.CheckResult.severity:type_name -> management.v1.Severity + 41, // 3: advisors.v1.CheckResult.labels:type_name -> advisors.v1.CheckResult.LabelsEntry + 42, // 4: advisors.v1.AdvisorCheckQuery.parameters:type_name -> advisors.v1.AdvisorCheckQuery.ParametersEntry + 0, // 5: advisors.v1.AdvisorCheck.interval:type_name -> advisors.v1.AdvisorCheckInterval + 1, // 6: advisors.v1.AdvisorCheck.family:type_name -> advisors.v1.AdvisorCheckFamily + 7, // 7: advisors.v1.AdvisorCheck.queries:type_name -> advisors.v1.AdvisorCheckQuery + 8, // 8: advisors.v1.Advisor.checks:type_name -> advisors.v1.AdvisorCheck + 0, // 9: advisors.v1.ChangeAdvisorCheckParams.interval:type_name -> advisors.v1.AdvisorCheckInterval + 8, // 10: advisors.v1.ListAdvisorChecksResponse.checks:type_name -> advisors.v1.AdvisorCheck + 8, // 11: advisors.v1.GetAdvisorCheckResponse.check:type_name -> advisors.v1.AdvisorCheck + 8, // 12: advisors.v1.CreateAdvisorCheckRequest.check:type_name -> advisors.v1.AdvisorCheck + 8, // 13: advisors.v1.CreateAdvisorCheckResponse.check:type_name -> advisors.v1.AdvisorCheck + 8, // 14: advisors.v1.UpdateAdvisorCheckRequest.check:type_name -> advisors.v1.AdvisorCheck + 8, // 15: advisors.v1.UpdateAdvisorCheckResponse.check:type_name -> advisors.v1.AdvisorCheck + 9, // 16: advisors.v1.ListAdvisorsResponse.advisors:type_name -> advisors.v1.Advisor + 10, // 17: advisors.v1.ChangeAdvisorChecksRequest.params:type_name -> advisors.v1.ChangeAdvisorCheckParams + 5, // 18: advisors.v1.ListFailedServicesResponse.result:type_name -> advisors.v1.CheckResultSummary + 6, // 19: advisors.v1.GetFailedChecksResponse.results:type_name -> advisors.v1.CheckResult + 0, // 20: advisors.v1.CheckResultHistoryItem.interval:type_name -> advisors.v1.AdvisorCheckInterval + 2, // 21: advisors.v1.CheckResultHistoryItem.status:type_name -> advisors.v1.AdvisorCheckResultStatus + 44, // 22: advisors.v1.CheckResultHistoryItem.severity:type_name -> management.v1.Severity + 43, // 23: advisors.v1.CheckResultHistoryItem.labels:type_name -> advisors.v1.CheckResultHistoryItem.LabelsEntry + 45, // 24: advisors.v1.CheckResultHistoryItem.checked_at:type_name -> google.protobuf.Timestamp + 3, // 25: advisors.v1.CheckResultHistoryItem.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy + 2, // 26: advisors.v1.ListCheckResultsHistoryRequest.status:type_name -> advisors.v1.AdvisorCheckResultStatus + 45, // 27: advisors.v1.ListCheckResultsHistoryRequest.from:type_name -> google.protobuf.Timestamp + 45, // 28: advisors.v1.ListCheckResultsHistoryRequest.to:type_name -> google.protobuf.Timestamp + 44, // 29: advisors.v1.ListCheckResultsHistoryRequest.severity:type_name -> management.v1.Severity + 3, // 30: advisors.v1.ListCheckResultsHistoryRequest.triggered_by:type_name -> advisors.v1.AdvisorCheckTriggeredBy + 33, // 31: advisors.v1.ListCheckResultsHistoryResponse.results:type_name -> advisors.v1.CheckResultHistoryItem + 29, // 32: advisors.v1.AdvisorService.ListFailedServices:input_type -> advisors.v1.ListFailedServicesRequest + 31, // 33: advisors.v1.AdvisorService.GetFailedChecks:input_type -> advisors.v1.GetFailedChecksRequest + 34, // 34: advisors.v1.AdvisorService.ListCheckResultsHistory:input_type -> advisors.v1.ListCheckResultsHistoryRequest + 36, // 35: advisors.v1.AdvisorService.ListCheckResultsFilterValues:input_type -> advisors.v1.ListCheckResultsFilterValuesRequest + 38, // 36: advisors.v1.AdvisorService.MarkCheckResultsRead:input_type -> advisors.v1.MarkCheckResultsReadRequest + 11, // 37: advisors.v1.AdvisorService.StartAdvisorChecks:input_type -> advisors.v1.StartAdvisorChecksRequest + 13, // 38: advisors.v1.AdvisorService.ListAdvisorChecks:input_type -> advisors.v1.ListAdvisorChecksRequest + 15, // 39: advisors.v1.AdvisorService.GetAdvisorCheckScript:input_type -> advisors.v1.GetAdvisorCheckScriptRequest + 25, // 40: advisors.v1.AdvisorService.ListAdvisors:input_type -> advisors.v1.ListAdvisorsRequest + 27, // 41: advisors.v1.AdvisorService.ChangeAdvisorChecks:input_type -> advisors.v1.ChangeAdvisorChecksRequest + 17, // 42: advisors.v1.AdvisorService.GetAdvisorCheck:input_type -> advisors.v1.GetAdvisorCheckRequest + 19, // 43: advisors.v1.AdvisorService.CreateAdvisorCheck:input_type -> advisors.v1.CreateAdvisorCheckRequest + 21, // 44: advisors.v1.AdvisorService.UpdateAdvisorCheck:input_type -> advisors.v1.UpdateAdvisorCheckRequest + 23, // 45: advisors.v1.AdvisorService.DeleteAdvisorCheck:input_type -> advisors.v1.DeleteAdvisorCheckRequest + 30, // 46: advisors.v1.AdvisorService.ListFailedServices:output_type -> advisors.v1.ListFailedServicesResponse + 32, // 47: advisors.v1.AdvisorService.GetFailedChecks:output_type -> advisors.v1.GetFailedChecksResponse + 35, // 48: advisors.v1.AdvisorService.ListCheckResultsHistory:output_type -> advisors.v1.ListCheckResultsHistoryResponse + 37, // 49: advisors.v1.AdvisorService.ListCheckResultsFilterValues:output_type -> advisors.v1.ListCheckResultsFilterValuesResponse + 39, // 50: advisors.v1.AdvisorService.MarkCheckResultsRead:output_type -> advisors.v1.MarkCheckResultsReadResponse + 12, // 51: advisors.v1.AdvisorService.StartAdvisorChecks:output_type -> advisors.v1.StartAdvisorChecksResponse + 14, // 52: advisors.v1.AdvisorService.ListAdvisorChecks:output_type -> advisors.v1.ListAdvisorChecksResponse + 16, // 53: advisors.v1.AdvisorService.GetAdvisorCheckScript:output_type -> advisors.v1.GetAdvisorCheckScriptResponse + 26, // 54: advisors.v1.AdvisorService.ListAdvisors:output_type -> advisors.v1.ListAdvisorsResponse + 28, // 55: advisors.v1.AdvisorService.ChangeAdvisorChecks:output_type -> advisors.v1.ChangeAdvisorChecksResponse + 18, // 56: advisors.v1.AdvisorService.GetAdvisorCheck:output_type -> advisors.v1.GetAdvisorCheckResponse + 20, // 57: advisors.v1.AdvisorService.CreateAdvisorCheck:output_type -> advisors.v1.CreateAdvisorCheckResponse + 22, // 58: advisors.v1.AdvisorService.UpdateAdvisorCheck:output_type -> advisors.v1.UpdateAdvisorCheckResponse + 24, // 59: advisors.v1.AdvisorService.DeleteAdvisorCheck:output_type -> advisors.v1.DeleteAdvisorCheckResponse + 46, // [46:60] is the sub-list for method output_type + 32, // [32:46] is the sub-list for method input_type + 32, // [32:32] is the sub-list for extension type_name + 32, // [32:32] is the sub-list for extension extendee + 0, // [0:32] is the sub-list for field type_name } func init() { file_advisors_v1_advisors_proto_init() } @@ -2438,16 +2964,16 @@ func file_advisors_v1_advisors_proto_init() { if File_advisors_v1_advisors_proto != nil { return } - file_advisors_v1_advisors_proto_msgTypes[5].OneofWrappers = []any{} - file_advisors_v1_advisors_proto_msgTypes[18].OneofWrappers = []any{} - file_advisors_v1_advisors_proto_msgTypes[21].OneofWrappers = []any{} + file_advisors_v1_advisors_proto_msgTypes[6].OneofWrappers = []any{} + file_advisors_v1_advisors_proto_msgTypes[27].OneofWrappers = []any{} + file_advisors_v1_advisors_proto_msgTypes[30].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_advisors_v1_advisors_proto_rawDesc), len(file_advisors_v1_advisors_proto_rawDesc)), NumEnums: 4, - NumMessages: 30, + NumMessages: 40, NumExtensions: 0, NumServices: 1, }, diff --git a/api/advisors/v1/advisors.pb.gw.go b/api/advisors/v1/advisors.pb.gw.go index 464e0fab1b0..559f07a13eb 100644 --- a/api/advisors/v1/advisors.pb.gw.go +++ b/api/advisors/v1/advisors.pb.gw.go @@ -309,6 +309,156 @@ func local_request_AdvisorService_ChangeAdvisorChecks_0(ctx context.Context, mar return msg, metadata, err } +func request_AdvisorService_GetAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetAdvisorCheckRequest + metadata runtime.ServerMetadata + err error + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := client.GetAdvisorCheck(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_GetAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq GetAdvisorCheckRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := server.GetAdvisorCheck(ctx, &protoReq) + return msg, metadata, err +} + +func request_AdvisorService_CreateAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq CreateAdvisorCheckRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + msg, err := client.CreateAdvisorCheck(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_CreateAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq CreateAdvisorCheckRequest + metadata runtime.ServerMetadata + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.CreateAdvisorCheck(ctx, &protoReq) + return msg, metadata, err +} + +func request_AdvisorService_UpdateAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UpdateAdvisorCheckRequest + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := client.UpdateAdvisorCheck(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_UpdateAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq UpdateAdvisorCheckRequest + metadata runtime.ServerMetadata + err error + ) + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := server.UpdateAdvisorCheck(ctx, &protoReq) + return msg, metadata, err +} + +func request_AdvisorService_DeleteAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, client AdvisorServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteAdvisorCheckRequest + metadata runtime.ServerMetadata + err error + ) + if req.Body != nil { + _, _ = io.Copy(io.Discard, req.Body) + } + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := client.DeleteAdvisorCheck(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err +} + +func local_request_AdvisorService_DeleteAdvisorCheck_0(ctx context.Context, marshaler runtime.Marshaler, server AdvisorServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var ( + protoReq DeleteAdvisorCheckRequest + metadata runtime.ServerMetadata + err error + ) + val, ok := pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + protoReq.Name, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + msg, err := server.DeleteAdvisorCheck(ctx, &protoReq) + return msg, metadata, err +} + // RegisterAdvisorServiceHandlerServer registers the http handlers for service AdvisorService to "mux". // UnaryRPC :call AdvisorServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -515,6 +665,86 @@ func RegisterAdvisorServiceHandlerServer(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ChangeAdvisorChecks_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_GetAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/GetAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}/definition")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_GetAdvisorCheck_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_GetAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_AdvisorService_CreateAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/CreateAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_CreateAdvisorCheck_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_CreateAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPut, pattern_AdvisorService_UpdateAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/UpdateAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_UpdateAdvisorCheck_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_UpdateAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_AdvisorService_DeleteAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/advisors.v1.AdvisorService/DeleteAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AdvisorService_DeleteAdvisorCheck_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_DeleteAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) return nil } @@ -725,6 +955,74 @@ func RegisterAdvisorServiceHandlerClient(ctx context.Context, mux *runtime.Serve } forward_AdvisorService_ChangeAdvisorChecks_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) + mux.Handle(http.MethodGet, pattern_AdvisorService_GetAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/GetAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}/definition")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_GetAdvisorCheck_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_GetAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPost, pattern_AdvisorService_CreateAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/CreateAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_CreateAdvisorCheck_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_CreateAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodPut, pattern_AdvisorService_UpdateAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/UpdateAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_UpdateAdvisorCheck_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_UpdateAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) + mux.Handle(http.MethodDelete, pattern_AdvisorService_DeleteAdvisorCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/advisors.v1.AdvisorService/DeleteAdvisorCheck", runtime.WithHTTPPathPattern("/v1/advisors/checks/{name}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AdvisorService_DeleteAdvisorCheck_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + forward_AdvisorService_DeleteAdvisorCheck_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + }) return nil } @@ -739,6 +1037,10 @@ var ( pattern_AdvisorService_GetAdvisorCheckScript_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"v1", "advisors", "checks", "name", "script"}, "")) pattern_AdvisorService_ListAdvisors_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "advisors"}, "")) pattern_AdvisorService_ChangeAdvisorChecks_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "batchChange")) + pattern_AdvisorService_GetAdvisorCheck_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"v1", "advisors", "checks", "name", "definition"}, "")) + pattern_AdvisorService_CreateAdvisorCheck_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "advisors", "checks"}, "")) + pattern_AdvisorService_UpdateAdvisorCheck_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "advisors", "checks", "name"}, "")) + pattern_AdvisorService_DeleteAdvisorCheck_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "advisors", "checks", "name"}, "")) ) var ( @@ -752,4 +1054,8 @@ var ( forward_AdvisorService_GetAdvisorCheckScript_0 = runtime.ForwardResponseMessage forward_AdvisorService_ListAdvisors_0 = runtime.ForwardResponseMessage forward_AdvisorService_ChangeAdvisorChecks_0 = runtime.ForwardResponseMessage + forward_AdvisorService_GetAdvisorCheck_0 = runtime.ForwardResponseMessage + forward_AdvisorService_CreateAdvisorCheck_0 = runtime.ForwardResponseMessage + forward_AdvisorService_UpdateAdvisorCheck_0 = runtime.ForwardResponseMessage + forward_AdvisorService_DeleteAdvisorCheck_0 = runtime.ForwardResponseMessage ) diff --git a/api/advisors/v1/advisors.pb.validate.go b/api/advisors/v1/advisors.pb.validate.go index ad38d7e448a..82dbc48fb28 100644 --- a/api/advisors/v1/advisors.pb.validate.go +++ b/api/advisors/v1/advisors.pb.validate.go @@ -395,6 +395,115 @@ var _ interface { ErrorName() string } = CheckResultValidationError{} +// Validate checks the field values on AdvisorCheckQuery with the rules defined +// in the proto definition for this message. If any rules are violated, the +// first error encountered is returned, or nil if there are no violations. +func (m *AdvisorCheckQuery) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on AdvisorCheckQuery with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// AdvisorCheckQueryMultiError, or nil if none found. +func (m *AdvisorCheckQuery) ValidateAll() error { + return m.validate(true) +} + +func (m *AdvisorCheckQuery) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Type + + // no validation rules for Query + + // no validation rules for Parameters + + if len(errors) > 0 { + return AdvisorCheckQueryMultiError(errors) + } + + return nil +} + +// AdvisorCheckQueryMultiError is an error wrapping multiple validation errors +// returned by AdvisorCheckQuery.ValidateAll() if the designated constraints +// aren't met. +type AdvisorCheckQueryMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m AdvisorCheckQueryMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m AdvisorCheckQueryMultiError) AllErrors() []error { return m } + +// AdvisorCheckQueryValidationError is the validation error returned by +// AdvisorCheckQuery.Validate if the designated constraints aren't met. +type AdvisorCheckQueryValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e AdvisorCheckQueryValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e AdvisorCheckQueryValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e AdvisorCheckQueryValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e AdvisorCheckQueryValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e AdvisorCheckQueryValidationError) ErrorName() string { + return "AdvisorCheckQueryValidationError" +} + +// Error satisfies the builtin error interface +func (e AdvisorCheckQueryValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sAdvisorCheckQuery.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = AdvisorCheckQueryValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = AdvisorCheckQueryValidationError{} + // Validate checks the field values on AdvisorCheck with the rules defined in // the proto definition for this message. If any rules are violated, the first // error encountered is returned, or nil if there are no violations. @@ -417,7 +526,27 @@ func (m *AdvisorCheck) validate(all bool) error { var errors []error - // no validation rules for Name + if utf8.RuneCountInString(m.GetName()) > 128 { + err := AdvisorCheckValidationError{ + field: "Name", + reason: "value length must be at most 128 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if !_AdvisorCheck_Name_Pattern.MatchString(m.GetName()) { + err := AdvisorCheckValidationError{ + field: "Name", + reason: "value does not match regex pattern \"^[a-zA-Z_][a-zA-Z0-9_]*$\"", + } + if !all { + return err + } + errors = append(errors, err) + } // no validation rules for Enabled @@ -429,6 +558,48 @@ func (m *AdvisorCheck) validate(all bool) error { // no validation rules for Family + // no validation rules for Category + + // no validation rules for Subcategory + + // no validation rules for UserDefined + + for idx, item := range m.GetQueries() { + _, _ = idx, item + + if all { + switch v := interface{}(item).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, AdvisorCheckValidationError{ + field: fmt.Sprintf("Queries[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, AdvisorCheckValidationError{ + field: fmt.Sprintf("Queries[%v]", idx), + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(item).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return AdvisorCheckValidationError{ + field: fmt.Sprintf("Queries[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + // no validation rules for Script + if len(errors) > 0 { return AdvisorCheckMultiError(errors) } @@ -507,6 +678,8 @@ var _ interface { ErrorName() string } = AdvisorCheckValidationError{} +var _AdvisorCheck_Name_Pattern = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") + // Validate checks the field values on Advisor with the rules defined in the // proto definition for this message. If any rules are violated, the first // error encountered is returned, or nil if there are no violations. @@ -1423,6 +1596,981 @@ var _ interface { ErrorName() string } = GetAdvisorCheckScriptResponseValidationError{} +// Validate checks the field values on GetAdvisorCheckRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetAdvisorCheckRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetAdvisorCheckRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetAdvisorCheckRequestMultiError, or nil if none found. +func (m *GetAdvisorCheckRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *GetAdvisorCheckRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Name + + if len(errors) > 0 { + return GetAdvisorCheckRequestMultiError(errors) + } + + return nil +} + +// GetAdvisorCheckRequestMultiError is an error wrapping multiple validation +// errors returned by GetAdvisorCheckRequest.ValidateAll() if the designated +// constraints aren't met. +type GetAdvisorCheckRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetAdvisorCheckRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetAdvisorCheckRequestMultiError) AllErrors() []error { return m } + +// GetAdvisorCheckRequestValidationError is the validation error returned by +// GetAdvisorCheckRequest.Validate if the designated constraints aren't met. +type GetAdvisorCheckRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetAdvisorCheckRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetAdvisorCheckRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetAdvisorCheckRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetAdvisorCheckRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetAdvisorCheckRequestValidationError) ErrorName() string { + return "GetAdvisorCheckRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e GetAdvisorCheckRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetAdvisorCheckRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetAdvisorCheckRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetAdvisorCheckRequestValidationError{} + +// Validate checks the field values on GetAdvisorCheckResponse with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *GetAdvisorCheckResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on GetAdvisorCheckResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// GetAdvisorCheckResponseMultiError, or nil if none found. +func (m *GetAdvisorCheckResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *GetAdvisorCheckResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetCheck()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, GetAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, GetAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCheck()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return GetAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return GetAdvisorCheckResponseMultiError(errors) + } + + return nil +} + +// GetAdvisorCheckResponseMultiError is an error wrapping multiple validation +// errors returned by GetAdvisorCheckResponse.ValidateAll() if the designated +// constraints aren't met. +type GetAdvisorCheckResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m GetAdvisorCheckResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m GetAdvisorCheckResponseMultiError) AllErrors() []error { return m } + +// GetAdvisorCheckResponseValidationError is the validation error returned by +// GetAdvisorCheckResponse.Validate if the designated constraints aren't met. +type GetAdvisorCheckResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e GetAdvisorCheckResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e GetAdvisorCheckResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e GetAdvisorCheckResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e GetAdvisorCheckResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e GetAdvisorCheckResponseValidationError) ErrorName() string { + return "GetAdvisorCheckResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e GetAdvisorCheckResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sGetAdvisorCheckResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = GetAdvisorCheckResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = GetAdvisorCheckResponseValidationError{} + +// Validate checks the field values on CreateAdvisorCheckRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *CreateAdvisorCheckRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on CreateAdvisorCheckRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// CreateAdvisorCheckRequestMultiError, or nil if none found. +func (m *CreateAdvisorCheckRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *CreateAdvisorCheckRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetCheck()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CreateAdvisorCheckRequestValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CreateAdvisorCheckRequestValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCheck()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CreateAdvisorCheckRequestValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return CreateAdvisorCheckRequestMultiError(errors) + } + + return nil +} + +// CreateAdvisorCheckRequestMultiError is an error wrapping multiple validation +// errors returned by CreateAdvisorCheckRequest.ValidateAll() if the +// designated constraints aren't met. +type CreateAdvisorCheckRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m CreateAdvisorCheckRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m CreateAdvisorCheckRequestMultiError) AllErrors() []error { return m } + +// CreateAdvisorCheckRequestValidationError is the validation error returned by +// CreateAdvisorCheckRequest.Validate if the designated constraints aren't met. +type CreateAdvisorCheckRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e CreateAdvisorCheckRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e CreateAdvisorCheckRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e CreateAdvisorCheckRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e CreateAdvisorCheckRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e CreateAdvisorCheckRequestValidationError) ErrorName() string { + return "CreateAdvisorCheckRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e CreateAdvisorCheckRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sCreateAdvisorCheckRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = CreateAdvisorCheckRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = CreateAdvisorCheckRequestValidationError{} + +// Validate checks the field values on CreateAdvisorCheckResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *CreateAdvisorCheckResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on CreateAdvisorCheckResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// CreateAdvisorCheckResponseMultiError, or nil if none found. +func (m *CreateAdvisorCheckResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *CreateAdvisorCheckResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetCheck()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, CreateAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, CreateAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCheck()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return CreateAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return CreateAdvisorCheckResponseMultiError(errors) + } + + return nil +} + +// CreateAdvisorCheckResponseMultiError is an error wrapping multiple +// validation errors returned by CreateAdvisorCheckResponse.ValidateAll() if +// the designated constraints aren't met. +type CreateAdvisorCheckResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m CreateAdvisorCheckResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m CreateAdvisorCheckResponseMultiError) AllErrors() []error { return m } + +// CreateAdvisorCheckResponseValidationError is the validation error returned +// by CreateAdvisorCheckResponse.Validate if the designated constraints aren't met. +type CreateAdvisorCheckResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e CreateAdvisorCheckResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e CreateAdvisorCheckResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e CreateAdvisorCheckResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e CreateAdvisorCheckResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e CreateAdvisorCheckResponseValidationError) ErrorName() string { + return "CreateAdvisorCheckResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e CreateAdvisorCheckResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sCreateAdvisorCheckResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = CreateAdvisorCheckResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = CreateAdvisorCheckResponseValidationError{} + +// Validate checks the field values on UpdateAdvisorCheckRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *UpdateAdvisorCheckRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UpdateAdvisorCheckRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// UpdateAdvisorCheckRequestMultiError, or nil if none found. +func (m *UpdateAdvisorCheckRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *UpdateAdvisorCheckRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Name + + if all { + switch v := interface{}(m.GetCheck()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, UpdateAdvisorCheckRequestValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, UpdateAdvisorCheckRequestValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCheck()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return UpdateAdvisorCheckRequestValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return UpdateAdvisorCheckRequestMultiError(errors) + } + + return nil +} + +// UpdateAdvisorCheckRequestMultiError is an error wrapping multiple validation +// errors returned by UpdateAdvisorCheckRequest.ValidateAll() if the +// designated constraints aren't met. +type UpdateAdvisorCheckRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UpdateAdvisorCheckRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m UpdateAdvisorCheckRequestMultiError) AllErrors() []error { return m } + +// UpdateAdvisorCheckRequestValidationError is the validation error returned by +// UpdateAdvisorCheckRequest.Validate if the designated constraints aren't met. +type UpdateAdvisorCheckRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UpdateAdvisorCheckRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UpdateAdvisorCheckRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UpdateAdvisorCheckRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UpdateAdvisorCheckRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UpdateAdvisorCheckRequestValidationError) ErrorName() string { + return "UpdateAdvisorCheckRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e UpdateAdvisorCheckRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUpdateAdvisorCheckRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = UpdateAdvisorCheckRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UpdateAdvisorCheckRequestValidationError{} + +// Validate checks the field values on UpdateAdvisorCheckResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *UpdateAdvisorCheckResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on UpdateAdvisorCheckResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// UpdateAdvisorCheckResponseMultiError, or nil if none found. +func (m *UpdateAdvisorCheckResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *UpdateAdvisorCheckResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if all { + switch v := interface{}(m.GetCheck()).(type) { + case interface{ ValidateAll() error }: + if err := v.ValidateAll(); err != nil { + errors = append(errors, UpdateAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + case interface{ Validate() error }: + if err := v.Validate(); err != nil { + errors = append(errors, UpdateAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + }) + } + } + } else if v, ok := interface{}(m.GetCheck()).(interface{ Validate() error }); ok { + if err := v.Validate(); err != nil { + return UpdateAdvisorCheckResponseValidationError{ + field: "Check", + reason: "embedded message failed validation", + cause: err, + } + } + } + + if len(errors) > 0 { + return UpdateAdvisorCheckResponseMultiError(errors) + } + + return nil +} + +// UpdateAdvisorCheckResponseMultiError is an error wrapping multiple +// validation errors returned by UpdateAdvisorCheckResponse.ValidateAll() if +// the designated constraints aren't met. +type UpdateAdvisorCheckResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m UpdateAdvisorCheckResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m UpdateAdvisorCheckResponseMultiError) AllErrors() []error { return m } + +// UpdateAdvisorCheckResponseValidationError is the validation error returned +// by UpdateAdvisorCheckResponse.Validate if the designated constraints aren't met. +type UpdateAdvisorCheckResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e UpdateAdvisorCheckResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e UpdateAdvisorCheckResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e UpdateAdvisorCheckResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e UpdateAdvisorCheckResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e UpdateAdvisorCheckResponseValidationError) ErrorName() string { + return "UpdateAdvisorCheckResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e UpdateAdvisorCheckResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sUpdateAdvisorCheckResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = UpdateAdvisorCheckResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = UpdateAdvisorCheckResponseValidationError{} + +// Validate checks the field values on DeleteAdvisorCheckRequest with the rules +// defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *DeleteAdvisorCheckRequest) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteAdvisorCheckRequest with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// DeleteAdvisorCheckRequestMultiError, or nil if none found. +func (m *DeleteAdvisorCheckRequest) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteAdvisorCheckRequest) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + // no validation rules for Name + + if len(errors) > 0 { + return DeleteAdvisorCheckRequestMultiError(errors) + } + + return nil +} + +// DeleteAdvisorCheckRequestMultiError is an error wrapping multiple validation +// errors returned by DeleteAdvisorCheckRequest.ValidateAll() if the +// designated constraints aren't met. +type DeleteAdvisorCheckRequestMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteAdvisorCheckRequestMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteAdvisorCheckRequestMultiError) AllErrors() []error { return m } + +// DeleteAdvisorCheckRequestValidationError is the validation error returned by +// DeleteAdvisorCheckRequest.Validate if the designated constraints aren't met. +type DeleteAdvisorCheckRequestValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteAdvisorCheckRequestValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteAdvisorCheckRequestValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteAdvisorCheckRequestValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteAdvisorCheckRequestValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteAdvisorCheckRequestValidationError) ErrorName() string { + return "DeleteAdvisorCheckRequestValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteAdvisorCheckRequestValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteAdvisorCheckRequest.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteAdvisorCheckRequestValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteAdvisorCheckRequestValidationError{} + +// Validate checks the field values on DeleteAdvisorCheckResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the first error encountered is returned, or nil if there are no violations. +func (m *DeleteAdvisorCheckResponse) Validate() error { + return m.validate(false) +} + +// ValidateAll checks the field values on DeleteAdvisorCheckResponse with the +// rules defined in the proto definition for this message. If any rules are +// violated, the result is a list of violation errors wrapped in +// DeleteAdvisorCheckResponseMultiError, or nil if none found. +func (m *DeleteAdvisorCheckResponse) ValidateAll() error { + return m.validate(true) +} + +func (m *DeleteAdvisorCheckResponse) validate(all bool) error { + if m == nil { + return nil + } + + var errors []error + + if len(errors) > 0 { + return DeleteAdvisorCheckResponseMultiError(errors) + } + + return nil +} + +// DeleteAdvisorCheckResponseMultiError is an error wrapping multiple +// validation errors returned by DeleteAdvisorCheckResponse.ValidateAll() if +// the designated constraints aren't met. +type DeleteAdvisorCheckResponseMultiError []error + +// Error returns a concatenation of all the error messages it wraps. +func (m DeleteAdvisorCheckResponseMultiError) Error() string { + msgs := make([]string, 0, len(m)) + for _, err := range m { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "; ") +} + +// AllErrors returns a list of validation violation errors. +func (m DeleteAdvisorCheckResponseMultiError) AllErrors() []error { return m } + +// DeleteAdvisorCheckResponseValidationError is the validation error returned +// by DeleteAdvisorCheckResponse.Validate if the designated constraints aren't met. +type DeleteAdvisorCheckResponseValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeleteAdvisorCheckResponseValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeleteAdvisorCheckResponseValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeleteAdvisorCheckResponseValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeleteAdvisorCheckResponseValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeleteAdvisorCheckResponseValidationError) ErrorName() string { + return "DeleteAdvisorCheckResponseValidationError" +} + +// Error satisfies the builtin error interface +func (e DeleteAdvisorCheckResponseValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeleteAdvisorCheckResponse.%s: %s%s", + key, + e.field, + e.reason, + cause, + ) +} + +var _ error = DeleteAdvisorCheckResponseValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeleteAdvisorCheckResponseValidationError{} + // Validate checks the field values on ListAdvisorsRequest with the rules // defined in the proto definition for this message. If any rules are // violated, the first error encountered is returned, or nil if there are no violations. diff --git a/api/advisors/v1/advisors.proto b/api/advisors/v1/advisors.proto index 9eafa926907..349e1931ab6 100644 --- a/api/advisors/v1/advisors.proto +++ b/api/advisors/v1/advisors.proto @@ -95,10 +95,23 @@ message CheckResult { bool silenced = 10; } +// AdvisorCheckQuery is a single data-collection query of an advisor check. +message AdvisorCheckQuery { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + string type = 1; + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + string query = 2; + // Optional query parameters (e.g. range/step for metrics range queries). + map parameters = 3; +} + // AdvisorCheck contains check name and status. message AdvisorCheck { // Machine-readable name (ID) that is used in expression. - string name = 1; + string name = 1 [(validate.rules).string = { + pattern: "^[a-zA-Z_][a-zA-Z0-9_]*$" + max_len: 128 + }]; // True if that check is enabled. bool enabled = 2; // Long human-readable description. @@ -109,6 +122,16 @@ message AdvisorCheck { AdvisorCheckInterval interval = 5; // DB family. AdvisorCheckFamily family = 6; + // Category (top-level grouping). + string category = 7; + // Subcategory (second-level grouping within a category). + string subcategory = 8; + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + bool user_defined = 9; + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + repeated AdvisorCheckQuery queries = 10; + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + string script = 11; } message Advisor { @@ -163,6 +186,42 @@ message GetAdvisorCheckScriptResponse { string script = 1; } +message GetAdvisorCheckRequest { + // Machine-readable name (ID) of the check. + string name = 1; +} + +message GetAdvisorCheckResponse { + AdvisorCheck check = 1; +} + +message CreateAdvisorCheckRequest { + // The check to create. Its name must be unique across all checks. + AdvisorCheck check = 1; +} + +message CreateAdvisorCheckResponse { + AdvisorCheck check = 1; +} + +message UpdateAdvisorCheckRequest { + // Machine-readable name (ID) of the check to update. + string name = 1; + // The updated check definition. + AdvisorCheck check = 2; +} + +message UpdateAdvisorCheckResponse { + AdvisorCheck check = 1; +} + +message DeleteAdvisorCheckRequest { + // Machine-readable name (ID) of the check to delete. + string name = 1; +} + +message DeleteAdvisorCheckResponse {} + message ListAdvisorsRequest {} message ListAdvisorsResponse { @@ -401,4 +460,43 @@ service AdvisorService { description: "Enables/disables advisor checks or changes their exec interval." }; } + // GetAdvisorCheck returns a single advisor check by name, including its queries and script. + rpc GetAdvisorCheck(GetAdvisorCheckRequest) returns (GetAdvisorCheckResponse) { + // deeper path than /checks/{failed,history} so the {name} wildcard cannot shadow them + option (google.api.http) = {get: "/v1/advisors/checks/{name}/definition"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Get Advisor Check" + description: "Returns a single advisor check by name, including its queries and script." + }; + } + // CreateAdvisorCheck creates a new user-authored advisor check. + rpc CreateAdvisorCheck(CreateAdvisorCheckRequest) returns (CreateAdvisorCheckResponse) { + option (google.api.http) = { + post: "/v1/advisors/checks" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Create Advisor Check" + description: "Creates a new user-authored advisor check." + }; + } + // UpdateAdvisorCheck updates an existing user-authored advisor check. + rpc UpdateAdvisorCheck(UpdateAdvisorCheckRequest) returns (UpdateAdvisorCheckResponse) { + option (google.api.http) = { + put: "/v1/advisors/checks/{name}" + body: "*" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Update Advisor Check" + description: "Updates an existing user-authored advisor check. Percona-shipped checks cannot be modified." + }; + } + // DeleteAdvisorCheck deletes a user-authored advisor check. + rpc DeleteAdvisorCheck(DeleteAdvisorCheckRequest) returns (DeleteAdvisorCheckResponse) { + option (google.api.http) = {delete: "/v1/advisors/checks/{name}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + summary: "Delete Advisor Check" + description: "Deletes a user-authored advisor check. Percona-shipped checks cannot be deleted." + }; + } } diff --git a/api/advisors/v1/advisors_grpc.pb.go b/api/advisors/v1/advisors_grpc.pb.go index aea03328025..86aae583a89 100644 --- a/api/advisors/v1/advisors_grpc.pb.go +++ b/api/advisors/v1/advisors_grpc.pb.go @@ -30,6 +30,10 @@ const ( AdvisorService_GetAdvisorCheckScript_FullMethodName = "/advisors.v1.AdvisorService/GetAdvisorCheckScript" AdvisorService_ListAdvisors_FullMethodName = "/advisors.v1.AdvisorService/ListAdvisors" AdvisorService_ChangeAdvisorChecks_FullMethodName = "/advisors.v1.AdvisorService/ChangeAdvisorChecks" + AdvisorService_GetAdvisorCheck_FullMethodName = "/advisors.v1.AdvisorService/GetAdvisorCheck" + AdvisorService_CreateAdvisorCheck_FullMethodName = "/advisors.v1.AdvisorService/CreateAdvisorCheck" + AdvisorService_UpdateAdvisorCheck_FullMethodName = "/advisors.v1.AdvisorService/UpdateAdvisorCheck" + AdvisorService_DeleteAdvisorCheck_FullMethodName = "/advisors.v1.AdvisorService/DeleteAdvisorCheck" ) // AdvisorServiceClient is the client API for AdvisorService service. @@ -58,6 +62,14 @@ type AdvisorServiceClient interface { ListAdvisors(ctx context.Context, in *ListAdvisorsRequest, opts ...grpc.CallOption) (*ListAdvisorsResponse, error) // ChangeAdvisorChecks enables/disables Advisor checks or changes their exec interval. ChangeAdvisorChecks(ctx context.Context, in *ChangeAdvisorChecksRequest, opts ...grpc.CallOption) (*ChangeAdvisorChecksResponse, error) + // GetAdvisorCheck returns a single advisor check by name, including its queries and script. + GetAdvisorCheck(ctx context.Context, in *GetAdvisorCheckRequest, opts ...grpc.CallOption) (*GetAdvisorCheckResponse, error) + // CreateAdvisorCheck creates a new user-authored advisor check. + CreateAdvisorCheck(ctx context.Context, in *CreateAdvisorCheckRequest, opts ...grpc.CallOption) (*CreateAdvisorCheckResponse, error) + // UpdateAdvisorCheck updates an existing user-authored advisor check. + UpdateAdvisorCheck(ctx context.Context, in *UpdateAdvisorCheckRequest, opts ...grpc.CallOption) (*UpdateAdvisorCheckResponse, error) + // DeleteAdvisorCheck deletes a user-authored advisor check. + DeleteAdvisorCheck(ctx context.Context, in *DeleteAdvisorCheckRequest, opts ...grpc.CallOption) (*DeleteAdvisorCheckResponse, error) } type advisorServiceClient struct { @@ -168,6 +180,46 @@ func (c *advisorServiceClient) ChangeAdvisorChecks(ctx context.Context, in *Chan return out, nil } +func (c *advisorServiceClient) GetAdvisorCheck(ctx context.Context, in *GetAdvisorCheckRequest, opts ...grpc.CallOption) (*GetAdvisorCheckResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetAdvisorCheckResponse) + err := c.cc.Invoke(ctx, AdvisorService_GetAdvisorCheck_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *advisorServiceClient) CreateAdvisorCheck(ctx context.Context, in *CreateAdvisorCheckRequest, opts ...grpc.CallOption) (*CreateAdvisorCheckResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateAdvisorCheckResponse) + err := c.cc.Invoke(ctx, AdvisorService_CreateAdvisorCheck_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *advisorServiceClient) UpdateAdvisorCheck(ctx context.Context, in *UpdateAdvisorCheckRequest, opts ...grpc.CallOption) (*UpdateAdvisorCheckResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateAdvisorCheckResponse) + err := c.cc.Invoke(ctx, AdvisorService_UpdateAdvisorCheck_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *advisorServiceClient) DeleteAdvisorCheck(ctx context.Context, in *DeleteAdvisorCheckRequest, opts ...grpc.CallOption) (*DeleteAdvisorCheckResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteAdvisorCheckResponse) + err := c.cc.Invoke(ctx, AdvisorService_DeleteAdvisorCheck_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // AdvisorServiceServer is the server API for AdvisorService service. // All implementations must embed UnimplementedAdvisorServiceServer // for forward compatibility. @@ -194,6 +246,14 @@ type AdvisorServiceServer interface { ListAdvisors(context.Context, *ListAdvisorsRequest) (*ListAdvisorsResponse, error) // ChangeAdvisorChecks enables/disables Advisor checks or changes their exec interval. ChangeAdvisorChecks(context.Context, *ChangeAdvisorChecksRequest) (*ChangeAdvisorChecksResponse, error) + // GetAdvisorCheck returns a single advisor check by name, including its queries and script. + GetAdvisorCheck(context.Context, *GetAdvisorCheckRequest) (*GetAdvisorCheckResponse, error) + // CreateAdvisorCheck creates a new user-authored advisor check. + CreateAdvisorCheck(context.Context, *CreateAdvisorCheckRequest) (*CreateAdvisorCheckResponse, error) + // UpdateAdvisorCheck updates an existing user-authored advisor check. + UpdateAdvisorCheck(context.Context, *UpdateAdvisorCheckRequest) (*UpdateAdvisorCheckResponse, error) + // DeleteAdvisorCheck deletes a user-authored advisor check. + DeleteAdvisorCheck(context.Context, *DeleteAdvisorCheckRequest) (*DeleteAdvisorCheckResponse, error) mustEmbedUnimplementedAdvisorServiceServer() } @@ -243,6 +303,22 @@ func (UnimplementedAdvisorServiceServer) ListAdvisors(context.Context, *ListAdvi func (UnimplementedAdvisorServiceServer) ChangeAdvisorChecks(context.Context, *ChangeAdvisorChecksRequest) (*ChangeAdvisorChecksResponse, error) { return nil, status.Error(codes.Unimplemented, "method ChangeAdvisorChecks not implemented") } + +func (UnimplementedAdvisorServiceServer) GetAdvisorCheck(context.Context, *GetAdvisorCheckRequest) (*GetAdvisorCheckResponse, error) { + return nil, status.Error(codes.Unimplemented, "method GetAdvisorCheck not implemented") +} + +func (UnimplementedAdvisorServiceServer) CreateAdvisorCheck(context.Context, *CreateAdvisorCheckRequest) (*CreateAdvisorCheckResponse, error) { + return nil, status.Error(codes.Unimplemented, "method CreateAdvisorCheck not implemented") +} + +func (UnimplementedAdvisorServiceServer) UpdateAdvisorCheck(context.Context, *UpdateAdvisorCheckRequest) (*UpdateAdvisorCheckResponse, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateAdvisorCheck not implemented") +} + +func (UnimplementedAdvisorServiceServer) DeleteAdvisorCheck(context.Context, *DeleteAdvisorCheckRequest) (*DeleteAdvisorCheckResponse, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteAdvisorCheck not implemented") +} func (UnimplementedAdvisorServiceServer) mustEmbedUnimplementedAdvisorServiceServer() {} func (UnimplementedAdvisorServiceServer) testEmbeddedByValue() {} @@ -444,6 +520,78 @@ func _AdvisorService_ChangeAdvisorChecks_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } +func _AdvisorService_GetAdvisorCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAdvisorCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).GetAdvisorCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_GetAdvisorCheck_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).GetAdvisorCheck(ctx, req.(*GetAdvisorCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdvisorService_CreateAdvisorCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateAdvisorCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).CreateAdvisorCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_CreateAdvisorCheck_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).CreateAdvisorCheck(ctx, req.(*CreateAdvisorCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdvisorService_UpdateAdvisorCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateAdvisorCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).UpdateAdvisorCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_UpdateAdvisorCheck_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).UpdateAdvisorCheck(ctx, req.(*UpdateAdvisorCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdvisorService_DeleteAdvisorCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteAdvisorCheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdvisorServiceServer).DeleteAdvisorCheck(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdvisorService_DeleteAdvisorCheck_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdvisorServiceServer).DeleteAdvisorCheck(ctx, req.(*DeleteAdvisorCheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AdvisorService_ServiceDesc is the grpc.ServiceDesc for AdvisorService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -491,6 +639,22 @@ var AdvisorService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ChangeAdvisorChecks", Handler: _AdvisorService_ChangeAdvisorChecks_Handler, }, + { + MethodName: "GetAdvisorCheck", + Handler: _AdvisorService_GetAdvisorCheck_Handler, + }, + { + MethodName: "CreateAdvisorCheck", + Handler: _AdvisorService_CreateAdvisorCheck_Handler, + }, + { + MethodName: "UpdateAdvisorCheck", + Handler: _AdvisorService_UpdateAdvisorCheck_Handler, + }, + { + MethodName: "DeleteAdvisorCheck", + Handler: _AdvisorService_DeleteAdvisorCheck_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "advisors/v1/advisors.proto", diff --git a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go index b1a85794199..7b1d923188e 100644 --- a/api/advisors/v1/json/client/advisor_service/advisor_service_client.go +++ b/api/advisors/v1/json/client/advisor_service/advisor_service_client.go @@ -53,6 +53,12 @@ type ClientOption func(*runtime.ClientOperation) type ClientService interface { ChangeAdvisorChecks(params *ChangeAdvisorChecksParams, opts ...ClientOption) (*ChangeAdvisorChecksOK, error) + CreateAdvisorCheck(params *CreateAdvisorCheckParams, opts ...ClientOption) (*CreateAdvisorCheckOK, error) + + DeleteAdvisorCheck(params *DeleteAdvisorCheckParams, opts ...ClientOption) (*DeleteAdvisorCheckOK, error) + + GetAdvisorCheck(params *GetAdvisorCheckParams, opts ...ClientOption) (*GetAdvisorCheckOK, error) + GetAdvisorCheckScript(params *GetAdvisorCheckScriptParams, opts ...ClientOption) (*GetAdvisorCheckScriptOK, error) GetFailedChecks(params *GetFailedChecksParams, opts ...ClientOption) (*GetFailedChecksOK, error) @@ -71,6 +77,8 @@ type ClientService interface { StartAdvisorChecks(params *StartAdvisorChecksParams, opts ...ClientOption) (*StartAdvisorChecksOK, error) + UpdateAdvisorCheck(params *UpdateAdvisorCheckParams, opts ...ClientOption) (*UpdateAdvisorCheckOK, error) + SetTransport(transport runtime.ClientTransport) } @@ -118,6 +126,138 @@ func (a *Client) ChangeAdvisorChecks(params *ChangeAdvisorChecksParams, opts ... return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +CreateAdvisorCheck creates advisor check + +Creates a new user-authored advisor check. +*/ +func (a *Client) CreateAdvisorCheck(params *CreateAdvisorCheckParams, opts ...ClientOption) (*CreateAdvisorCheckOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewCreateAdvisorCheckParams() + } + op := &runtime.ClientOperation{ + ID: "CreateAdvisorCheck", + Method: "POST", + PathPattern: "/v1/advisors/checks", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &CreateAdvisorCheckReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*CreateAdvisorCheckOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*CreateAdvisorCheckDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +DeleteAdvisorCheck deletes advisor check + +Deletes a user-authored advisor check. Percona-shipped checks cannot be deleted. +*/ +func (a *Client) DeleteAdvisorCheck(params *DeleteAdvisorCheckParams, opts ...ClientOption) (*DeleteAdvisorCheckOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewDeleteAdvisorCheckParams() + } + op := &runtime.ClientOperation{ + ID: "DeleteAdvisorCheck", + Method: "DELETE", + PathPattern: "/v1/advisors/checks/{name}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &DeleteAdvisorCheckReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*DeleteAdvisorCheckOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*DeleteAdvisorCheckDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + +/* +GetAdvisorCheck gets advisor check + +Returns a single advisor check by name, including its queries and script. +*/ +func (a *Client) GetAdvisorCheck(params *GetAdvisorCheckParams, opts ...ClientOption) (*GetAdvisorCheckOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewGetAdvisorCheckParams() + } + op := &runtime.ClientOperation{ + ID: "GetAdvisorCheck", + Method: "GET", + PathPattern: "/v1/advisors/checks/{name}/definition", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &GetAdvisorCheckReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*GetAdvisorCheckOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*GetAdvisorCheckDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + /* GetAdvisorCheckScript gets advisor check script @@ -514,6 +654,50 @@ func (a *Client) StartAdvisorChecks(params *StartAdvisorChecksParams, opts ...Cl return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) } +/* +UpdateAdvisorCheck updates advisor check + +Updates an existing user-authored advisor check. Percona-shipped checks cannot be modified. +*/ +func (a *Client) UpdateAdvisorCheck(params *UpdateAdvisorCheckParams, opts ...ClientOption) (*UpdateAdvisorCheckOK, error) { + // NOTE: parameters are not validated before sending + if params == nil { + params = NewUpdateAdvisorCheckParams() + } + op := &runtime.ClientOperation{ + ID: "UpdateAdvisorCheck", + Method: "PUT", + PathPattern: "/v1/advisors/checks/{name}", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http", "https"}, + Params: params, + Reader: &UpdateAdvisorCheckReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + } + for _, opt := range opts { + opt(op) + } + result, err := a.transport.Submit(op) + if err != nil { + return nil, err + } + + // only one success response has to be checked + success, ok := result.(*UpdateAdvisorCheckOK) + if ok { + return success, nil + } + + // unexpected success response. + // + // a default response is provided: fill this and return an error + unexpectedSuccess := result.(*UpdateAdvisorCheckDefault) + + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) +} + // SetTransport changes the transport on the client func (a *Client) SetTransport(transport runtime.ClientTransport) { a.transport = transport diff --git a/api/advisors/v1/json/client/advisor_service/create_advisor_check_parameters.go b/api/advisors/v1/json/client/advisor_service/create_advisor_check_parameters.go new file mode 100644 index 00000000000..633f6fd6fdd --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/create_advisor_check_parameters.go @@ -0,0 +1,141 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewCreateAdvisorCheckParams creates a new CreateAdvisorCheckParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewCreateAdvisorCheckParams() *CreateAdvisorCheckParams { + return &CreateAdvisorCheckParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewCreateAdvisorCheckParamsWithTimeout creates a new CreateAdvisorCheckParams object +// with the ability to set a timeout on a request. +func NewCreateAdvisorCheckParamsWithTimeout(timeout time.Duration) *CreateAdvisorCheckParams { + return &CreateAdvisorCheckParams{ + timeout: timeout, + } +} + +// NewCreateAdvisorCheckParamsWithContext creates a new CreateAdvisorCheckParams object +// with the ability to set a context for a request. +func NewCreateAdvisorCheckParamsWithContext(ctx context.Context) *CreateAdvisorCheckParams { + return &CreateAdvisorCheckParams{ + Context: ctx, + } +} + +// NewCreateAdvisorCheckParamsWithHTTPClient creates a new CreateAdvisorCheckParams object +// with the ability to set a custom HTTPClient for a request. +func NewCreateAdvisorCheckParamsWithHTTPClient(client *http.Client) *CreateAdvisorCheckParams { + return &CreateAdvisorCheckParams{ + HTTPClient: client, + } +} + +/* +CreateAdvisorCheckParams contains all the parameters to send to the API endpoint + + for the create advisor check operation. + + Typically these are written to a http.Request. +*/ +type CreateAdvisorCheckParams struct { + // Body. + Body CreateAdvisorCheckBody + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the create advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateAdvisorCheckParams) WithDefaults() *CreateAdvisorCheckParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the create advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *CreateAdvisorCheckParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the create advisor check params +func (o *CreateAdvisorCheckParams) WithTimeout(timeout time.Duration) *CreateAdvisorCheckParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the create advisor check params +func (o *CreateAdvisorCheckParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the create advisor check params +func (o *CreateAdvisorCheckParams) WithContext(ctx context.Context) *CreateAdvisorCheckParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the create advisor check params +func (o *CreateAdvisorCheckParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the create advisor check params +func (o *CreateAdvisorCheckParams) WithHTTPClient(client *http.Client) *CreateAdvisorCheckParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the create advisor check params +func (o *CreateAdvisorCheckParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the create advisor check params +func (o *CreateAdvisorCheckParams) WithBody(body CreateAdvisorCheckBody) *CreateAdvisorCheckParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the create advisor check params +func (o *CreateAdvisorCheckParams) SetBody(body CreateAdvisorCheckBody) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *CreateAdvisorCheckParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/create_advisor_check_responses.go b/api/advisors/v1/json/client/advisor_service/create_advisor_check_responses.go new file mode 100644 index 00000000000..11f76b0640a --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/create_advisor_check_responses.go @@ -0,0 +1,1198 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// CreateAdvisorCheckReader is a Reader for the CreateAdvisorCheck structure. +type CreateAdvisorCheckReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *CreateAdvisorCheckReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewCreateAdvisorCheckOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewCreateAdvisorCheckDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewCreateAdvisorCheckOK creates a CreateAdvisorCheckOK with default headers values +func NewCreateAdvisorCheckOK() *CreateAdvisorCheckOK { + return &CreateAdvisorCheckOK{} +} + +/* +CreateAdvisorCheckOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type CreateAdvisorCheckOK struct { + Payload *CreateAdvisorCheckOKBody +} + +// IsSuccess returns true when this create advisor check Ok response has a 2xx status code +func (o *CreateAdvisorCheckOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this create advisor check Ok response has a 3xx status code +func (o *CreateAdvisorCheckOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this create advisor check Ok response has a 4xx status code +func (o *CreateAdvisorCheckOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this create advisor check Ok response has a 5xx status code +func (o *CreateAdvisorCheckOK) IsServerError() bool { + return false +} + +// IsCode returns true when this create advisor check Ok response a status code equal to that given +func (o *CreateAdvisorCheckOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the create advisor check Ok response +func (o *CreateAdvisorCheckOK) Code() int { + return 200 +} + +func (o *CreateAdvisorCheckOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks][%d] createAdvisorCheckOk %s", 200, payload) +} + +func (o *CreateAdvisorCheckOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks][%d] createAdvisorCheckOk %s", 200, payload) +} + +func (o *CreateAdvisorCheckOK) GetPayload() *CreateAdvisorCheckOKBody { + return o.Payload +} + +func (o *CreateAdvisorCheckOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(CreateAdvisorCheckOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewCreateAdvisorCheckDefault creates a CreateAdvisorCheckDefault with default headers values +func NewCreateAdvisorCheckDefault(code int) *CreateAdvisorCheckDefault { + return &CreateAdvisorCheckDefault{ + _statusCode: code, + } +} + +/* +CreateAdvisorCheckDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type CreateAdvisorCheckDefault struct { + _statusCode int + + Payload *CreateAdvisorCheckDefaultBody +} + +// IsSuccess returns true when this create advisor check default response has a 2xx status code +func (o *CreateAdvisorCheckDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this create advisor check default response has a 3xx status code +func (o *CreateAdvisorCheckDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this create advisor check default response has a 4xx status code +func (o *CreateAdvisorCheckDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this create advisor check default response has a 5xx status code +func (o *CreateAdvisorCheckDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this create advisor check default response a status code equal to that given +func (o *CreateAdvisorCheckDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the create advisor check default response +func (o *CreateAdvisorCheckDefault) Code() int { + return o._statusCode +} + +func (o *CreateAdvisorCheckDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks][%d] CreateAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *CreateAdvisorCheckDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[POST /v1/advisors/checks][%d] CreateAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *CreateAdvisorCheckDefault) GetPayload() *CreateAdvisorCheckDefaultBody { + return o.Payload +} + +func (o *CreateAdvisorCheckDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(CreateAdvisorCheckDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +CreateAdvisorCheckBody create advisor check body +swagger:model CreateAdvisorCheckBody +*/ +type CreateAdvisorCheckBody struct { + // check + Check *CreateAdvisorCheckParamsBodyCheck `json:"check,omitempty"` +} + +// Validate validates this create advisor check body +func (o *CreateAdvisorCheckBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateCheck(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckBody) validateCheck(formats strfmt.Registry) error { + if swag.IsZero(o.Check) { // not required + return nil + } + + if o.Check != nil { + if err := o.Check.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this create advisor check body based on the context it is used +func (o *CreateAdvisorCheckBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateCheck(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckBody) contextValidateCheck(ctx context.Context, formats strfmt.Registry) error { + if o.Check != nil { + + if swag.IsZero(o.Check) { // not required + return nil + } + + if err := o.Check.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckBody) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +CreateAdvisorCheckDefaultBody create advisor check default body +swagger:model CreateAdvisorCheckDefaultBody +*/ +type CreateAdvisorCheckDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*CreateAdvisorCheckDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this create advisor check default body +func (o *CreateAdvisorCheckDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("CreateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("CreateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this create advisor check default body based on the context it is used +func (o *CreateAdvisorCheckDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("CreateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("CreateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckDefaultBody) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +CreateAdvisorCheckDefaultBodyDetailsItems0 create advisor check default body details items0 +swagger:model CreateAdvisorCheckDefaultBodyDetailsItems0 +*/ +type CreateAdvisorCheckDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // create advisor check default body details items0 + CreateAdvisorCheckDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *CreateAdvisorCheckDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv CreateAdvisorCheckDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.CreateAdvisorCheckDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o CreateAdvisorCheckDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.CreateAdvisorCheckDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.CreateAdvisorCheckDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this create advisor check default body details items0 +func (o *CreateAdvisorCheckDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this create advisor check default body details items0 based on context it is used +func (o *CreateAdvisorCheckDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +CreateAdvisorCheckOKBody create advisor check OK body +swagger:model CreateAdvisorCheckOKBody +*/ +type CreateAdvisorCheckOKBody struct { + // check + Check *CreateAdvisorCheckOKBodyCheck `json:"check,omitempty"` +} + +// Validate validates this create advisor check OK body +func (o *CreateAdvisorCheckOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateCheck(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckOKBody) validateCheck(formats strfmt.Registry) error { + if swag.IsZero(o.Check) { // not required + return nil + } + + if o.Check != nil { + if err := o.Check.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("createAdvisorCheckOk" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("createAdvisorCheckOk" + "." + "check") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this create advisor check OK body based on the context it is used +func (o *CreateAdvisorCheckOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateCheck(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckOKBody) contextValidateCheck(ctx context.Context, formats strfmt.Registry) error { + if o.Check != nil { + + if swag.IsZero(o.Check) { // not required + return nil + } + + if err := o.Check.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("createAdvisorCheckOk" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("createAdvisorCheckOk" + "." + "check") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckOKBody) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +CreateAdvisorCheckOKBodyCheck AdvisorCheck contains check name and status. +swagger:model CreateAdvisorCheckOKBodyCheck +*/ +type CreateAdvisorCheckOKBodyCheck struct { + // Machine-readable name (ID) that is used in expression. + Name string `json:"name,omitempty"` + + // True if that check is enabled. + Enabled bool `json:"enabled,omitempty"` + + // Long human-readable description. + Description string `json:"description,omitempty"` + + // Short human-readable summary. + Summary string `json:"summary,omitempty"` + + // AdvisorCheckInterval represents possible execution interval values for checks. + // Enum: ["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"] + Interval *string `json:"interval,omitempty"` + + // family + // Enum: ["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"] + Family *string `json:"family,omitempty"` + + // Category (top-level grouping). + Category string `json:"category,omitempty"` + + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `json:"user_defined,omitempty"` + + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*CreateAdvisorCheckOKBodyCheckQueriesItems0 `json:"queries"` + + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `json:"script,omitempty"` +} + +// Validate validates this create advisor check OK body check +func (o *CreateAdvisorCheckOKBodyCheck) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateInterval(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFamily(formats); err != nil { + res = append(res, err) + } + + if err := o.validateQueries(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var createAdvisorCheckOkBodyCheckTypeIntervalPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + createAdvisorCheckOkBodyCheckTypeIntervalPropEnum = append(createAdvisorCheckOkBodyCheckTypeIntervalPropEnum, v) + } +} + +const ( + + // CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED captures enum value "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED string = "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + + // CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALSTANDARD captures enum value "ADVISOR_CHECK_INTERVAL_STANDARD" + CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALSTANDARD string = "ADVISOR_CHECK_INTERVAL_STANDARD" + + // CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALFREQUENT captures enum value "ADVISOR_CHECK_INTERVAL_FREQUENT" + CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALFREQUENT string = "ADVISOR_CHECK_INTERVAL_FREQUENT" + + // CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALRARE captures enum value "ADVISOR_CHECK_INTERVAL_RARE" + CreateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALRARE string = "ADVISOR_CHECK_INTERVAL_RARE" +) + +// prop value enum +func (o *CreateAdvisorCheckOKBodyCheck) validateIntervalEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, createAdvisorCheckOkBodyCheckTypeIntervalPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *CreateAdvisorCheckOKBodyCheck) validateInterval(formats strfmt.Registry) error { + if swag.IsZero(o.Interval) { // not required + return nil + } + + // value enum + if err := o.validateIntervalEnum("createAdvisorCheckOk"+"."+"check"+"."+"interval", "body", *o.Interval); err != nil { + return err + } + + return nil +} + +var createAdvisorCheckOkBodyCheckTypeFamilyPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + createAdvisorCheckOkBodyCheckTypeFamilyPropEnum = append(createAdvisorCheckOkBodyCheckTypeFamilyPropEnum, v) + } +} + +const ( + + // CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED captures enum value "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED string = "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + + // CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMYSQL captures enum value "ADVISOR_CHECK_FAMILY_MYSQL" + CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMYSQL string = "ADVISOR_CHECK_FAMILY_MYSQL" + + // CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL captures enum value "ADVISOR_CHECK_FAMILY_POSTGRESQL" + CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL string = "ADVISOR_CHECK_FAMILY_POSTGRESQL" + + // CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMONGODB captures enum value "ADVISOR_CHECK_FAMILY_MONGODB" + CreateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMONGODB string = "ADVISOR_CHECK_FAMILY_MONGODB" +) + +// prop value enum +func (o *CreateAdvisorCheckOKBodyCheck) validateFamilyEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, createAdvisorCheckOkBodyCheckTypeFamilyPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *CreateAdvisorCheckOKBodyCheck) validateFamily(formats strfmt.Registry) error { + if swag.IsZero(o.Family) { // not required + return nil + } + + // value enum + if err := o.validateFamilyEnum("createAdvisorCheckOk"+"."+"check"+"."+"family", "body", *o.Family); err != nil { + return err + } + + return nil +} + +func (o *CreateAdvisorCheckOKBodyCheck) validateQueries(formats strfmt.Registry) error { + if swag.IsZero(o.Queries) { // not required + return nil + } + + for i := 0; i < len(o.Queries); i++ { + if swag.IsZero(o.Queries[i]) { // not required + continue + } + + if o.Queries[i] != nil { + if err := o.Queries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("createAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("createAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this create advisor check OK body check based on the context it is used +func (o *CreateAdvisorCheckOKBodyCheck) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckOKBodyCheck) contextValidateQueries(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Queries); i++ { + if o.Queries[i] != nil { + + if swag.IsZero(o.Queries[i]) { // not required + return nil + } + + if err := o.Queries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("createAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("createAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckOKBodyCheck) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckOKBodyCheck) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckOKBodyCheck + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +CreateAdvisorCheckOKBodyCheckQueriesItems0 AdvisorCheckQuery is a single data-collection query of an advisor check. +swagger:model CreateAdvisorCheckOKBodyCheckQueriesItems0 +*/ +type CreateAdvisorCheckOKBodyCheckQueriesItems0 struct { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `json:"type,omitempty"` + + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `json:"query,omitempty"` + + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `json:"parameters,omitempty"` +} + +// Validate validates this create advisor check OK body check queries items0 +func (o *CreateAdvisorCheckOKBodyCheckQueriesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this create advisor check OK body check queries items0 based on context it is used +func (o *CreateAdvisorCheckOKBodyCheckQueriesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckOKBodyCheckQueriesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckOKBodyCheckQueriesItems0) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckOKBodyCheckQueriesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +CreateAdvisorCheckParamsBodyCheck AdvisorCheck contains check name and status. +swagger:model CreateAdvisorCheckParamsBodyCheck +*/ +type CreateAdvisorCheckParamsBodyCheck struct { + // Machine-readable name (ID) that is used in expression. + Name string `json:"name,omitempty"` + + // True if that check is enabled. + Enabled bool `json:"enabled,omitempty"` + + // Long human-readable description. + Description string `json:"description,omitempty"` + + // Short human-readable summary. + Summary string `json:"summary,omitempty"` + + // AdvisorCheckInterval represents possible execution interval values for checks. + // Enum: ["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"] + Interval *string `json:"interval,omitempty"` + + // family + // Enum: ["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"] + Family *string `json:"family,omitempty"` + + // Category (top-level grouping). + Category string `json:"category,omitempty"` + + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `json:"user_defined,omitempty"` + + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*CreateAdvisorCheckParamsBodyCheckQueriesItems0 `json:"queries"` + + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `json:"script,omitempty"` +} + +// Validate validates this create advisor check params body check +func (o *CreateAdvisorCheckParamsBodyCheck) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateInterval(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFamily(formats); err != nil { + res = append(res, err) + } + + if err := o.validateQueries(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var createAdvisorCheckParamsBodyCheckTypeIntervalPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + createAdvisorCheckParamsBodyCheckTypeIntervalPropEnum = append(createAdvisorCheckParamsBodyCheckTypeIntervalPropEnum, v) + } +} + +const ( + + // CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED captures enum value "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED string = "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + + // CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALSTANDARD captures enum value "ADVISOR_CHECK_INTERVAL_STANDARD" + CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALSTANDARD string = "ADVISOR_CHECK_INTERVAL_STANDARD" + + // CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALFREQUENT captures enum value "ADVISOR_CHECK_INTERVAL_FREQUENT" + CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALFREQUENT string = "ADVISOR_CHECK_INTERVAL_FREQUENT" + + // CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALRARE captures enum value "ADVISOR_CHECK_INTERVAL_RARE" + CreateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALRARE string = "ADVISOR_CHECK_INTERVAL_RARE" +) + +// prop value enum +func (o *CreateAdvisorCheckParamsBodyCheck) validateIntervalEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, createAdvisorCheckParamsBodyCheckTypeIntervalPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *CreateAdvisorCheckParamsBodyCheck) validateInterval(formats strfmt.Registry) error { + if swag.IsZero(o.Interval) { // not required + return nil + } + + // value enum + if err := o.validateIntervalEnum("body"+"."+"check"+"."+"interval", "body", *o.Interval); err != nil { + return err + } + + return nil +} + +var createAdvisorCheckParamsBodyCheckTypeFamilyPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + createAdvisorCheckParamsBodyCheckTypeFamilyPropEnum = append(createAdvisorCheckParamsBodyCheckTypeFamilyPropEnum, v) + } +} + +const ( + + // CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED captures enum value "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED string = "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + + // CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMYSQL captures enum value "ADVISOR_CHECK_FAMILY_MYSQL" + CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMYSQL string = "ADVISOR_CHECK_FAMILY_MYSQL" + + // CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL captures enum value "ADVISOR_CHECK_FAMILY_POSTGRESQL" + CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL string = "ADVISOR_CHECK_FAMILY_POSTGRESQL" + + // CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMONGODB captures enum value "ADVISOR_CHECK_FAMILY_MONGODB" + CreateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMONGODB string = "ADVISOR_CHECK_FAMILY_MONGODB" +) + +// prop value enum +func (o *CreateAdvisorCheckParamsBodyCheck) validateFamilyEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, createAdvisorCheckParamsBodyCheckTypeFamilyPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *CreateAdvisorCheckParamsBodyCheck) validateFamily(formats strfmt.Registry) error { + if swag.IsZero(o.Family) { // not required + return nil + } + + // value enum + if err := o.validateFamilyEnum("body"+"."+"check"+"."+"family", "body", *o.Family); err != nil { + return err + } + + return nil +} + +func (o *CreateAdvisorCheckParamsBodyCheck) validateQueries(formats strfmt.Registry) error { + if swag.IsZero(o.Queries) { // not required + return nil + } + + for i := 0; i < len(o.Queries); i++ { + if swag.IsZero(o.Queries[i]) { // not required + continue + } + + if o.Queries[i] != nil { + if err := o.Queries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this create advisor check params body check based on the context it is used +func (o *CreateAdvisorCheckParamsBodyCheck) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *CreateAdvisorCheckParamsBodyCheck) contextValidateQueries(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Queries); i++ { + if o.Queries[i] != nil { + + if swag.IsZero(o.Queries[i]) { // not required + return nil + } + + if err := o.Queries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckParamsBodyCheck) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckParamsBodyCheck) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckParamsBodyCheck + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +CreateAdvisorCheckParamsBodyCheckQueriesItems0 AdvisorCheckQuery is a single data-collection query of an advisor check. +swagger:model CreateAdvisorCheckParamsBodyCheckQueriesItems0 +*/ +type CreateAdvisorCheckParamsBodyCheckQueriesItems0 struct { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `json:"type,omitempty"` + + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `json:"query,omitempty"` + + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `json:"parameters,omitempty"` +} + +// Validate validates this create advisor check params body check queries items0 +func (o *CreateAdvisorCheckParamsBodyCheckQueriesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this create advisor check params body check queries items0 based on context it is used +func (o *CreateAdvisorCheckParamsBodyCheckQueriesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *CreateAdvisorCheckParamsBodyCheckQueriesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *CreateAdvisorCheckParamsBodyCheckQueriesItems0) UnmarshalBinary(b []byte) error { + var res CreateAdvisorCheckParamsBodyCheckQueriesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/delete_advisor_check_parameters.go b/api/advisors/v1/json/client/advisor_service/delete_advisor_check_parameters.go new file mode 100644 index 00000000000..9e4e3f8ee2e --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/delete_advisor_check_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewDeleteAdvisorCheckParams creates a new DeleteAdvisorCheckParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewDeleteAdvisorCheckParams() *DeleteAdvisorCheckParams { + return &DeleteAdvisorCheckParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewDeleteAdvisorCheckParamsWithTimeout creates a new DeleteAdvisorCheckParams object +// with the ability to set a timeout on a request. +func NewDeleteAdvisorCheckParamsWithTimeout(timeout time.Duration) *DeleteAdvisorCheckParams { + return &DeleteAdvisorCheckParams{ + timeout: timeout, + } +} + +// NewDeleteAdvisorCheckParamsWithContext creates a new DeleteAdvisorCheckParams object +// with the ability to set a context for a request. +func NewDeleteAdvisorCheckParamsWithContext(ctx context.Context) *DeleteAdvisorCheckParams { + return &DeleteAdvisorCheckParams{ + Context: ctx, + } +} + +// NewDeleteAdvisorCheckParamsWithHTTPClient creates a new DeleteAdvisorCheckParams object +// with the ability to set a custom HTTPClient for a request. +func NewDeleteAdvisorCheckParamsWithHTTPClient(client *http.Client) *DeleteAdvisorCheckParams { + return &DeleteAdvisorCheckParams{ + HTTPClient: client, + } +} + +/* +DeleteAdvisorCheckParams contains all the parameters to send to the API endpoint + + for the delete advisor check operation. + + Typically these are written to a http.Request. +*/ +type DeleteAdvisorCheckParams struct { + /* Name. + + Machine-readable name (ID) of the check to delete. + */ + Name string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the delete advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteAdvisorCheckParams) WithDefaults() *DeleteAdvisorCheckParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the delete advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *DeleteAdvisorCheckParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the delete advisor check params +func (o *DeleteAdvisorCheckParams) WithTimeout(timeout time.Duration) *DeleteAdvisorCheckParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the delete advisor check params +func (o *DeleteAdvisorCheckParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the delete advisor check params +func (o *DeleteAdvisorCheckParams) WithContext(ctx context.Context) *DeleteAdvisorCheckParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the delete advisor check params +func (o *DeleteAdvisorCheckParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the delete advisor check params +func (o *DeleteAdvisorCheckParams) WithHTTPClient(client *http.Client) *DeleteAdvisorCheckParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the delete advisor check params +func (o *DeleteAdvisorCheckParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithName adds the name to the delete advisor check params +func (o *DeleteAdvisorCheckParams) WithName(name string) *DeleteAdvisorCheckParams { + o.SetName(name) + return o +} + +// SetName adds the name to the delete advisor check params +func (o *DeleteAdvisorCheckParams) SetName(name string) { + o.Name = name +} + +// WriteToRequest writes these params to a swagger request +func (o *DeleteAdvisorCheckParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param name + if err := r.SetPathParam("name", o.Name); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/delete_advisor_check_responses.go b/api/advisors/v1/json/client/advisor_service/delete_advisor_check_responses.go new file mode 100644 index 00000000000..801ff8196d8 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/delete_advisor_check_responses.go @@ -0,0 +1,411 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DeleteAdvisorCheckReader is a Reader for the DeleteAdvisorCheck structure. +type DeleteAdvisorCheckReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *DeleteAdvisorCheckReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewDeleteAdvisorCheckOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewDeleteAdvisorCheckDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewDeleteAdvisorCheckOK creates a DeleteAdvisorCheckOK with default headers values +func NewDeleteAdvisorCheckOK() *DeleteAdvisorCheckOK { + return &DeleteAdvisorCheckOK{} +} + +/* +DeleteAdvisorCheckOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type DeleteAdvisorCheckOK struct { + Payload any +} + +// IsSuccess returns true when this delete advisor check Ok response has a 2xx status code +func (o *DeleteAdvisorCheckOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this delete advisor check Ok response has a 3xx status code +func (o *DeleteAdvisorCheckOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this delete advisor check Ok response has a 4xx status code +func (o *DeleteAdvisorCheckOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this delete advisor check Ok response has a 5xx status code +func (o *DeleteAdvisorCheckOK) IsServerError() bool { + return false +} + +// IsCode returns true when this delete advisor check Ok response a status code equal to that given +func (o *DeleteAdvisorCheckOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the delete advisor check Ok response +func (o *DeleteAdvisorCheckOK) Code() int { + return 200 +} + +func (o *DeleteAdvisorCheckOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/advisors/checks/{name}][%d] deleteAdvisorCheckOk %s", 200, payload) +} + +func (o *DeleteAdvisorCheckOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/advisors/checks/{name}][%d] deleteAdvisorCheckOk %s", 200, payload) +} + +func (o *DeleteAdvisorCheckOK) GetPayload() any { + return o.Payload +} + +func (o *DeleteAdvisorCheckOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + // response payload + if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewDeleteAdvisorCheckDefault creates a DeleteAdvisorCheckDefault with default headers values +func NewDeleteAdvisorCheckDefault(code int) *DeleteAdvisorCheckDefault { + return &DeleteAdvisorCheckDefault{ + _statusCode: code, + } +} + +/* +DeleteAdvisorCheckDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type DeleteAdvisorCheckDefault struct { + _statusCode int + + Payload *DeleteAdvisorCheckDefaultBody +} + +// IsSuccess returns true when this delete advisor check default response has a 2xx status code +func (o *DeleteAdvisorCheckDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this delete advisor check default response has a 3xx status code +func (o *DeleteAdvisorCheckDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this delete advisor check default response has a 4xx status code +func (o *DeleteAdvisorCheckDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this delete advisor check default response has a 5xx status code +func (o *DeleteAdvisorCheckDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this delete advisor check default response a status code equal to that given +func (o *DeleteAdvisorCheckDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the delete advisor check default response +func (o *DeleteAdvisorCheckDefault) Code() int { + return o._statusCode +} + +func (o *DeleteAdvisorCheckDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/advisors/checks/{name}][%d] DeleteAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *DeleteAdvisorCheckDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[DELETE /v1/advisors/checks/{name}][%d] DeleteAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *DeleteAdvisorCheckDefault) GetPayload() *DeleteAdvisorCheckDefaultBody { + return o.Payload +} + +func (o *DeleteAdvisorCheckDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(DeleteAdvisorCheckDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +DeleteAdvisorCheckDefaultBody delete advisor check default body +swagger:model DeleteAdvisorCheckDefaultBody +*/ +type DeleteAdvisorCheckDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*DeleteAdvisorCheckDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this delete advisor check default body +func (o *DeleteAdvisorCheckDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteAdvisorCheckDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this delete advisor check default body based on the context it is used +func (o *DeleteAdvisorCheckDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *DeleteAdvisorCheckDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("DeleteAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("DeleteAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteAdvisorCheckDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteAdvisorCheckDefaultBody) UnmarshalBinary(b []byte) error { + var res DeleteAdvisorCheckDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +DeleteAdvisorCheckDefaultBodyDetailsItems0 delete advisor check default body details items0 +swagger:model DeleteAdvisorCheckDefaultBodyDetailsItems0 +*/ +type DeleteAdvisorCheckDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // delete advisor check default body details items0 + DeleteAdvisorCheckDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *DeleteAdvisorCheckDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv DeleteAdvisorCheckDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.DeleteAdvisorCheckDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o DeleteAdvisorCheckDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.DeleteAdvisorCheckDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.DeleteAdvisorCheckDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this delete advisor check default body details items0 +func (o *DeleteAdvisorCheckDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this delete advisor check default body details items0 based on context it is used +func (o *DeleteAdvisorCheckDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *DeleteAdvisorCheckDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *DeleteAdvisorCheckDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res DeleteAdvisorCheckDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/get_advisor_check_parameters.go b/api/advisors/v1/json/client/advisor_service/get_advisor_check_parameters.go new file mode 100644 index 00000000000..598a527add9 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/get_advisor_check_parameters.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewGetAdvisorCheckParams creates a new GetAdvisorCheckParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewGetAdvisorCheckParams() *GetAdvisorCheckParams { + return &GetAdvisorCheckParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewGetAdvisorCheckParamsWithTimeout creates a new GetAdvisorCheckParams object +// with the ability to set a timeout on a request. +func NewGetAdvisorCheckParamsWithTimeout(timeout time.Duration) *GetAdvisorCheckParams { + return &GetAdvisorCheckParams{ + timeout: timeout, + } +} + +// NewGetAdvisorCheckParamsWithContext creates a new GetAdvisorCheckParams object +// with the ability to set a context for a request. +func NewGetAdvisorCheckParamsWithContext(ctx context.Context) *GetAdvisorCheckParams { + return &GetAdvisorCheckParams{ + Context: ctx, + } +} + +// NewGetAdvisorCheckParamsWithHTTPClient creates a new GetAdvisorCheckParams object +// with the ability to set a custom HTTPClient for a request. +func NewGetAdvisorCheckParamsWithHTTPClient(client *http.Client) *GetAdvisorCheckParams { + return &GetAdvisorCheckParams{ + HTTPClient: client, + } +} + +/* +GetAdvisorCheckParams contains all the parameters to send to the API endpoint + + for the get advisor check operation. + + Typically these are written to a http.Request. +*/ +type GetAdvisorCheckParams struct { + /* Name. + + Machine-readable name (ID) of the check. + */ + Name string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the get advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetAdvisorCheckParams) WithDefaults() *GetAdvisorCheckParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the get advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *GetAdvisorCheckParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the get advisor check params +func (o *GetAdvisorCheckParams) WithTimeout(timeout time.Duration) *GetAdvisorCheckParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the get advisor check params +func (o *GetAdvisorCheckParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the get advisor check params +func (o *GetAdvisorCheckParams) WithContext(ctx context.Context) *GetAdvisorCheckParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the get advisor check params +func (o *GetAdvisorCheckParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the get advisor check params +func (o *GetAdvisorCheckParams) WithHTTPClient(client *http.Client) *GetAdvisorCheckParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the get advisor check params +func (o *GetAdvisorCheckParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithName adds the name to the get advisor check params +func (o *GetAdvisorCheckParams) WithName(name string) *GetAdvisorCheckParams { + o.SetName(name) + return o +} + +// SetName adds the name to the get advisor check params +func (o *GetAdvisorCheckParams) SetName(name string) { + o.Name = name +} + +// WriteToRequest writes these params to a swagger request +func (o *GetAdvisorCheckParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + // path param name + if err := r.SetPathParam("name", o.Name); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/get_advisor_check_responses.go b/api/advisors/v1/json/client/advisor_service/get_advisor_check_responses.go new file mode 100644 index 00000000000..975f1ebd614 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/get_advisor_check_responses.go @@ -0,0 +1,806 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// GetAdvisorCheckReader is a Reader for the GetAdvisorCheck structure. +type GetAdvisorCheckReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *GetAdvisorCheckReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewGetAdvisorCheckOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewGetAdvisorCheckDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewGetAdvisorCheckOK creates a GetAdvisorCheckOK with default headers values +func NewGetAdvisorCheckOK() *GetAdvisorCheckOK { + return &GetAdvisorCheckOK{} +} + +/* +GetAdvisorCheckOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type GetAdvisorCheckOK struct { + Payload *GetAdvisorCheckOKBody +} + +// IsSuccess returns true when this get advisor check Ok response has a 2xx status code +func (o *GetAdvisorCheckOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this get advisor check Ok response has a 3xx status code +func (o *GetAdvisorCheckOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this get advisor check Ok response has a 4xx status code +func (o *GetAdvisorCheckOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this get advisor check Ok response has a 5xx status code +func (o *GetAdvisorCheckOK) IsServerError() bool { + return false +} + +// IsCode returns true when this get advisor check Ok response a status code equal to that given +func (o *GetAdvisorCheckOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the get advisor check Ok response +func (o *GetAdvisorCheckOK) Code() int { + return 200 +} + +func (o *GetAdvisorCheckOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/definition][%d] getAdvisorCheckOk %s", 200, payload) +} + +func (o *GetAdvisorCheckOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/definition][%d] getAdvisorCheckOk %s", 200, payload) +} + +func (o *GetAdvisorCheckOK) GetPayload() *GetAdvisorCheckOKBody { + return o.Payload +} + +func (o *GetAdvisorCheckOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetAdvisorCheckOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewGetAdvisorCheckDefault creates a GetAdvisorCheckDefault with default headers values +func NewGetAdvisorCheckDefault(code int) *GetAdvisorCheckDefault { + return &GetAdvisorCheckDefault{ + _statusCode: code, + } +} + +/* +GetAdvisorCheckDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type GetAdvisorCheckDefault struct { + _statusCode int + + Payload *GetAdvisorCheckDefaultBody +} + +// IsSuccess returns true when this get advisor check default response has a 2xx status code +func (o *GetAdvisorCheckDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this get advisor check default response has a 3xx status code +func (o *GetAdvisorCheckDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this get advisor check default response has a 4xx status code +func (o *GetAdvisorCheckDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this get advisor check default response has a 5xx status code +func (o *GetAdvisorCheckDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this get advisor check default response a status code equal to that given +func (o *GetAdvisorCheckDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the get advisor check default response +func (o *GetAdvisorCheckDefault) Code() int { + return o._statusCode +} + +func (o *GetAdvisorCheckDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/definition][%d] GetAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *GetAdvisorCheckDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[GET /v1/advisors/checks/{name}/definition][%d] GetAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *GetAdvisorCheckDefault) GetPayload() *GetAdvisorCheckDefaultBody { + return o.Payload +} + +func (o *GetAdvisorCheckDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(GetAdvisorCheckDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +GetAdvisorCheckDefaultBody get advisor check default body +swagger:model GetAdvisorCheckDefaultBody +*/ +type GetAdvisorCheckDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*GetAdvisorCheckDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this get advisor check default body +func (o *GetAdvisorCheckDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetAdvisorCheckDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get advisor check default body based on the context it is used +func (o *GetAdvisorCheckDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetAdvisorCheckDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("GetAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("GetAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckDefaultBody) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetAdvisorCheckDefaultBodyDetailsItems0 get advisor check default body details items0 +swagger:model GetAdvisorCheckDefaultBodyDetailsItems0 +*/ +type GetAdvisorCheckDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // get advisor check default body details items0 + GetAdvisorCheckDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *GetAdvisorCheckDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv GetAdvisorCheckDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.GetAdvisorCheckDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o GetAdvisorCheckDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.GetAdvisorCheckDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.GetAdvisorCheckDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this get advisor check default body details items0 +func (o *GetAdvisorCheckDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get advisor check default body details items0 based on context it is used +func (o *GetAdvisorCheckDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetAdvisorCheckOKBody get advisor check OK body +swagger:model GetAdvisorCheckOKBody +*/ +type GetAdvisorCheckOKBody struct { + // check + Check *GetAdvisorCheckOKBodyCheck `json:"check,omitempty"` +} + +// Validate validates this get advisor check OK body +func (o *GetAdvisorCheckOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateCheck(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetAdvisorCheckOKBody) validateCheck(formats strfmt.Registry) error { + if swag.IsZero(o.Check) { // not required + return nil + } + + if o.Check != nil { + if err := o.Check.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getAdvisorCheckOk" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getAdvisorCheckOk" + "." + "check") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this get advisor check OK body based on the context it is used +func (o *GetAdvisorCheckOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateCheck(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetAdvisorCheckOKBody) contextValidateCheck(ctx context.Context, formats strfmt.Registry) error { + if o.Check != nil { + + if swag.IsZero(o.Check) { // not required + return nil + } + + if err := o.Check.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getAdvisorCheckOk" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getAdvisorCheckOk" + "." + "check") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckOKBody) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetAdvisorCheckOKBodyCheck AdvisorCheck contains check name and status. +swagger:model GetAdvisorCheckOKBodyCheck +*/ +type GetAdvisorCheckOKBodyCheck struct { + // Machine-readable name (ID) that is used in expression. + Name string `json:"name,omitempty"` + + // True if that check is enabled. + Enabled bool `json:"enabled,omitempty"` + + // Long human-readable description. + Description string `json:"description,omitempty"` + + // Short human-readable summary. + Summary string `json:"summary,omitempty"` + + // AdvisorCheckInterval represents possible execution interval values for checks. + // Enum: ["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"] + Interval *string `json:"interval,omitempty"` + + // family + // Enum: ["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"] + Family *string `json:"family,omitempty"` + + // Category (top-level grouping). + Category string `json:"category,omitempty"` + + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `json:"user_defined,omitempty"` + + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*GetAdvisorCheckOKBodyCheckQueriesItems0 `json:"queries"` + + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `json:"script,omitempty"` +} + +// Validate validates this get advisor check OK body check +func (o *GetAdvisorCheckOKBodyCheck) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateInterval(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFamily(formats); err != nil { + res = append(res, err) + } + + if err := o.validateQueries(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var getAdvisorCheckOkBodyCheckTypeIntervalPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getAdvisorCheckOkBodyCheckTypeIntervalPropEnum = append(getAdvisorCheckOkBodyCheckTypeIntervalPropEnum, v) + } +} + +const ( + + // GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED captures enum value "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED string = "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + + // GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALSTANDARD captures enum value "ADVISOR_CHECK_INTERVAL_STANDARD" + GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALSTANDARD string = "ADVISOR_CHECK_INTERVAL_STANDARD" + + // GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALFREQUENT captures enum value "ADVISOR_CHECK_INTERVAL_FREQUENT" + GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALFREQUENT string = "ADVISOR_CHECK_INTERVAL_FREQUENT" + + // GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALRARE captures enum value "ADVISOR_CHECK_INTERVAL_RARE" + GetAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALRARE string = "ADVISOR_CHECK_INTERVAL_RARE" +) + +// prop value enum +func (o *GetAdvisorCheckOKBodyCheck) validateIntervalEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getAdvisorCheckOkBodyCheckTypeIntervalPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetAdvisorCheckOKBodyCheck) validateInterval(formats strfmt.Registry) error { + if swag.IsZero(o.Interval) { // not required + return nil + } + + // value enum + if err := o.validateIntervalEnum("getAdvisorCheckOk"+"."+"check"+"."+"interval", "body", *o.Interval); err != nil { + return err + } + + return nil +} + +var getAdvisorCheckOkBodyCheckTypeFamilyPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + getAdvisorCheckOkBodyCheckTypeFamilyPropEnum = append(getAdvisorCheckOkBodyCheckTypeFamilyPropEnum, v) + } +} + +const ( + + // GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED captures enum value "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED string = "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + + // GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMYSQL captures enum value "ADVISOR_CHECK_FAMILY_MYSQL" + GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMYSQL string = "ADVISOR_CHECK_FAMILY_MYSQL" + + // GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL captures enum value "ADVISOR_CHECK_FAMILY_POSTGRESQL" + GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL string = "ADVISOR_CHECK_FAMILY_POSTGRESQL" + + // GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMONGODB captures enum value "ADVISOR_CHECK_FAMILY_MONGODB" + GetAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMONGODB string = "ADVISOR_CHECK_FAMILY_MONGODB" +) + +// prop value enum +func (o *GetAdvisorCheckOKBodyCheck) validateFamilyEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, getAdvisorCheckOkBodyCheckTypeFamilyPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *GetAdvisorCheckOKBodyCheck) validateFamily(formats strfmt.Registry) error { + if swag.IsZero(o.Family) { // not required + return nil + } + + // value enum + if err := o.validateFamilyEnum("getAdvisorCheckOk"+"."+"check"+"."+"family", "body", *o.Family); err != nil { + return err + } + + return nil +} + +func (o *GetAdvisorCheckOKBodyCheck) validateQueries(formats strfmt.Registry) error { + if swag.IsZero(o.Queries) { // not required + return nil + } + + for i := 0; i < len(o.Queries); i++ { + if swag.IsZero(o.Queries[i]) { // not required + continue + } + + if o.Queries[i] != nil { + if err := o.Queries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this get advisor check OK body check based on the context it is used +func (o *GetAdvisorCheckOKBodyCheck) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *GetAdvisorCheckOKBodyCheck) contextValidateQueries(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Queries); i++ { + if o.Queries[i] != nil { + + if swag.IsZero(o.Queries[i]) { // not required + return nil + } + + if err := o.Queries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("getAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("getAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckOKBodyCheck) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckOKBodyCheck) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckOKBodyCheck + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +GetAdvisorCheckOKBodyCheckQueriesItems0 AdvisorCheckQuery is a single data-collection query of an advisor check. +swagger:model GetAdvisorCheckOKBodyCheckQueriesItems0 +*/ +type GetAdvisorCheckOKBodyCheckQueriesItems0 struct { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `json:"type,omitempty"` + + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `json:"query,omitempty"` + + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `json:"parameters,omitempty"` +} + +// Validate validates this get advisor check OK body check queries items0 +func (o *GetAdvisorCheckOKBodyCheckQueriesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this get advisor check OK body check queries items0 based on context it is used +func (o *GetAdvisorCheckOKBodyCheckQueriesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *GetAdvisorCheckOKBodyCheckQueriesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *GetAdvisorCheckOKBodyCheckQueriesItems0) UnmarshalBinary(b []byte) error { + var res GetAdvisorCheckOKBodyCheckQueriesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/list_advisor_checks_responses.go b/api/advisors/v1/json/client/advisor_service/list_advisor_checks_responses.go index bb55fdb00b7..dd0395613ef 100644 --- a/api/advisors/v1/json/client/advisor_service/list_advisor_checks_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_advisor_checks_responses.go @@ -548,6 +548,21 @@ type ListAdvisorChecksOKBodyChecksItems0 struct { // family // Enum: ["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"] Family *string `json:"family,omitempty"` + + // Category (top-level grouping). + Category string `json:"category,omitempty"` + + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `json:"user_defined,omitempty"` + + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*ListAdvisorChecksOKBodyChecksItems0QueriesItems0 `json:"queries"` + + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `json:"script,omitempty"` } // Validate validates this list advisor checks OK body checks items0 @@ -562,6 +577,10 @@ func (o *ListAdvisorChecksOKBodyChecksItems0) Validate(formats strfmt.Registry) res = append(res, err) } + if err := o.validateQueries(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -664,8 +683,73 @@ func (o *ListAdvisorChecksOKBodyChecksItems0) validateFamily(formats strfmt.Regi return nil } -// ContextValidate validates this list advisor checks OK body checks items0 based on context it is used +func (o *ListAdvisorChecksOKBodyChecksItems0) validateQueries(formats strfmt.Registry) error { + if swag.IsZero(o.Queries) { // not required + return nil + } + + for i := 0; i < len(o.Queries); i++ { + if swag.IsZero(o.Queries[i]) { // not required + continue + } + + if o.Queries[i] != nil { + if err := o.Queries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list advisor checks OK body checks items0 based on the context it is used func (o *ListAdvisorChecksOKBodyChecksItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListAdvisorChecksOKBodyChecksItems0) contextValidateQueries(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Queries); i++ { + if o.Queries[i] != nil { + + if swag.IsZero(o.Queries[i]) { // not required + return nil + } + + if err := o.Queries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + return nil } @@ -686,3 +770,46 @@ func (o *ListAdvisorChecksOKBodyChecksItems0) UnmarshalBinary(b []byte) error { *o = res return nil } + +/* +ListAdvisorChecksOKBodyChecksItems0QueriesItems0 AdvisorCheckQuery is a single data-collection query of an advisor check. +swagger:model ListAdvisorChecksOKBodyChecksItems0QueriesItems0 +*/ +type ListAdvisorChecksOKBodyChecksItems0QueriesItems0 struct { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `json:"type,omitempty"` + + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `json:"query,omitempty"` + + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `json:"parameters,omitempty"` +} + +// Validate validates this list advisor checks OK body checks items0 queries items0 +func (o *ListAdvisorChecksOKBodyChecksItems0QueriesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list advisor checks OK body checks items0 queries items0 based on context it is used +func (o *ListAdvisorChecksOKBodyChecksItems0QueriesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListAdvisorChecksOKBodyChecksItems0QueriesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListAdvisorChecksOKBodyChecksItems0QueriesItems0) UnmarshalBinary(b []byte) error { + var res ListAdvisorChecksOKBodyChecksItems0QueriesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go b/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go index de970fd7aaa..aa036644b15 100644 --- a/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go +++ b/api/advisors/v1/json/client/advisor_service/list_advisors_responses.go @@ -677,6 +677,21 @@ type ListAdvisorsOKBodyAdvisorsItems0ChecksItems0 struct { // family // Enum: ["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"] Family *string `json:"family,omitempty"` + + // Category (top-level grouping). + Category string `json:"category,omitempty"` + + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `json:"user_defined,omitempty"` + + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0 `json:"queries"` + + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `json:"script,omitempty"` } // Validate validates this list advisors OK body advisors items0 checks items0 @@ -691,6 +706,10 @@ func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0) Validate(formats strfmt.R res = append(res, err) } + if err := o.validateQueries(formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } @@ -793,8 +812,73 @@ func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0) validateFamily(formats st return nil } -// ContextValidate validates this list advisors OK body advisors items0 checks items0 based on context it is used +func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0) validateQueries(formats strfmt.Registry) error { + if swag.IsZero(o.Queries) { // not required + return nil + } + + for i := 0; i < len(o.Queries); i++ { + if swag.IsZero(o.Queries[i]) { // not required + continue + } + + if o.Queries[i] != nil { + if err := o.Queries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this list advisors OK body advisors items0 checks items0 based on the context it is used func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0) contextValidateQueries(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Queries); i++ { + if o.Queries[i] != nil { + + if swag.IsZero(o.Queries[i]) { // not required + return nil + } + + if err := o.Queries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + return nil } @@ -815,3 +899,46 @@ func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0) UnmarshalBinary(b []byte) *o = res return nil } + +/* +ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0 AdvisorCheckQuery is a single data-collection query of an advisor check. +swagger:model ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0 +*/ +type ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0 struct { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `json:"type,omitempty"` + + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `json:"query,omitempty"` + + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `json:"parameters,omitempty"` +} + +// Validate validates this list advisors OK body advisors items0 checks items0 queries items0 +func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this list advisors OK body advisors items0 checks items0 queries items0 based on context it is used +func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0) UnmarshalBinary(b []byte) error { + var res ListAdvisorsOKBodyAdvisorsItems0ChecksItems0QueriesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/update_advisor_check_parameters.go b/api/advisors/v1/json/client/advisor_service/update_advisor_check_parameters.go new file mode 100644 index 00000000000..270439e1ab6 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/update_advisor_check_parameters.go @@ -0,0 +1,163 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + "github.com/go-openapi/strfmt" +) + +// NewUpdateAdvisorCheckParams creates a new UpdateAdvisorCheckParams object, +// with the default timeout for this client. +// +// Default values are not hydrated, since defaults are normally applied by the API server side. +// +// To enforce default values in parameter, use SetDefaults or WithDefaults. +func NewUpdateAdvisorCheckParams() *UpdateAdvisorCheckParams { + return &UpdateAdvisorCheckParams{ + timeout: cr.DefaultTimeout, + } +} + +// NewUpdateAdvisorCheckParamsWithTimeout creates a new UpdateAdvisorCheckParams object +// with the ability to set a timeout on a request. +func NewUpdateAdvisorCheckParamsWithTimeout(timeout time.Duration) *UpdateAdvisorCheckParams { + return &UpdateAdvisorCheckParams{ + timeout: timeout, + } +} + +// NewUpdateAdvisorCheckParamsWithContext creates a new UpdateAdvisorCheckParams object +// with the ability to set a context for a request. +func NewUpdateAdvisorCheckParamsWithContext(ctx context.Context) *UpdateAdvisorCheckParams { + return &UpdateAdvisorCheckParams{ + Context: ctx, + } +} + +// NewUpdateAdvisorCheckParamsWithHTTPClient creates a new UpdateAdvisorCheckParams object +// with the ability to set a custom HTTPClient for a request. +func NewUpdateAdvisorCheckParamsWithHTTPClient(client *http.Client) *UpdateAdvisorCheckParams { + return &UpdateAdvisorCheckParams{ + HTTPClient: client, + } +} + +/* +UpdateAdvisorCheckParams contains all the parameters to send to the API endpoint + + for the update advisor check operation. + + Typically these are written to a http.Request. +*/ +type UpdateAdvisorCheckParams struct { + // Body. + Body UpdateAdvisorCheckBody + + /* Name. + + Machine-readable name (ID) of the check to update. + */ + Name string + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithDefaults hydrates default values in the update advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateAdvisorCheckParams) WithDefaults() *UpdateAdvisorCheckParams { + o.SetDefaults() + return o +} + +// SetDefaults hydrates default values in the update advisor check params (not the query body). +// +// All values with no default are reset to their zero value. +func (o *UpdateAdvisorCheckParams) SetDefaults() { + // no default values defined for this parameter +} + +// WithTimeout adds the timeout to the update advisor check params +func (o *UpdateAdvisorCheckParams) WithTimeout(timeout time.Duration) *UpdateAdvisorCheckParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the update advisor check params +func (o *UpdateAdvisorCheckParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the update advisor check params +func (o *UpdateAdvisorCheckParams) WithContext(ctx context.Context) *UpdateAdvisorCheckParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the update advisor check params +func (o *UpdateAdvisorCheckParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the update advisor check params +func (o *UpdateAdvisorCheckParams) WithHTTPClient(client *http.Client) *UpdateAdvisorCheckParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the update advisor check params +func (o *UpdateAdvisorCheckParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the update advisor check params +func (o *UpdateAdvisorCheckParams) WithBody(body UpdateAdvisorCheckBody) *UpdateAdvisorCheckParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the update advisor check params +func (o *UpdateAdvisorCheckParams) SetBody(body UpdateAdvisorCheckBody) { + o.Body = body +} + +// WithName adds the name to the update advisor check params +func (o *UpdateAdvisorCheckParams) WithName(name string) *UpdateAdvisorCheckParams { + o.SetName(name) + return o +} + +// SetName adds the name to the update advisor check params +func (o *UpdateAdvisorCheckParams) SetName(name string) { + o.Name = name +} + +// WriteToRequest writes these params to a swagger request +func (o *UpdateAdvisorCheckParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + + // path param name + if err := r.SetPathParam("name", o.Name); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/api/advisors/v1/json/client/advisor_service/update_advisor_check_responses.go b/api/advisors/v1/json/client/advisor_service/update_advisor_check_responses.go new file mode 100644 index 00000000000..130cf8f7ff4 --- /dev/null +++ b/api/advisors/v1/json/client/advisor_service/update_advisor_check_responses.go @@ -0,0 +1,1198 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package advisor_service + +import ( + "context" + "encoding/json" + stderrors "errors" + "fmt" + "io" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// UpdateAdvisorCheckReader is a Reader for the UpdateAdvisorCheck structure. +type UpdateAdvisorCheckReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *UpdateAdvisorCheckReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { + switch response.Code() { + case 200: + result := NewUpdateAdvisorCheckOK() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + default: + result := NewUpdateAdvisorCheckDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewUpdateAdvisorCheckOK creates a UpdateAdvisorCheckOK with default headers values +func NewUpdateAdvisorCheckOK() *UpdateAdvisorCheckOK { + return &UpdateAdvisorCheckOK{} +} + +/* +UpdateAdvisorCheckOK describes a response with status code 200, with default header values. + +A successful response. +*/ +type UpdateAdvisorCheckOK struct { + Payload *UpdateAdvisorCheckOKBody +} + +// IsSuccess returns true when this update advisor check Ok response has a 2xx status code +func (o *UpdateAdvisorCheckOK) IsSuccess() bool { + return true +} + +// IsRedirect returns true when this update advisor check Ok response has a 3xx status code +func (o *UpdateAdvisorCheckOK) IsRedirect() bool { + return false +} + +// IsClientError returns true when this update advisor check Ok response has a 4xx status code +func (o *UpdateAdvisorCheckOK) IsClientError() bool { + return false +} + +// IsServerError returns true when this update advisor check Ok response has a 5xx status code +func (o *UpdateAdvisorCheckOK) IsServerError() bool { + return false +} + +// IsCode returns true when this update advisor check Ok response a status code equal to that given +func (o *UpdateAdvisorCheckOK) IsCode(code int) bool { + return code == 200 +} + +// Code gets the status code for the update advisor check Ok response +func (o *UpdateAdvisorCheckOK) Code() int { + return 200 +} + +func (o *UpdateAdvisorCheckOK) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/advisors/checks/{name}][%d] updateAdvisorCheckOk %s", 200, payload) +} + +func (o *UpdateAdvisorCheckOK) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/advisors/checks/{name}][%d] updateAdvisorCheckOk %s", 200, payload) +} + +func (o *UpdateAdvisorCheckOK) GetPayload() *UpdateAdvisorCheckOKBody { + return o.Payload +} + +func (o *UpdateAdvisorCheckOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UpdateAdvisorCheckOKBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +// NewUpdateAdvisorCheckDefault creates a UpdateAdvisorCheckDefault with default headers values +func NewUpdateAdvisorCheckDefault(code int) *UpdateAdvisorCheckDefault { + return &UpdateAdvisorCheckDefault{ + _statusCode: code, + } +} + +/* +UpdateAdvisorCheckDefault describes a response with status code -1, with default header values. + +An unexpected error response. +*/ +type UpdateAdvisorCheckDefault struct { + _statusCode int + + Payload *UpdateAdvisorCheckDefaultBody +} + +// IsSuccess returns true when this update advisor check default response has a 2xx status code +func (o *UpdateAdvisorCheckDefault) IsSuccess() bool { + return o._statusCode/100 == 2 +} + +// IsRedirect returns true when this update advisor check default response has a 3xx status code +func (o *UpdateAdvisorCheckDefault) IsRedirect() bool { + return o._statusCode/100 == 3 +} + +// IsClientError returns true when this update advisor check default response has a 4xx status code +func (o *UpdateAdvisorCheckDefault) IsClientError() bool { + return o._statusCode/100 == 4 +} + +// IsServerError returns true when this update advisor check default response has a 5xx status code +func (o *UpdateAdvisorCheckDefault) IsServerError() bool { + return o._statusCode/100 == 5 +} + +// IsCode returns true when this update advisor check default response a status code equal to that given +func (o *UpdateAdvisorCheckDefault) IsCode(code int) bool { + return o._statusCode == code +} + +// Code gets the status code for the update advisor check default response +func (o *UpdateAdvisorCheckDefault) Code() int { + return o._statusCode +} + +func (o *UpdateAdvisorCheckDefault) Error() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/advisors/checks/{name}][%d] UpdateAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *UpdateAdvisorCheckDefault) String() string { + payload, _ := json.Marshal(o.Payload) + return fmt.Sprintf("[PUT /v1/advisors/checks/{name}][%d] UpdateAdvisorCheck default %s", o._statusCode, payload) +} + +func (o *UpdateAdvisorCheckDefault) GetPayload() *UpdateAdvisorCheckDefaultBody { + return o.Payload +} + +func (o *UpdateAdvisorCheckDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(UpdateAdvisorCheckDefaultBody) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + return err + } + + return nil +} + +/* +UpdateAdvisorCheckBody update advisor check body +swagger:model UpdateAdvisorCheckBody +*/ +type UpdateAdvisorCheckBody struct { + // check + Check *UpdateAdvisorCheckParamsBodyCheck `json:"check,omitempty"` +} + +// Validate validates this update advisor check body +func (o *UpdateAdvisorCheckBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateCheck(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckBody) validateCheck(formats strfmt.Registry) error { + if swag.IsZero(o.Check) { // not required + return nil + } + + if o.Check != nil { + if err := o.Check.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this update advisor check body based on the context it is used +func (o *UpdateAdvisorCheckBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateCheck(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckBody) contextValidateCheck(ctx context.Context, formats strfmt.Registry) error { + if o.Check != nil { + + if swag.IsZero(o.Check) { // not required + return nil + } + + if err := o.Check.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckBody) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateAdvisorCheckDefaultBody update advisor check default body +swagger:model UpdateAdvisorCheckDefaultBody +*/ +type UpdateAdvisorCheckDefaultBody struct { + // code + Code int32 `json:"code,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // details + Details []*UpdateAdvisorCheckDefaultBodyDetailsItems0 `json:"details"` +} + +// Validate validates this update advisor check default body +func (o *UpdateAdvisorCheckDefaultBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateDetails(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckDefaultBody) validateDetails(formats strfmt.Registry) error { + if swag.IsZero(o.Details) { // not required + return nil + } + + for i := 0; i < len(o.Details); i++ { + if swag.IsZero(o.Details[i]) { // not required + continue + } + + if o.Details[i] != nil { + if err := o.Details[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("UpdateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("UpdateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this update advisor check default body based on the context it is used +func (o *UpdateAdvisorCheckDefaultBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateDetails(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckDefaultBody) contextValidateDetails(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Details); i++ { + if o.Details[i] != nil { + + if swag.IsZero(o.Details[i]) { // not required + return nil + } + + if err := o.Details[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("UpdateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("UpdateAdvisorCheck default" + "." + "details" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckDefaultBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckDefaultBody) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckDefaultBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateAdvisorCheckDefaultBodyDetailsItems0 update advisor check default body details items0 +swagger:model UpdateAdvisorCheckDefaultBodyDetailsItems0 +*/ +type UpdateAdvisorCheckDefaultBodyDetailsItems0 struct { + // at type + AtType string `json:"@type,omitempty"` + + // update advisor check default body details items0 + UpdateAdvisorCheckDefaultBodyDetailsItems0 map[string]any `json:"-"` +} + +// UnmarshalJSON unmarshals this object with additional properties from JSON +func (o *UpdateAdvisorCheckDefaultBodyDetailsItems0) UnmarshalJSON(data []byte) error { + // stage 1, bind the properties + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + if err := json.Unmarshal(data, &stage1); err != nil { + return err + } + var rcv UpdateAdvisorCheckDefaultBodyDetailsItems0 + + rcv.AtType = stage1.AtType + *o = rcv + + // stage 2, remove properties and add to map + stage2 := make(map[string]json.RawMessage) + if err := json.Unmarshal(data, &stage2); err != nil { + return err + } + + delete(stage2, "@type") + // stage 3, add additional properties values + if len(stage2) > 0 { + result := make(map[string]any) + for k, v := range stage2 { + var toadd any + if err := json.Unmarshal(v, &toadd); err != nil { + return err + } + result[k] = toadd + } + o.UpdateAdvisorCheckDefaultBodyDetailsItems0 = result + } + + return nil +} + +// MarshalJSON marshals this object with additional properties into a JSON object +func (o UpdateAdvisorCheckDefaultBodyDetailsItems0) MarshalJSON() ([]byte, error) { + var stage1 struct { + // at type + AtType string `json:"@type,omitempty"` + } + + stage1.AtType = o.AtType + + // make JSON object for known properties + props, err := json.Marshal(stage1) + if err != nil { + return nil, err + } + + if len(o.UpdateAdvisorCheckDefaultBodyDetailsItems0) == 0 { // no additional properties + return props, nil + } + + // make JSON object for the additional properties + additional, err := json.Marshal(o.UpdateAdvisorCheckDefaultBodyDetailsItems0) + if err != nil { + return nil, err + } + + if len(props) < 3 { // "{}": only additional properties + return additional, nil + } + + // concatenate the 2 objects + return swag.ConcatJSON(props, additional), nil +} + +// Validate validates this update advisor check default body details items0 +func (o *UpdateAdvisorCheckDefaultBodyDetailsItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this update advisor check default body details items0 based on context it is used +func (o *UpdateAdvisorCheckDefaultBodyDetailsItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckDefaultBodyDetailsItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckDefaultBodyDetailsItems0) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckDefaultBodyDetailsItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateAdvisorCheckOKBody update advisor check OK body +swagger:model UpdateAdvisorCheckOKBody +*/ +type UpdateAdvisorCheckOKBody struct { + // check + Check *UpdateAdvisorCheckOKBodyCheck `json:"check,omitempty"` +} + +// Validate validates this update advisor check OK body +func (o *UpdateAdvisorCheckOKBody) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateCheck(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckOKBody) validateCheck(formats strfmt.Registry) error { + if swag.IsZero(o.Check) { // not required + return nil + } + + if o.Check != nil { + if err := o.Check.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("updateAdvisorCheckOk" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("updateAdvisorCheckOk" + "." + "check") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this update advisor check OK body based on the context it is used +func (o *UpdateAdvisorCheckOKBody) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateCheck(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckOKBody) contextValidateCheck(ctx context.Context, formats strfmt.Registry) error { + if o.Check != nil { + + if swag.IsZero(o.Check) { // not required + return nil + } + + if err := o.Check.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("updateAdvisorCheckOk" + "." + "check") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("updateAdvisorCheckOk" + "." + "check") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckOKBody) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckOKBody) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckOKBody + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateAdvisorCheckOKBodyCheck AdvisorCheck contains check name and status. +swagger:model UpdateAdvisorCheckOKBodyCheck +*/ +type UpdateAdvisorCheckOKBodyCheck struct { + // Machine-readable name (ID) that is used in expression. + Name string `json:"name,omitempty"` + + // True if that check is enabled. + Enabled bool `json:"enabled,omitempty"` + + // Long human-readable description. + Description string `json:"description,omitempty"` + + // Short human-readable summary. + Summary string `json:"summary,omitempty"` + + // AdvisorCheckInterval represents possible execution interval values for checks. + // Enum: ["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"] + Interval *string `json:"interval,omitempty"` + + // family + // Enum: ["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"] + Family *string `json:"family,omitempty"` + + // Category (top-level grouping). + Category string `json:"category,omitempty"` + + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `json:"user_defined,omitempty"` + + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*UpdateAdvisorCheckOKBodyCheckQueriesItems0 `json:"queries"` + + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `json:"script,omitempty"` +} + +// Validate validates this update advisor check OK body check +func (o *UpdateAdvisorCheckOKBodyCheck) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateInterval(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFamily(formats); err != nil { + res = append(res, err) + } + + if err := o.validateQueries(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var updateAdvisorCheckOkBodyCheckTypeIntervalPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + updateAdvisorCheckOkBodyCheckTypeIntervalPropEnum = append(updateAdvisorCheckOkBodyCheckTypeIntervalPropEnum, v) + } +} + +const ( + + // UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED captures enum value "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED string = "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + + // UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALSTANDARD captures enum value "ADVISOR_CHECK_INTERVAL_STANDARD" + UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALSTANDARD string = "ADVISOR_CHECK_INTERVAL_STANDARD" + + // UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALFREQUENT captures enum value "ADVISOR_CHECK_INTERVAL_FREQUENT" + UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALFREQUENT string = "ADVISOR_CHECK_INTERVAL_FREQUENT" + + // UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALRARE captures enum value "ADVISOR_CHECK_INTERVAL_RARE" + UpdateAdvisorCheckOKBodyCheckIntervalADVISORCHECKINTERVALRARE string = "ADVISOR_CHECK_INTERVAL_RARE" +) + +// prop value enum +func (o *UpdateAdvisorCheckOKBodyCheck) validateIntervalEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, updateAdvisorCheckOkBodyCheckTypeIntervalPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *UpdateAdvisorCheckOKBodyCheck) validateInterval(formats strfmt.Registry) error { + if swag.IsZero(o.Interval) { // not required + return nil + } + + // value enum + if err := o.validateIntervalEnum("updateAdvisorCheckOk"+"."+"check"+"."+"interval", "body", *o.Interval); err != nil { + return err + } + + return nil +} + +var updateAdvisorCheckOkBodyCheckTypeFamilyPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + updateAdvisorCheckOkBodyCheckTypeFamilyPropEnum = append(updateAdvisorCheckOkBodyCheckTypeFamilyPropEnum, v) + } +} + +const ( + + // UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED captures enum value "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED string = "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + + // UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMYSQL captures enum value "ADVISOR_CHECK_FAMILY_MYSQL" + UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMYSQL string = "ADVISOR_CHECK_FAMILY_MYSQL" + + // UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL captures enum value "ADVISOR_CHECK_FAMILY_POSTGRESQL" + UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL string = "ADVISOR_CHECK_FAMILY_POSTGRESQL" + + // UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMONGODB captures enum value "ADVISOR_CHECK_FAMILY_MONGODB" + UpdateAdvisorCheckOKBodyCheckFamilyADVISORCHECKFAMILYMONGODB string = "ADVISOR_CHECK_FAMILY_MONGODB" +) + +// prop value enum +func (o *UpdateAdvisorCheckOKBodyCheck) validateFamilyEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, updateAdvisorCheckOkBodyCheckTypeFamilyPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *UpdateAdvisorCheckOKBodyCheck) validateFamily(formats strfmt.Registry) error { + if swag.IsZero(o.Family) { // not required + return nil + } + + // value enum + if err := o.validateFamilyEnum("updateAdvisorCheckOk"+"."+"check"+"."+"family", "body", *o.Family); err != nil { + return err + } + + return nil +} + +func (o *UpdateAdvisorCheckOKBodyCheck) validateQueries(formats strfmt.Registry) error { + if swag.IsZero(o.Queries) { // not required + return nil + } + + for i := 0; i < len(o.Queries); i++ { + if swag.IsZero(o.Queries[i]) { // not required + continue + } + + if o.Queries[i] != nil { + if err := o.Queries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("updateAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("updateAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this update advisor check OK body check based on the context it is used +func (o *UpdateAdvisorCheckOKBodyCheck) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckOKBodyCheck) contextValidateQueries(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Queries); i++ { + if o.Queries[i] != nil { + + if swag.IsZero(o.Queries[i]) { // not required + return nil + } + + if err := o.Queries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("updateAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("updateAdvisorCheckOk" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckOKBodyCheck) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckOKBodyCheck) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckOKBodyCheck + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateAdvisorCheckOKBodyCheckQueriesItems0 AdvisorCheckQuery is a single data-collection query of an advisor check. +swagger:model UpdateAdvisorCheckOKBodyCheckQueriesItems0 +*/ +type UpdateAdvisorCheckOKBodyCheckQueriesItems0 struct { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `json:"type,omitempty"` + + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `json:"query,omitempty"` + + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `json:"parameters,omitempty"` +} + +// Validate validates this update advisor check OK body check queries items0 +func (o *UpdateAdvisorCheckOKBodyCheckQueriesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this update advisor check OK body check queries items0 based on context it is used +func (o *UpdateAdvisorCheckOKBodyCheckQueriesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckOKBodyCheckQueriesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckOKBodyCheckQueriesItems0) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckOKBodyCheckQueriesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateAdvisorCheckParamsBodyCheck AdvisorCheck contains check name and status. +swagger:model UpdateAdvisorCheckParamsBodyCheck +*/ +type UpdateAdvisorCheckParamsBodyCheck struct { + // Machine-readable name (ID) that is used in expression. + Name string `json:"name,omitempty"` + + // True if that check is enabled. + Enabled bool `json:"enabled,omitempty"` + + // Long human-readable description. + Description string `json:"description,omitempty"` + + // Short human-readable summary. + Summary string `json:"summary,omitempty"` + + // AdvisorCheckInterval represents possible execution interval values for checks. + // Enum: ["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"] + Interval *string `json:"interval,omitempty"` + + // family + // Enum: ["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"] + Family *string `json:"family,omitempty"` + + // Category (top-level grouping). + Category string `json:"category,omitempty"` + + // Subcategory (second-level grouping within a category). + Subcategory string `json:"subcategory,omitempty"` + + // True if the check is user-authored (editable/deletable); false for Percona-shipped checks. + UserDefined bool `json:"user_defined,omitempty"` + + // Data-collection queries. Populated by Get/Create/Update; may be empty in list responses. + Queries []*UpdateAdvisorCheckParamsBodyCheckQueriesItems0 `json:"queries"` + + // Starlark source script. Populated by Get/Create/Update; may be empty in list responses. + Script string `json:"script,omitempty"` +} + +// Validate validates this update advisor check params body check +func (o *UpdateAdvisorCheckParamsBodyCheck) Validate(formats strfmt.Registry) error { + var res []error + + if err := o.validateInterval(formats); err != nil { + res = append(res, err) + } + + if err := o.validateFamily(formats); err != nil { + res = append(res, err) + } + + if err := o.validateQueries(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var updateAdvisorCheckParamsBodyCheckTypeIntervalPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_INTERVAL_UNSPECIFIED","ADVISOR_CHECK_INTERVAL_STANDARD","ADVISOR_CHECK_INTERVAL_FREQUENT","ADVISOR_CHECK_INTERVAL_RARE"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + updateAdvisorCheckParamsBodyCheckTypeIntervalPropEnum = append(updateAdvisorCheckParamsBodyCheckTypeIntervalPropEnum, v) + } +} + +const ( + + // UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED captures enum value "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALUNSPECIFIED string = "ADVISOR_CHECK_INTERVAL_UNSPECIFIED" + + // UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALSTANDARD captures enum value "ADVISOR_CHECK_INTERVAL_STANDARD" + UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALSTANDARD string = "ADVISOR_CHECK_INTERVAL_STANDARD" + + // UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALFREQUENT captures enum value "ADVISOR_CHECK_INTERVAL_FREQUENT" + UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALFREQUENT string = "ADVISOR_CHECK_INTERVAL_FREQUENT" + + // UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALRARE captures enum value "ADVISOR_CHECK_INTERVAL_RARE" + UpdateAdvisorCheckParamsBodyCheckIntervalADVISORCHECKINTERVALRARE string = "ADVISOR_CHECK_INTERVAL_RARE" +) + +// prop value enum +func (o *UpdateAdvisorCheckParamsBodyCheck) validateIntervalEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, updateAdvisorCheckParamsBodyCheckTypeIntervalPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *UpdateAdvisorCheckParamsBodyCheck) validateInterval(formats strfmt.Registry) error { + if swag.IsZero(o.Interval) { // not required + return nil + } + + // value enum + if err := o.validateIntervalEnum("body"+"."+"check"+"."+"interval", "body", *o.Interval); err != nil { + return err + } + + return nil +} + +var updateAdvisorCheckParamsBodyCheckTypeFamilyPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["ADVISOR_CHECK_FAMILY_UNSPECIFIED","ADVISOR_CHECK_FAMILY_MYSQL","ADVISOR_CHECK_FAMILY_POSTGRESQL","ADVISOR_CHECK_FAMILY_MONGODB"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + updateAdvisorCheckParamsBodyCheckTypeFamilyPropEnum = append(updateAdvisorCheckParamsBodyCheckTypeFamilyPropEnum, v) + } +} + +const ( + + // UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED captures enum value "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYUNSPECIFIED string = "ADVISOR_CHECK_FAMILY_UNSPECIFIED" + + // UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMYSQL captures enum value "ADVISOR_CHECK_FAMILY_MYSQL" + UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMYSQL string = "ADVISOR_CHECK_FAMILY_MYSQL" + + // UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL captures enum value "ADVISOR_CHECK_FAMILY_POSTGRESQL" + UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYPOSTGRESQL string = "ADVISOR_CHECK_FAMILY_POSTGRESQL" + + // UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMONGODB captures enum value "ADVISOR_CHECK_FAMILY_MONGODB" + UpdateAdvisorCheckParamsBodyCheckFamilyADVISORCHECKFAMILYMONGODB string = "ADVISOR_CHECK_FAMILY_MONGODB" +) + +// prop value enum +func (o *UpdateAdvisorCheckParamsBodyCheck) validateFamilyEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, updateAdvisorCheckParamsBodyCheckTypeFamilyPropEnum, true); err != nil { + return err + } + return nil +} + +func (o *UpdateAdvisorCheckParamsBodyCheck) validateFamily(formats strfmt.Registry) error { + if swag.IsZero(o.Family) { // not required + return nil + } + + // value enum + if err := o.validateFamilyEnum("body"+"."+"check"+"."+"family", "body", *o.Family); err != nil { + return err + } + + return nil +} + +func (o *UpdateAdvisorCheckParamsBodyCheck) validateQueries(formats strfmt.Registry) error { + if swag.IsZero(o.Queries) { // not required + return nil + } + + for i := 0; i < len(o.Queries); i++ { + if swag.IsZero(o.Queries[i]) { // not required + continue + } + + if o.Queries[i] != nil { + if err := o.Queries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this update advisor check params body check based on the context it is used +func (o *UpdateAdvisorCheckParamsBodyCheck) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := o.contextValidateQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (o *UpdateAdvisorCheckParamsBodyCheck) contextValidateQueries(ctx context.Context, formats strfmt.Registry) error { + for i := 0; i < len(o.Queries); i++ { + if o.Queries[i] != nil { + + if swag.IsZero(o.Queries[i]) { // not required + return nil + } + + if err := o.Queries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("body" + "." + "check" + "." + "queries" + "." + strconv.Itoa(i)) + } + + return err + } + } + } + + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckParamsBodyCheck) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckParamsBodyCheck) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckParamsBodyCheck + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} + +/* +UpdateAdvisorCheckParamsBodyCheckQueriesItems0 AdvisorCheckQuery is a single data-collection query of an advisor check. +swagger:model UpdateAdvisorCheckParamsBodyCheckQueriesItems0 +*/ +type UpdateAdvisorCheckParamsBodyCheckQueriesItems0 struct { + // Query type, e.g. "MYSQL_SHOW", "POSTGRESQL_SELECT", "METRICS_RANGE". + Type string `json:"type,omitempty"` + + // Query text (may be empty for parameterless types such as MYSQL_SHOW). + Query string `json:"query,omitempty"` + + // Optional query parameters (e.g. range/step for metrics range queries). + Parameters map[string]string `json:"parameters,omitempty"` +} + +// Validate validates this update advisor check params body check queries items0 +func (o *UpdateAdvisorCheckParamsBodyCheckQueriesItems0) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this update advisor check params body check queries items0 based on context it is used +func (o *UpdateAdvisorCheckParamsBodyCheckQueriesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (o *UpdateAdvisorCheckParamsBodyCheckQueriesItems0) MarshalBinary() ([]byte, error) { + if o == nil { + return nil, nil + } + return swag.WriteJSON(o) +} + +// UnmarshalBinary interface implementation +func (o *UpdateAdvisorCheckParamsBodyCheckQueriesItems0) UnmarshalBinary(b []byte) error { + var res UpdateAdvisorCheckParamsBodyCheckQueriesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *o = res + return nil +} diff --git a/api/advisors/v1/json/v1.json b/api/advisors/v1/json/v1.json index 8568f2a4539..f5dee514383 100644 --- a/api/advisors/v1/json/v1.json +++ b/api/advisors/v1/json/v1.json @@ -113,6 +113,55 @@ "ADVISOR_CHECK_FAMILY_MONGODB" ], "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 } } }, @@ -221,6 +270,55 @@ "ADVISOR_CHECK_FAMILY_MONGODB" ], "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 } } }, @@ -261,6 +359,265 @@ } } } + }, + "post": { + "description": "Creates a new user-authored advisor check.", + "tags": [ + "AdvisorService" + ], + "summary": "Create Advisor Check", + "operationId": "CreateAdvisorCheck", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } } }, "/v1/advisors/checks/failed": { @@ -902,6 +1259,489 @@ } } }, + "/v1/advisors/checks/{name}": { + "put": { + "description": "Updates an existing user-authored advisor check. Percona-shipped checks cannot be modified.", + "tags": [ + "AdvisorService" + ], + "summary": "Update Advisor Check", + "operationId": "UpdateAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check to update.", + "name": "name", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Deletes a user-authored advisor check. Percona-shipped checks cannot be deleted.", + "tags": [ + "AdvisorService" + ], + "summary": "Delete Advisor Check", + "operationId": "DeleteAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check to delete.", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/advisors/checks/{name}/definition": { + "get": { + "description": "Returns a single advisor check by name, including its queries and script.", + "tags": [ + "AdvisorService" + ], + "summary": "Get Advisor Check", + "operationId": "GetAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check.", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks/{name}/script": { "get": { "description": "Returns the source script of a single advisor check by name.", diff --git a/api/alerting/v1/alerting.pb.go b/api/alerting/v1/alerting.pb.go index 3b2c47d73ec..532745138f2 100644 --- a/api/alerting/v1/alerting.pb.go +++ b/api/alerting/v1/alerting.pb.go @@ -35,7 +35,7 @@ const ( TemplateSource_TEMPLATE_SOURCE_UNSPECIFIED TemplateSource = 0 // Template that is shipped with PMM Server releases. TemplateSource_TEMPLATE_SOURCE_BUILT_IN TemplateSource = 1 - // Template that is downloaded from check.percona.com. + // Template that is downloaded from check.percona.com. Deprecated. TemplateSource_TEMPLATE_SOURCE_SAAS TemplateSource = 2 // Templated loaded from user-suplied file. TemplateSource_TEMPLATE_SOURCE_USER_FILE TemplateSource = 3 diff --git a/api/alerting/v1/json/client/alerting_service/list_templates_responses.go b/api/alerting/v1/json/client/alerting_service/list_templates_responses.go index 44ee5384edf..25bfff37103 100644 --- a/api/alerting/v1/json/client/alerting_service/list_templates_responses.go +++ b/api/alerting/v1/json/client/alerting_service/list_templates_responses.go @@ -563,7 +563,7 @@ type ListTemplatesOKBodyTemplatesItems0 struct { // TemplateSource defines template source. // // - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases. - // - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com. + // - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com. Deprecated. // - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file. // - TEMPLATE_SOURCE_USER_API: Templated created via API. // Enum: ["TEMPLATE_SOURCE_UNSPECIFIED","TEMPLATE_SOURCE_BUILT_IN","TEMPLATE_SOURCE_SAAS","TEMPLATE_SOURCE_USER_FILE","TEMPLATE_SOURCE_USER_API"] diff --git a/api/alerting/v1/json/v1.json b/api/alerting/v1/json/v1.json index 3e38a2987c6..e2a8a86e8b9 100644 --- a/api/alerting/v1/json/v1.json +++ b/api/alerting/v1/json/v1.json @@ -409,7 +409,7 @@ "x-order": 7 }, "source": { - "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API.", + "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com. Deprecated.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API.", "type": "string", "default": "TEMPLATE_SOURCE_UNSPECIFIED", "enum": [ diff --git a/api/descriptor.bin b/api/descriptor.bin index 46037448203d467f1a37b88711815305ab1697f2..b2b517645641eb69272c9f6a8958eec4dc21c0a0 100644 GIT binary patch delta 12484 zcmbta33OG}xxRb5O8QwDU*U#WU|%~LvoQkV-j)`EmhYQ zEm8+&@l*vB!2to$A|Mp0QXGmrMT%CQ)%pq#Yf-QjX=@+a@85f$dzm`C^|Dshy5HXW z`=>qp|32qDyu1JZP9JdFkHnAU^Yr~|%o#|N3P@s(&TJ_b? z%C>mPZK8k4HCNX4`Qea0S4_Ox{OH%`TNAJDRTDf>PrEvKF(+DI*Pghp1vX~~of1?r zGOA2>lO2=799U^Zfs68l;mJYbezj=!*!E)wv)}CHztxLj&iU9675Gj7JN0C%1^t{DL$@!Tq4=p(wt0q zeVwd&o)hJ{+rLz4J!711th&f49oCkBgGb98mw=_o_LEc345=48v6E5%ncA9=d#zJ? zX=}sD)h_tscMH3ut>$$ST79(YlhOZ~>UgNSuTwfa(S((Dw8tun@p312VpkZ*^`oz& zMR{^d+4@i0DcdRXJ`+yojK>JnlZPBYL7;_61 zrtXlAcj6j2&ioSxoZS4AjWgyygegmUUG<2J`Axi~Vpr;B*x&3Ye$bd~=ZX1eUif1Y zZS^h9b$yak8e3c8q?+EOUtibU+|uq(O87UlG&D|bOf+bRE8%b~7L2`x3U~suQ{I=D zwi6fWaekjT;N*UvY@G3X7W|&#b=4!%eoxfPb&PK2dHer)+n{!$akjkIQJ&^r`1S(f zWP4eW$d?qNWO>veqt1B8V#L6UjX2-edN{xJ z_7k<&)%sNzUp{{9MH9!5yyUW~-hS1XOU6&QVB84RG~%KW!zOU!#Umz+8#QeF#BoDL zUofI7`0H#sts&}6P@rj=v=DQNe10xBmGNSIVyEcCN60ONx!G^ ztF5m2x>%pUn3RlHhm1`o4;fz;*<8&7sr4;%Ic_gkEwqI*LmSi@>@Gtlo-+uA73q zsnK4wy!>v;32h_pC(6p**gR;Q7S$1_w z6$@%_4(86KLa?&Hy1B3{90%6T6`>3p18;?WIw}xxYf!d;POG)Sxiu%>aBOgH?OJG1 zHaID8Mkr0$073f#8kWiiCzXyvHaIE7K~G^c%d@5ng#SMj2@?ub61z&rzj3nPJ|$tY zAa?b!$4$>fLt}g0q^3k)b&&9{QwRBz>za}YwOGw*n>y~e#qKb=1#8PL2qBJ?>7uCE zz#Pl7?hw*(rYOsD6zUbb!XJK;69si$tv{xvwWA4DO#>%vWcj{2zoq)>JTb^WWb&QX3Y?&@N==-vpoC9A`%GUxDM4=SZLOd zMN|*X;{9&j%_d(DlK~k82jlB^AaNoH>Bqs+^0l(6VjMeo#an4f@?jBdd7igCgpy zk+xcAi^6~cde)-g!TYFp3coROQMkkaA#+i<#B3>G@M1PN7X||=RA!{|0$VIxy_nId zdb<>by^yq6l*SB{aODw!Gy7B}2@3`&rzTdWeGaClsNhoLxXlRz{W!-ts(_I7h)@SP zJoW6yMC5V3r7Rq&)?*^tO^wW!5g5FT4ITtFfIz{zg>=@{_ziQH30F@nAc)I^r(+8U z70X17bAYs>p8ceVJZ)4&G4e?ftx_tYO3rc)=Cx1(=vm8y3-70^QuvLL%fqz;2${=y z?KqH$V{@g5RP#AtTrFa8|qi{`d}@tXa7`0)*3A?wER>=^-`EZS(8*-oLHNtXpJ$t=~Y&3FnA$Prqc2@@GD!Ch2E}lAAfS$D>I22I-@%W9A z8^S{q5HdFiuRzJn^XyF`@^d3I4&X zuZYO&EH#B0?u?sOgRJ3JJdrEv;8p~(sqQ?2ME18!b2%v3M~7bY%-T*fC`nyDpfGGBy*wkGxz+o zY#dW5(9JA@4&ggPr##PoM?`*Yobn+0oiJ3M3e~$|r~o|+NQVjtW8V#>0z&G$q0|D; z-Yp`(F;WXechA}#u8jf}s`tZC0eTkDKMs|?DjIh%9D3gmLj?%E?{ld5$m!}?ABsqK zb>wu#xDVME?kM!Ek3^(GbrhoGBN5dHUy*13PDJ(^ON%&EzY|eie-)|2Xis<;0eTjY z&M`okl|91s)LsFE*gc{^=L$gBwMVF;T3W@Py-!4bZ?qI++@2N5|%Iaz{ne-P1X)luqMpNdG0>L^9W zr#u(Dhhv_7Ktw(_cE!+jAQc)GQ-&Q34FmKnAYFU{!LEbCjVnU{!96G{^!W-1yAFyT zJ(ZR+&;FB${MBeF!^l5{r(2m)a)^}-z}f}`@lbH!0qWZTfCP3(xVokS1oM!{*9q1P z6>)t`0-_2!Bq|3x`MCcvTpi`I>X7iyQ#O{V+$&cmBXyRg-3U}3eOQCv(>E-(6f#N z(;uRmf%uJ)M?_T11cb~Z;r*sudHW3$Pl0)Wp7o6go?S)Vz+~6I$uQaVZ!%1YYGb-Y z2;+(g$EM4mb`h1FQ7*aQnJ!&j4go^YbXlyY2M~g$OXTK8xE1&888Wg?1~)IF`sz4F z&X6YG#g$t#rOC~Jo;6bjVlfRE2!Nq8Wsa-j3<#k!WhY&b#g$)oF_SMufSz@i45lom zNno;HcS%#_0)ly$G*xa~@`T;P%+nMTe%&L3uNTuPV6vQhq?sQ;Fz=D(t{9iR#%3{d zm|~)HmJGiCFr5b`m+iAMI=O70mC?y{`5b0mshEiD92snTn7#)l*W`1gxvBtyIY*kS zN?hVzZ_SgYv;<_t&jWl_(W3$EdD0YWSH1MK(W|a z{)B0*!Ke4qz@Xm~WDUYVhzT-c_$m`*#NBnAfw>irBrh^0GLZ=(u|7fm)Mz|dx0DK@oQu83GiG;&h{rQ#cY%l}Sp?t1 zH2~|Fr%b7V^G4mM(P0MH$m|SozmpS@)0R(foEY(MJ zTzX)xVCMG}(_<8TvW&)p$yLpYjI|z^D>Bv=AXKZQEOB}$W&xw1`EjaB#bp7Qt7K^y zssb=qWkS^z%+(SPRx1<}#RpJTtc#D=J{?W%epB6~L{s=|CoZ`lSuKlnZ2<^jt7T;< zyAZ;jld?=5=5dLFMLs8k{3oay9&pL>oGcILs1VfW(Z8Nq4&PpqNpx^9kyG3HrcXD`TO~VldaTPEJb| zp8bN1ykpW*1xCIgqk3e8%IF(8NAM;E^sJ3CIQRh7HUPlXjnZUvKrlB-lhFa8W1}<~ z9T3OFMrkrSL!Hq#N|VtmR7T&#s(7&i;@%Ye_DMPmnmD6x%4p)_f0HyB9lg-BNt%of z2u+)$$>jaOy4PW6BwzRIay6FFHnh{zhR2RA-VBS7S&@p^dL z1A_Q^c-mK}q_K^O{OAb~*SO%o(=-%BP7~Y0vl>Q_(? z5IH?;4^uKAh}&h?kjUxb&CDz#J-ivbxI)b`XNNa4v&`AyO!YG5Y7T1q<5NJ?^)-6BqO!zy5wWvM>499y>7TH z%E-qi2;I>2I~nb*mU%aI?CoWf>R}R~XYCE{e}*Ow#c#~&UTGf00fM+!dipv62<3aj z@~oRW)Aq3(e%c0zyJB$GYP#xb{Dz!;895xHebUnj1-+27Pgd$@Y*n89iHsaDrdDC( zCla?o-jP+x)cvf2s~|wn+8=zrnodvQH&pBoRRDsxUwXQH0)&eF;RXf7mfSC6!_-BH z;p!;o+WoR@sL{k0f5xea6HFC515^;JMvAP%mkaH9W#Z#$ND|*g;00~)=(FUVhhb`* zNm_u=`kBOAH@@Und)DVN(nC#7HO74|@lbD)BkhQ1e<34Z2A@Amb>0^;TEuT|?FhWH zzm)QCLH%6f)t2RUESfK6X@9nqA(VV6&%G>!SYU^xHJn}JUhCOyo2t0U9p=E0 zbQ6Remi|zuvle1`_MfHo6&%iYvelsZc(nRw>3$`%@EWpT)U<*27io9rx0j{`>i;V3 zNnGloMR@iRDes`5;ioh@bwt`~2Dk&vBeF;>I)cLI@uTUn{4QlxYm)p z2XF1yAl5U;R^=#nfH{LI&M{{4cAG&LOb#KezLV0imd5HkDIIIw1R-})I@UM>?3rZU zowiykt7npXx3YR5N0!?_`!U%AjMdx%^>>kdxsy;rSjnR=ke-t z7TM}xgcO2^SyX+#u~*&WXlzFaVg78g#+s!<#{Ajjjxj;kO%O7h{7X#GQ5V>A$eN!v zAHNawIpoe)=AX{ya~o)L$^I6khb`n~%_Dn`aIRAJL(oE!4^z;wmaa%GBwIZo0owv~ zA(fqJ?BqgVAq~0O7=VJpzMrfIU_gOdblD#OL9lWJlLGn2Yez6|2vx00@mmwH7s4J+X zpP3ylnpV)D2_b}yE6F;?EGpY9s+HspGG^;02w6$~w@nc6y3JmN)s~(FTUot|+-H^5 z>ipq0(4HZ?#_S1hf%?^C4>oHGubkG9+(^Op7hv@ovQ_yAtFyseL*-{1Gr3}0L&L5O zA*^0Y)`iCEY-9CWaz`1fbrXcFC4Z!`IvZB6BWpw2>TG58I&wECtNZfW;Wp6LlYOeO znp>d$1+vFFW7X2Z{@FxwOR#GLjY(}nd2P&M;wCCk7ZiwM)+RcAMA!?XUnJ`cV|3IQ z{UW&ojnTRZLS7_)fH67>qc@ZFa@y#qGI}$)FK3MAHqd@fc7-vTTcG|W-qHH_$?@#1 zB>ywmxe?2KE7|I?0j$gcaVy0J8Y{U{-AaS6FzWG%g8d3vuS31wy*XyNze4WoFhK8K z-3b3)CA-ftZCLKFWtKZj`z2Z1Q)zEAhCG0t!c%zA_D3H(AI zWAJM4Et2ozEWMIHgBWtur@<)6{^ggBsekWNNA(p4YeW8ji_*E#fpu?DIyZ8O{uZTk zqk}NKP1a~L&5oJox5>TOM8>gFoaG_qZSpTNfdsOpH zbVlbEsNY5QHT(t)w&Hc4`*gpW^UQpbH5Y+jQgD*xtZ zmSJr8PP8Wzn_SqjCledKBJIh&jF1x6&Q-> zx`qfeG7*8n4Mif2x|Eg3TO&jikwOP4Wso96Ei#NUlp-rKmc^i!`F{KCb8q`c*1F%` z`}=<1e*X48`MQ2s^M4L~>S^&b?U4WYAg$|YzyCowC|=Sjyuw?j{mZO5vmYBbbNbYW zSAB6;N^h7Zf770sA%92hg%8VhMYJ^8zVT^ zox}rfl3352y!zacfDZ|fF8J3_6Li=nwf~g z5?C`UDlJQb^$=JC3=35c>4z7)*MY@mA4-%&?YOEe(ojwy>!{qj&af1KKD}1fW+f@G z>MD9#7J4u1s%tEYgY_sSy(+^(;72KwF3gM{o0&2Bky&*M26<6Kh&-C=8X<^0+M}oE zV>DF||7q+gAw18MievrMEjG;*4`-R2gRVRTdB6amPkPexFUpMm(Rw+0B9A)CL7I~& zib&9&Q&Jis7bxiM6?qP~bh)yu)>aA_o(K7xjXYH5>5J>-2rJ7oGtZ8(BA%Ifc8q}_ zJFjYhl@%;IFWukD^0du|>@XvXX`8PfZgL-?0D|oN)OA*tSayDS zUn|S=x&X4g8Wi&u=&ze)Un|RVyC5ekxjH8+A-fC zL69tYUJpaW3d&MVx-?_=YGx{L);V_NC~~-gUtxnf(9Kr%h!AwMy{f(MV;#iIee1fjGCs02Z*k=8V5*eg7|5DaWi1VgK zC3adE6;ljowi;n~I?F`tS!@#@+XSPamI=3)Y3Wc5{+ig|D5wGg=}e0pISIevu1WY| zPXIw|5xvHJ-^00wHM-q9i-$l^Cz zt`t}#Y#R`oD+N}G2TeCnt3|BFn0C=_HO~eIO9YM0#!QdPr~$PO*GzsfdZ;A z`al@MH3AEQ!zI3N!mkln5(b;_YXsH=NAUt@orpEtC?2A$6K<_(>6tFA=PuodE&&E= zy*~A_96kZR(QL-I5PU_r;gl2w&Z{D}(Z(u5)vLnoW?~hY zQF<*JCBQ%dg=-xMqx72agQzX2uVqD9xM)$0@UID+z}%xQfzv8tuiGeH(6lw0_%0?& zTNDK_P(arkSs+Ad6Mi@~fS|UC+HXa*2+}47VkaX=aiFrBMXZnMWHB0U7H*BHDGAh8 z5vw&7C8*fS3xR!=2F`X7d&BxFMb-AmSE=!}Bk~0pD4>2OG7x<25PtUvg1STWxILVC zRKwT~(f2wNB?z2$5qrl*3DC4%xZ!FFOq87*h0k)pK5%9OIRG2^MlUyExBLlo@ULe8_ZgDBi>Yp9LL4|Dn+xI+K?c z3edbG9}d|Gur!=d)FNC5PpEB-a2+CZiw!4ixDL^4jBSAfTkYnR+SP=^NwixJZj}{x z2j(2wEfQr>OGxh)<$MB@Dhr%FB6h%zRvAp}5pEc@%#6rhK?UX#0T`&gLO-%w)(itc z)4jqCMFAnYmqpocnd#g)+Rvlb-4M|Ypqg}X z#$5R_k4>L5uWs%f&xYaScfat%!@10Kbib$w=Lite`}ydYg^nfz=b(tuS3)mulT&Mw zaB(nN7fI98L($m*7^p)+r(T!Ch6AAKA(8M+OhBj}5?#WLpENx^%*=m+VZcBg7W#?T z<&+x%46-LFAee{wB;_$m63^HXX7)EsbQP#F-Cd7aEi3h)P0~Yf7CaKo9Uvr*M5C1? zUUElSVw{mc}dN9_qn9&RH+4bsam-op zM82;Mm?!dmEdcW*Gx>g!qyk2I(!a@@ZVi<=!JQO|Xmks}J}D}zY+M)YkMnG7C!lnC zWai!l|2$oHZj~d^an5KT=Ou8j0?bJyAaRN%`0Pkhf{{*dm4m?Kgm+5dx)yp#fO$%k zMP58GPcw6bVS0@86ICQ{O;LjQQ190w-nq)+p13&H#}@3sicv&_85FpC)JqubJcnU5w;@1Adg69ji@m^U=$z;pUU2}yJSS@V*a0g> z%<~+R56dJWxd4@?2kP02-R}C}cA0_%XPNVP+r^MLpSN8Ci3=<-+DIS^0j1M}^$@I0 z-S#Kp>M=WH5jw$1=|X_vy72m^ajq$B=MPiNmNAx zR|e*#{J6!iqGzO? zg4kug3G<^dNvS~5Wube&DQnP!6sVU)w`j&vpk5aJ`di_0^!JUguZnaOvjWVk9FsFwDsa9L zv0qSlgJyT%2sdn*GI{=5l;;5hbuN8o%fz9)P2v<)w&jTV{J=r|ZFbr2uHqWO_)@Z=P z((8@k0>q0*Kl_&KmBnvJH;~QqfRJt=o03x`;d3$jtTsec0$ra@W^SKVH+TADnJEi0 zv**p7I{T67cC~L7vuBmS6sADF+Chg{WJ);;#ZcHhuE6 z%$&KC=jLN@B3erJxs@`xXDOA0=N}+qEG0Z>Obp`O(@0pLobOVcdw_bUM_{$K5K006|y8zLroxuy;|7DUcD%aKfM z2+ldnDHWbDDdL>7f{A=b00h$WJ7ixFIpwS%o8JLJTtUf*$SG%4ewiTUtkVC{A$x(y z8D~{~nQ+EgMdjg zhEItUasJV4Ak;zr(RvAVV1Uz)&O7Jyqw~&-U|?;2KOz0B)hFJ@<2OY`FtC>VXgW9< zt)-eMA}6D@G<3K*9m)ge1&Y07PX|7MULd!x8RT+v0yLAo*8&ErS=a5BwZrinEt|<+ zYXPCz9POcUvzIq8k*~FYcq@|rycNR=U{H?98+${Z$@kh8?p4Mxv29y);_c@!9wax#3}0iH9Y{+H7|#QS~ah{5dPG zD$QZIkz-FqY`{PP)uw-#89!@|-u{lfZ!8KiT^q@MR{(^jcg zyoE#Xl?gCVTeR9EhfKq7gxC^=00eOh1>s!_5FxfiI}Z?hZ40HxnTHd@%`T_nE!1_a zjl_<(VG>OKsp8IT(`)z0fur%80olX_2!yR$c=pe=YRkd5tGUP@=fOy>2qGPn8S52?A}Vm+CiO0QRq7R(Mk`$|^53PnSKwV-OFs_HQM=k^HSLA%ly5gk*YrMt}0StkBQBFGpq%l4EYFP~p6Jkb2x?{qiO|NZ*|iLD>Hw zKj>ube~=&aum~a_kS{>>nckw|VEd`OwQ?daov;2b0MQO>?J_K%VOk+DC7N1w|;`yDyohI&*YgZOcBmJ9Cz;~zpN ziT;~(~-G?kDNiN!9@F56=(=Y?o?@a4Ia z=rZY#4q$dV$uV~=42A=0Cshu%v%`0vP8xM@1mW=uQa9N}<=92_1^J__?XUd zb`bEd0p}8_Kj$XFF|IF>|7YXc97J3O+W(SMYxe|~ApDo)jInD9AG5CzT_b(^*KmD> z9CIav>jE&ZP`4YcO}=aQnAY5N1b*FV*U|nA&{|@UqEP}{Y%6!kdE`aN=Nc|<} zy1=;piu}JA*Vpsf;WE&^Ca0fu%_Ru`4LK9NiDv2G^s1M%RG<5Ic~7<;*J*2uiS@F~ zyjCE^ta>@*wx|}S7fCh3ns%+}MbaN`O@~DgStK*VtZ5gf8>Ctyqch(%rW>TcMDm$$ zOmi7%PfMqVHO(amzgS{NhsO^-e^Z9#{;x8(ds*#SsaAYD*PDdt&9l;9 zVS2+ez(w%1TsnPhXSf8mo|DeKOK&+M@u%=+!YJ-q}!Cc=P`QBnJfV diff --git a/api/swagger/swagger-dev.json b/api/swagger/swagger-dev.json index 2c8934d7c4c..ada77db9ec4 100644 --- a/api/swagger/swagger-dev.json +++ b/api/swagger/swagger-dev.json @@ -1426,6 +1426,55 @@ "ADVISOR_CHECK_FAMILY_MONGODB" ], "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 } } }, @@ -1534,6 +1583,55 @@ "ADVISOR_CHECK_FAMILY_MONGODB" ], "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 } } }, @@ -1574,6 +1672,265 @@ } } } + }, + "post": { + "description": "Creates a new user-authored advisor check.", + "tags": [ + "AdvisorService" + ], + "summary": "Create Advisor Check", + "operationId": "CreateAdvisorCheck", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } } }, "/v1/advisors/checks/failed": { @@ -2215,6 +2572,489 @@ } } }, + "/v1/advisors/checks/{name}": { + "put": { + "description": "Updates an existing user-authored advisor check. Percona-shipped checks cannot be modified.", + "tags": [ + "AdvisorService" + ], + "summary": "Update Advisor Check", + "operationId": "UpdateAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check to update.", + "name": "name", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Deletes a user-authored advisor check. Percona-shipped checks cannot be deleted.", + "tags": [ + "AdvisorService" + ], + "summary": "Delete Advisor Check", + "operationId": "DeleteAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check to delete.", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/advisors/checks/{name}/definition": { + "get": { + "description": "Returns a single advisor check by name, including its queries and script.", + "tags": [ + "AdvisorService" + ], + "summary": "Get Advisor Check", + "operationId": "GetAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check.", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks/{name}/script": { "get": { "description": "Returns the source script of a single advisor check by name.", @@ -2960,7 +3800,7 @@ "x-order": 7 }, "source": { - "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API.", + "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com. Deprecated.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API.", "type": "string", "default": "TEMPLATE_SOURCE_UNSPECIFIED", "enum": [ diff --git a/api/swagger/swagger.json b/api/swagger/swagger.json index 443e015732e..50e80716675 100644 --- a/api/swagger/swagger.json +++ b/api/swagger/swagger.json @@ -909,6 +909,55 @@ "ADVISOR_CHECK_FAMILY_MONGODB" ], "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 } } }, @@ -1017,6 +1066,55 @@ "ADVISOR_CHECK_FAMILY_MONGODB" ], "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 } } }, @@ -1057,6 +1155,265 @@ } } } + }, + "post": { + "description": "Creates a new user-authored advisor check.", + "tags": [ + "AdvisorService" + ], + "summary": "Create Advisor Check", + "operationId": "CreateAdvisorCheck", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } } }, "/v1/advisors/checks/failed": { @@ -1698,6 +2055,489 @@ } } }, + "/v1/advisors/checks/{name}": { + "put": { + "description": "Updates an existing user-authored advisor check. Percona-shipped checks cannot be modified.", + "tags": [ + "AdvisorService" + ], + "summary": "Update Advisor Check", + "operationId": "UpdateAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check to update.", + "name": "name", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + }, + "delete": { + "description": "Deletes a user-authored advisor check. Percona-shipped checks cannot be deleted.", + "tags": [ + "AdvisorService" + ], + "summary": "Delete Advisor Check", + "operationId": "DeleteAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check to delete.", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, + "/v1/advisors/checks/{name}/definition": { + "get": { + "description": "Returns a single advisor check by name, including its queries and script.", + "tags": [ + "AdvisorService" + ], + "summary": "Get Advisor Check", + "operationId": "GetAdvisorCheck", + "parameters": [ + { + "type": "string", + "description": "Machine-readable name (ID) of the check.", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "check": { + "description": "AdvisorCheck contains check name and status.", + "type": "object", + "properties": { + "name": { + "description": "Machine-readable name (ID) that is used in expression.", + "type": "string", + "x-order": 0 + }, + "enabled": { + "description": "True if that check is enabled.", + "type": "boolean", + "x-order": 1 + }, + "description": { + "description": "Long human-readable description.", + "type": "string", + "x-order": 2 + }, + "summary": { + "description": "Short human-readable summary.", + "type": "string", + "x-order": 3 + }, + "interval": { + "description": "AdvisorCheckInterval represents possible execution interval values for checks.", + "type": "string", + "default": "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_INTERVAL_UNSPECIFIED", + "ADVISOR_CHECK_INTERVAL_STANDARD", + "ADVISOR_CHECK_INTERVAL_FREQUENT", + "ADVISOR_CHECK_INTERVAL_RARE" + ], + "x-order": 4 + }, + "family": { + "type": "string", + "default": "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "enum": [ + "ADVISOR_CHECK_FAMILY_UNSPECIFIED", + "ADVISOR_CHECK_FAMILY_MYSQL", + "ADVISOR_CHECK_FAMILY_POSTGRESQL", + "ADVISOR_CHECK_FAMILY_MONGODB" + ], + "x-order": 5 + }, + "category": { + "description": "Category (top-level grouping).", + "type": "string", + "x-order": 6 + }, + "subcategory": { + "description": "Subcategory (second-level grouping within a category).", + "type": "string", + "x-order": 7 + }, + "user_defined": { + "description": "True if the check is user-authored (editable/deletable); false for Percona-shipped checks.", + "type": "boolean", + "x-order": 8 + }, + "queries": { + "description": "Data-collection queries. Populated by Get/Create/Update; may be empty in list responses.", + "type": "array", + "items": { + "description": "AdvisorCheckQuery is a single data-collection query of an advisor check.", + "type": "object", + "properties": { + "type": { + "description": "Query type, e.g. \"MYSQL_SHOW\", \"POSTGRESQL_SELECT\", \"METRICS_RANGE\".", + "type": "string", + "x-order": 0 + }, + "query": { + "description": "Query text (may be empty for parameterless types such as MYSQL_SHOW).", + "type": "string", + "x-order": 1 + }, + "parameters": { + "description": "Optional query parameters (e.g. range/step for metrics range queries).", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "x-order": 2 + } + } + }, + "x-order": 9 + }, + "script": { + "description": "Starlark source script. Populated by Get/Create/Update; may be empty in list responses.", + "type": "string", + "x-order": 10 + } + }, + "x-order": 0 + } + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32", + "x-order": 0 + }, + "message": { + "type": "string", + "x-order": 1 + }, + "details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "@type": { + "type": "string", + "x-order": 0 + } + }, + "additionalProperties": {} + }, + "x-order": 2 + } + } + } + } + } + } + }, "/v1/advisors/checks/{name}/script": { "get": { "description": "Returns the source script of a single advisor check by name.", @@ -2443,7 +3283,7 @@ "x-order": 7 }, "source": { - "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API.", + "description": "TemplateSource defines template source.\n\n - TEMPLATE_SOURCE_BUILT_IN: Template that is shipped with PMM Server releases.\n - TEMPLATE_SOURCE_SAAS: Template that is downloaded from check.percona.com. Deprecated.\n - TEMPLATE_SOURCE_USER_FILE: Templated loaded from user-suplied file.\n - TEMPLATE_SOURCE_USER_API: Templated created via API.", "type": "string", "default": "TEMPLATE_SOURCE_UNSPECIFIED", "enum": [ diff --git a/managed/models/advisor_check_helpers.go b/managed/models/advisor_check_helpers.go new file mode 100644 index 00000000000..097d90ef68a --- /dev/null +++ b/managed/models/advisor_check_helpers.go @@ -0,0 +1,97 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models + +import ( + "fmt" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "gopkg.in/reform.v1" +) + +// FindAdvisorChecks returns all user-authored advisor checks ordered by name. +func FindAdvisorChecks(q *reform.Querier) ([]*AdvisorCheck, error) { + rows, err := q.SelectAllFrom(AdvisorCheckTable, "ORDER BY name") + if err != nil { + return nil, fmt.Errorf("failed to select advisor checks: %w", err) + } + + checks := make([]*AdvisorCheck, 0, len(rows)) + for _, r := range rows { + checks = append(checks, r.(*AdvisorCheck)) //nolint:forcetypeassert + } + return checks, nil +} + +// FindAdvisorCheckByName finds a user-authored advisor check by name. +// It returns reform.ErrNoRows if the check does not exist. +func FindAdvisorCheckByName(q *reform.Querier, name string) (*AdvisorCheck, error) { + if name == "" { + return nil, status.Error(codes.InvalidArgument, "Empty advisor check name.") + } + + c := &AdvisorCheck{Name: name} + err := q.Reload(c) + if err != nil { + return nil, err + } + + return c, nil +} + +// CreateAdvisorCheck persists a new user-authored advisor check. +func CreateAdvisorCheck(q *reform.Querier, c *AdvisorCheck) (*AdvisorCheck, error) { + err := q.Insert(c) + if err != nil { + return nil, fmt.Errorf("failed to create advisor check: %w", err) + } + + return c, nil +} + +// UpdateAdvisorCheck updates an existing user-authored advisor check, preserving its creation time. +// It returns reform.ErrNoRows if the check does not exist. +func UpdateAdvisorCheck(q *reform.Querier, c *AdvisorCheck) (*AdvisorCheck, error) { + existing := &AdvisorCheck{Name: c.Name} + err := q.Reload(existing) + if err != nil { + return nil, err + } + + c.CreatedAt = existing.CreatedAt + err = q.Update(c) + if err != nil { + return nil, fmt.Errorf("failed to update advisor check: %w", err) + } + + return c, nil +} + +// RemoveAdvisorCheck deletes a user-authored advisor check by name. +// It returns reform.ErrNoRows if the check does not exist. +func RemoveAdvisorCheck(q *reform.Querier, name string) error { + if name == "" { + return status.Error(codes.InvalidArgument, "Empty advisor check name.") + } + + err := q.Delete(&AdvisorCheck{Name: name}) + if err != nil { + return err + } + + return nil +} diff --git a/managed/models/advisor_check_model.go b/managed/models/advisor_check_model.go new file mode 100644 index 00000000000..cef3397977f --- /dev/null +++ b/managed/models/advisor_check_model.go @@ -0,0 +1,71 @@ +// Copyright (C) 2023 Percona LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package models + +import ( + "time" + + "gopkg.in/reform.v1" +) + +//go:generate go tool reform + +// AdvisorCheck represents a user-authored advisor check stored in the database. +// Percona-shipped checks are loaded from disk and are not stored here. +// +//reform:advisor_checks +type AdvisorCheck struct { + Name string `reform:"name,pk"` + Summary string `reform:"summary"` + Description string `reform:"description"` + Category string `reform:"category"` + Subcategory string `reform:"subcategory"` + Family string `reform:"family"` + Interval string `reform:"interval"` + // Queries holds the JSON-encoded []check.Query. + Queries []byte `reform:"queries"` + Script string `reform:"script"` + CreatedAt time.Time `reform:"created_at"` + UpdatedAt time.Time `reform:"updated_at"` +} + +// BeforeInsert implements reform.BeforeInserter interface. +func (c *AdvisorCheck) BeforeInsert() error { + now := Now() + c.CreatedAt = now + c.UpdatedAt = now + return nil +} + +// BeforeUpdate implements reform.BeforeUpdater interface. +func (c *AdvisorCheck) BeforeUpdate() error { + c.UpdatedAt = Now() + return nil +} + +// AfterFind implements reform.AfterFinder interface. +func (c *AdvisorCheck) AfterFind() error { + c.CreatedAt = c.CreatedAt.UTC() + c.UpdatedAt = c.UpdatedAt.UTC() + return nil +} + +// check interfaces. +var ( + _ reform.BeforeInserter = (*AdvisorCheck)(nil) + _ reform.BeforeUpdater = (*AdvisorCheck)(nil) + _ reform.AfterFinder = (*AdvisorCheck)(nil) +) diff --git a/managed/models/advisor_check_model_reform.go b/managed/models/advisor_check_model_reform.go new file mode 100644 index 00000000000..32ffea9e604 --- /dev/null +++ b/managed/models/advisor_check_model_reform.go @@ -0,0 +1,181 @@ +// Code generated by gopkg.in/reform.v1. DO NOT EDIT. + +package models + +import ( + "fmt" + "strings" + + "gopkg.in/reform.v1" + "gopkg.in/reform.v1/parse" +) + +type advisorCheckTableType struct { + s parse.StructInfo + z []interface{} +} + +// Schema returns a schema name in SQL database (""). +func (v *advisorCheckTableType) Schema() string { + return v.s.SQLSchema +} + +// Name returns a view or table name in SQL database ("advisor_checks"). +func (v *advisorCheckTableType) Name() string { + return v.s.SQLName +} + +// Columns returns a new slice of column names for that view or table in SQL database. +func (v *advisorCheckTableType) Columns() []string { + return []string{ + "name", + "summary", + "description", + "category", + "subcategory", + "family", + "interval", + "queries", + "script", + "created_at", + "updated_at", + } +} + +// NewStruct makes a new struct for that view or table. +func (v *advisorCheckTableType) NewStruct() reform.Struct { + return new(AdvisorCheck) +} + +// NewRecord makes a new record for that table. +func (v *advisorCheckTableType) NewRecord() reform.Record { + return new(AdvisorCheck) +} + +// PKColumnIndex returns an index of primary key column for that table in SQL database. +func (v *advisorCheckTableType) PKColumnIndex() uint { + return uint(v.s.PKFieldIndex) +} + +// AdvisorCheckTable represents advisor_checks view or table in SQL database. +var AdvisorCheckTable = &advisorCheckTableType{ + s: parse.StructInfo{ + Type: "AdvisorCheck", + SQLName: "advisor_checks", + Fields: []parse.FieldInfo{ + {Name: "Name", Type: "string", Column: "name"}, + {Name: "Summary", Type: "string", Column: "summary"}, + {Name: "Description", Type: "string", Column: "description"}, + {Name: "Category", Type: "string", Column: "category"}, + {Name: "Subcategory", Type: "string", Column: "subcategory"}, + {Name: "Family", Type: "string", Column: "family"}, + {Name: "Interval", Type: "string", Column: "interval"}, + {Name: "Queries", Type: "[]uint8", Column: "queries"}, + {Name: "Script", Type: "string", Column: "script"}, + {Name: "CreatedAt", Type: "time.Time", Column: "created_at"}, + {Name: "UpdatedAt", Type: "time.Time", Column: "updated_at"}, + }, + PKFieldIndex: 0, + }, + z: new(AdvisorCheck).Values(), +} + +// String returns a string representation of this struct or record. +func (s AdvisorCheck) String() string { + res := make([]string, 11) + res[0] = "Name: " + reform.Inspect(s.Name, true) + res[1] = "Summary: " + reform.Inspect(s.Summary, true) + res[2] = "Description: " + reform.Inspect(s.Description, true) + res[3] = "Category: " + reform.Inspect(s.Category, true) + res[4] = "Subcategory: " + reform.Inspect(s.Subcategory, true) + res[5] = "Family: " + reform.Inspect(s.Family, true) + res[6] = "Interval: " + reform.Inspect(s.Interval, true) + res[7] = "Queries: " + reform.Inspect(s.Queries, true) + res[8] = "Script: " + reform.Inspect(s.Script, true) + res[9] = "CreatedAt: " + reform.Inspect(s.CreatedAt, true) + res[10] = "UpdatedAt: " + reform.Inspect(s.UpdatedAt, true) + return strings.Join(res, ", ") +} + +// Values returns a slice of struct or record field values. +// Returned interface{} values are never untyped nils. +func (s *AdvisorCheck) Values() []interface{} { + return []interface{}{ + s.Name, + s.Summary, + s.Description, + s.Category, + s.Subcategory, + s.Family, + s.Interval, + s.Queries, + s.Script, + s.CreatedAt, + s.UpdatedAt, + } +} + +// Pointers returns a slice of pointers to struct or record fields. +// Returned interface{} values are never untyped nils. +func (s *AdvisorCheck) Pointers() []interface{} { + return []interface{}{ + &s.Name, + &s.Summary, + &s.Description, + &s.Category, + &s.Subcategory, + &s.Family, + &s.Interval, + &s.Queries, + &s.Script, + &s.CreatedAt, + &s.UpdatedAt, + } +} + +// View returns View object for that struct. +func (s *AdvisorCheck) View() reform.View { + return AdvisorCheckTable +} + +// Table returns Table object for that record. +func (s *AdvisorCheck) Table() reform.Table { + return AdvisorCheckTable +} + +// PKValue returns a value of primary key for that record. +// Returned interface{} value is never untyped nil. +func (s *AdvisorCheck) PKValue() interface{} { + return s.Name +} + +// PKPointer returns a pointer to primary key field for that record. +// Returned interface{} value is never untyped nil. +func (s *AdvisorCheck) PKPointer() interface{} { + return &s.Name +} + +// HasPK returns true if record has non-zero primary key set, false otherwise. +func (s *AdvisorCheck) HasPK() bool { + return s.Name != AdvisorCheckTable.z[AdvisorCheckTable.s.PKFieldIndex] +} + +// SetPK sets record primary key, if possible. +// +// Deprecated: prefer direct field assignment where possible: s.Name = pk. +func (s *AdvisorCheck) SetPK(pk interface{}) { + reform.SetPK(s, pk) +} + +// check interfaces +var ( + _ reform.View = AdvisorCheckTable + _ reform.Struct = (*AdvisorCheck)(nil) + _ reform.Table = AdvisorCheckTable + _ reform.Record = (*AdvisorCheck)(nil) + _ fmt.Stringer = (*AdvisorCheck)(nil) +) + +func init() { + parse.AssertUpToDate(&AdvisorCheckTable.s, new(AdvisorCheck)) +} diff --git a/managed/models/database.go b/managed/models/database.go index 869a8094a6e..fbe0780dc08 100644 --- a/managed/models/database.go +++ b/managed/models/database.go @@ -1218,6 +1218,23 @@ var databaseSchema = [][]string{ `CREATE INDEX check_results_service_id_idx ON check_results (service_id)`, `CREATE INDEX check_results_checked_at_idx ON check_results (checked_at)`, }, + 120: { + `CREATE TABLE advisor_checks ( + name VARCHAR(128) NOT NULL CHECK (name <> ''), + summary VARCHAR NOT NULL, + description TEXT NOT NULL, + category VARCHAR NOT NULL, + subcategory VARCHAR NOT NULL, + family VARCHAR NOT NULL, + interval VARCHAR NOT NULL, + queries TEXT NOT NULL, + script TEXT NOT NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + + PRIMARY KEY (name) + )`, + }, } // ^^^ Avoid default values in schema definition. ^^^ diff --git a/managed/pi/check/check.go b/managed/pi/check/check.go index 0e0779af971..f47f4505fea 100644 --- a/managed/pi/check/check.go +++ b/managed/pi/check/check.go @@ -234,9 +234,9 @@ const ( // Query represents DB query of specified type. type Query struct { - Query string - Type Type - Parameters map[Parameter]string + Query string `json:"query"` + Type Type `json:"type"` + Parameters map[Parameter]string `json:"parameters,omitempty"` } // Validate validates query. @@ -276,6 +276,10 @@ type Check struct { Interval Interval `yaml:"interval,omitempty"` Queries []Query `yaml:"queries"` Script string `yaml:"script"` + // UserDefined is true for checks authored by a user and stored in the DB, + // false for Percona-shipped checks loaded from disk. It is not part of the + // check's YAML/JSON representation. + UserDefined bool `yaml:"-" json:"-"` } // Validate validates check for minimal correctness. diff --git a/managed/services/checks/checks.go b/managed/services/checks/checks.go index 08ac51943a4..6ba84b3bfd6 100644 --- a/managed/services/checks/checks.go +++ b/managed/services/checks/checks.go @@ -41,6 +41,8 @@ import ( "github.com/prometheus/common/model" "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "gopkg.in/reform.v1" agentv1 "github.com/percona/pmm/api/agent/v1" @@ -57,7 +59,6 @@ const ( defaultStartDelay = time.Minute // Environment variables that affect checks service; only for testing. - envCheckFile = "PMM_DEV_ADVISOR_CHECKS_FILE" envDisableStartDelay = "PMM_ADVISORS_CHECKS_DISABLE_START_DELAY" builtinChecksPath = "/usr/local/percona/checks" @@ -89,9 +90,8 @@ type Service struct { vmClient v1.API clickhouseDB *sql.DB - l *logrus.Entry - startDelay time.Duration - customCheckFile string // For testing + l *logrus.Entry + startDelay time.Duration // startCheckCh delivers on-demand check runs from StartChecks to // runChecksLoop, which owns the service lifecycle context. @@ -134,10 +134,9 @@ func New( vmClient: vmClient, clickhouseDB: clickhouseDB, - l: l, - startDelay: defaultStartDelay, - customCheckFile: os.Getenv(envCheckFile), - startCheckCh: make(chan checkRunRequest, 1), + l: l, + startDelay: defaultStartDelay, + startCheckCh: make(chan checkRunRequest, 1), mChecksExecuted: prom.NewCounterVec(prom.CounterOpts{ Namespace: prometheusNamespace, @@ -530,6 +529,169 @@ func (s *Service) ChangeInterval(params map[string]check.Interval) error { return nil } +// CreateAdvisorCheck creates a new user-authored advisor check and reloads the check list. +func (s *Service) CreateAdvisorCheck(ctx context.Context, c check.Check) error { + c.Version = check.MaxSupportedVersion + c.UserDefined = true + + err := c.Validate() + if err != nil { + return status.Errorf(codes.InvalidArgument, "invalid advisor check: %v", err) + } + + existing, err := s.GetChecks() + if err != nil { + return err + } + if _, ok := existing[c.Name]; ok { + return status.Errorf(codes.AlreadyExists, "advisor check '%s' already exists", c.Name) + } + + m, err := userCheckToModel(c) + if err != nil { + return err + } + + errTx := s.db.InTransaction(func(tx *reform.TX) error { + _, err := models.CreateAdvisorCheck(tx.Querier, m) + return err + }) + if errTx != nil { + return fmt.Errorf("failed to create advisor check: %w", errTx) + } + + s.UpdateAdvisorsList(ctx) + return nil +} + +// UpdateAdvisorCheck updates an existing user-authored advisor check and reloads the check list. +func (s *Service) UpdateAdvisorCheck(ctx context.Context, c check.Check) error { + c.Version = check.MaxSupportedVersion + c.UserDefined = true + + err := c.Validate() + if err != nil { + return status.Errorf(codes.InvalidArgument, "invalid advisor check: %v", err) + } + + err = s.ensureUserCheck(c.Name) + if err != nil { + return err + } + + m, err := userCheckToModel(c) + if err != nil { + return err + } + + errTx := s.db.InTransaction(func(tx *reform.TX) error { + _, err := models.UpdateAdvisorCheck(tx.Querier, m) + return err + }) + if errTx != nil { + return fmt.Errorf("failed to update advisor check: %w", errTx) + } + + s.UpdateAdvisorsList(ctx) + return nil +} + +// DeleteAdvisorCheck deletes a user-authored advisor check and reloads the check list. +func (s *Service) DeleteAdvisorCheck(ctx context.Context, name string) error { + err := s.ensureUserCheck(name) + if err != nil { + return err + } + + errTx := s.db.InTransaction(func(tx *reform.TX) error { + err := models.RemoveAdvisorCheck(tx.Querier, name) + if err != nil { + return err + } + + // drop any interval override recorded for this check + cs, err := models.FindCheckSettingsByName(tx.Querier, name) + if err != nil { + if errors.Is(err, reform.ErrNoRows) { + return nil + } + return err + } + return tx.Delete(cs) + }) + if errTx != nil { + return fmt.Errorf("failed to delete advisor check: %w", errTx) + } + + s.UpdateAdvisorsList(ctx) + return nil +} + +// ensureUserCheck verifies that the named check exists and is user-authored. +// It returns a NotFound error for unknown checks and a FailedPrecondition error +// for Percona-shipped checks, which are immutable. +func (s *Service) ensureUserCheck(name string) error { + _, err := models.FindAdvisorCheckByName(s.db.Querier, name) + if err == nil { + return nil + } + if !errors.Is(err, reform.ErrNoRows) { + return err + } + + checks, gErr := s.GetChecks() + if gErr != nil { + return gErr + } + if _, ok := checks[name]; ok { + return status.Errorf(codes.FailedPrecondition, "advisor check '%s' is shipped by Percona and cannot be modified", name) + } + return status.Errorf(codes.NotFound, "advisor check '%s' not found", name) +} + +// userCheckToModel converts a check.Check into its DB representation. +func userCheckToModel(c check.Check) (*models.AdvisorCheck, error) { + queries, err := json.Marshal(c.Queries) + if err != nil { + return nil, fmt.Errorf("failed to encode queries: %w", err) + } + + return &models.AdvisorCheck{ + Name: c.Name, + Summary: c.Summary, + Description: c.Description, + Category: c.Category, + Subcategory: c.Subcategory, + Family: string(c.Family), + Interval: string(c.Interval), + Queries: queries, + Script: c.Script, + }, nil +} + +// modelToUserCheck converts a DB advisor check into a check.Check. +func modelToUserCheck(m *models.AdvisorCheck) (check.Check, error) { + var queries []check.Query + err := json.Unmarshal(m.Queries, &queries) + if err != nil { + return check.Check{}, fmt.Errorf("failed to decode queries: %w", err) + } + + return check.Check{ + Version: check.MaxSupportedVersion, + Name: m.Name, + Summary: m.Summary, + Description: m.Description, + Category: m.Category, + Subcategory: m.Subcategory, + Family: check.Family(m.Family), + Interval: check.Interval(m.Interval), + Queries: queries, + Script: m.Script, + UserDefined: true, + }, nil +} + // waitForResult periodically checks result state and returns it when complete. func (s *Service) waitForResult(ctx context.Context, resultID string) ([]byte, error) { ctx, cancel := context.WithTimeout(ctx, resultAwaitTimeout) @@ -1597,18 +1759,52 @@ func (s *Service) UpdateAdvisorsList(ctx context.Context) { s.l.Errorf("Failed to load built-in checks: %s.", err) return // keep previously loaded advisors } - // if custom check file is provided, load it and append to the list of checks - if s.customCheckFile != "" { - s.l.Infof("Using local test checks file: %s.", s.customCheckFile) - devChecks, err := s.loadChecksFromFiles([]string{s.customCheckFile}) + + // Append user-authored checks stored in the DB. Names colliding with a + // built-in check are skipped so Percona-shipped checks cannot be shadowed. + checks = append(checks, s.loadUserChecks(checks)...) + + s.updateAdvisors(s.filterSupportedChecks(groupChecksIntoAdvisors(checks))) +} + +// loadUserChecks loads user-authored checks from the DB. Checks whose name +// collides with a built-in check, or which fail validation, are skipped with a +// warning so a single bad row cannot break the whole load. +func (s *Service) loadUserChecks(builtin []check.Check) []check.Check { + rows, err := models.FindAdvisorChecks(s.db.Querier) + if err != nil { + s.l.Errorf("Failed to load user-authored checks: %s.", err) + return nil + } + + builtinNames := make(map[string]struct{}, len(builtin)) + for _, c := range builtin { + builtinNames[c.Name] = struct{}{} + } + + res := make([]check.Check, 0, len(rows)) + for _, row := range rows { + if _, ok := builtinNames[row.Name]; ok { + s.l.Warnf("User check '%s' collides with a built-in check and is ignored.", row.Name) + continue + } + + c, err := modelToUserCheck(row) if err != nil { - s.l.Errorf("Failed to load local checks file: %s.", err) - return // keep previously loaded advisors + s.l.Warnf("Failed to decode user check '%s': %s.", row.Name, err) + continue } - checks = append(checks, devChecks...) + + err = c.Validate() + if err != nil { + s.l.Warnf("User check '%s' is invalid and is ignored: %s.", row.Name, err) + continue + } + + res = append(res, c) } - s.updateAdvisors(s.filterSupportedChecks(groupChecksIntoAdvisors(checks))) + return res } // loadBuiltinChecks loads builtin checks from the checks directory. @@ -1676,7 +1872,6 @@ func (s *Service) loadChecksFromFiles(files []string) ([]check.Check, error) { return res, nil } -// loadAdvisorsFromFiles loads Advisors from a list of given files. // filterSupportedChecks returns supported advisor checks and prints warning log messages about unsupported. func (s *Service) filterSupportedChecks(advisors []check.Advisor) []check.Advisor { res := make([]check.Advisor, 0, len(advisors)) diff --git a/managed/services/checks/checks_test.go b/managed/services/checks/checks_test.go index 60cda69a9cb..01ef86d1d0e 100644 --- a/managed/services/checks/checks_test.go +++ b/managed/services/checks/checks_test.go @@ -16,8 +16,10 @@ package checks import ( + "bytes" "context" "database/sql" + "os" "testing" "time" @@ -28,6 +30,8 @@ import ( "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "gopkg.in/reform.v1" "gopkg.in/reform.v1/dialects/postgresql" @@ -48,6 +52,34 @@ var ( clickhouseDB *sql.DB ) +// loadTestCheck parses the good-check test fixture into a check.Check. +func loadTestCheck(t *testing.T) check.Check { + t.Helper() + + b, err := os.ReadFile(testChecksFile) + require.NoError(t, err) + + checks, err := check.ParseChecks(bytes.NewReader(b), &check.ParseParams{ + DisallowUnknownFields: true, + DisallowInvalidChecks: true, + }) + require.NoError(t, err) + require.Len(t, checks, 1) + + return checks[0] +} + +// seedUserCheck stores the good-check test fixture as a user-authored check in the DB. +func seedUserCheck(t *testing.T, db *reform.DB) { + t.Helper() + + c := loadTestCheck(t) + m, err := userCheckToModel(c) + require.NoError(t, err) + _, err = models.CreateAdvisorCheck(db.Querier, m) + require.NoError(t, err) +} + func TestLoadBuiltinAdvisors(t *testing.T) { setupClients(t) sqlDB := testdb.Open(t, models.SkipFixtures, nil) @@ -106,7 +138,7 @@ func TestUpdateAdvisorsList(t *testing.T) { t.Run("collect custom checks", func(t *testing.T) { s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile + seedUserCheck(t, db) s.UpdateAdvisorsList(t.Context()) @@ -114,7 +146,7 @@ func TestUpdateAdvisorsList(t *testing.T) { require.NoError(t, err) require.GreaterOrEqual(t, len(advisors), 1) - // the custom check carries a unique (category, subcategory), so it forms + // the user check carries a unique (category, subcategory), so it forms // its own advisor group loaded last. advisor := advisors[len(advisors)-1] require.Equal(t, "Development", advisor.Category) @@ -141,7 +173,7 @@ func TestDisableChecks(t *testing.T) { db := reform.NewDB(sqlDB, postgresql.Dialect, nil) s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile + seedUserCheck(t, db) s.UpdateAdvisorsList(t.Context()) @@ -170,7 +202,7 @@ func TestDisableChecks(t *testing.T) { db := reform.NewDB(sqlDB, postgresql.Dialect, nil) s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile + seedUserCheck(t, db) s.UpdateAdvisorsList(t.Context()) @@ -202,7 +234,7 @@ func TestDisableChecks(t *testing.T) { db := reform.NewDB(sqlDB, postgresql.Dialect, nil) s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile + seedUserCheck(t, db) s.UpdateAdvisorsList(t.Context()) @@ -225,7 +257,7 @@ func TestEnableChecks(t *testing.T) { db := reform.NewDB(sqlDB, postgresql.Dialect, nil) s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile + seedUserCheck(t, db) s.UpdateAdvisorsList(t.Context()) @@ -256,7 +288,7 @@ func TestChangeInterval(t *testing.T) { db := reform.NewDB(sqlDB, postgresql.Dialect, nil) s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile + seedUserCheck(t, db) s.UpdateAdvisorsList(t.Context()) @@ -302,7 +334,6 @@ func TestStartChecks(t *testing.T) { t.Run("unknown interval", func(t *testing.T) { s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile err := s.runChecksGroup(t.Context(), "unknown") require.EqualError(t, err, "unknown check interval: unknown") @@ -311,7 +342,7 @@ func TestStartChecks(t *testing.T) { t.Run("advisors enabled", func(t *testing.T) { s := New(db, nil, vmClient, clickhouseDB) - s.customCheckFile = testChecksFile + seedUserCheck(t, db) s.UpdateAdvisorsList(t.Context()) assert.NotEmpty(t, s.advisors) assert.NotEmpty(t, s.checks) @@ -335,6 +366,73 @@ func TestStartChecks(t *testing.T) { }) } +func TestUserAdvisorChecks(t *testing.T) { + sqlDB := testdb.Open(t, models.SkipFixtures, nil) + t.Cleanup(func() { + require.NoError(t, sqlDB.Close()) + }) + + db := reform.NewDB(sqlDB, postgresql.Dialect, nil) + ctx := t.Context() + + s := New(db, nil, vmClient, clickhouseDB) + + // author a valid user check from a known-good template + c := loadTestCheck(t) + c.Name = "test_user_check_crud" + + err := s.CreateAdvisorCheck(ctx, c) + require.NoError(t, err) + + checks, err := s.GetChecks() + require.NoError(t, err) + created, ok := checks[c.Name] + require.True(t, ok) + assert.True(t, created.UserDefined) + assert.Equal(t, c.Summary, created.Summary) + + t.Run("duplicate name rejected", func(t *testing.T) { + err := s.CreateAdvisorCheck(ctx, c) + require.Error(t, err) + assert.Equal(t, codes.AlreadyExists, status.Code(err)) + }) + + t.Run("update", func(t *testing.T) { + updated := c + updated.Summary = "updated summary" + err := s.UpdateAdvisorCheck(ctx, updated) + require.NoError(t, err) + + checks, err := s.GetChecks() + require.NoError(t, err) + require.Contains(t, checks, c.Name) + assert.Equal(t, "updated summary", checks[c.Name].Summary) + }) + + t.Run("update unknown rejected", func(t *testing.T) { + unknown := c + unknown.Name = "no_such_check" + err := s.UpdateAdvisorCheck(ctx, unknown) + require.Error(t, err) + assert.Equal(t, codes.NotFound, status.Code(err)) + }) + + t.Run("delete", func(t *testing.T) { + err := s.DeleteAdvisorCheck(ctx, c.Name) + require.NoError(t, err) + + checks, err := s.GetChecks() + require.NoError(t, err) + assert.NotContains(t, checks, c.Name) + }) + + t.Run("delete unknown rejected", func(t *testing.T) { + err := s.DeleteAdvisorCheck(ctx, "no_such_check") + require.Error(t, err) + assert.Equal(t, codes.NotFound, status.Code(err)) + }) +} + func TestNewInitializesStartCheckChannel(t *testing.T) { t.Parallel() // New must initialize the on-demand channel so StartChecks can enqueue a diff --git a/managed/services/management/checks.go b/managed/services/management/checks.go index ac21816aa7e..a9a337932a6 100644 --- a/managed/services/management/checks.go +++ b/managed/services/management/checks.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "maps" + "slices" "github.com/AlekSi/pointer" "github.com/sirupsen/logrus" @@ -347,6 +348,9 @@ func (s *ChecksAPIService) ListAdvisorChecks(_ context.Context, _ *advisorsv1.Li Family: convertFamily(c.Family), Description: c.Description, Interval: convertInterval(c.Interval), + Category: c.Category, + Subcategory: c.Subcategory, + UserDefined: c.UserDefined, }) } @@ -397,6 +401,9 @@ func (s *ChecksAPIService) ListAdvisors(_ context.Context, _ *advisorsv1.ListAdv Family: convertFamily(c.Family), Description: c.Description, Interval: convertInterval(c.Interval), + Category: c.Category, + Subcategory: c.Subcategory, + UserDefined: c.UserDefined, }) } @@ -452,6 +459,90 @@ func (s *ChecksAPIService) ChangeAdvisorChecks(_ context.Context, req *advisorsv return &advisorsv1.ChangeAdvisorChecksResponse{}, nil } +// GetAdvisorCheck returns a single advisor check by name, including its queries and script. +func (s *ChecksAPIService) GetAdvisorCheck(_ context.Context, req *advisorsv1.GetAdvisorCheckRequest) (*advisorsv1.GetAdvisorCheckResponse, error) { + c, enabled, err := s.getCheck(req.Name) + if err != nil { + return nil, err + } + + return &advisorsv1.GetAdvisorCheckResponse{Check: advisorCheckToAPI(c, enabled)}, nil +} + +// CreateAdvisorCheck creates a new user-authored advisor check. +func (s *ChecksAPIService) CreateAdvisorCheck(ctx context.Context, req *advisorsv1.CreateAdvisorCheckRequest) (*advisorsv1.CreateAdvisorCheckResponse, error) { + if req.Check == nil { + return nil, status.Error(codes.InvalidArgument, "Check is required.") + } + + err := s.checksService.CreateAdvisorCheck(ctx, apiToAdvisorCheck(req.Check)) + if err != nil { + return nil, err + } + + c, enabled, err := s.getCheck(req.Check.Name) + if err != nil { + return nil, err + } + + return &advisorsv1.CreateAdvisorCheckResponse{Check: advisorCheckToAPI(c, enabled)}, nil +} + +// UpdateAdvisorCheck updates an existing user-authored advisor check. +func (s *ChecksAPIService) UpdateAdvisorCheck(ctx context.Context, req *advisorsv1.UpdateAdvisorCheckRequest) (*advisorsv1.UpdateAdvisorCheckResponse, error) { + if req.Check == nil { + return nil, status.Error(codes.InvalidArgument, "Check is required.") + } + + c := apiToAdvisorCheck(req.Check) + // the path parameter is authoritative; the name cannot be changed on update + c.Name = req.Name + + err := s.checksService.UpdateAdvisorCheck(ctx, c) + if err != nil { + return nil, err + } + + updated, enabled, err := s.getCheck(req.Name) + if err != nil { + return nil, err + } + + return &advisorsv1.UpdateAdvisorCheckResponse{Check: advisorCheckToAPI(updated, enabled)}, nil +} + +// DeleteAdvisorCheck deletes a user-authored advisor check. +func (s *ChecksAPIService) DeleteAdvisorCheck(ctx context.Context, req *advisorsv1.DeleteAdvisorCheckRequest) (*advisorsv1.DeleteAdvisorCheckResponse, error) { + err := s.checksService.DeleteAdvisorCheck(ctx, req.Name) + if err != nil { + return nil, err + } + + return &advisorsv1.DeleteAdvisorCheckResponse{}, nil +} + +// getCheck returns a check by name together with its enabled state. +func (s *ChecksAPIService) getCheck(name string) (check.Check, bool, error) { + checks, err := s.checksService.GetChecks() + if err != nil { + return check.Check{}, false, fmt.Errorf("failed to get available checks list: %w", err) + } + + c, ok := checks[name] + if !ok { + return check.Check{}, false, status.Errorf(codes.NotFound, "Advisor check %q not found.", name) + } + + disabled, err := s.checksService.GetDisabledChecks() + if err != nil { + return check.Check{}, false, fmt.Errorf("failed to get disabled checks list: %w", err) + } + + enabled := !slices.Contains(disabled, name) + + return c, enabled, nil +} + // convertInterval converts check.Interval type to advisorsv1.AdvisorCheckInterval. func convertInterval(interval check.Interval) advisorsv1.AdvisorCheckInterval { switch interval { @@ -615,3 +706,122 @@ func convertAPIInterval(interval advisorsv1.AdvisorCheckInterval) (check.Interva return "", errors.New("unknown advisor check interval") } } + +// convertAPIFamily converts advisorsv1.AdvisorCheckFamily to check.Family. +// An unspecified family maps to an empty family, which fails check validation. +func convertAPIFamily(family advisorsv1.AdvisorCheckFamily) check.Family { + switch family { + case advisorsv1.AdvisorCheckFamily_ADVISOR_CHECK_FAMILY_MYSQL: + return check.MySQL + case advisorsv1.AdvisorCheckFamily_ADVISOR_CHECK_FAMILY_POSTGRESQL: + return check.PostgreSQL + case advisorsv1.AdvisorCheckFamily_ADVISOR_CHECK_FAMILY_MONGODB: + return check.MongoDB + default: + return "" + } +} + +// convertAPIIntervalOptional converts advisorsv1.AdvisorCheckInterval to check.Interval. +// Unlike convertAPIInterval, an unspecified interval maps to an empty interval +// (treated as standard by the loader) rather than an error. +func convertAPIIntervalOptional(interval advisorsv1.AdvisorCheckInterval) check.Interval { + switch interval { + case advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_STANDARD: + return check.Standard + case advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_FREQUENT: + return check.Frequent + case advisorsv1.AdvisorCheckInterval_ADVISOR_CHECK_INTERVAL_RARE: + return check.Rare + default: + return "" + } +} + +// advisorCheckToAPI converts a check.Check into its full API representation, including queries and script. +func advisorCheckToAPI(c check.Check, enabled bool) *advisorsv1.AdvisorCheck { + return &advisorsv1.AdvisorCheck{ + Name: c.Name, + Enabled: enabled, + Summary: c.Summary, + Description: c.Description, + Family: convertFamily(c.Family), + Interval: convertInterval(c.Interval), + Category: c.Category, + Subcategory: c.Subcategory, + UserDefined: c.UserDefined, + Queries: convertQueriesToAPI(c.Queries), + Script: c.Script, + } +} + +// apiToAdvisorCheck converts an API advisor check (from a create/update request) into a check.Check. +func apiToAdvisorCheck(c *advisorsv1.AdvisorCheck) check.Check { + return check.Check{ + Name: c.Name, + Summary: c.Summary, + Description: c.Description, + Category: c.Category, + Subcategory: c.Subcategory, + Family: convertAPIFamily(c.Family), + Interval: convertAPIIntervalOptional(c.Interval), + Queries: convertAPIQueries(c.Queries), + Script: c.Script, + } +} + +// convertQueriesToAPI converts check queries to their API representation. +func convertQueriesToAPI(queries []check.Query) []*advisorsv1.AdvisorCheckQuery { + if len(queries) == 0 { + return nil + } + + res := make([]*advisorsv1.AdvisorCheckQuery, 0, len(queries)) + for _, q := range queries { + var params map[string]string + if len(q.Parameters) != 0 { + params = make(map[string]string, len(q.Parameters)) + for k, v := range q.Parameters { + params[string(k)] = v + } + } + + res = append(res, &advisorsv1.AdvisorCheckQuery{ + Type: string(q.Type), + Query: q.Query, + Parameters: params, + }) + } + + return res +} + +// convertAPIQueries converts API queries into check queries. +func convertAPIQueries(queries []*advisorsv1.AdvisorCheckQuery) []check.Query { + if len(queries) == 0 { + return nil + } + + res := make([]check.Query, 0, len(queries)) + for _, q := range queries { + if q == nil { + continue + } + + var params map[check.Parameter]string + if len(q.Parameters) != 0 { + params = make(map[check.Parameter]string, len(q.Parameters)) + for k, v := range q.Parameters { + params[check.Parameter(k)] = v + } + } + + res = append(res, check.Query{ + Type: check.Type(q.Type), + Query: q.Query, + Parameters: params, + }) + } + + return res +} diff --git a/managed/services/management/deps.go b/managed/services/management/deps.go index 8f72087fae2..b447c2f3519 100644 --- a/managed/services/management/deps.go +++ b/managed/services/management/deps.go @@ -66,6 +66,9 @@ type checksService interface { DisableChecks(checkNames []string) error EnableChecks(checkNames []string) error ChangeInterval(params map[string]check.Interval) error + CreateAdvisorCheck(ctx context.Context, c check.Check) error + UpdateAdvisorCheck(ctx context.Context, c check.Check) error + DeleteAdvisorCheck(ctx context.Context, name string) error } // grafanaClient is a subset of methods of grafana.Client used by this package. diff --git a/managed/services/management/mock_checks_service_test.go b/managed/services/management/mock_checks_service_test.go index 34c53c9bb45..137f0ae0374 100644 --- a/managed/services/management/mock_checks_service_test.go +++ b/managed/services/management/mock_checks_service_test.go @@ -35,6 +35,42 @@ func (_m *mockChecksService) ChangeInterval(params map[string]check.Interval) er return r0 } +// CreateAdvisorCheck provides a mock function with given fields: ctx, c +func (_m *mockChecksService) CreateAdvisorCheck(ctx context.Context, c check.Check) error { + ret := _m.Called(ctx, c) + + if len(ret) == 0 { + panic("no return value specified for CreateAdvisorCheck") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, check.Check) error); ok { + r0 = rf(ctx, c) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteAdvisorCheck provides a mock function with given fields: ctx, name +func (_m *mockChecksService) DeleteAdvisorCheck(ctx context.Context, name string) error { + ret := _m.Called(ctx, name) + + if len(ret) == 0 { + panic("no return value specified for DeleteAdvisorCheck") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // DisableChecks provides a mock function with given fields: checkNames func (_m *mockChecksService) DisableChecks(checkNames []string) error { ret := _m.Called(checkNames) @@ -313,6 +349,24 @@ func (_m *mockChecksService) StartChecks(checkNames []string) (string, error) { return r0, r1 } +// UpdateAdvisorCheck provides a mock function with given fields: ctx, c +func (_m *mockChecksService) UpdateAdvisorCheck(ctx context.Context, c check.Check) error { + ret := _m.Called(ctx, c) + + if len(ret) == 0 { + panic("no return value specified for UpdateAdvisorCheck") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, check.Check) error); ok { + r0 = rf(ctx, c) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // newMockChecksService creates a new instance of mockChecksService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func newMockChecksService(t interface { diff --git a/ui/apps/pmm/src/api/advisors.ts b/ui/apps/pmm/src/api/advisors.ts index 2e16f5327ec..9f669a465e9 100644 --- a/ui/apps/pmm/src/api/advisors.ts +++ b/ui/apps/pmm/src/api/advisors.ts @@ -1,8 +1,13 @@ import { Advisor, + AdvisorCheck, + AdvisorCheckInput, ChangeAdvisorCheckParams, ChangeAdvisorChecksRequest, CheckResultHistoryItem, + CreateAdvisorCheckRequest, + CreateAdvisorCheckResponse, + GetAdvisorCheckResponse, GetAdvisorCheckScriptResponse, ListAdvisorsResponse, ListCheckResultsFilterValuesResponse, @@ -10,6 +15,8 @@ import { MarkCheckResultsReadRequest, StartAdvisorChecksRequest, StartAdvisorChecksResponse, + UpdateAdvisorCheckRequest, + UpdateAdvisorCheckResponse, } from 'types/advisors.types'; import { EmptyResponse, PaginatedResponse } from 'types/util.types'; import { api } from './api'; @@ -26,6 +33,42 @@ export const getAdvisorCheckScript = async (name: string): Promise => { return res.data.script; }; +export const getAdvisorCheck = async (name: string): Promise => { + const res = await api.get( + `/advisors/checks/${encodeURIComponent(name)}/definition` + ); + return res.data.check; +}; + +export const createAdvisorCheck = async ( + check: AdvisorCheckInput +): Promise => { + const payload: CreateAdvisorCheckRequest = { check }; + const res = await api.post( + '/advisors/checks', + payload + ); + return res.data.check; +}; + +export const updateAdvisorCheck = async ( + name: string, + check: AdvisorCheckInput +): Promise => { + const payload: UpdateAdvisorCheckRequest = { check }; + const res = await api.put( + `/advisors/checks/${encodeURIComponent(name)}`, + payload + ); + return res.data.check; +}; + +export const deleteAdvisorCheck = async (name: string): Promise => { + await api.delete( + `/advisors/checks/${encodeURIComponent(name)}` + ); +}; + export const startAdvisorChecks = async (names: string[]): Promise => { const payload: StartAdvisorChecksRequest = { names }; const res = await api.post( diff --git a/ui/apps/pmm/src/hooks/api/useAdvisors.ts b/ui/apps/pmm/src/hooks/api/useAdvisors.ts index 064da4983b3..a6c5709fe8f 100644 --- a/ui/apps/pmm/src/hooks/api/useAdvisors.ts +++ b/ui/apps/pmm/src/hooks/api/useAdvisors.ts @@ -8,15 +8,21 @@ import { } from '@tanstack/react-query'; import { changeAdvisorChecks, + createAdvisorCheck, + deleteAdvisorCheck, + getAdvisorCheck, getAdvisorCheckScript, listAdvisors, listCheckResultsFilterValues, listCheckResultsHistory, markCheckResultsRead, startAdvisorChecks, + updateAdvisorCheck, } from 'api/advisors'; import { Advisor, + AdvisorCheck, + AdvisorCheckInput, ChangeAdvisorCheckParams, CheckResultHistoryItem, ListCheckResultsFilterValuesResponse, @@ -27,9 +33,13 @@ import { PaginatedResponse } from 'types/util.types'; const KEYS = { LIST: 'advisors:list', + CHECK: 'advisors:check', CHECK_SCRIPT: 'advisors:check-script', START_CHECKS: 'advisors:start-checks', CHANGE_CHECKS: 'advisors:change-checks', + CREATE_CHECK: 'advisors:create-check', + UPDATE_CHECK: 'advisors:update-check', + DELETE_CHECK: 'advisors:delete-check', HISTORY: 'advisors:history', HISTORY_FILTER_VALUES: 'advisors:history-filter-values', MARK_READ: 'advisors:mark-read', @@ -54,6 +64,18 @@ export const useAdvisorCheckScript = ( ...options, }); +export const useAdvisorCheck = ( + name?: string, + options?: Partial> +) => + useQuery({ + queryKey: [KEYS.CHECK, name], + queryFn: () => getAdvisorCheck(name!), + // only fetch once a check is selected (lazy, on overlay open) + enabled: !!name, + ...options, + }); + export const useStartAdvisorChecks = ( options?: Partial> ) => @@ -117,3 +139,60 @@ export const useChangeAdvisorChecks = ( }, }); }; + +export const useCreateAdvisorCheck = ( + options?: Partial> +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: [KEYS.CREATE_CHECK], + mutationFn: createAdvisorCheck, + ...options, + onSuccess: async (data, variables, onMutate, context) => { + await options?.onSuccess?.(data, variables, onMutate, context); + await queryClient.invalidateQueries({ queryKey: [KEYS.LIST] }); + }, + }); +}; + +export const useUpdateAdvisorCheck = ( + options?: Partial< + UseMutationOptions< + AdvisorCheck, + Error, + { name: string; check: AdvisorCheckInput } + > + > +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: [KEYS.UPDATE_CHECK], + mutationFn: ({ name, check }) => updateAdvisorCheck(name, check), + ...options, + onSuccess: async (data, variables, onMutate, context) => { + await options?.onSuccess?.(data, variables, onMutate, context); + await queryClient.invalidateQueries({ queryKey: [KEYS.LIST] }); + await queryClient.invalidateQueries({ + queryKey: [KEYS.CHECK, variables.name], + }); + }, + }); +}; + +export const useDeleteAdvisorCheck = ( + options?: Partial> +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: [KEYS.DELETE_CHECK], + mutationFn: deleteAdvisorCheck, + ...options, + onSuccess: async (data, variables, onMutate, context) => { + await options?.onSuccess?.(data, variables, onMutate, context); + await queryClient.invalidateQueries({ queryKey: [KEYS.LIST] }); + }, + }); +}; diff --git a/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx index 8344d20d7df..615cda2ac84 100644 --- a/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx +++ b/ui/apps/pmm/src/pages/advisors/AdvisorsList.constants.tsx @@ -26,11 +26,6 @@ export const getAdvisorsColumns = ({ accessorKey: 'summary', size: 250, }, - { - header: Messages.columns.description, - accessorKey: 'description', - size: 350, - }, { id: 'category', header: Messages.columns.category, @@ -48,12 +43,22 @@ export const getAdvisorsColumns = ({ header: Messages.columns.vendor, accessorFn: (row) => ADVISOR_FAMILY[row.family], size: 140, + grow: false, + }, + { + id: 'author', + header: Messages.columns.author, + accessorFn: (row) => + row.userDefined ? Messages.author.custom : Messages.author.percona, + size: 110, + grow: false, }, { id: 'interval', header: Messages.columns.interval, accessorFn: (row) => ADVISOR_INTERVAL[row.interval], size: 130, + grow: false, Cell: ({ row }) => (