/* 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 . */ package cfg import ( "errors" "fmt" "net/http" "os" "github.com/elastic/elastic-transport-go/v8/elastictransport" "github.com/elastic/go-elasticsearch/v9" "gopkg.in/yaml.v3" ) // used in general config struct type Cluster struct { Uri, User, Pass string client *elasticsearch.TypedClient Default bool } // used just for writing back to the config file type ClusterConfig struct { Uri, User, Pass string Default bool } // to write the config, we avoid all other config settings type WriteConfig struct { Clusters map[string]*ClusterConfig } func (cluster *Cluster) ES() *elasticsearch.TypedClient { if cluster.client == nil { fmt.Println("no current cluster, use 'esctl cluster switch ' to set one") os.Exit(1) } return cluster.client } func (cluster *Cluster) SetClient(client *elasticsearch.TypedClient) { cluster.client = client } // set Default=true for the given cluster in the config (if exists) func (conf *Config) SwitchCluster(name string) error { _, exists := conf.Clusters[name] if !exists { return errors.New("no cluster with that name configured") } cfg := WriteConfig{Clusters: map[string]*ClusterConfig{}} for clustername, cluster := range conf.Clusters { cfg.Clusters[clustername] = &ClusterConfig{ Uri: cluster.Uri, User: cluster.User, Pass: cluster.Pass, Default: false, } if clustername == name { cfg.Clusters[clustername].Default = true } } raw, err := yaml.Marshal(cfg) if err != nil { return fmt.Errorf("failed to marshal cluster config: %w", err) } outfile := getDefaultPath() if conf.ConfigFile != "" { outfile = conf.ConfigFile } if err := os.WriteFile(outfile, raw, 0600); err != nil { return err } return nil } func (conf *Config) SetupES() error { // These headers are not needed with ES 9, but with ES 8, we set // them here so every API call uses it. The only exception being // the api repl, which does it on its own. headers := http.Header{} headers.Add("content-type", "application/json") headers.Add("Accept", "application/json") for _, cluster := range conf.Clusters { es, err := elasticsearch.NewTyped( elasticsearch.WithAddresses(cluster.Uri), elasticsearch.WithBasicAuth(cluster.User, cluster.Pass), elasticsearch.WithTransportOptions( conf.getTransport(), elastictransport.WithHeader(headers), ), ) if err != nil { return fmt.Errorf("failed to setup elasticsearch connection: %w", err) } cluster.SetClient(es) } return nil }