Skip to content

Commit 9909e9d

Browse files
TUN-5754: Allow ingress validate to take plaintext option
Ingress validate currently validates config from a file. This PR adds a new --json/-j flag to provide the ingress/config data as a plaintext command line argument.
1 parent 051b2cf commit 9909e9d

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

cmd/cloudflared/tunnel/ingress_subcommands.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tunnel
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"net/url"
67

@@ -12,6 +13,15 @@ import (
1213
"github.com/urfave/cli/v2"
1314
)
1415

16+
const ingressDataJSONFlagName = "json"
17+
18+
var ingressDataJSON = &cli.StringFlag{
19+
Name: ingressDataJSONFlagName,
20+
Aliases: []string{"j"},
21+
Usage: `Accepts data in the form of json as an input rather than read from a file`,
22+
EnvVars: []string{"TUNNEL_INGRESS_VALIDATE_JSON"},
23+
}
24+
1525
func buildIngressSubcommand() *cli.Command {
1626
return &cli.Command{
1727
Name: "ingress",
@@ -49,6 +59,7 @@ func buildValidateIngressCommand() *cli.Command {
4959
Usage: "Validate the ingress configuration ",
5060
UsageText: "cloudflared tunnel [--config FILEPATH] ingress validate",
5161
Description: "Validates the configuration file, ensuring your ingress rules are OK.",
62+
Flags: []cli.Flag{ingressDataJSON},
5263
}
5364
}
5465

@@ -69,12 +80,11 @@ func buildTestURLCommand() *cli.Command {
6980

7081
// validateIngressCommand check the syntax of the ingress rules in the cloudflared config file
7182
func validateIngressCommand(c *cli.Context, warnings string) error {
72-
conf := config.GetConfiguration()
73-
if conf.Source() == "" {
74-
fmt.Println("No configuration file was found. Please create one, or use the --config flag to specify its filepath. You can use the help command to learn more about configuration files")
75-
return nil
83+
conf, err := getConfiguration(c)
84+
if err != nil {
85+
return err
7686
}
77-
fmt.Println("Validating rules from", conf.Source())
87+
7888
if _, err := ingress.ParseIngress(conf); err != nil {
7989
return errors.Wrap(err, "Validation failed")
8090
}
@@ -90,6 +100,22 @@ func validateIngressCommand(c *cli.Context, warnings string) error {
90100
return nil
91101
}
92102

103+
func getConfiguration(c *cli.Context) (*config.Configuration, error) {
104+
var conf *config.Configuration
105+
if c.IsSet(ingressDataJSONFlagName) {
106+
ingressJSON := c.String(ingressDataJSONFlagName)
107+
fmt.Println("Validating rules from cmdline flag --json")
108+
err := json.Unmarshal([]byte(ingressJSON), &conf)
109+
return conf, err
110+
}
111+
conf = config.GetConfiguration()
112+
if conf.Source() == "" {
113+
return nil, errors.New("No configuration file was found. Please create one, or use the --config flag to specify its filepath. You can use the help command to learn more about configuration files")
114+
}
115+
fmt.Println("Validating rules from", conf.Source())
116+
return conf, nil
117+
}
118+
93119
// testURLCommand checks which ingress rule matches the given URL.
94120
func testURLCommand(c *cli.Context) error {
95121
requestArg := c.Args().First()

cmd/cloudflared/tunnel/subcommand_context_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/google/uuid"
1212
"github.com/pkg/errors"
1313
"github.com/rs/zerolog"
14+
"github.com/stretchr/testify/assert"
1415
"github.com/urfave/cli/v2"
1516

1617
"github.com/cloudflare/cloudflared/cfapi"
@@ -322,3 +323,48 @@ func Test_subcommandContext_Delete(t *testing.T) {
322323
})
323324
}
324325
}
326+
327+
func Test_subcommandContext_ValidateIngressCommand(t *testing.T) {
328+
var tests = []struct {
329+
name string
330+
c *cli.Context
331+
wantErr bool
332+
expectedErr error
333+
}{
334+
{
335+
name: "read a valid configuration from data",
336+
c: func() *cli.Context {
337+
data := `{ "warp-routing": {"enabled": true}, "originRequest" : {"connectTimeout": 10}, "ingress" : [ {"hostname": "test", "service": "https://localhost:8000" } , {"service": "http_status:404"} ]}`
338+
flagSet := flag.NewFlagSet("json", flag.PanicOnError)
339+
flagSet.String(ingressDataJSONFlagName, data, "")
340+
c := cli.NewContext(cli.NewApp(), flagSet, nil)
341+
_ = c.Set(ingressDataJSONFlagName, data)
342+
return c
343+
}(),
344+
},
345+
{
346+
name: "read an invalid configuration with multiple mistakes",
347+
c: func() *cli.Context {
348+
data := `{ "ingress" : [ {"hostname": "test", "service": "localhost:8000" } , {"service": "http_status:invalid_status"} ]}`
349+
flagSet := flag.NewFlagSet("json", flag.PanicOnError)
350+
flagSet.String(ingressDataJSONFlagName, data, "")
351+
c := cli.NewContext(cli.NewApp(), flagSet, nil)
352+
_ = c.Set(ingressDataJSONFlagName, data)
353+
return c
354+
}(),
355+
wantErr: true,
356+
expectedErr: errors.New("Validation failed: localhost:8000 is an invalid address, please make sure it has a scheme and a hostname"),
357+
},
358+
}
359+
360+
for _, tt := range tests {
361+
t.Run(tt.name, func(t *testing.T) {
362+
err := validateIngressCommand(tt.c, "")
363+
if tt.wantErr {
364+
assert.Equal(t, tt.expectedErr.Error(), err.Error())
365+
} else {
366+
assert.Nil(t, err)
367+
}
368+
})
369+
}
370+
}

0 commit comments

Comments
 (0)