diff --git a/cmd/cloudflared/tunnel/cmd.go b/cmd/cloudflared/tunnel/cmd.go index 92f20bd7752..f7482154df5 100644 --- a/cmd/cloudflared/tunnel/cmd.go +++ b/cmd/cloudflared/tunnel/cmd.go @@ -139,6 +139,7 @@ func Commands() []*cli.Command { buildVirtualNetworkSubcommand(false), buildRunCommand(), buildListCommand(), + buildReadyCommand(), buildInfoCommand(), buildIngressSubcommand(), buildDeleteCommand(), diff --git a/cmd/cloudflared/tunnel/subcommands.go b/cmd/cloudflared/tunnel/subcommands.go index bef86887ebc..20604290bb8 100644 --- a/cmd/cloudflared/tunnel/subcommands.go +++ b/cmd/cloudflared/tunnel/subcommands.go @@ -5,6 +5,8 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" + "net/http" "os" "path/filepath" "regexp" @@ -397,6 +399,35 @@ func fmtConnections(connections []cfapi.Connection, showRecentlyDisconnected boo return strings.Join(output, ", ") } +func buildReadyCommand() *cli.Command { + return &cli.Command{ + Name: "ready", + Action: cliutil.ConfiguredAction(readyCommand), + Usage: "Call /ready endpoint and return proper exit code", + UsageText: "cloudflared tunnel [tunnel command options] ready [subcommand options]", + Description: "cloudflared tunnel ready will return proper exit code based on the /ready endpoint", + Flags: []cli.Flag{}, + CustomHelpTemplate: commandHelpTemplate(), + } +} + +func readyCommand(c *cli.Context) error { + metricsOpts := c.String("metrics") + requestURL := fmt.Sprintf("http://%s/ready", metricsOpts) + res, err := http.Get(requestURL) + if err != nil { + return err + } + if res.StatusCode != 200 { + body, err := io.ReadAll(res.Body) + if err != nil { + return err + } + return fmt.Errorf("http://%s/ready endpoint returned status code %d\n%s", metricsOpts, res.StatusCode, body) + } + return nil +} + func buildInfoCommand() *cli.Command { return &cli.Command{ Name: "info",