mirror of
https://codeberg.org/scip/esctl.git
synced 2026-08-24 08:04:17 +02:00
Additions and enhancements (#14)
- add interactive API repl - enhance cluster status output (use -v) - add more ccr commands - refactoring
This commit is contained in:
153
pkg/es/repl.go
Normal file
153
pkg/es/repl.go
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
Copyright © 2026 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package es
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"codeberg.org/scip/esctl/pkg/cfg"
|
||||
"github.com/chzyer/readline"
|
||||
)
|
||||
|
||||
func encodeAuth(username, password string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||
}
|
||||
|
||||
func CallAPI(conf *cfg.Config, input []string) error {
|
||||
var data string
|
||||
|
||||
verb := strings.ToUpper(input[0])
|
||||
path := input[1]
|
||||
|
||||
if len(input) == 3 {
|
||||
data = input[2]
|
||||
}
|
||||
|
||||
// we're using port-forwards anyway
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: tr}
|
||||
|
||||
req, err := http.NewRequest(verb, conf.DefaultCluster.Uri+path, bytes.NewBuffer([]byte(data)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("accept", "application/json")
|
||||
req.Header.Add("Authorization", "Basic "+encodeAuth(conf.DefaultCluster.User, conf.DefaultCluster.Pass))
|
||||
|
||||
// actually execute the request
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read and print response
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %s", err)
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
error := json.Indent(&pretty, body, "", "\t")
|
||||
if error != nil {
|
||||
return fmt.Errorf("json parse error: %s", err)
|
||||
}
|
||||
|
||||
fmt.Println(pretty.String())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Repl(conf *cfg.Config) error {
|
||||
verbs := []string{"post", "get", "put", "delete"}
|
||||
|
||||
fmt.Println("Input format: verb path [data]")
|
||||
fmt.Println("example: post /yourindex/_ccr/pause_follow")
|
||||
|
||||
reader, err := readline.NewEx(&readline.Config{
|
||||
Prompt: "> ",
|
||||
HistoryFile: os.Getenv("HOME") + "/.config/esctl/history",
|
||||
HistoryLimit: 500,
|
||||
InterruptPrompt: "^C",
|
||||
EOFPrompt: "exit",
|
||||
HistorySearchFold: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize readline lib: %s", err)
|
||||
}
|
||||
|
||||
for {
|
||||
text, err := reader.Readline()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
text = strings.TrimSpace(text)
|
||||
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.SplitN(strings.TrimSpace(text), " ", 3)
|
||||
if len(parts) < 2 {
|
||||
fmt.Println("error: you need to input a verb, uri [and post data]")
|
||||
continue
|
||||
}
|
||||
|
||||
if !slices.Contains(verbs, strings.ToLower(parts[0])) {
|
||||
fmt.Println("error: verb must be one of " + strings.Join(verbs, ","))
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(parts[1], "/") {
|
||||
fmt.Println("error: url path must start with /")
|
||||
continue
|
||||
}
|
||||
|
||||
if len(parts) == 3 {
|
||||
data := map[string]any{}
|
||||
err := json.Unmarshal([]byte(parts[2]), &data)
|
||||
if err != nil {
|
||||
fmt.Printf("error: input data is not proper JSON: %s", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
err = CallAPI(conf, parts)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to call API: %s\n", err)
|
||||
}
|
||||
|
||||
reader.SetPrompt("> ")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user