TUN-3451: Cloudflared tunnel ingress command
This commit is contained in:
		
							parent
							
								
									407c9550d7
								
							
						
					
					
						commit
						86a7af3dc4
					
				|  | @ -182,8 +182,7 @@ func Commands() []*cli.Command { | |||
| 	subcommands = append(subcommands, buildRunCommand()) | ||||
| 	subcommands = append(subcommands, buildCleanupCommand()) | ||||
| 	subcommands = append(subcommands, buildRouteCommand()) | ||||
| 	subcommands = append(subcommands, buildValidateCommand()) | ||||
| 	subcommands = append(subcommands, buildRuleCommand()) | ||||
| 	subcommands = append(subcommands, buildIngressSubcommand()) | ||||
| 
 | ||||
| 	cmds = append(cmds, buildTunnelCommand(subcommands)) | ||||
| 
 | ||||
|  | @ -221,6 +220,38 @@ func buildTunnelCommand(subcommands []*cli.Command) *cli.Command { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func buildIngressSubcommand() *cli.Command { | ||||
| 	return &cli.Command{ | ||||
| 		Name:     "ingress", | ||||
| 		Category: "Tunnel", | ||||
| 		Usage:    "Validate and test cloudflared tunnel's ingress configuration", | ||||
| 		Hidden:   true, | ||||
| 		Description: ` | ||||
| 		Cloudflared lets you route traffic from the internet to multiple different addresses on your | ||||
| 		origin. Multiple-origin routing is configured by a set of rules. Each rule matches traffic | ||||
| 		by its hostname or path, and routes it to an address. These rules are configured under the | ||||
| 		'ingress' key of your config.yaml, for example: | ||||
| 
 | ||||
| 		ingress: | ||||
| 		  - hostname: www.example.com | ||||
| 		    service: https://localhost:8000
 | ||||
| 		  - hostname: *.example.xyz | ||||
| 		    path: /[a-zA-Z]+.html | ||||
| 		    service: https://localhost:8001
 | ||||
| 		  - hostname: * | ||||
| 		    service: https://localhost:8002
 | ||||
| 
 | ||||
| 		To ensure cloudflared can route all incoming requests, the last rule must be a catch-all | ||||
| 		rule that matches all traffic. You can validate these rules with the 'ingress validate' | ||||
| 		command, and test which rule matches a particular URL with 'ingress rule <URL>'. | ||||
| 
 | ||||
| 		Multiple-origin routing is incompatible with the --url flag. | ||||
| 		`, | ||||
| 		Subcommands: []*cli.Command{buildValidateCommand(), buildRuleCommand()}, | ||||
| 		Flags:       tunnelFlags(false), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TunnelCommand(c *cli.Context) error { | ||||
| 	if name := c.String("name"); name != "" { // Start a named tunnel
 | ||||
| 		return adhocNamedTunnel(c, name) | ||||
|  |  | |||
|  | @ -9,7 +9,6 @@ import ( | |||
| 
 | ||||
| 	"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" | ||||
|  | @ -91,6 +90,9 @@ func (ing ingress) validate() ([]rule, error) { | |||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if service.Scheme == "" || service.Hostname() == "" { | ||||
| 			return nil, fmt.Errorf("The service %s must have a scheme and a hostname", r.Service) | ||||
| 		} | ||||
| 
 | ||||
| 		// Ensure that there are no wildcards anywhere except the first character
 | ||||
| 		// of the hostname.
 | ||||
|  | @ -148,32 +150,28 @@ 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 | ||||
| 	} | ||||
| func ingressContext(c *cli.Context) ([]rule, error) { | ||||
| 	configFilePath := c.String("config") | ||||
| 	if configFilePath == "" { | ||||
| 		return nil, nil, config.ErrNoConfigFile | ||||
| 		return nil, config.ErrNoConfigFile | ||||
| 	} | ||||
| 	log.Infof("Validating %s", configFilePath) | ||||
| 	fmt.Printf("Reading from config file %s\n", configFilePath) | ||||
| 	configBytes, err := ioutil.ReadFile(configFilePath) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	rules, err := parseIngress(configBytes) | ||||
| 	return rules, log, err | ||||
| 	return rules, err | ||||
| } | ||||
| 
 | ||||
| // Validates the ingress rules in the cloudflared config file
 | ||||
| func validateCommand(c *cli.Context) error { | ||||
| 	_, log, err := ingressContext(c) | ||||
| 	_, err := ingressContext(c) | ||||
| 	if err != nil { | ||||
| 		log.Error(err.Error()) | ||||
| 		fmt.Println(err.Error()) | ||||
| 		return errors.New("Validation failed") | ||||
| 	} | ||||
| 	log.Infof("OK") | ||||
| 	fmt.Println("OK") | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
|  | @ -189,7 +187,7 @@ func buildValidateCommand() *cli.Command { | |||
| 
 | ||||
| // Checks which ingress rule matches the given URL.
 | ||||
| func ruleCommand(c *cli.Context) error { | ||||
| 	rules, log, err := ingressContext(c) | ||||
| 	rules, err := ingressContext(c) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -206,7 +204,7 @@ func ruleCommand(c *cli.Context) error { | |||
| 	} | ||||
| 	for i, r := range rules { | ||||
| 		if r.matches(requestURL) { | ||||
| 			log.Infof("Matched rule #%d", i+1) | ||||
| 			fmt.Printf("Matched rule #%d\n", i+1) | ||||
| 			fmt.Println(r.String()) | ||||
| 			return nil | ||||
| 		} | ||||
|  |  | |||
|  | @ -127,6 +127,14 @@ ingress: | |||
|     service: https://localhost:8000
 | ||||
|     path: "*/subpath2" | ||||
|   - service: https://localhost:8001
 | ||||
| `}, | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "Service must have a scheme", | ||||
| 			args: args{rawYAML: ` | ||||
| ingress: | ||||
|   - service: localhost:8000 | ||||
| `}, | ||||
| 			wantErr: true, | ||||
| 		}, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue