diff --git a/cmd/cloudflared/tunnel/cmd.go b/cmd/cloudflared/tunnel/cmd.go index e5b0ebb5..98a889e3 100644 --- a/cmd/cloudflared/tunnel/cmd.go +++ b/cmd/cloudflared/tunnel/cmd.go @@ -128,6 +128,7 @@ func Commands() []*cli.Command { buildVirtualNetworkSubcommand(false), buildRunCommand(), buildListCommand(), + buildHealthCommand(), buildInfoCommand(), buildIngressSubcommand(), buildDeleteCommand(), diff --git a/cmd/cloudflared/tunnel/subcommands.go b/cmd/cloudflared/tunnel/subcommands.go index bef86887..62605c89 100644 --- a/cmd/cloudflared/tunnel/subcommands.go +++ b/cmd/cloudflared/tunnel/subcommands.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "net/http" "os" "path/filepath" "regexp" @@ -397,6 +398,31 @@ func fmtConnections(connections []cfapi.Connection, showRecentlyDisconnected boo return strings.Join(output, ", ") } +func buildHealthCommand() *cli.Command { + return &cli.Command{ + Name: "health", + Action: cliutil.ConfiguredAction(healthCommand), + Usage: "Tunnel health exit code", + UsageText: "cloudflared tunnel [tunnel command options] health [subcommand options]", + Description: "cloudflared tunnel health will return proper exit code if tunnel is healthy or unhealthy", + Flags: []cli.Flag{}, + CustomHelpTemplate: commandHelpTemplate(), + } +} + +func healthCommand(c *cli.Context) error { + metrics := strings.Split(c.String("metrics"), ":") + requestURL := fmt.Sprintf("http://%s:%s/ready", metrics[0], metrics[1]) + res, err := http.Get(requestURL) + if err != nil { + return err + } + if res.StatusCode != 200 { + return fmt.Errorf("health /ready endpoint returned status code %d", res.StatusCode) + } + return nil +} + func buildInfoCommand() *cli.Command { return &cli.Command{ Name: "info",