Skip to content

Adding CLI validation #8

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 5 commits into from
Nov 30, 2021
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
13 changes: 13 additions & 0 deletions cmd/gateway/gateway_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"testing"
)

func TestGateway(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Gateway Suite")
}
21 changes: 15 additions & 6 deletions cmd/gateway/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"fmt"
"os"

"github.com/nginxinc/nginx-gateway-kubernetes/internal/config"
Expand All @@ -10,30 +11,38 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)

const (
domain string = "gateway.nginx.org"
)

var (
// Set during go build
version string
commit string
date string

// Command-line flags
gatewayCtlrName = flag.String("gateway-ctlr-name", "", "The name of the Gateway controller")
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'.", domain),
)
)

func main() {
flag.Parse()

if *gatewayCtlrName == "" {
flag.PrintDefaults()
os.Exit(1)
}

logger := zap.New()
conf := config.Config{
GatewayCtlrName: *gatewayCtlrName,
Logger: logger,
}

MustValidateArguments(
flag.CommandLine,
GatewayControllerParam(domain, "nginx-gateway" /* TODO dynamically set */),
)

logger.Info("Starting NGINX Gateway",
"version", version,
"commit", commit,
Expand Down
95 changes: 95 additions & 0 deletions cmd/gateway/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package main

import (
"errors"
"fmt"
"os"
"strings"

flag "github.com/spf13/pflag"
)

const (
errTmpl = "failed validation - flag: '--%s' reason: '%s'\n"
)

type Validator func(*flag.FlagSet) error
type ValidatorContext struct {
Key string
V Validator
}

func GatewayControllerParam(domain string, namespace string) ValidatorContext {
name := "gateway-ctlr-name"
return ValidatorContext{
name,
func(flagset *flag.FlagSet) error {
// FIXME(yacobucci) 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
}

if len(param) == 0 {
return errors.New("flag must be set")
}

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

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")
}
}
}

return nil
},
}
}

func ValidateArguments(flagset *flag.FlagSet, validators ...ValidatorContext) []string {
var msgs []string
for _, v := range validators {
if flagset.Lookup(v.Key) != nil {
err := v.V(flagset)
if err != nil {
msgs = append(msgs, fmt.Sprintf(errTmpl, v.Key, err.Error()))
}
}
}

return msgs
}

func MustValidateArguments(flagset *flag.FlagSet, validators ...ValidatorContext) {
msgs := ValidateArguments(flagset, validators...)
if msgs != nil {
for i := range msgs {
fmt.Fprintf(os.Stderr, "%s", msgs[i])
}
fmt.Fprintln(os.Stderr, "")

fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
flag.PrintDefaults()

os.Exit(1)
}
}
Loading