mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-15 17:50:49 +00:00
Merge pull request #1139 from AhmedGrati/feat-configure-master-resync
feat: add master resync period configurability
This commit is contained in:
commit
2356223ffc
12 changed files with 118 additions and 37 deletions
|
@ -20,6 +20,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
|
@ -67,6 +68,8 @@ func main() {
|
||||||
args.Overrides.EnableTaints = overrides.EnableTaints
|
args.Overrides.EnableTaints = overrides.EnableTaints
|
||||||
case "no-publish":
|
case "no-publish":
|
||||||
args.Overrides.NoPublish = overrides.NoPublish
|
args.Overrides.NoPublish = overrides.NoPublish
|
||||||
|
case "-resync-period":
|
||||||
|
args.Overrides.ResyncPeriod = overrides.ResyncPeriod
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -131,6 +134,7 @@ func initFlags(flagset *flag.FlagSet) (*master.Args, *master.ConfigOverrideArgs)
|
||||||
DenyLabelNs: &utils.StringSetVal{},
|
DenyLabelNs: &utils.StringSetVal{},
|
||||||
ExtraLabelNs: &utils.StringSetVal{},
|
ExtraLabelNs: &utils.StringSetVal{},
|
||||||
ResourceLabels: &utils.StringSetVal{},
|
ResourceLabels: &utils.StringSetVal{},
|
||||||
|
ResyncPeriod: &utils.DurationVal{Duration: time.Duration(1) * time.Hour},
|
||||||
}
|
}
|
||||||
flagset.Var(overrides.ExtraLabelNs, "extra-label-ns",
|
flagset.Var(overrides.ExtraLabelNs, "extra-label-ns",
|
||||||
"Comma separated list of allowed extra label namespaces")
|
"Comma separated list of allowed extra label namespaces")
|
||||||
|
@ -145,6 +149,8 @@ func initFlags(flagset *flag.FlagSet) (*master.Args, *master.ConfigOverrideArgs)
|
||||||
"Comma separated list of denied label namespaces")
|
"Comma separated list of denied label namespaces")
|
||||||
flagset.Var(overrides.ResourceLabels, "resource-labels",
|
flagset.Var(overrides.ResourceLabels, "resource-labels",
|
||||||
"Comma separated list of labels to be exposed as extended resources. DEPRECATED: use NodeFeatureRule objects instead")
|
"Comma separated list of labels to be exposed as extended resources. DEPRECATED: use NodeFeatureRule objects instead")
|
||||||
|
flagset.Var(overrides.ResyncPeriod, "resync-period",
|
||||||
|
"Specify the NFD API controller resync period."+
|
||||||
|
"It has an effect when the NodeFeature API has been enabled (with -enable-nodefeature-api).")
|
||||||
return args, overrides
|
return args, overrides
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
# resourceLabels: ["vendor-1.com/feature-1","vendor-2.io/feature-2"]
|
# resourceLabels: ["vendor-1.com/feature-1","vendor-2.io/feature-2"]
|
||||||
# enableTaints: false
|
# enableTaints: false
|
||||||
# labelWhiteList: "foo"
|
# labelWhiteList: "foo"
|
||||||
|
# resyncPeriod: "2h"
|
||||||
|
|
|
@ -104,6 +104,9 @@ spec:
|
||||||
{{- if .Values.master.featureRulesController | kindIs "invalid" | not }}
|
{{- if .Values.master.featureRulesController | kindIs "invalid" | not }}
|
||||||
- "-featurerules-controller={{ .Values.master.featureRulesController }}"
|
- "-featurerules-controller={{ .Values.master.featureRulesController }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.master.resyncPeriod }}
|
||||||
|
- "-resync-period={{ .Values.master.resyncPeriod }}"
|
||||||
|
{{- end }}
|
||||||
{{- if .Values.tls.enable }}
|
{{- if .Values.tls.enable }}
|
||||||
- "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt"
|
- "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt"
|
||||||
- "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key"
|
- "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key"
|
||||||
|
|
|
@ -20,11 +20,13 @@ master:
|
||||||
# resourceLabels: ["vendor-1.com/feature-1","vendor-2.io/feature-2"]
|
# resourceLabels: ["vendor-1.com/feature-1","vendor-2.io/feature-2"]
|
||||||
# enableTaints: false
|
# enableTaints: false
|
||||||
# labelWhiteList: "foo"
|
# labelWhiteList: "foo"
|
||||||
|
# resyncPeriod: "2h"
|
||||||
### <NFD-MASTER-CONF-END-DO-NOT-REMOVE>
|
### <NFD-MASTER-CONF-END-DO-NOT-REMOVE>
|
||||||
# The TCP port that nfd-master listens for incoming requests. Default: 8080
|
# The TCP port that nfd-master listens for incoming requests. Default: 8080
|
||||||
port: 8080
|
port: 8080
|
||||||
instance:
|
instance:
|
||||||
featureApi:
|
featureApi:
|
||||||
|
resyncPeriod:
|
||||||
denyLabelNs: []
|
denyLabelNs: []
|
||||||
extraLabelNs: []
|
extraLabelNs: []
|
||||||
resourceLabels: []
|
resourceLabels: []
|
||||||
|
|
|
@ -110,6 +110,7 @@ We have introduced the following Chart parameters.
|
||||||
| `master.*` | dict | | NFD master deployment configuration |
|
| `master.*` | dict | | NFD master deployment configuration |
|
||||||
| `master.port` | integer | | Specifies the TCP port that nfd-master listens for incoming requests. |
|
| `master.port` | integer | | Specifies the TCP port that nfd-master listens for incoming requests. |
|
||||||
| `master.instance` | string | | Instance name. Used to separate annotation namespaces for multiple parallel deployments |
|
| `master.instance` | string | | Instance name. Used to separate annotation namespaces for multiple parallel deployments |
|
||||||
|
| `master.resyncPeriod` | string | | NFD API controller resync period. |
|
||||||
| `master.extraLabelNs` | array | [] | List of allowed extra label namespaces |
|
| `master.extraLabelNs` | array | [] | List of allowed extra label namespaces |
|
||||||
| `master.resourceLabels` | array | [] | List of labels to be registered as extended resources |
|
| `master.resourceLabels` | array | [] | List of labels to be registered as extended resources |
|
||||||
| `master.enableTaints` | bool | false | Specifies whether to enable or disable node tainting |
|
| `master.enableTaints` | bool | false | Specifies whether to enable or disable node tainting |
|
||||||
|
|
|
@ -376,3 +376,20 @@ Default: 0
|
||||||
Comma-separated list of `pattern=N` settings for file-filtered logging.
|
Comma-separated list of `pattern=N` settings for file-filtered logging.
|
||||||
|
|
||||||
Default: *empty*
|
Default: *empty*
|
||||||
|
|
||||||
|
### -resync-period
|
||||||
|
|
||||||
|
The `-resync-period` flag specifies the NFD API controller resync period.
|
||||||
|
The resync means nfd-master replaying all NodeFeature and NodeFeatureRule objects,
|
||||||
|
thus effectively re-syncing all nodes in the cluster (i.e. ensuring labels, annotations,
|
||||||
|
extended resources and taints are in place).
|
||||||
|
Only has effect when the [NodeFeature](../usage/custom-resources.md#nodefeature)
|
||||||
|
CRD API has been enabled with [`-enable-nodefeature-api`](master-commandline-reference.md#-enable-nodefeature-api).
|
||||||
|
|
||||||
|
Default: 1 hour.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nfd-master -resync-period=2h
|
||||||
|
```
|
||||||
|
|
|
@ -113,3 +113,20 @@ Example:
|
||||||
```yaml
|
```yaml
|
||||||
labelWhiteList: "foo"
|
labelWhiteList: "foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### resyncPeriod
|
||||||
|
|
||||||
|
The `resyncPeriod` option specifies the NFD API controller resync period.
|
||||||
|
The resync means nfd-master replaying all NodeFeature and NodeFeatureRule objects,
|
||||||
|
thus effectively re-syncing all nodes in the cluster (i.e. ensuring labels, annotations,
|
||||||
|
extended resources and taints are in place).
|
||||||
|
Only has effect when the [NodeFeature](../usage/custom-resources.md#nodefeature)
|
||||||
|
CRD API has been enabled with [`-enable-nodefeature-api`](master-commandline-reference.md#-enable-nodefeature-api).
|
||||||
|
|
||||||
|
Default: 1 hour.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
resyncPeriod=2h
|
||||||
|
```
|
||||||
|
|
|
@ -41,7 +41,12 @@ type nfdController struct {
|
||||||
updateOneNodeChan chan string
|
updateOneNodeChan chan string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNfdController(config *restclient.Config, disableNodeFeature bool) (*nfdController, error) {
|
type nfdApiControllerOptions struct {
|
||||||
|
disableNodeFeature bool
|
||||||
|
resyncPeriod time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNfdController(config *restclient.Config, nfdApiControllerOptions nfdApiControllerOptions) (*nfdController, error) {
|
||||||
c := &nfdController{
|
c := &nfdController{
|
||||||
stopChan: make(chan struct{}, 1),
|
stopChan: make(chan struct{}, 1),
|
||||||
updateAllNodesChan: make(chan struct{}, 1),
|
updateAllNodesChan: make(chan struct{}, 1),
|
||||||
|
@ -49,11 +54,10 @@ func newNfdController(config *restclient.Config, disableNodeFeature bool) (*nfdC
|
||||||
}
|
}
|
||||||
|
|
||||||
nfdClient := nfdclientset.NewForConfigOrDie(config)
|
nfdClient := nfdclientset.NewForConfigOrDie(config)
|
||||||
|
informerFactory := nfdinformers.NewSharedInformerFactory(nfdClient, nfdApiControllerOptions.resyncPeriod)
|
||||||
informerFactory := nfdinformers.NewSharedInformerFactory(nfdClient, 1*time.Hour)
|
|
||||||
|
|
||||||
// Add informer for NodeFeature objects
|
// Add informer for NodeFeature objects
|
||||||
if !disableNodeFeature {
|
if !nfdApiControllerOptions.disableNodeFeature {
|
||||||
featureInformer := informerFactory.Nfd().V1alpha1().NodeFeatures()
|
featureInformer := informerFactory.Nfd().V1alpha1().NodeFeatures()
|
||||||
if _, err := featureInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
if _, err := featureInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||||
AddFunc: func(obj interface{}) {
|
AddFunc: func(obj interface{}) {
|
||||||
|
@ -83,7 +87,7 @@ func newNfdController(config *restclient.Config, disableNodeFeature bool) (*nfdC
|
||||||
AddFunc: func(object interface{}) {
|
AddFunc: func(object interface{}) {
|
||||||
key, _ := cache.MetaNamespaceKeyFunc(object)
|
key, _ := cache.MetaNamespaceKeyFunc(object)
|
||||||
klog.V(2).Infof("NodeFeatureRule %v added", key)
|
klog.V(2).Infof("NodeFeatureRule %v added", key)
|
||||||
if !disableNodeFeature {
|
if !nfdApiControllerOptions.disableNodeFeature {
|
||||||
c.updateAllNodes()
|
c.updateAllNodes()
|
||||||
}
|
}
|
||||||
// else: rules will be processed only when gRPC requests are received
|
// else: rules will be processed only when gRPC requests are received
|
||||||
|
@ -91,7 +95,7 @@ func newNfdController(config *restclient.Config, disableNodeFeature bool) (*nfdC
|
||||||
UpdateFunc: func(oldObject, newObject interface{}) {
|
UpdateFunc: func(oldObject, newObject interface{}) {
|
||||||
key, _ := cache.MetaNamespaceKeyFunc(newObject)
|
key, _ := cache.MetaNamespaceKeyFunc(newObject)
|
||||||
klog.V(2).Infof("NodeFeatureRule %v updated", key)
|
klog.V(2).Infof("NodeFeatureRule %v updated", key)
|
||||||
if !disableNodeFeature {
|
if !nfdApiControllerOptions.disableNodeFeature {
|
||||||
c.updateAllNodes()
|
c.updateAllNodes()
|
||||||
}
|
}
|
||||||
// else: rules will be processed only when gRPC requests are received
|
// else: rules will be processed only when gRPC requests are received
|
||||||
|
@ -99,7 +103,7 @@ func newNfdController(config *restclient.Config, disableNodeFeature bool) (*nfdC
|
||||||
DeleteFunc: func(object interface{}) {
|
DeleteFunc: func(object interface{}) {
|
||||||
key, _ := cache.MetaNamespaceKeyFunc(object)
|
key, _ := cache.MetaNamespaceKeyFunc(object)
|
||||||
klog.V(2).Infof("NodeFeatureRule %v deleted", key)
|
klog.V(2).Infof("NodeFeatureRule %v deleted", key)
|
||||||
if !disableNodeFeature {
|
if !nfdApiControllerOptions.disableNodeFeature {
|
||||||
c.updateAllNodes()
|
c.updateAllNodes()
|
||||||
}
|
}
|
||||||
// else: rules will be processed only when gRPC requests are received
|
// else: rules will be processed only when gRPC requests are received
|
||||||
|
|
|
@ -637,24 +637,32 @@ extraLabelNs: ["added.ns.io"]
|
||||||
// Update config and verify the effect
|
// Update config and verify the effect
|
||||||
writeConfig(`
|
writeConfig(`
|
||||||
extraLabelNs: ["override.ns.io"]
|
extraLabelNs: ["override.ns.io"]
|
||||||
|
resyncPeriod: '2h'
|
||||||
`)
|
`)
|
||||||
So(func() interface{} { return master.config.ExtraLabelNs },
|
So(func() interface{} { return master.config.ExtraLabelNs },
|
||||||
withTimeout, 2*time.Second, ShouldResemble, utils.StringSetVal{"override.ns.io": struct{}{}})
|
withTimeout, 2*time.Second, ShouldResemble, utils.StringSetVal{"override.ns.io": struct{}{}})
|
||||||
|
So(func() interface{} { return master.config.ResyncPeriod.Duration },
|
||||||
|
withTimeout, 2*time.Second, ShouldResemble, time.Duration(2)*time.Hour)
|
||||||
|
|
||||||
// Removing config file should get back our defaults
|
// Removing config file should get back our defaults
|
||||||
err = os.RemoveAll(tmpDir)
|
err = os.RemoveAll(tmpDir)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(func() interface{} { return master.config.ExtraLabelNs },
|
So(func() interface{} { return master.config.ExtraLabelNs },
|
||||||
withTimeout, 2*time.Second, ShouldResemble, utils.StringSetVal{})
|
withTimeout, 2*time.Second, ShouldResemble, utils.StringSetVal{})
|
||||||
|
So(func() interface{} { return master.config.ResyncPeriod.Duration },
|
||||||
|
withTimeout, 2*time.Second, ShouldResemble, time.Duration(1)*time.Hour)
|
||||||
|
|
||||||
// Re-creating config dir and file should change the config
|
// Re-creating config dir and file should change the config
|
||||||
err = os.MkdirAll(configDir, 0755)
|
err = os.MkdirAll(configDir, 0755)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
writeConfig(`
|
writeConfig(`
|
||||||
extraLabelNs: ["another.override.ns"]
|
extraLabelNs: ["another.override.ns"]
|
||||||
|
resyncPeriod: '3m'
|
||||||
`)
|
`)
|
||||||
So(func() interface{} { return master.config.ExtraLabelNs },
|
So(func() interface{} { return master.config.ExtraLabelNs },
|
||||||
withTimeout, 2*time.Second, ShouldResemble, utils.StringSetVal{"another.override.ns": struct{}{}})
|
withTimeout, 2*time.Second, ShouldResemble, utils.StringSetVal{"another.override.ns": struct{}{}})
|
||||||
|
So(func() interface{} { return master.config.ResyncPeriod.Duration },
|
||||||
|
withTimeout, 2*time.Second, ShouldResemble, time.Duration(3)*time.Minute)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ type NFDConfig struct {
|
||||||
NoPublish bool
|
NoPublish bool
|
||||||
ResourceLabels utils.StringSetVal
|
ResourceLabels utils.StringSetVal
|
||||||
EnableTaints bool
|
EnableTaints bool
|
||||||
|
ResyncPeriod utils.DurationVal
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigOverrideArgs are args that override config file options
|
// ConfigOverrideArgs are args that override config file options
|
||||||
|
@ -80,6 +81,7 @@ type ConfigOverrideArgs struct {
|
||||||
ResourceLabels *utils.StringSetVal
|
ResourceLabels *utils.StringSetVal
|
||||||
EnableTaints *bool
|
EnableTaints *bool
|
||||||
NoPublish *bool
|
NoPublish *bool
|
||||||
|
ResyncPeriod *utils.DurationVal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Args holds command line arguments
|
// Args holds command line arguments
|
||||||
|
@ -96,6 +98,7 @@ type Args struct {
|
||||||
Prune bool
|
Prune bool
|
||||||
VerifyNodeName bool
|
VerifyNodeName bool
|
||||||
Options string
|
Options string
|
||||||
|
ResyncPeriod utils.DurationVal
|
||||||
|
|
||||||
Overrides ConfigOverrideArgs
|
Overrides ConfigOverrideArgs
|
||||||
}
|
}
|
||||||
|
@ -172,6 +175,7 @@ func newDefaultConfig() *NFDConfig {
|
||||||
NoPublish: false,
|
NoPublish: false,
|
||||||
ResourceLabels: utils.StringSetVal{},
|
ResourceLabels: utils.StringSetVal{},
|
||||||
EnableTaints: false,
|
EnableTaints: false,
|
||||||
|
ResyncPeriod: utils.DurationVal{Duration: time.Duration(1) * time.Hour},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +204,10 @@ func (m *nfdMaster) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
klog.Info("starting nfd api controller")
|
klog.Info("starting nfd api controller")
|
||||||
m.nfdController, err = newNfdController(kubeconfig, !m.args.EnableNodeFeatureApi)
|
m.nfdController, err = newNfdController(kubeconfig, nfdApiControllerOptions{
|
||||||
|
disableNodeFeature: !m.args.EnableNodeFeatureApi,
|
||||||
|
resyncPeriod: m.args.ResyncPeriod.Duration,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to initialize CRD controller: %w", err)
|
return fmt.Errorf("failed to initialize CRD controller: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -1133,6 +1140,9 @@ func (m *nfdMaster) configure(filepath string, overrides string) error {
|
||||||
if m.args.Overrides.LabelWhiteList != nil {
|
if m.args.Overrides.LabelWhiteList != nil {
|
||||||
c.LabelWhiteList = *m.args.Overrides.LabelWhiteList
|
c.LabelWhiteList = *m.args.Overrides.LabelWhiteList
|
||||||
}
|
}
|
||||||
|
if m.args.Overrides.ResyncPeriod != nil {
|
||||||
|
c.ResyncPeriod = *m.args.Overrides.ResyncPeriod
|
||||||
|
}
|
||||||
|
|
||||||
m.config = c
|
m.config = c
|
||||||
if !c.NoPublish {
|
if !c.NoPublish {
|
||||||
|
|
|
@ -80,7 +80,7 @@ type coreConfig struct {
|
||||||
FeatureSources []string
|
FeatureSources []string
|
||||||
Sources *[]string
|
Sources *[]string
|
||||||
LabelSources []string
|
LabelSources []string
|
||||||
SleepInterval duration
|
SleepInterval utils.DurationVal
|
||||||
}
|
}
|
||||||
|
|
||||||
type sourcesConfig map[string]source.Config
|
type sourcesConfig map[string]source.Config
|
||||||
|
@ -127,10 +127,6 @@ type nfdWorker struct {
|
||||||
labelSources []source.LabelSource
|
labelSources []source.LabelSource
|
||||||
}
|
}
|
||||||
|
|
||||||
type duration struct {
|
|
||||||
time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// This ticker can represent infinite and normal intervals.
|
// This ticker can represent infinite and normal intervals.
|
||||||
type infiniteTicker struct {
|
type infiniteTicker struct {
|
||||||
*time.Ticker
|
*time.Ticker
|
||||||
|
@ -169,7 +165,7 @@ func newDefaultConfig() *NFDConfig {
|
||||||
return &NFDConfig{
|
return &NFDConfig{
|
||||||
Core: coreConfig{
|
Core: coreConfig{
|
||||||
LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
|
LabelWhiteList: utils.RegexpVal{Regexp: *regexp.MustCompile("")},
|
||||||
SleepInterval: duration{60 * time.Second},
|
SleepInterval: utils.DurationVal{Duration: 60 * time.Second},
|
||||||
FeatureSources: []string{"all"},
|
FeatureSources: []string{"all"},
|
||||||
LabelSources: []string{"all"},
|
LabelSources: []string{"all"},
|
||||||
Klog: make(map[string]string),
|
Klog: make(map[string]string),
|
||||||
|
@ -369,7 +365,7 @@ func (c *coreConfig) sanitize() {
|
||||||
if c.SleepInterval.Duration > 0 && c.SleepInterval.Duration < time.Second {
|
if c.SleepInterval.Duration > 0 && c.SleepInterval.Duration < time.Second {
|
||||||
klog.Warningf("too short sleep interval specified (%s), forcing to 1s",
|
klog.Warningf("too short sleep interval specified (%s), forcing to 1s",
|
||||||
c.SleepInterval.Duration.String())
|
c.SleepInterval.Duration.String())
|
||||||
c.SleepInterval = duration{time.Second}
|
c.SleepInterval = utils.DurationVal{Duration: time.Second}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,27 +752,6 @@ func (m *nfdWorker) getNfdClient() (*nfdclient.Clientset, error) {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements the Unmarshaler interface from "encoding/json"
|
|
||||||
func (d *duration) UnmarshalJSON(data []byte) error {
|
|
||||||
var v interface{}
|
|
||||||
if err := json.Unmarshal(data, &v); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch val := v.(type) {
|
|
||||||
case float64:
|
|
||||||
d.Duration = time.Duration(val)
|
|
||||||
case string:
|
|
||||||
var err error
|
|
||||||
d.Duration, err = time.ParseDuration(val)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("invalid duration %s", data)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON implements the Unmarshaler interface from "encoding/json"
|
// UnmarshalJSON implements the Unmarshaler interface from "encoding/json"
|
||||||
func (c *sourcesConfig) UnmarshalJSON(data []byte) error {
|
func (c *sourcesConfig) UnmarshalJSON(data []byte) error {
|
||||||
// First do a raw parse to get the per-source data
|
// First do a raw parse to get the per-source data
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegexpVal is a wrapper for regexp command line flags
|
// RegexpVal is a wrapper for regexp command line flags
|
||||||
|
@ -173,3 +174,39 @@ func NewKlogFlagVal(f *flag.Flag) *KlogFlagVal {
|
||||||
type boolFlag interface {
|
type boolFlag interface {
|
||||||
IsBoolFlag() bool
|
IsBoolFlag() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DurationVal is a wrapper for handling time.Duration as a command line flag
|
||||||
|
type DurationVal struct {
|
||||||
|
time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the Unmarshaler interface from "encoding/json"
|
||||||
|
func (d *DurationVal) UnmarshalJSON(data []byte) error {
|
||||||
|
var v interface{}
|
||||||
|
if err := json.Unmarshal(data, &v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch val := v.(type) {
|
||||||
|
case float64:
|
||||||
|
d.Duration = time.Duration(val)
|
||||||
|
case string:
|
||||||
|
var err error
|
||||||
|
d.Duration, err = time.ParseDuration(val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid duration %s", data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements the flag.Value interface
|
||||||
|
func (d *DurationVal) Set(val string) error {
|
||||||
|
m, err := time.ParseDuration(val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*d = DurationVal{m}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue