Skip to content

Resolve FIXMEs for gateway-ctlr-name CLI arg #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions cmd/gateway/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import (
)

const (
domain string = "k8s-gateway.nginx.org"
namespace string = "nginx-gateway"
domain string = "k8s-gateway.nginx.org"
)

var (
Expand All @@ -26,13 +25,14 @@ var (
gatewayCtlrName = flag.String(
"gateway-ctlr-name",
"",
fmt.Sprintf("The name of the Gateway controller. The controller name must be of the form: DOMAIN/NAMESPACE/NAME. The controller's domain is '%s'; the namespace is '%s'", domain, namespace),
fmt.Sprintf("The name of the Gateway controller. The controller name must be of the form: DOMAIN/PATH. The controller's domain is '%s'", domain),
)

gatewayClassName = flag.String(
"gatewayclass",
"",
"The name of the GatewayClass resource. Every NGINX Gateway must have a unique corresponding GatewayClass resource")
"The name of the GatewayClass resource. Every NGINX Gateway must have a unique corresponding GatewayClass resource",
)
)

func main() {
Expand All @@ -47,7 +47,7 @@ func main() {

MustValidateArguments(
flag.CommandLine,
GatewayControllerParam(domain, namespace /* FIXME(f5yacobucci) dynamically set */),
GatewayControllerParam(domain),
GatewayClassParam(),
)

Expand Down
45 changes: 21 additions & 24 deletions cmd/gateway/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ import (
"errors"
"fmt"
"os"
"regexp"
"strings"

flag "github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/validation"

// Adding a dummy import here to remind us to check the controllerNameRegex when we update the Gateway API version.
_ "sigs.k8s.io/gateway-api/apis/v1beta1"
)

const (
errTmpl = "failed validation - flag: '--%s' reason: '%s'\n"
errTmpl = "failed validation - flag: '--%s' reason: '%s'\n"
controllerNameRegex = `^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$`
)

type (
Expand All @@ -22,13 +27,11 @@ type (
}
)

func GatewayControllerParam(domain string, namespace string) ValidatorContext {
func GatewayControllerParam(domain string) ValidatorContext {
name := "gateway-ctlr-name"
return ValidatorContext{
name,
func(flagset *flag.FlagSet) error {
// FIXME(f5yacobucci) this does not provide the same regex validation as
// GatewayClass.ControllerName. provide equal and then specific validation
param, err := flagset.GetString(name)
if err != nil {
return err
Expand All @@ -40,34 +43,28 @@ func GatewayControllerParam(domain string, namespace string) ValidatorContext {

fields := strings.Split(param, "/")
l := len(fields)
if l != 3 {
return errors.New("unsupported path length, must be form DOMAIN/NAMESPACE/NAME")
if l < 2 {
return errors.New("invalid format; must be DOMAIN/PATH")
}

for i := len(fields); i > 0; i-- {
switch i {
case 3:
if fields[0] != domain {
return fmt.Errorf("invalid domain: %s", fields[0])
}
fields = fields[1:]
case 2:
if fields[0] != namespace {
return fmt.Errorf("cross namespace unsupported: %s", fields[0])
}
fields = fields[1:]
case 1:
if fields[0] == "" {
return errors.New("must provide a name")
}
}
if fields[0] != domain {
return fmt.Errorf("invalid domain: %s; domain must be: %s", fields[0], domain)
}

return nil
return validateControllerName(param)
},
}
}

func validateControllerName(name string) error {
// Regex from: https://github.com/kubernetes-sigs/gateway-api/blob/547122f7f55ac0464685552898c560658fb40073/apis/v1alpha2/shared_types.go#L462
re := regexp.MustCompile(controllerNameRegex)
if !re.MatchString(name) {
return fmt.Errorf("invalid gateway controller name: %s; expected format is DOMAIN/PATH", name)
}
return nil
}

func GatewayClassParam() ValidatorContext {
name := "gatewayclass"
return ValidatorContext{
Expand Down
52 changes: 23 additions & 29 deletions cmd/gateway/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ var _ = Describe("Main", func() {
return testCase{
Flag: "gateway-ctlr-name",
Value: value,
ValidatorContext: GatewayControllerParam("k8s-gateway.nginx.org", "nginx-gateway"),
ValidatorContext: GatewayControllerParam("k8s-gateway.nginx.org"),
ExpError: expError,
}
}
Expand All @@ -171,29 +171,32 @@ var _ = Describe("Main", func() {
mockFlags = nil
})

It("should parse full gateway-ctlr-name", func() {
t := prepareTestCase(
"k8s-gateway.nginx.org/nginx-gateway/my-gateway",
expectSuccess,
)
tester(t)
}) // should parse full gateway-ctlr-name

It("should fail with too many path elements", func() {
t := prepareTestCase(
"k8s-gateway.nginx.org/nginx-gateway/my-gateway/broken",
expectError)
tester(t)
}) // should fail with too many path elements
It("should parse valid gateway-ctlr-name", func() {
table := []testCase{
prepareTestCase(
"k8s-gateway.nginx.org/my-gateway",
expectSuccess,
),
prepareTestCase(
"k8s-gateway.nginx.org/nginx-gateway/my-gateway",
expectSuccess,
),
prepareTestCase(
"k8s-gateway.nginx.org/nginx-gateway/my-gateway/v1",
expectSuccess,
),
}
runner(table)
}) // should parse valid gateway-ctlr-name

It("should fail with too few path elements", func() {
table := []testCase{
prepareTestCase(
"nginx-gateway/my-gateway",
"k8s-gateway.nginx.org",
expectError,
),
prepareTestCase(
"my-gateway",
"k8s-gateway.nginx.org/",
expectError,
),
}
Expand All @@ -205,26 +208,17 @@ var _ = Describe("Main", func() {
table := []testCase{
prepareTestCase(
// bad domain
"invalid-domain/nginx-gateway/my-gateway",
"invalid-domain/my-gateway",
expectError,
),
prepareTestCase(
// bad domain
"/default/my-gateway",
expectError,
),
prepareTestCase(
// bad namespace
"k8s-gateway.nginx.org/default/my-gateway",
expectError),
prepareTestCase(
// bad namespace
"k8s-gateway.nginx.org//my-gateway",
expectError,
),
prepareTestCase(
// bad name
"k8s-gateway.nginx.org/default/",
"k8s-gateway.nginx.org/",
expectError,
),
}
Expand Down Expand Up @@ -266,7 +260,7 @@ var _ = Describe("Main", func() {
"$nginx",
expectError)
tester(t)
}) // should fail with invalid name"
}) // should fail with invalid name
}) // gatewayclass validation
}) // CLI argument validation
}) // end Main
58 changes: 0 additions & 58 deletions deploy/manifests/crds/gateway.nginx.org_gatewayconfigs.yaml

This file was deleted.

2 changes: 1 addition & 1 deletion deploy/manifests/gatewayclass.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ kind: GatewayClass
metadata:
name: nginx
spec:
controllerName: k8s-gateway.nginx.org/nginx-gateway/gateway
controllerName: k8s-gateway.nginx.org/nginx-gateway-controller
11 changes: 0 additions & 11 deletions deploy/manifests/gatewayconfig.yaml

This file was deleted.

2 changes: 1 addition & 1 deletion deploy/manifests/nginx-gateway.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ spec:
# dropping ALL and adding only CAP_KILL doesn't work
# Note: CAP_KILL is needed for sending HUP signal to NGINX main process
args:
- --gateway-ctlr-name=k8s-gateway.nginx.org/nginx-gateway/gateway
- --gateway-ctlr-name=k8s-gateway.nginx.org/nginx-gateway-controller
- --gatewayclass=nginx
- image: nginx:1.23.1
imagePullPolicy: IfNotPresent
Expand Down
2 changes: 1 addition & 1 deletion docs/cli-args.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ The table below describes the command-line arguments of the `gateway` binary fro

| Name | Type | Description |
|-|-|-|
|`gateway-ctlr-name` | `string` | The name of the Gateway controller. The controller name must be of the form: `DOMAIN/NAMESPACE/NAME`. The controller's domain is `k8s-gateway.nginx.org`; the namespace is `nginx-ingress`. |
|`gateway-ctlr-name` | `string` | The name of the Gateway controller. The controller name must be of the form: `DOMAIN/PATH`. The controller's domain is `k8s-gateway.nginx.org`. |
|`gatewayclass`| `string` | The name of the GatewayClass resource. Every NGINX Gateway must have a unique corresponding GatewayClass resource. |