1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-19 14:53:07 +00:00

nfd-master: use flag for command line parsing

This commit is contained in:
Markus Lehtonen 2021-02-19 07:38:55 +02:00
parent a7d0439af6
commit 47033db9c1
8 changed files with 171 additions and 205 deletions

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2019 The Kubernetes Authors. Copyright 2019-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -17,14 +17,14 @@ limitations under the License.
package main package main
import ( import (
"flag"
"fmt" "fmt"
"log" "log"
"os"
"regexp" "regexp"
"strconv"
"strings"
"github.com/docopt/docopt-go"
master "sigs.k8s.io/node-feature-discovery/pkg/nfd-master" master "sigs.k8s.io/node-feature-discovery/pkg/nfd-master"
"sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/pkg/version" "sigs.k8s.io/node-feature-discovery/pkg/version"
) )
@ -34,17 +34,29 @@ const (
) )
func main() { func main() {
flags := flag.NewFlagSet(ProgramName, flag.ExitOnError)
printVersion := flags.Bool("version", false, "Print version and exit.")
args := initFlags(flags)
_ = flags.Parse(os.Args[1:])
if len(flags.Args()) > 0 {
fmt.Printf("unknown command line argument: %s\n", flags.Args()[0])
flags.Usage()
os.Exit(2)
}
if *printVersion {
fmt.Println(ProgramName, version.Get())
os.Exit(0)
}
// Assert that the version is known // Assert that the version is known
if version.Undefined() { if version.Undefined() {
log.Print("WARNING: version not set! Set -ldflags \"-X sigs.k8s.io/node-feature-discovery/pkg/version.version=`git describe --tags --dirty --always`\" during build or run.") log.Print("WARNING: version not set! Set -ldflags \"-X sigs.k8s.io/node-feature-discovery/pkg/version.version=`git describe --tags --dirty --always`\" during build or run.")
} }
// Parse command-line arguments.
args, err := argsParse(nil)
if err != nil {
log.Fatalf("failed to parse command line: %v", err)
}
// Get new NfdMaster instance // Get new NfdMaster instance
instance, err := master.NewNfdMaster(args) instance, err := master.NewNfdMaster(args)
if err != nil { if err != nil {
@ -56,88 +68,37 @@ func main() {
} }
} }
// argsParse parses the command line arguments passed to the program. func initFlags(flagset *flag.FlagSet) *master.Args {
// The argument argv is passed only for testing purposes. args := &master.Args{
func argsParse(argv []string) (master.Args, error) { LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
args := master.Args{}
usage := fmt.Sprintf(`%s.
Usage:
%s [--prune] [--no-publish] [--label-whitelist=<pattern>] [--port=<port>]
[--ca-file=<path>] [--cert-file=<path>] [--key-file=<path>]
[--verify-node-name] [--extra-label-ns=<list>] [--resource-labels=<list>]
[--kubeconfig=<path>] [--instance=<name>]
%s -h | --help
%s --version
Options:
-h --help Show this screen.
--version Output version and exit.
--prune Prune all NFD related attributes from all nodes
of the cluster and exit.
--instance=<name> Instance name. Used to separate annotation
namespaces for multiple parallel deployments.
[Default: ]
--kubeconfig=<path> Kubeconfig to use [Default: ]
of the cluster and exit.
--port=<port> Port on which to listen for connections.
[Default: 8080]
--ca-file=<path> Root certificate for verifying connections
[Default: ]
--cert-file=<path> Certificate used for authenticating connections
[Default: ]
--key-file=<path> Private key matching --cert-file
[Default: ]
--verify-node-name Verify worker node name against CN from the TLS
certificate. Only has effect when TLS authentication
has been enabled.
--no-publish Do not publish feature labels
--label-whitelist=<pattern> Regular expression to filter label names to
publish to the Kubernetes API server.
NB: the label namespace is omitted i.e. the filter
is only applied to the name part after '/'.
[Default: ]
--extra-label-ns=<list> Comma separated list of allowed extra label namespaces
[Default: ]
--resource-labels=<list> Comma separated list of labels to be exposed as extended resources.
[Default: ]`,
ProgramName,
ProgramName,
ProgramName,
ProgramName,
)
arguments, _ := docopt.ParseArgs(usage, argv,
fmt.Sprintf("%s %s", ProgramName, version.Get()))
// Parse argument values as usable types.
var err error
args.Instance = arguments["--instance"].(string)
if ok, _ := regexp.MatchString(`^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$`, args.Instance); args.Instance != "" && !ok {
return args, fmt.Errorf("invalid --instance %q: instance name "+
"must start and end with an alphanumeric character and may only contain "+
"alphanumerics, `-`, `_` or `.`", args.Instance)
} }
args.CaFile = arguments["--ca-file"].(string)
args.CertFile = arguments["--cert-file"].(string)
args.KeyFile = arguments["--key-file"].(string)
args.NoPublish = arguments["--no-publish"].(bool)
args.Port, err = strconv.Atoi(arguments["--port"].(string))
if err != nil {
return args, fmt.Errorf("invalid --port defined: %s", err)
}
args.LabelWhiteList, err = regexp.Compile(arguments["--label-whitelist"].(string))
if err != nil {
return args, fmt.Errorf("error parsing whitelist regex (%s): %s", arguments["--label-whitelist"], err)
}
args.VerifyNodeName = arguments["--verify-node-name"].(bool)
args.ExtraLabelNs = map[string]struct{}{}
for _, n := range strings.Split(arguments["--extra-label-ns"].(string), ",") {
args.ExtraLabelNs[n] = struct{}{}
}
args.ResourceLabels = strings.Split(arguments["--resource-labels"].(string), ",")
args.Prune = arguments["--prune"].(bool)
args.Kubeconfig = arguments["--kubeconfig"].(string)
return args, nil flagset.StringVar(&args.CaFile, "ca-file", "",
"Root certificate for verifying connections")
flagset.StringVar(&args.CertFile, "cert-file", "",
"Certificate used for authenticating connections")
flagset.Var(&args.ExtraLabelNs, "extra-label-ns",
"Comma separated list of allowed extra label namespaces")
flagset.StringVar(&args.Instance, "instance", "",
"Instance name. Used to separate annotation namespaces for multiple parallel deployments.")
flagset.StringVar(&args.KeyFile, "key-file", "",
"Private key matching -cert-file")
flagset.StringVar(&args.Kubeconfig, "kubeconfig", "",
"Kubeconfig to use")
flagset.Var(&args.LabelWhiteList, "label-whitelist",
"Regular expression to filter label names to publish to the Kubernetes API server. "+
"NB: the label namespace is omitted i.e. the filter is only applied to the name part after '/'.")
flagset.BoolVar(&args.NoPublish, "no-publish", false,
"Do not publish feature labels")
flagset.IntVar(&args.Port, "port", 8080,
"Port on which to listen for connections.")
flagset.BoolVar(&args.Prune, "prune", false,
"Prune all NFD related attributes from all nodes of the cluaster and exit.")
flagset.Var(&args.ResourceLabels, "resource-labels",
"Comma separated list of labels to be exposed as extended resources.")
flagset.BoolVar(&args.VerifyNodeName, "verify-node-name", false,
"Verify worker node name against CN from the TLS certificate. "+
"Only takes effect when TLS authentication has been enabled.")
return args
} }

View file

@ -1,55 +0,0 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestArgsParse(t *testing.T) {
Convey("When parsing command line arguments", t, func() {
Convey("When --no-publish and --oneshot flags are passed", func() {
args, err := argsParse([]string{"--no-publish"})
Convey("noPublish is set and args.sources is set to the default value", func() {
So(args.NoPublish, ShouldBeTrue)
So(len(args.LabelWhiteList.String()), ShouldEqual, 0)
So(err, ShouldBeNil)
})
})
Convey("When valid args are specified", func() {
args, err := argsParse([]string{"--label-whitelist=.*rdt.*", "--port=1234", "--cert-file=crt", "--key-file=key", "--ca-file=ca"})
Convey("Argument parsing should succeed and args set to correct values", func() {
So(args.NoPublish, ShouldBeFalse)
So(args.Port, ShouldEqual, 1234)
So(args.CertFile, ShouldEqual, "crt")
So(args.KeyFile, ShouldEqual, "key")
So(args.CaFile, ShouldEqual, "ca")
So(args.LabelWhiteList.String(), ShouldResemble, ".*rdt.*")
So(err, ShouldBeNil)
})
})
Convey("When invalid --port is defined", func() {
_, err := argsParse([]string{"--port=123a"})
Convey("argsParse should fail", func() {
So(err, ShouldNotBeNil)
})
})
})
}

View file

@ -164,43 +164,34 @@ $ docker run --rm --name=nfd-test ${NFD_CONTAINER_IMAGE} nfd-master --no-publish
Command line flags of nfd-master: Command line flags of nfd-master:
```bash ```bash
$ docker run --rm ${NFD_CONTAINER_IMAGE} nfd-master --help $ docker run --rm ${NFD_CONTAINER_IMAGE} nfd-master -help
... Usage of nfd-master:
Usage: -ca-file string
nfd-master [--prune] [--no-publish] [--label-whitelist=<pattern>] [--port=<port>] Root certificate for verifying connections
[--ca-file=<path>] [--cert-file=<path>] [--key-file=<path>] -cert-file string
[--verify-node-name] [--extra-label-ns=<list>] [--resource-labels=<list>] Certificate used for authenticating connections
[--kubeconfig=<path>] -extra-label-ns value
nfd-master -h | --help Comma separated list of allowed extra label namespaces
nfd-master --version -instance string
Instance name. Used to separate annotation namespaces for multiple parallel deployments.
Options: -key-file string
-h --help Show this screen. Private key matching -cert-file
--version Output version and exit. -kubeconfig string
--prune Prune all NFD related attributes from all nodes Kubeconfig to use
of the cluster and exit. -label-whitelist value
--kubeconfig=<path> Kubeconfig to use [Default: ] Regular expression to filter label names to publish to the Kubernetes API server. NB: the label namespace is omitted i.e. the filter is only applied to the name part after '/'.
--port=<port> Port on which to listen for connections. -no-publish
[Default: 8080] Do not publish feature labels
--ca-file=<path> Root certificate for verifying connections -port int
[Default: ] Port on which to listen for connections. (default 8080)
--cert-file=<path> Certificate used for authenticating connections -prune
[Default: ] Prune all NFD related attributes from all nodes of the cluaster and exit.
--key-file=<path> Private key matching --cert-file -resource-labels value
[Default: ] Comma separated list of labels to be exposed as extended resources.
--verify-node-name Verify worker node name against CN from the TLS -verify-node-name
certificate. Only has effect when TLS authentication Verify worker node name against CN from the TLS certificate. Only takes effect when TLS authentication has been enabled.
has been enabled. -version
--no-publish Do not publish feature labels Print version and exit.
--label-whitelist=<pattern> Regular expression to filter label names to
publish to the Kubernetes API server.
NB: the label namespace is omitted i.e. the filter
is only applied to the name part after '/'.
[Default: ]
--extra-label-ns=<list> Comma separated list of allowed extra label namespaces
[Default: ]
--resource-labels=<list> Comma separated list of labels to be exposed as extended resources.
[Default: ]
``` ```
### NFD-Worker ### NFD-Worker

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2019 The Kubernetes Authors. Copyright 2019-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -34,6 +34,7 @@ import (
k8sclient "k8s.io/client-go/kubernetes" k8sclient "k8s.io/client-go/kubernetes"
"sigs.k8s.io/node-feature-discovery/pkg/apihelper" "sigs.k8s.io/node-feature-discovery/pkg/apihelper"
"sigs.k8s.io/node-feature-discovery/pkg/labeler" "sigs.k8s.io/node-feature-discovery/pkg/labeler"
"sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/pkg/version" "sigs.k8s.io/node-feature-discovery/pkg/version"
"sigs.k8s.io/yaml" "sigs.k8s.io/yaml"
) )
@ -55,7 +56,7 @@ func newMockMaster(apihelper apihelper.APIHelpers) *nfdMaster {
return &nfdMaster{ return &nfdMaster{
nodeName: mockNodeName, nodeName: mockNodeName,
annotationNs: AnnotationNsBase, annotationNs: AnnotationNsBase,
args: Args{LabelWhiteList: regexp.MustCompile("")}, args: Args{LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")}},
apihelper: apihelper, apihelper: apihelper,
} }
} }
@ -339,7 +340,7 @@ func TestSetLabels(t *testing.T) {
apihelper.NewJsonPatch("add", "/metadata/labels", LabelNs+"/feature-2", mockLabels["feature-2"]), apihelper.NewJsonPatch("add", "/metadata/labels", LabelNs+"/feature-2", mockLabels["feature-2"]),
} }
mockMaster.args.LabelWhiteList = regexp.MustCompile("^f.*2$") mockMaster.args.LabelWhiteList.Regexp = *regexp.MustCompile("^f.*2$")
mockHelper.On("GetClient").Return(mockClient, nil) mockHelper.On("GetClient").Return(mockClient, nil)
mockHelper.On("GetNode", mockClient, workerName).Return(mockNode, nil) mockHelper.On("GetNode", mockClient, workerName).Return(mockNode, nil)
mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil) mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil)
@ -390,7 +391,7 @@ func TestSetLabels(t *testing.T) {
apihelper.NewJsonPatch("add", "/status/capacity", LabelNs+"/feature-3", mockLabels["feature-3"]), apihelper.NewJsonPatch("add", "/status/capacity", LabelNs+"/feature-3", mockLabels["feature-3"]),
} }
mockMaster.args.ResourceLabels = []string{"feature-3", "feature-1"} mockMaster.args.ResourceLabels = map[string]struct{}{"feature-3": struct{}{}, "feature-1": struct{}{}}
mockHelper.On("GetClient").Return(mockClient, nil) mockHelper.On("GetClient").Return(mockClient, nil)
mockHelper.On("GetNode", mockClient, workerName).Return(mockNode, nil) mockHelper.On("GetNode", mockClient, workerName).Return(mockNode, nil)
mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil) mockHelper.On("PatchNode", mockClient, mockNodeName, mock.MatchedBy(jsonPatchMatcher(expectedPatches))).Return(nil)

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2019 The Kubernetes Authors. Copyright 2019-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -38,6 +38,7 @@ import (
api "k8s.io/api/core/v1" api "k8s.io/api/core/v1"
"sigs.k8s.io/node-feature-discovery/pkg/apihelper" "sigs.k8s.io/node-feature-discovery/pkg/apihelper"
pb "sigs.k8s.io/node-feature-discovery/pkg/labeler" pb "sigs.k8s.io/node-feature-discovery/pkg/labeler"
"sigs.k8s.io/node-feature-discovery/pkg/utils"
"sigs.k8s.io/node-feature-discovery/pkg/version" "sigs.k8s.io/node-feature-discovery/pkg/version"
) )
@ -74,16 +75,16 @@ type Annotations map[string]string
type Args struct { type Args struct {
CaFile string CaFile string
CertFile string CertFile string
ExtraLabelNs map[string]struct{} ExtraLabelNs utils.StringSetVal
Instance string Instance string
KeyFile string KeyFile string
Kubeconfig string Kubeconfig string
LabelWhiteList *regexp.Regexp LabelWhiteList utils.RegexpVal
NoPublish bool NoPublish bool
Port int Port int
Prune bool Prune bool
VerifyNodeName bool VerifyNodeName bool
ResourceLabels []string ResourceLabels utils.StringSetVal
} }
type NfdMaster interface { type NfdMaster interface {
@ -102,8 +103,8 @@ type nfdMaster struct {
} }
// Create new NfdMaster server instance. // Create new NfdMaster server instance.
func NewNfdMaster(args Args) (NfdMaster, error) { func NewNfdMaster(args *Args) (NfdMaster, error) {
nfd := &nfdMaster{args: args, nfd := &nfdMaster{args: *args,
nodeName: os.Getenv("NODE_NAME"), nodeName: os.Getenv("NODE_NAME"),
ready: make(chan bool, 1), ready: make(chan bool, 1),
} }
@ -111,6 +112,11 @@ func NewNfdMaster(args Args) (NfdMaster, error) {
if args.Instance == "" { if args.Instance == "" {
nfd.annotationNs = AnnotationNsBase nfd.annotationNs = AnnotationNsBase
} else { } else {
if ok, _ := regexp.MatchString(`^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$`, args.Instance); !ok {
return nfd, fmt.Errorf("invalid --instance %q: instance name "+
"must start and end with an alphanumeric character and may only contain "+
"alphanumerics, `-`, `_` or `.`", args.Instance)
}
nfd.annotationNs = args.Instance + "." + AnnotationNsBase nfd.annotationNs = args.Instance + "." + AnnotationNsBase
} }
@ -283,7 +289,7 @@ func (m *nfdMaster) updateMasterNode() error {
// into extended resources. This function also handles proper namespacing of // into extended resources. This function also handles proper namespacing of
// labels and ERs, i.e. adds the possibly missing default namespace for labels // labels and ERs, i.e. adds the possibly missing default namespace for labels
// arriving through the gRPC API. // arriving through the gRPC API.
func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelWhiteList *regexp.Regexp, extendedResourceNames []string) (Labels, ExtendedResources) { func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelWhiteList regexp.Regexp, extendedResourceNames map[string]struct{}) (Labels, ExtendedResources) {
outLabels := Labels{} outLabels := Labels{}
for label, value := range labels { for label, value := range labels {
@ -310,7 +316,7 @@ func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelW
// Remove labels which are intended to be extended resources // Remove labels which are intended to be extended resources
extendedResources := ExtendedResources{} extendedResources := ExtendedResources{}
for _, extendedResourceName := range extendedResourceNames { for extendedResourceName := range extendedResourceNames {
// Add possibly missing default ns // Add possibly missing default ns
extendedResourceName = addNs(extendedResourceName, LabelNs) extendedResourceName = addNs(extendedResourceName, LabelNs)
if value, ok := outLabels[extendedResourceName]; ok { if value, ok := outLabels[extendedResourceName]; ok {
@ -354,7 +360,7 @@ func (m *nfdMaster) SetLabels(c context.Context, r *pb.SetLabelsRequest) (*pb.Se
} }
stdoutLogger.Printf("REQUEST Node: %s NFD-version: %s Labels: %s", r.NodeName, r.NfdVersion, r.Labels) stdoutLogger.Printf("REQUEST Node: %s NFD-version: %s Labels: %s", r.NodeName, r.NfdVersion, r.Labels)
labels, extendedResources := filterFeatureLabels(r.Labels, m.args.ExtraLabelNs, m.args.LabelWhiteList, m.args.ResourceLabels) labels, extendedResources := filterFeatureLabels(r.Labels, m.args.ExtraLabelNs, m.args.LabelWhiteList.Regexp, m.args.ResourceLabels)
if !m.args.NoPublish { if !m.args.NoPublish {
// Advertise NFD worker version as an annotation // Advertise NFD worker version as an annotation

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2019 The Kubernetes Authors. Copyright 2019-2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -26,9 +26,9 @@ import (
func TestNewNfdMaster(t *testing.T) { func TestNewNfdMaster(t *testing.T) {
Convey("When initializing new NfdMaster instance", t, func() { Convey("When initializing new NfdMaster instance", t, func() {
Convey("When one of --cert-file, --key-file or --ca-file is missing", func() { Convey("When one of --cert-file, --key-file or --ca-file is missing", func() {
_, err := m.NewNfdMaster(m.Args{CertFile: "crt", KeyFile: "key"}) _, err := m.NewNfdMaster(&m.Args{CertFile: "crt", KeyFile: "key"})
_, err2 := m.NewNfdMaster(m.Args{KeyFile: "key", CaFile: "ca"}) _, err2 := m.NewNfdMaster(&m.Args{KeyFile: "key", CaFile: "ca"})
_, err3 := m.NewNfdMaster(m.Args{CertFile: "crt", CaFile: "ca"}) _, err3 := m.NewNfdMaster(&m.Args{CertFile: "crt", CaFile: "ca"})
Convey("An error should be returned", func() { Convey("An error should be returned", func() {
So(err, ShouldNotBeNil) So(err, ShouldNotBeNil)
So(err2, ShouldNotBeNil) So(err2, ShouldNotBeNil)

View file

@ -34,11 +34,11 @@ type testContext struct {
errs chan error errs chan error
} }
func setupTest(args nfdmaster.Args) testContext { func setupTest(args *nfdmaster.Args) testContext {
// Fixed port and no-publish, for convenience // Fixed port and no-publish, for convenience
args.NoPublish = true args.NoPublish = true
args.Port = 8192 args.Port = 8192
args.LabelWhiteList = regexp.MustCompile("") args.LabelWhiteList.Regexp = *regexp.MustCompile("")
m, err := nfdmaster.NewNfdMaster(args) m, err := nfdmaster.NewNfdMaster(args)
if err != nil { if err != nil {
fmt.Printf("Test setup failed: %v\n", err) fmt.Printf("Test setup failed: %v\n", err)
@ -86,7 +86,7 @@ func TestNewNfdWorker(t *testing.T) {
} }
func TestRun(t *testing.T) { func TestRun(t *testing.T) {
ctx := setupTest(nfdmaster.Args{}) ctx := setupTest(&nfdmaster.Args{})
defer teardownTest(ctx) defer teardownTest(ctx)
Convey("When running nfd-worker against nfd-master", t, func() { Convey("When running nfd-worker against nfd-master", t, func() {
Convey("When publishing features from fake source", func() { Convey("When publishing features from fake source", func() {
@ -100,7 +100,7 @@ func TestRun(t *testing.T) {
} }
func TestRunTls(t *testing.T) { func TestRunTls(t *testing.T) {
masterArgs := nfdmaster.Args{ masterArgs := &nfdmaster.Args{
CaFile: data.FilePath("ca.crt"), CaFile: data.FilePath("ca.crt"),
CertFile: data.FilePath("nfd-test-master.crt"), CertFile: data.FilePath("nfd-test-master.crt"),
KeyFile: data.FilePath("nfd-test-master.key"), KeyFile: data.FilePath("nfd-test-master.key"),

62
pkg/utils/flags.go Normal file
View file

@ -0,0 +1,62 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
"regexp"
"sort"
"strings"
)
// RegexpVal is a wrapper for regexp command line flags
type RegexpVal struct {
regexp.Regexp
}
// Set implements the flag.Value interface
func (a *RegexpVal) Set(val string) error {
r, err := regexp.Compile(val)
a.Regexp = *r
return err
}
// StringSetVal is a Value encapsulating a set of comma-separated strings
type StringSetVal map[string]struct{}
// Set implements the flag.Value interface
func (a *StringSetVal) Set(val string) error {
m := map[string]struct{}{}
for _, n := range strings.Split(val, ",") {
m[n] = struct{}{}
}
*a = m
return nil
}
// String implements the flag.Value interface
func (a *StringSetVal) String() string {
if *a == nil {
return ""
}
vals := make([]string, len(*a), 0)
for val := range *a {
vals = append(vals, val)
}
sort.Strings(vals)
return strings.Join(vals, ",")
}