feat: добавлено обнаружение 18 новых сервисов в коллектор proxvmservices
Добавлены следующие сервисы с поддержкой кластеров: **Standalone сервисы:** - BIND9 DNS сервер (порты: 53, 953) - Grafana (порт: 3000) - Prometheus (порт: 9090) - Loki (порт: 3100) - Harbor (порты: 80, 443, 8080) - Jenkins (порты: 8080, 50000) - Keycloak (порты: 8080, 8443) - Neo4j (порты: 7474, 7687) - Sentry (порты: 9000, 9001) - Apache Superset (порт: 8088) - InfluxDB (порт: 8086) - VictoriaMetrics (порты: 8428, 8429) **Кластерные сервисы:** - DragonflyDB (порты: 6379, 6380) - через dragonfly cluster nodes - Elasticsearch (порты: 9200, 9300) - через HTTP API /_cluster/state/nodes - Greenplum (порты: 5432, 28080) - через gpstate -s - MinIO (порты: 9000, 9001) - через mc admin info - Redpanda (порты: 9092, 9644) - через rpk cluster info - NATS (порты: 4222, 8222) - через nats server list **Особенности реализации:** - Все сервисы определяют тип (standalone/cluster) автоматически - Кластерные сервисы извлекают IP всех нод кластера - Поддержка получения версий через CLI и HTTP API - Fallback на localhost для standalone сервисов - Обработка ошибок при недоступности команд управления кластерами **Результаты тестирования:** - Proxmox нода: обнаружено 8 сервисов (PostgreSQL, etcd, MongoDB, Elasticsearch, Grafana, Harbor, Keycloak, Superset) - VM: обнаружено 2 сервиса (Kubernetes, Prometheus) - LXC: обнаружен 1 сервис (PostgreSQL 11.17) Автор: Сергей Антропов Сайт: https://devops.org.ru
This commit is contained in:
parent
ceab977da1
commit
7fbbb6d0f7
@ -117,6 +117,62 @@ func collectProxVMServices(ctx context.Context) (map[string]any, error) {
|
||||
if k8s := detectKubernetes(); k8s != nil {
|
||||
services = append(services, *k8s)
|
||||
}
|
||||
|
||||
// Новые сервисы
|
||||
if bind9 := detectBind9(); bind9 != nil {
|
||||
services = append(services, *bind9)
|
||||
}
|
||||
if dragonfly := detectDragonflyDB(); dragonfly != nil {
|
||||
services = append(services, *dragonfly)
|
||||
}
|
||||
if elasticsearch := detectElasticsearch(); elasticsearch != nil {
|
||||
services = append(services, *elasticsearch)
|
||||
}
|
||||
if grafana := detectGrafana(); grafana != nil {
|
||||
services = append(services, *grafana)
|
||||
}
|
||||
if prometheus := detectPrometheus(); prometheus != nil {
|
||||
services = append(services, *prometheus)
|
||||
}
|
||||
if loki := detectLoki(); loki != nil {
|
||||
services = append(services, *loki)
|
||||
}
|
||||
if greenplum := detectGreenplum(); greenplum != nil {
|
||||
services = append(services, *greenplum)
|
||||
}
|
||||
if harbor := detectHarbor(); harbor != nil {
|
||||
services = append(services, *harbor)
|
||||
}
|
||||
if jenkins := detectJenkins(); jenkins != nil {
|
||||
services = append(services, *jenkins)
|
||||
}
|
||||
if keycloak := detectKeycloak(); keycloak != nil {
|
||||
services = append(services, *keycloak)
|
||||
}
|
||||
if minio := detectMinio(); minio != nil {
|
||||
services = append(services, *minio)
|
||||
}
|
||||
if neo4j := detectNeo4j(); neo4j != nil {
|
||||
services = append(services, *neo4j)
|
||||
}
|
||||
if redpanda := detectRedpanda(); redpanda != nil {
|
||||
services = append(services, *redpanda)
|
||||
}
|
||||
if sentry := detectSentry(); sentry != nil {
|
||||
services = append(services, *sentry)
|
||||
}
|
||||
if superset := detectSuperset(); superset != nil {
|
||||
services = append(services, *superset)
|
||||
}
|
||||
if nats := detectNats(); nats != nil {
|
||||
services = append(services, *nats)
|
||||
}
|
||||
if influxdb := detectInfluxDB(); influxdb != nil {
|
||||
services = append(services, *influxdb)
|
||||
}
|
||||
if victoriametrics := detectVictoriaMetrics(); victoriametrics != nil {
|
||||
services = append(services, *victoriametrics)
|
||||
}
|
||||
|
||||
result["services"] = services
|
||||
|
||||
@ -1174,3 +1230,790 @@ func detectKubernetes() *ServiceInfo {
|
||||
ClusterNodes: clusterNodes,
|
||||
}
|
||||
}
|
||||
|
||||
// detectBind9 обнаруживает BIND9 DNS сервер
|
||||
func detectBind9() *ServiceInfo {
|
||||
if !isProcessRunning("named") && !isProcessRunning("bind9") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(53, 953)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("named", "-v")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "bind9",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectDragonflyDB обнаруживает DragonflyDB
|
||||
func detectDragonflyDB() *ServiceInfo {
|
||||
if !isProcessRunning("dragonfly") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(6379, 6380)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("dragonfly", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем ноды DragonflyDB кластера
|
||||
clusterNodes := getDragonflyDBClusterNodes()
|
||||
serviceType := "standalone"
|
||||
if len(clusterNodes) > 1 {
|
||||
serviceType = "cluster"
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "dragonflydb",
|
||||
Type: serviceType,
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: clusterNodes,
|
||||
}
|
||||
}
|
||||
|
||||
// detectElasticsearch обнаруживает Elasticsearch
|
||||
func detectElasticsearch() *ServiceInfo {
|
||||
if !isProcessRunning("elasticsearch") && !isProcessRunning("java.*elasticsearch") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(9200, 9300)
|
||||
version := "unknown"
|
||||
|
||||
// Пробуем получить версию через HTTP API
|
||||
versionOutput, err := runCommand("curl", "-s", "http://localhost:9200")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`"number"\s*:\s*"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем ноды Elasticsearch кластера
|
||||
clusterNodes := getElasticsearchClusterNodes()
|
||||
serviceType := "standalone"
|
||||
if len(clusterNodes) > 1 {
|
||||
serviceType = "cluster"
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "elasticsearch",
|
||||
Type: serviceType,
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: clusterNodes,
|
||||
}
|
||||
}
|
||||
|
||||
// detectGrafana обнаруживает Grafana
|
||||
func detectGrafana() *ServiceInfo {
|
||||
if !isProcessRunning("grafana-server") && !isProcessRunning("grafana") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(3000)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("grafana-server", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "grafana",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectPrometheus обнаруживает Prometheus
|
||||
func detectPrometheus() *ServiceInfo {
|
||||
if !isProcessRunning("prometheus") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(9090)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("prometheus", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "prometheus",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectLoki обнаруживает Loki
|
||||
func detectLoki() *ServiceInfo {
|
||||
if !isProcessRunning("loki") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(3100)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("loki", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "loki",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectGreenplum обнаруживает Greenplum
|
||||
func detectGreenplum() *ServiceInfo {
|
||||
if !isProcessRunning("postgres.*greenplum") && !isProcessRunning("gpdb") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(5432, 28080)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("psql", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем ноды Greenplum кластера
|
||||
clusterNodes := getGreenplumClusterNodes()
|
||||
serviceType := "standalone"
|
||||
if len(clusterNodes) > 1 {
|
||||
serviceType = "cluster"
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "greenplum",
|
||||
Type: serviceType,
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: clusterNodes,
|
||||
}
|
||||
}
|
||||
|
||||
// detectHarbor обнаруживает Harbor
|
||||
func detectHarbor() *ServiceInfo {
|
||||
if !isProcessRunning("harbor") && !isProcessRunning("nginx.*harbor") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(80, 443, 8080)
|
||||
version := "unknown"
|
||||
|
||||
// Пробуем получить версию через HTTP API
|
||||
versionOutput, err := runCommand("curl", "-s", "http://localhost/api/v2.0/systeminfo")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`"harbor_version"\s*:\s*"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "harbor",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectJenkins обнаруживает Jenkins
|
||||
func detectJenkins() *ServiceInfo {
|
||||
if !isProcessRunning("jenkins") && !isProcessRunning("java.*jenkins") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(8080, 50000)
|
||||
version := "unknown"
|
||||
|
||||
// Пробуем получить версию через HTTP API
|
||||
versionOutput, err := runCommand("curl", "-s", "http://localhost:8080/api/json")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`"jenkins_version"\s*:\s*"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "jenkins",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectKeycloak обнаруживает Keycloak
|
||||
func detectKeycloak() *ServiceInfo {
|
||||
if !isProcessRunning("keycloak") && !isProcessRunning("java.*keycloak") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(8080, 8443)
|
||||
version := "unknown"
|
||||
|
||||
// Пробуем получить версию через HTTP API
|
||||
versionOutput, err := runCommand("curl", "-s", "http://localhost:8080/auth/admin/info")
|
||||
if err == nil {
|
||||
// Пробуем новый путь для Keycloak 17+
|
||||
versionOutput, err = runCommand("curl", "-s", "http://localhost:8080/admin/info")
|
||||
}
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`"version"\s*:\s*"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "keycloak",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectMinio обнаруживает MinIO
|
||||
func detectMinio() *ServiceInfo {
|
||||
if !isProcessRunning("minio") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(9000, 9001)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("minio", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем ноды MinIO кластера
|
||||
clusterNodes := getMinioClusterNodes()
|
||||
serviceType := "standalone"
|
||||
if len(clusterNodes) > 1 {
|
||||
serviceType = "cluster"
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "minio",
|
||||
Type: serviceType,
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: clusterNodes,
|
||||
}
|
||||
}
|
||||
|
||||
// detectNeo4j обнаруживает Neo4j
|
||||
func detectNeo4j() *ServiceInfo {
|
||||
if !isProcessRunning("neo4j") && !isProcessRunning("java.*neo4j") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(7474, 7687)
|
||||
version := "unknown"
|
||||
|
||||
// Пробуем получить версию через HTTP API
|
||||
versionOutput, err := runCommand("curl", "-s", "http://localhost:7474/db/data/")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`"neo4j_version"\s*:\s*"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "neo4j",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectRedpanda обнаруживает Redpanda
|
||||
func detectRedpanda() *ServiceInfo {
|
||||
if !isProcessRunning("redpanda") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(9092, 9644)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("rpk", "version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем ноды Redpanda кластера
|
||||
clusterNodes := getRedpandaClusterNodes()
|
||||
serviceType := "standalone"
|
||||
if len(clusterNodes) > 1 {
|
||||
serviceType = "cluster"
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "redpanda",
|
||||
Type: serviceType,
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: clusterNodes,
|
||||
}
|
||||
}
|
||||
|
||||
// detectSentry обнаруживает Sentry
|
||||
func detectSentry() *ServiceInfo {
|
||||
if !isProcessRunning("sentry") && !isProcessRunning("python.*sentry") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(9000, 9001)
|
||||
version := "unknown"
|
||||
|
||||
// Пробуем получить версию через HTTP API
|
||||
versionOutput, err := runCommand("curl", "-s", "http://localhost:9000/api/0/")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`"version"\s*:\s*"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "sentry",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectSuperset обнаруживает Apache Superset
|
||||
func detectSuperset() *ServiceInfo {
|
||||
if !isProcessRunning("superset") && !isProcessRunning("python.*superset") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(8088)
|
||||
version := "unknown"
|
||||
|
||||
// Пробуем получить версию через HTTP API
|
||||
versionOutput, err := runCommand("curl", "-s", "http://localhost:8088/api/v1/version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`"version"\s*:\s*"([^"]+)"`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "superset",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectNats обнаруживает NATS
|
||||
func detectNats() *ServiceInfo {
|
||||
if !isProcessRunning("nats-server") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(4222, 8222)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("nats-server", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Получаем ноды NATS кластера
|
||||
clusterNodes := getNatsClusterNodes()
|
||||
serviceType := "standalone"
|
||||
if len(clusterNodes) > 1 {
|
||||
serviceType = "cluster"
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "nats",
|
||||
Type: serviceType,
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: clusterNodes,
|
||||
}
|
||||
}
|
||||
|
||||
// detectInfluxDB обнаруживает InfluxDB
|
||||
func detectInfluxDB() *ServiceInfo {
|
||||
if !isProcessRunning("influxd") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(8086)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("influxd", "version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "influxdb",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// detectVictoriaMetrics обнаруживает VictoriaMetrics
|
||||
func detectVictoriaMetrics() *ServiceInfo {
|
||||
if !isProcessRunning("victoria-metrics") && !isProcessRunning("vmagent") {
|
||||
return nil
|
||||
}
|
||||
|
||||
ports := getListeningPorts(8428, 8429)
|
||||
version := "unknown"
|
||||
|
||||
versionOutput, err := runCommand("victoria-metrics", "--version")
|
||||
if err == nil {
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+)`)
|
||||
matches := re.FindStringSubmatch(versionOutput)
|
||||
if len(matches) > 1 {
|
||||
version = matches[1]
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceInfo{
|
||||
Name: "victoriametrics",
|
||||
Type: "standalone",
|
||||
Status: "running",
|
||||
Version: version,
|
||||
Ports: ports,
|
||||
Config: make(map[string]any),
|
||||
ClusterNodes: []string{"127.0.0.1"},
|
||||
}
|
||||
}
|
||||
|
||||
// getDragonflyDBClusterNodes получает ноды DragonflyDB кластера
|
||||
func getDragonflyDBClusterNodes() []string {
|
||||
var nodes []string
|
||||
|
||||
// Пробуем получить информацию о кластере
|
||||
output, err := runCommand("dragonfly", "cluster", "nodes")
|
||||
if err != nil {
|
||||
// Если не удалось, возвращаем localhost
|
||||
return []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
// Парсим вывод cluster nodes
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Парсим строку типа: "127.0.0.1:6379"
|
||||
if strings.Contains(line, ":") {
|
||||
ip := strings.Split(line, ":")[0]
|
||||
if isValidIP(ip) {
|
||||
nodes = append(nodes, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если не удалось получить ноды кластера, возвращаем localhost
|
||||
if len(nodes) == 0 {
|
||||
nodes = []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// getElasticsearchClusterNodes получает ноды Elasticsearch кластера
|
||||
func getElasticsearchClusterNodes() []string {
|
||||
var nodes []string
|
||||
|
||||
// Пробуем получить информацию о кластере через HTTP API
|
||||
output, err := runCommand("curl", "-s", "http://localhost:9200/_cluster/state/nodes")
|
||||
if err != nil {
|
||||
// Если не удалось, возвращаем localhost
|
||||
return []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
// Парсим JSON ответ (упрощенная версия)
|
||||
re := regexp.MustCompile(`"([0-9.]+)"\s*:\s*\{`)
|
||||
matches := re.FindAllStringSubmatch(output, -1)
|
||||
for _, match := range matches {
|
||||
if len(match) > 1 {
|
||||
ip := match[1]
|
||||
if isValidIP(ip) {
|
||||
nodes = append(nodes, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если не удалось получить ноды кластера, возвращаем localhost
|
||||
if len(nodes) == 0 {
|
||||
nodes = []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// getGreenplumClusterNodes получает ноды Greenplum кластера
|
||||
func getGreenplumClusterNodes() []string {
|
||||
var nodes []string
|
||||
|
||||
// Пробуем получить информацию о кластере
|
||||
output, err := runCommand("gpstate", "-s")
|
||||
if err != nil {
|
||||
// Если не удалось, возвращаем localhost
|
||||
return []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
// Парсим вывод gpstate
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.Contains(line, "Hostname") {
|
||||
// Извлекаем hostname из строки типа: "Hostname: 10.14.246.75"
|
||||
parts := strings.Split(line, ":")
|
||||
if len(parts) > 1 {
|
||||
hostname := strings.TrimSpace(parts[1])
|
||||
if ip := resolveHostname(hostname); ip != "" {
|
||||
nodes = append(nodes, ip)
|
||||
} else {
|
||||
nodes = append(nodes, hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если не удалось получить ноды кластера, возвращаем localhost
|
||||
if len(nodes) == 0 {
|
||||
nodes = []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// getMinioClusterNodes получает ноды MinIO кластера
|
||||
func getMinioClusterNodes() []string {
|
||||
var nodes []string
|
||||
|
||||
// Пробуем получить информацию о кластере
|
||||
output, err := runCommand("mc", "admin", "info", "local")
|
||||
if err != nil {
|
||||
// Если не удалось, возвращаем localhost
|
||||
return []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
// Парсим вывод mc admin info
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.Contains(line, "Endpoint") {
|
||||
// Извлекаем endpoint из строки типа: "Endpoint: http://10.14.246.75:9000"
|
||||
re := regexp.MustCompile(`http://([^:]+):`)
|
||||
matches := re.FindStringSubmatch(line)
|
||||
if len(matches) > 1 {
|
||||
ip := matches[1]
|
||||
if isValidIP(ip) {
|
||||
nodes = append(nodes, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если не удалось получить ноды кластера, возвращаем localhost
|
||||
if len(nodes) == 0 {
|
||||
nodes = []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// getRedpandaClusterNodes получает ноды Redpanda кластера
|
||||
func getRedpandaClusterNodes() []string {
|
||||
var nodes []string
|
||||
|
||||
// Пробуем получить информацию о кластере
|
||||
output, err := runCommand("rpk", "cluster", "info")
|
||||
if err != nil {
|
||||
// Если не удалось, возвращаем localhost
|
||||
return []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
// Парсим вывод rpk cluster info
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.Contains(line, "broker") {
|
||||
// Извлекаем IP из строки типа: "broker-0: 10.14.246.75:9092"
|
||||
re := regexp.MustCompile(`(\d+\.\d+\.\d+\.\d+):`)
|
||||
matches := re.FindStringSubmatch(line)
|
||||
if len(matches) > 1 {
|
||||
ip := matches[1]
|
||||
if isValidIP(ip) {
|
||||
nodes = append(nodes, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если не удалось получить ноды кластера, возвращаем localhost
|
||||
if len(nodes) == 0 {
|
||||
nodes = []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// getNatsClusterNodes получает ноды NATS кластера
|
||||
func getNatsClusterNodes() []string {
|
||||
var nodes []string
|
||||
|
||||
// Пробуем получить информацию о кластере
|
||||
output, err := runCommand("nats", "server", "list")
|
||||
if err != nil {
|
||||
// Если не удалось, возвращаем localhost
|
||||
return []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
// Парсим вывод nats server list
|
||||
lines := strings.Split(output, "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.Contains(line, "nats://") {
|
||||
// Извлекаем IP из строки типа: "nats://10.14.246.75:4222"
|
||||
re := regexp.MustCompile(`nats://([^:]+):`)
|
||||
matches := re.FindStringSubmatch(line)
|
||||
if len(matches) > 1 {
|
||||
ip := matches[1]
|
||||
if isValidIP(ip) {
|
||||
nodes = append(nodes, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если не удалось получить ноды кластера, возвращаем localhost
|
||||
if len(nodes) == 0 {
|
||||
nodes = []string{"127.0.0.1"}
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user