diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d37564..370c660 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: 1.19 + go-version: 1.21 - name: Test run: go test -v ./... diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 8d7fce1..b8ea0ae 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -16,3 +16,5 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 diff --git a/README.md b/README.md index dd88d14..d117eb5 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,15 @@ Available Commands: query Checks the total hits/results of an Elasticsearch query Flags: - -H, --hostname string Hostname of the Elasticsearch instance (default "localhost") + -H, --hostname string Hostname of the Elasticsearch instance (CHECK_ELASTICSEARCH_HOSTNAME) (default "localhost") -p, --port int Port of the Elasticsearch instance (default 9200) - -U, --username string Username if authentication is required - -P, --password string Password if authentication is required + -U, --username string Username for HTTP Basic Authentication (CHECK_ELASTICSEARCH_USERNAME) + -P, --password string Password for HTTP Basic Authentication (CHECK_ELASTICSEARCH_PASSWORD) -S, --tls Use a HTTPS connection --insecure Skip the verification of the server's TLS certificate + --ca-file string Specify the CA File for TLS authentication (CHECK_ELASTICSEARCH_CA_FILE) + --cert-file string Specify the Certificate File for TLS authentication (CHECK_ELASTICSEARCH_CERT_FILE) + --key-file string Specify the Key File for TLS authentication (CHECK_ELASTICSEARCH_KEY_FILE) -t, --timeout int Timeout in seconds for the CheckPlugin (default 30) -h, --help help for check_elasticsearch -v, --version version for check_elasticsearch @@ -28,6 +31,8 @@ Flags: The check plugin respects the environment variables `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY`. +Various flags can be set with environment variables, refer to the help to see which flags. + ### Health Checks the health status of an Elasticsearch cluster. diff --git a/cmd/config.go b/cmd/config.go index fe1afa6..d5c772a 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -5,6 +5,8 @@ import ( "net" "net/http" "net/url" + "os" + "reflect" "strconv" "time" @@ -14,17 +16,50 @@ import ( ) type Config struct { - Hostname string - BasicAuth string - Bearer string - CAFile string - CertFile string - KeyFile string - Username string - Password string - Port int - TLS bool - Insecure bool + Bearer string // Currently unused in CLI + Hostname string `env:"CHECK_ELASTICSEARCH_HOSTNAME"` + CAFile string `env:"CHECK_ELASTICSEARCH_CA_FILE"` + CertFile string `env:"CHECK_ELASTICSEARCH_CERT_FILE"` + KeyFile string `env:"CHECK_ELASTICSEARCH_KEY_FILE"` + Username string `env:"CHECK_ELASTICSEARCH_USERNAME"` + Password string `env:"CHECK_ELASTICSEARCH_PASSWORD"` + Port int + TLS bool + Insecure bool +} + +// LoadFromEnv can be used to load struct values from 'env' tags. +// Mainly used to avoid passing secrets via the CLI +// +// type Config struct { +// Token string `env:"BEARER_TOKEN"` +// } +func loadFromEnv(config interface{}) { + configValue := reflect.ValueOf(config).Elem() + configType := configValue.Type() + + for i := 0; i < configValue.NumField(); i++ { + field := configType.Field(i) + tag := field.Tag.Get("env") + + // If there's no "env" tag, skip this field. + if tag == "" { + continue + } + + envValue := os.Getenv(tag) + + if envValue == "" { + continue + } + + // Potential for addding different types + // nolint: exhaustive, gocritic + switch field.Type.Kind() { + case reflect.String: + configValue.Field(i).SetString(envValue) + } + } } var cliConfig Config diff --git a/cmd/config_test.go b/cmd/config_test.go new file mode 100644 index 0000000..2b5ea0c --- /dev/null +++ b/cmd/config_test.go @@ -0,0 +1,26 @@ +package cmd + +import ( + "os" + "testing" +) + +func TestLoadFromEnv(t *testing.T) { + c := Config{} + + err := os.Setenv("CHECK_ELASTICSEARCH_USERNAME", "foobar") + defer os.Unsetenv("CHECK_ELASTICSEARCH_USERNAME") // to not impact other tests + + if err != nil { + t.Error("Did not expect error, got: %w", err) + } + + loadFromEnv(&c) + + if "foobar" != c.Username { + t.Error("\nActual: ", c.Username, "\nExpected: ", "foobar") + } + if "" != c.Password { + t.Error("\nActual: ", c.Password, "\nExpected: ", "empty-string") + } +} diff --git a/cmd/root.go b/cmd/root.go index bd11625..b395c3c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -42,22 +42,30 @@ func init() { pfs := rootCmd.PersistentFlags() pfs.StringVarP(&cliConfig.Hostname, "hostname", "H", "localhost", - "Hostname of the Elasticsearch instance") + "Hostname of the Elasticsearch instance (CHECK_ELASTICSEARCH_HOSTNAME)") pfs.IntVarP(&cliConfig.Port, "port", "p", 9200, "Port of the Elasticsearch instance") pfs.StringVarP(&cliConfig.Username, "username", "U", "", - "Username for HTTP Basic Authentication") + "Username for HTTP Basic Authentication (CHECK_ELASTICSEARCH_USERNAME)") pfs.StringVarP(&cliConfig.Password, "password", "P", "", - "Password for HTTP Basic Authentication") + "Password for HTTP Basic Authentication (CHECK_ELASTICSEARCH_PASSWORD)") pfs.BoolVarP(&cliConfig.TLS, "tls", "S", false, "Use a HTTPS connection") pfs.BoolVar(&cliConfig.Insecure, "insecure", false, "Skip the verification of the server's TLS certificate") + pfs.StringVarP(&cliConfig.CAFile, "ca-file", "", "", + "Specify the CA File for TLS authentication (CHECK_ELASTICSEARCH_CA_FILE)") + pfs.StringVarP(&cliConfig.CertFile, "cert-file", "", "", + "Specify the Certificate File for TLS authentication (CHECK_ELASTICSEARCH_CERT_FILE)") + pfs.StringVarP(&cliConfig.KeyFile, "key-file", "", "", + "Specify the Key File for TLS authentication (CHECK_ELASTICSEARCH_KEY_FILE)") pfs.IntVarP(&timeout, "timeout", "t", timeout, "Timeout in seconds for the CheckPlugin") rootCmd.Flags().SortFlags = false pfs.SortFlags = false + + loadFromEnv(&cliConfig) } func Help(cmd *cobra.Command, _ []string) {