add a health check command
Useful in restricted environments where commands like curl and such are not available. Fixes #1129 Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
8be8343fee
commit
c8d94f0a27
5 changed files with 124 additions and 4 deletions
120
internal/cmd/ping.go
Normal file
120
internal/cmd/ping.go
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright (C) 2019-2023 Nicola Murino
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published
|
||||||
|
// by the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// 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 Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/drakkan/sftpgo/v2/internal/config"
|
||||||
|
"github.com/drakkan/sftpgo/v2/internal/httpclient"
|
||||||
|
"github.com/drakkan/sftpgo/v2/internal/httpd"
|
||||||
|
"github.com/drakkan/sftpgo/v2/internal/logger"
|
||||||
|
"github.com/drakkan/sftpgo/v2/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getHealthzURLFromBindings(bindings []httpd.Binding) string {
|
||||||
|
for _, b := range bindings {
|
||||||
|
if b.Port > 0 && b.IsValid() {
|
||||||
|
var url string
|
||||||
|
if b.EnableHTTPS {
|
||||||
|
url = "https://"
|
||||||
|
} else {
|
||||||
|
url = "http://"
|
||||||
|
}
|
||||||
|
if b.Address == "" {
|
||||||
|
url += "127.0.0.1"
|
||||||
|
} else {
|
||||||
|
url += b.Address
|
||||||
|
}
|
||||||
|
url += fmt.Sprintf(":%d", b.Port)
|
||||||
|
url += "/healthz"
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pingCmd = &cobra.Command{
|
||||||
|
Use: "ping",
|
||||||
|
Short: "Issues an health check to SFTPGo",
|
||||||
|
Long: `This command is only useful in environments where system commands like
|
||||||
|
"curl", "wget" and similar are not available.
|
||||||
|
Checks over UNIX domain sockets are not supported`,
|
||||||
|
Run: func(_ *cobra.Command, _ []string) {
|
||||||
|
logger.DisableLogger()
|
||||||
|
logger.EnableConsoleLogger(zerolog.DebugLevel)
|
||||||
|
configDir = util.CleanDirInput(configDir)
|
||||||
|
err := config.LoadConfig(configDir, configFile)
|
||||||
|
if err != nil {
|
||||||
|
logger.WarnToConsole("Unable to load configuration: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
httpConfig := config.GetHTTPConfig()
|
||||||
|
err = httpConfig.Initialize(configDir)
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorToConsole("error initializing http client: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
telemetryConfig := config.GetTelemetryConfig()
|
||||||
|
var url string
|
||||||
|
if telemetryConfig.BindPort > 0 {
|
||||||
|
if telemetryConfig.CertificateFile != "" && telemetryConfig.CertificateKeyFile != "" {
|
||||||
|
url += "https://"
|
||||||
|
} else {
|
||||||
|
url += "http://"
|
||||||
|
}
|
||||||
|
if telemetryConfig.BindAddress == "" {
|
||||||
|
url += "127.0.0.1"
|
||||||
|
} else {
|
||||||
|
url += telemetryConfig.BindAddress
|
||||||
|
}
|
||||||
|
url += fmt.Sprintf(":%d", telemetryConfig.BindPort)
|
||||||
|
url += "/healthz"
|
||||||
|
}
|
||||||
|
if url == "" {
|
||||||
|
httpdConfig := config.GetHTTPDConfig()
|
||||||
|
url = getHealthzURLFromBindings(httpdConfig.Bindings)
|
||||||
|
}
|
||||||
|
if url == "" {
|
||||||
|
logger.ErrorToConsole("no suitable configuration found, please enable the telemetry server or REST API over HTTP/S")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.DebugToConsole("Health Check URL %q", url)
|
||||||
|
resp, err := httpclient.RetryableGet(url)
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorToConsole("Unable to connect to SFTPGo: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
logger.ErrorToConsole("Unexpected status code %d", resp.StatusCode)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
logger.InfoToConsole("OK")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
addConfigFlags(pingCmd)
|
||||||
|
rootCmd.AddCommand(pingCmd)
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ Please take a look at the usage below to customize the options.`,
|
||||||
configDir = util.CleanDirInput(configDir)
|
configDir = util.CleanDirInput(configDir)
|
||||||
err := config.LoadConfig(configDir, configFile)
|
err := config.LoadConfig(configDir, configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.WarnToConsole("Unable to initialize data provider, config load error: %v", err)
|
logger.WarnToConsole("Unable to load configuration: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
kmsConfig := config.GetKMSConfig()
|
kmsConfig := config.GetKMSConfig()
|
||||||
|
|
|
@ -48,7 +48,7 @@ Please take a look at the usage below to customize the options.`,
|
||||||
configDir = util.CleanDirInput(configDir)
|
configDir = util.CleanDirInput(configDir)
|
||||||
err := config.LoadConfig(configDir, configFile)
|
err := config.LoadConfig(configDir, configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.WarnToConsole("Unable to initialize data provider, config load error: %v", err)
|
logger.WarnToConsole("Unable to load configuration: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
kmsConfig := config.GetKMSConfig()
|
kmsConfig := config.GetKMSConfig()
|
||||||
|
|
|
@ -47,7 +47,7 @@ Please take a look at the usage below to customize the options.`,
|
||||||
configDir = util.CleanDirInput(configDir)
|
configDir = util.CleanDirInput(configDir)
|
||||||
err := config.LoadConfig(configDir, configFile)
|
err := config.LoadConfig(configDir, configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.WarnToConsole("Unable to initialize data provider, config load error: %v", err)
|
logger.WarnToConsole("Unable to load configuration: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
kmsConfig := config.GetKMSConfig()
|
kmsConfig := config.GetKMSConfig()
|
||||||
|
|
|
@ -39,7 +39,7 @@ If the SMTP configuration is correct you should receive this email.`,
|
||||||
configDir = util.CleanDirInput(configDir)
|
configDir = util.CleanDirInput(configDir)
|
||||||
err := config.LoadConfig(configDir, configFile)
|
err := config.LoadConfig(configDir, configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.WarnToConsole("Unable to initialize data provider, config load error: %v", err)
|
logger.WarnToConsole("Unable to load configuration: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
smtpConfig := config.GetSMTPConfig()
|
smtpConfig := config.GetSMTPConfig()
|
||||||
|
|
Loading…
Reference in a new issue