diff --git a/cmd/cloudflared/config/configuration.go b/cmd/cloudflared/config/configuration.go index ea453008..20de4eb8 100644 --- a/cmd/cloudflared/config/configuration.go +++ b/cmd/cloudflared/config/configuration.go @@ -2,6 +2,7 @@ package config import ( "errors" + "fmt" "os" "path/filepath" "runtime" @@ -28,6 +29,8 @@ var ( // Windows default config dir was ~/cloudflare-warp in documentation; let's keep it compatible defaultUserConfigDirs = []string{"~/.cloudflared", "~/.cloudflare-warp", "~/cloudflare-warp"} defaultNixConfigDirs = []string{"/etc/cloudflared", DefaultUnixConfigLocation} + + ErrNoConfigFile = fmt.Errorf("Cannot determine default configuration path. No file %v in %v", DefaultConfigFiles, DefaultConfigSearchDirectories()) ) const DefaultCredentialFile = "cert.pem" diff --git a/cmd/cloudflared/tunnel/cmd.go b/cmd/cloudflared/tunnel/cmd.go index 8d8bfeb9..d679dcfe 100644 --- a/cmd/cloudflared/tunnel/cmd.go +++ b/cmd/cloudflared/tunnel/cmd.go @@ -182,6 +182,7 @@ func Commands() []*cli.Command { subcommands = append(subcommands, buildRunCommand()) subcommands = append(subcommands, buildCleanupCommand()) subcommands = append(subcommands, buildRouteCommand()) + subcommands = append(subcommands, buildValidateCommand()) cmds = append(cmds, buildTunnelCommand(subcommands)) @@ -334,11 +335,7 @@ func StartServer( dnsReadySignal := make(chan struct{}) if c.String("config") == "" { - log.Infof( - "Cannot determine default configuration path. No file %v in %v", - config.DefaultConfigFiles, - config.DefaultConfigSearchDirectories(), - ) + log.Infof(config.ErrNoConfigFile.Error()) } if c.IsSet("trace-output") { @@ -602,7 +599,7 @@ func Before(c *cli.Context) error { } if c.String("config") == "" { - logger.Debugf("Cannot determine default configuration path. No file %v in %v", config.DefaultConfigFiles, config.DefaultConfigSearchDirectories()) + logger.Debugf(config.ErrNoConfigFile.Error()) } inputSource, err := config.FindInputSourceContext(c) if err != nil { diff --git a/cmd/cloudflared/tunnel/configuration.go b/cmd/cloudflared/tunnel/configuration.go index 79550165..13d61361 100644 --- a/cmd/cloudflared/tunnel/configuration.go +++ b/cmd/cloudflared/tunnel/configuration.go @@ -95,7 +95,7 @@ func dnsProxyStandAlone(c *cli.Context) bool { func findOriginCert(c *cli.Context, logger logger.Service) (string, error) { originCertPath := c.String("origincert") if originCertPath == "" { - logger.Infof("Cannot determine default origin certificate path. No file %s in %v", config.DefaultCredentialFile, config.DefaultConfigSearchDirectories()) + logger.Infof(config.ErrNoConfigFile.Error()) if isRunningFromTerminal() { logger.Errorf("You need to specify the origin certificate path with --origincert option, or set TUNNEL_ORIGIN_CERT environment variable. See %s for more information.", argumentsUrl) return "", fmt.Errorf("Client didn't specify origincert path when running from terminal") diff --git a/cmd/cloudflared/tunnel/ingress.go b/cmd/cloudflared/tunnel/ingress.go index 027339e2..d76b8362 100644 --- a/cmd/cloudflared/tunnel/ingress.go +++ b/cmd/cloudflared/tunnel/ingress.go @@ -2,10 +2,16 @@ package tunnel import ( "fmt" + "io/ioutil" "net/url" "regexp" + "github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil" + "github.com/cloudflare/cloudflared/cmd/cloudflared/config" + "github.com/cloudflare/cloudflared/logger" + "github.com/pkg/errors" + "github.com/urfave/cli/v2" "gopkg.in/yaml.v2" ) @@ -96,3 +102,42 @@ func parseIngress(rawYAML []byte) ([]rule, error) { } return ing.validate() } + +func ingressContext(c *cli.Context) ([]rule, *logger.OutputWriter, error) { + log, err := createLogger(c, false, false) + if err != nil { + return nil, nil, err + } + configFilePath := c.String("config") + if configFilePath == "" { + return nil, nil, config.ErrNoConfigFile + } + log.Infof("Validating %s", configFilePath) + configBytes, err := ioutil.ReadFile(configFilePath) + if err != nil { + return nil, nil, err + } + rules, err := parseIngress(configBytes) + return rules, log, err +} + +// Validates the ingress rules in the cloudflared config file +func validateCommand(c *cli.Context) error { + _, log, err := ingressContext(c) + if err != nil { + log.Error(err.Error()) + return errors.New("Validation failed") + } + log.Infof("OK") + return nil +} + +func buildValidateCommand() *cli.Command { + return &cli.Command{ + Name: "validate", + Action: cliutil.ErrorHandler(validateCommand), + Usage: "Validate the ingress configuration ", + UsageText: "cloudflared tunnel [--config FILEPATH] ingress validate", + Description: "Validates the configuration file, ensuring your ingress rules are OK.", + } +}