helm-elasticstack/tools/elasticlicense/main.go

205 строки
5.3 KiB
Go

// Copyright (c) Microsoft and contributors. All rights reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
package main
import (
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
"github.com/google/subcommands"
)
func buildLicenseURL(host string, port int) string {
return fmt.Sprintf("http://%s:%d/_xpack/license", host, port)
}
func buildHTTPClient() *http.Client {
return &http.Client{
Timeout: time.Minute * 1,
}
}
func loadBasicAuth(authFile string) (*basicAuth, error) {
file, err := ioutil.ReadFile(authFile) // #nosec
if err != nil {
return nil, fmt.Errorf(`Failed to read the basic authentication
credentials from the file: %v`, err)
}
var auth basicAuth
err = json.Unmarshal(file, &auth)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal the basic auth: %v", err)
}
return &auth, nil
}
func setBasicAuth(req *http.Request, authFile string) error {
if authFile != "" {
basicAuth, err := loadBasicAuth(authFile)
if err != nil {
return err
}
req.SetBasicAuth(basicAuth.Username, basicAuth.Password)
}
return nil
}
type basicAuth struct {
Username string
Password string
}
type viewCmd struct {
host string
port int
authFile string
}
func (*viewCmd) Name() string { return "view" }
func (*viewCmd) Synopsis() string { return "Display the installed license in Elasticsearch" }
func (*viewCmd) Usage() string {
return `view [-host] <host name> [-port] <port> [-auth-file] <basic auth file path>:
Display the installed license to stdout
`
}
func (v *viewCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&v.host, "host", "localhost", "Host name of the Elasticsearch API")
f.IntVar(&v.port, "port", 9200, "Port of the Elastisearch API")
f.StringVar(&v.authFile, "auth-file", "", "File with basic authentication credentials")
}
func (v *viewCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
client := buildHTTPClient()
licenseURL := buildLicenseURL(v.host, v.port)
req, err := http.NewRequest(http.MethodGet, licenseURL, nil)
if err != nil {
fmt.Println(err)
return subcommands.ExitFailure
}
err = setBasicAuth(req, v.authFile)
if err != nil {
fmt.Println(err)
return subcommands.ExitFailure
}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
return subcommands.ExitFailure
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("Failed to get the license information with status code [%d]",
resp.StatusCode)
return subcommands.ExitFailure
}
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Failed to read the license from the HTTP response body")
return subcommands.ExitFailure
}
var prettyContent bytes.Buffer
err = json.Indent(&prettyContent, content, "", " ")
if err != nil {
fmt.Printf("Failed to indent the license content: %s\n", string(content))
return subcommands.ExitFailure
}
fmt.Print(string(prettyContent.Bytes()))
return subcommands.ExitSuccess
}
type installCmd struct {
host string
port int
licenseFile string
authFile string
}
func (*installCmd) Name() string { return "install" }
func (*installCmd) Synopsis() string { return "Install a new Elasticsearch license" }
func (*installCmd) Usage() string {
return `install [-host] <host name> [-port] <port> [-license-file] <path to license file> [-auth-file] <path to basic auth file>
Install a new license into Elasticsearch cluster
`
}
func (i *installCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&i.host, "host", "localhost", "Host name of the Elasticsearch API")
f.IntVar(&i.port, "port", 9200, "Port of the Elastisearch API")
f.StringVar(&i.licenseFile, "license-file", "", "Path to license file")
f.StringVar(&i.authFile, "auth-file", "", "Path to basic auth file")
}
func (i *installCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if _, err := os.Stat(i.licenseFile); os.IsNotExist(err) {
fmt.Printf("License file '%s' not found\n", i.licenseFile)
return subcommands.ExitFailure
}
file, err := os.Open(i.licenseFile)
if err != nil {
fmt.Printf("Failed to open the license file '%s'\n", i.licenseFile)
return subcommands.ExitFailure
}
licenseURL := buildLicenseURL(i.host, i.port)
req, err := http.NewRequest(http.MethodPut, licenseURL, file)
if err != nil {
fmt.Printf("Failed to build the request to install the license: %v\n", err)
return subcommands.ExitFailure
}
req.Header.Set("Content-Type", "application/json")
err = setBasicAuth(req, i.authFile)
if err != nil {
fmt.Println(err)
return subcommands.ExitFailure
}
client := buildHTTPClient()
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
return subcommands.ExitFailure
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("Failed to install the license with status code [%d]\n", resp.StatusCode)
return subcommands.ExitFailure
}
return subcommands.ExitSuccess
}
func main() {
subcommands.Register(subcommands.HelpCommand(), "")
subcommands.Register(subcommands.FlagsCommand(), "")
subcommands.Register(subcommands.CommandsCommand(), "")
subcommands.Register(&viewCmd{}, "")
subcommands.Register(&installCmd{}, "")
flag.Parse()
ctx := context.Background()
os.Exit(int(subcommands.Execute(ctx)))
}