console/modules/agent/client/client.go

275 lines
8.0 KiB
Go

/* Copyright © INFINI Ltd. All rights reserved.
* Web: https://infinilabs.com
* Email: hello#infini.ltd */
package client
import (
"context"
"fmt"
"infini.sh/console/modules/agent/common"
"infini.sh/framework/core/agent"
"infini.sh/framework/core/elastic"
"infini.sh/framework/core/host"
"infini.sh/framework/core/util"
"net/http"
)
var defaultClient ClientAPI
func GetClient() ClientAPI {
if defaultClient == nil {
panic("agent client not init")
}
return defaultClient
}
func RegisterClient(client ClientAPI) {
defaultClient = client
}
type ClientAPI interface {
GetHostInfo(ctx context.Context, agentBaseURL string) (*host.HostInfo, error)
GetElasticProcess(ctx context.Context, agentBaseURL string, agentID string)(interface{}, error)
GetElasticLogFiles(ctx context.Context, agentBaseURL string, logsPath string)(interface{}, error)
GetElasticLogFileContent(ctx context.Context, agentBaseURL string, body interface{})(interface{}, error)
GetInstanceBasicInfo(ctx context.Context, agentBaseURL string) (*agent.Instance, error)
RegisterElasticsearch(ctx context.Context, agentBaseURL string, cfgs []elastic.ElasticsearchConfig) error
GetElasticsearchNodes(ctx context.Context, agentBaseURL string) ([]agent.ESNodeInfo, error)
AuthESNode(ctx context.Context, agentBaseURL string, cfg elastic.ElasticsearchConfig) (*agent.ESNodeInfo, error)
CreatePipeline(ctx context.Context, agentBaseURL string, body []byte) error
DeletePipeline(ctx context.Context, agentBaseURL, pipelineID string) error
SetKeystoreValue(ctx context.Context, agentBaseURL string, key, value string) error
SaveDynamicConfig(ctx context.Context, agentBaseURL string, name, content string) error
SaveIngestConfig(ctx context.Context, agentBaseURL string) error
DoRequest(req *util.Request, respObj interface{}) error
}
type Client struct {
Executor Executor
}
func (client *Client) GetHostInfo(ctx context.Context, agentBaseURL string) (*host.HostInfo, error) {
req := &util.Request{
Method: http.MethodGet,
Url: fmt.Sprintf("%s/agent/host/_basic", agentBaseURL),
Context: ctx,
}
resBody := struct {
Success bool `json:"success"`
Error string `json:"error"`
HostInfo *host.HostInfo `json:"result"`
}{}
err := client.DoRequest(req, &resBody)
if err != nil {
return nil, err
}
if resBody.Success != true {
return nil, fmt.Errorf("enroll error from client: %v", resBody.Error)
}
return resBody.HostInfo, nil
}
func (client *Client) GetElasticProcess(ctx context.Context, agentBaseURL string, agentID string)(interface{}, error) {
req := &util.Request{
Method: http.MethodGet,
Url: fmt.Sprintf("%s/elasticsearch/%s/process/_elastic", agentBaseURL, agentID),
Context: ctx,
}
resBody := map[string]interface{}{}
err := client.DoRequest(req, &resBody)
if err != nil {
return nil, err
}
if resBody["success"] != true {
return nil, fmt.Errorf("discover host callback error: %v", resBody["error"])
}
return resBody["elastic_process"], nil
}
func (client *Client) GetElasticLogFiles(ctx context.Context, agentBaseURL string, logsPath string)(interface{}, error) {
reqBody := util.MustToJSONBytes(util.MapStr{
"logs_path": logsPath,
})
req := &util.Request{
Method: http.MethodPost,
Url: fmt.Sprintf("%s/agent/logs/elastic/list", agentBaseURL),
Context: ctx,
Body: reqBody,
}
resBody := map[string]interface{}{}
err := client.DoRequest(req, &resBody)
if err != nil {
return nil, err
}
if resBody["success"] != true {
return nil, fmt.Errorf("get elasticsearch log files error: %v", resBody["error"])
}
return resBody["result"], nil
}
func (client *Client) GetElasticLogFileContent(ctx context.Context, agentBaseURL string, body interface{})(interface{}, error) {
req := &util.Request{
Method: http.MethodPost,
Url: fmt.Sprintf("%s/agent/logs/elastic/_read", agentBaseURL),
Context: ctx,
Body: util.MustToJSONBytes(body),
}
resBody := map[string]interface{}{}
err := client.DoRequest(req, &resBody)
if err != nil {
return nil, err
}
if resBody["success"] != true {
return nil, fmt.Errorf("get elasticsearch log files error: %v", resBody["error"])
}
var hasMore bool
if v, ok := resBody["EOF"].(bool); ok && !v {
hasMore = true
}
return map[string]interface{}{
"lines": resBody["result"],
"has_more": hasMore,
} , nil
}
func (client *Client) GetInstanceBasicInfo(ctx context.Context, agentBaseURL string) (*agent.Instance, error){
req := &util.Request{
Method: http.MethodGet,
Url: fmt.Sprintf("%s/agent/_info", agentBaseURL ),
Context: ctx,
}
resBody := &agent.Instance{}
err := client.DoRequest(req, &resBody)
return resBody, err
}
func (client *Client) RegisterElasticsearch(ctx context.Context, agentBaseURL string, cfgs []elastic.ElasticsearchConfig) error {
reqBody, err := util.ToJSONBytes(cfgs)
if err != nil {
return err
}
req := &util.Request{
Method: http.MethodPost,
Url: fmt.Sprintf("%s/elasticsearch/_register", agentBaseURL ),
Context: ctx,
Body: reqBody,
}
resBody := util.MapStr{}
err = client.DoRequest(req, &resBody)
if err != nil {
return err
}
if resBody["acknowledged"] != true {
return fmt.Errorf("%v", resBody["error"])
}
return nil
}
func (client *Client) GetElasticsearchNodes(ctx context.Context, agentBaseURL string) ([]agent.ESNodeInfo, error) {
req := &util.Request{
Method: http.MethodGet,
Url: fmt.Sprintf("%s/elasticsearch/_nodes", agentBaseURL ),
Context: ctx,
}
resBody := []agent.ESNodeInfo{}
err := client.DoRequest(req, &resBody)
if err != nil {
return nil, err
}
return resBody, nil
}
func (client *Client) AuthESNode(ctx context.Context, agentBaseURL string, cfg elastic.ElasticsearchConfig) (*agent.ESNodeInfo, error) {
reqBody, err := util.ToJSONBytes(cfg)
if err != nil {
return nil, err
}
req := &util.Request{
Method: http.MethodPost,
Url: fmt.Sprintf("%s/elasticsearch/_auth", agentBaseURL ),
Context: ctx,
Body: reqBody,
}
resBody := &agent.ESNodeInfo{}
err = client.DoRequest(req, resBody)
if err != nil {
return nil, err
}
return resBody, nil
}
func (client *Client) CreatePipeline(ctx context.Context, agentBaseURL string, body []byte) error{
req := &util.Request{
Method: http.MethodPost,
Url: agentBaseURL + "/pipeline/tasks/",
Body: body,
Context: ctx,
}
resBody := util.MapStr{}
return client.DoRequest(req, &resBody)
}
func (client *Client) DeletePipeline(ctx context.Context, agentBaseURL, pipelineID string) error{
req := &util.Request{
Method: http.MethodDelete,
Url: fmt.Sprintf("%s/pipeline/task/%s", agentBaseURL, pipelineID),
Context: ctx,
}
return client.DoRequest(req, nil)
}
func (client *Client) SetKeystoreValue(ctx context.Context, agentBaseURL string, key, value string) error{
body := util.MapStr{
"key": key,
"value": value,
}
req := &util.Request{
Method: http.MethodPost,
Url: fmt.Sprintf("%s/_framework/keystore", agentBaseURL),
Context: ctx,
Body: util.MustToJSONBytes(body),
}
return client.DoRequest(req, nil)
}
func (client *Client) SaveDynamicConfig(ctx context.Context, agentBaseURL string, name, content string) error{
body := util.MapStr{
"configs": util.MapStr{
name: content,
},
}
req := &util.Request{
Method: http.MethodPost,
Url: fmt.Sprintf("%s/agent/config", agentBaseURL),
Context: ctx,
Body: util.MustToJSONBytes(body),
}
return client.DoRequest(req, nil)
}
func (client *Client) SaveIngestConfig(ctx context.Context, agentBaseURL string) error {
ingestCfg, basicAuth, err := common.GetAgentIngestConfig()
if err != nil {
return err
}
if basicAuth != nil && basicAuth.Password != "" {
err = client.SetKeystoreValue(ctx, agentBaseURL, "ingest_cluster_password", basicAuth.Password)
if err != nil {
return fmt.Errorf("set keystore value to agent error: %w", err)
}
}
err = client.SaveDynamicConfig(context.Background(), agentBaseURL, "ingest", ingestCfg )
if err != nil {
return fmt.Errorf("save dynamic config to agent error: %w", err)
}
return nil
}
func (client *Client) DoRequest(req *util.Request, respObj interface{}) error {
return client.Executor.DoRequest(req, respObj)
}