diff --git a/README.md b/README.md index 89227e0..16a862c 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,12 @@ The script downloads the latest release, extracts it to `/usr/local/pulse`, and ## Configuration -Pulse reads a `config.yml` file from the **current working directory**. The file has two sections: +Pulse reads a `config.yml` file from the **current working directory**. The file has the following sections: - **`services`** — a map of service names to lists of `host:port` addresses for TCP connectivity checks +- **`elasticsearch`** — Elasticsearch-specific configuration with credentials for authenticated HTTP health checks +- **`kibana`** — Kibana-specific configuration with credentials for authenticated HTTP status checks +- **`redis`** — Redis-specific configuration with optional password for protocol-level checks - **`minio`** — MinIO-specific configuration with credentials and addresses for authenticated connection checks ```yaml @@ -60,17 +63,32 @@ services: - 10.0.31.131:30310 nacos: - 10.0.31.131:30848 - redis: - - 10.0.1.38:6379 - - 10.0.1.38:6380 kafka: - 10.0.1.30:9092 - elasticsearch: - - 10.0.1.24:9300 - kibana: - - 10.0.1.26:5601 zookeeper: - - 10.0.1.27:3000 + - 10.0.1.27:2181,10.0.1.28:2181,10.0.1.29:2181 + zk-ui: + - 10.0.1.27:9090 + +elasticsearch: + addresses: + - 10.0.1.24:9200 + - 10.0.1.25:9200 + - 10.0.1.26:9200 + username: elastic + password: changeme + +kibana: + addresses: + - 10.0.1.26:5601 + username: elastic + password: changeme + +redis: + password: "" + addresses: + - 10.0.1.38:6379 + - 10.0.1.38:6380 minio: username: minioadmin @@ -79,7 +97,9 @@ minio: - 10.0.1.35:9000 ``` -Add or remove services under `services` as needed — any service name is accepted. The `minio` section is optional; omit it if you do not need MinIO checks. +**Elasticsearch** connects via the HTTP API (`/_cluster/health`) and supports Basic Auth. `username` and `password` are optional — omit them for clusters with security disabled. + +Add or remove services under `services` as needed — any service name is accepted. The `elasticsearch`, `kibana`, `redis`, and `minio` sections are optional; omit them if not needed. ## Usage @@ -93,9 +113,10 @@ Pulse will: 1. Load `config.yml`. 2. Attempt a TCP connection to every address under `services` (3-second timeout per address). -3. Attempt an authenticated connection to every MinIO address using the provided `username` and `password`. -4. Print a report to standard output. -5. Write detailed logs to `logs//`. +3. Check the Elasticsearch cluster health via HTTP API using optional Basic Auth credentials. +4. Attempt an authenticated connection to every MinIO address using the provided `username` and `password`. +5. Print a report to standard output. +6. Write detailed logs to `logs//`. ### Example output @@ -170,7 +191,7 @@ cp docker/config.yml config.yml |----|-----|---------------------| | Nacos | | nacos / nacos | | MinIO console | | minioadmin / minioadmin | -| Kibana | | — | +| Kibana | | elastic / changeme | | ZooKeeper Navigator | | — | ### Tear down @@ -207,7 +228,7 @@ Use the provided build scripts in the `build/` directory, or set the environment ``` pulse/ ├── build/ # Platform-specific build scripts -├── checker/ # TCP connection checker package +├── checker/ # TCP and Elasticsearch connection checker package ├── config/ # YAML configuration loader package ├── logger/ # Structured logger (success / failure / report) ├── scripts/ # Installation script diff --git a/checker/elasticsearch.go b/checker/elasticsearch.go new file mode 100644 index 0000000..57ec60d --- /dev/null +++ b/checker/elasticsearch.go @@ -0,0 +1,39 @@ +// checker/elasticsearch.go +package checker + +import ( + "fmt" + "io" + "net/http" + "time" +) + +// CheckElasticsearch 通过 Elasticsearch HTTP API(/_cluster/health)验证单个节点的连通性。 +// 若提供了 username 或 password,则使用 HTTP Basic Auth 进行认证。 +func CheckElasticsearch(address, username, password string, timeout time.Duration) error { + client := &http.Client{Timeout: timeout} + url := fmt.Sprintf("http://%s/_cluster/health", address) + + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + return fmt.Errorf("创建请求失败: %w", err) + } + + if username != "" || password != "" { + req.SetBasicAuth(username, password) + } + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("连接失败: %w", err) + } + defer resp.Body.Close() + if _, err = io.Copy(io.Discard, resp.Body); err != nil { + return fmt.Errorf("读取响应失败: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("HTTP 状态 %d", resp.StatusCode) + } + return nil +} diff --git a/checker/zookeeper.go b/checker/zookeeper.go index 1307183..aa688be 100644 --- a/checker/zookeeper.go +++ b/checker/zookeeper.go @@ -8,7 +8,6 @@ import ( "time" ) - // CheckZookeeperConnection 验证 Zookeeper 节点的连通性,使用 Zookeeper 四字命令 "ruok"。 // connectString 可以是单个 "host:port",也可以是标准 Zookeeper 连接字符串, // 例如 "host1:2181,host2:2181,host3:2181" 或 "host1:2181,host2:2181/chroot"。 diff --git a/config.yml b/config.yml index 6e0339e..f45b1a3 100644 --- a/config.yml +++ b/config.yml @@ -7,10 +7,6 @@ services: - 10.0.1.30:9092 - 10.0.1.31:9092 - 10.0.1.32:9092 - elasticsearch: - - 10.0.1.24:9300 - - 10.0.1.25:9300 - - 10.0.1.26:9300 zookeeper: - 10.0.1.27:2181,10.0.1.28:2181,10.0.1.29:2181 zk-ui: @@ -26,6 +22,14 @@ redis: - 10.0.1.40:6379 - 10.0.1.40:6380 +elasticsearch: + addresses: + - 10.0.1.24:9200 + - 10.0.1.25:9200 + - 10.0.1.26:9200 + username: elastic + password: changeme + kibana: addresses: - 10.0.1.26:5601 @@ -37,4 +41,3 @@ minio: password: minioadmin addresses: - 10.0.1.35:9000 - diff --git a/config/config.go b/config/config.go index f4a8824..e5e83e5 100644 --- a/config/config.go +++ b/config/config.go @@ -10,6 +10,13 @@ import ( // NetworkConfig 定义了各个服务的地址列表,键为服务名称,值为字符串数组 type NetworkConfig map[string][]string +// ElasticsearchConfig 保存 Elasticsearch 集群的连接参数 +type ElasticsearchConfig struct { + Addresses []string `yaml:"addresses"` + Username string `yaml:"username"` + Password string `yaml:"password"` +} + // KibanaConfig 定义了 Kibana 服务的连接配置,支持用户名和密码认证 type KibanaConfig struct { Addresses []string `yaml:"addresses"` @@ -32,12 +39,13 @@ type RedisConfig struct { Addresses []string `yaml:"addresses"` } -// AppConfig 顶层配置结构,包含通用 TCP 服务、MinIO、Kibana 和 Redis 专项配置 +// AppConfig 顶层配置结构,包含通用 TCP 服务、MinIO、Kibana、Redis 和 Elasticsearch 专项配置 type AppConfig struct { - Services NetworkConfig `yaml:"services"` - Minio *MinioConfig `yaml:"minio"` - Kibana KibanaConfig `yaml:"kibana"` - Redis RedisConfig `yaml:"redis"` + Services NetworkConfig `yaml:"services"` + Minio *MinioConfig `yaml:"minio"` + Kibana KibanaConfig `yaml:"kibana"` + Redis RedisConfig `yaml:"redis"` + Elasticsearch *ElasticsearchConfig `yaml:"elasticsearch"` } // LoadConfig 从指定文件中读取 YAML 配置,并解析为 AppConfig 类型 diff --git a/docker/config.yml b/docker/config.yml index 613585c..e055414 100644 --- a/docker/config.yml +++ b/docker/config.yml @@ -18,14 +18,17 @@ services: kafka: - localhost:9092 - elasticsearch: - - localhost:9300 - redis: password: "" addresses: - localhost:6379 +elasticsearch: + addresses: + - localhost:9200 + username: elastic + password: changeme + kibana: addresses: - localhost:5601 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index ccf1e4b..614b2df 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -13,7 +13,7 @@ # Default credentials # MinIO console http://localhost:9001 minioadmin / minioadmin # Nacos console http://localhost:8848/nacos nacos / nacos -# Kibana http://localhost:5601 +# Kibana http://localhost:5601 elastic / changeme # ZK Navigator http://localhost:9090 version: "3.9" @@ -113,12 +113,13 @@ services: environment: discovery.type: single-node ES_JAVA_OPTS: "-Xms256m -Xmx256m" - xpack.security.enabled: "false" + xpack.security.enabled: "true" + ELASTIC_PASSWORD: "changeme" ports: - - "9200:9200" # HTTP API - - "9300:9300" # transport (inter-node / monitored by Pulse) + - "9200:9200" # HTTP API (monitored by Pulse) + - "9300:9300" # transport (inter-node) healthcheck: - test: ["CMD", "curl", "-sf", "http://localhost:9200/_cluster/health"] + test: ["CMD", "curl", "-sf", "-u", "elastic:changeme", "http://localhost:9200/_cluster/health"] interval: 30s timeout: 10s retries: 5 @@ -130,6 +131,8 @@ services: container_name: pulse-kibana environment: ELASTICSEARCH_HOSTS: "http://elasticsearch:9200" + ELASTICSEARCH_USERNAME: "elastic" + ELASTICSEARCH_PASSWORD: "changeme" ports: - "5601:5601" depends_on: diff --git a/main.go b/main.go index 9641359..33aa3ff 100644 --- a/main.go +++ b/main.go @@ -74,7 +74,7 @@ func main() { } } - // ── 通用 TCP 服务检测(zookeeper 使用专用检测器)──────────────────── + // ── 通用 TCP 服务检测(zookeeper/kafka 使用专用检测器)─────────────── for service, addresses := range cfg.Services { results[service] = ServiceResult{Success: []string{}, Failure: []string{}} @@ -98,6 +98,15 @@ func main() { } } + // ── Elasticsearch 集群(HTTP API + 可选 Basic Auth)────────────────── + if cfg.Elasticsearch != nil { + results["elasticsearch"] = ServiceResult{Success: []string{}, Failure: []string{}} + for _, addr := range cfg.Elasticsearch.Addresses { + err := checker.CheckElasticsearch(addr, cfg.Elasticsearch.Username, cfg.Elasticsearch.Password, timeout) + recordResult(results, "elasticsearch", addr, err, successLogger, failureLogger) + } + } + // ── MinIO 认证连接检测 ──────────────────────────────────────────────── if cfg.Minio != nil { results["minio"] = ServiceResult{Success: []string{}, Failure: []string{}}