mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2024-12-15 17:50:49 +00:00
Merge pull request #1285 from AhmedGrati/feat-add-expiry-date-feature-files
Feat: add expiry date for feature files
This commit is contained in:
commit
0b218a1eca
8 changed files with 160 additions and 4 deletions
|
@ -317,6 +317,38 @@ Label namespace may be specified with `<namespace>/<name>[=<value>]`.
|
|||
|
||||
Comment lines (starting with `#`) are ignored.
|
||||
|
||||
Adding following line anywhere to feature file defines date when
|
||||
its content expires / is ignored:
|
||||
|
||||
```plaintext
|
||||
# +expiry-time=2023-07-29T11:22:33Z
|
||||
```
|
||||
|
||||
Also, the expiry-time value would stay the same during the processing of the
|
||||
feature file until another expiry-time directive is encountered.
|
||||
Considering the following file:
|
||||
|
||||
```plaintext
|
||||
# +expiry-time=2012-07-28T11:22:33Z
|
||||
featureKey=featureValue
|
||||
|
||||
# +expiry-time=2080-07-28T11:22:33Z
|
||||
featureKey2=featureValue2
|
||||
|
||||
# +expiry-time=2070-07-28T11:22:33Z
|
||||
featureKey3=featureValue3
|
||||
|
||||
# +expiry-time=2002-07-28T11:22:33Z
|
||||
featureKey4=featureValue4
|
||||
```
|
||||
|
||||
After processing the above file, only `featureKey2` and `featureKey3` would be
|
||||
included in the list of accepted features.
|
||||
|
||||
> **NOTE:** The time format that we are supporting is RFC3339. Also, the `expiry-time`
|
||||
> tag is only evaluated in each re-discovery period, and the expiration of
|
||||
> node labels is not tracked.
|
||||
|
||||
### Mounts
|
||||
|
||||
The standard NFD deployments contain `hostPath` mounts for
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
|
@ -37,6 +38,13 @@ const Name = "local"
|
|||
// LabelFeature of this feature source
|
||||
const LabelFeature = "label"
|
||||
|
||||
// ExpiryTimeKey is the key of this feature source indicating
|
||||
// when features should be removed.
|
||||
const ExpiryTimeKey = "expiry-time"
|
||||
|
||||
// DirectivePrefix defines the prefix of directives that should be parsed
|
||||
const DirectivePrefix = "# +"
|
||||
|
||||
// Config
|
||||
var (
|
||||
featureFilesDir = "/etc/kubernetes/node-feature-discovery/features.d/"
|
||||
|
@ -53,6 +61,11 @@ type Config struct {
|
|||
HooksEnabled bool `json:"hooksEnabled,omitempty"`
|
||||
}
|
||||
|
||||
// parsingOpts contains options used for directives parsing
|
||||
type parsingOpts struct {
|
||||
ExpiryTime time.Time
|
||||
}
|
||||
|
||||
// Singleton source instance
|
||||
var (
|
||||
src = localSource{config: newDefaultConfig()}
|
||||
|
@ -144,14 +157,56 @@ func (s *localSource) GetFeatures() *nfdv1alpha1.Features {
|
|||
return s.features
|
||||
}
|
||||
|
||||
func parseFeatures(lines [][]byte) map[string]string {
|
||||
func parseDirectives(line string, opts *parsingOpts) error {
|
||||
if !strings.HasPrefix(line, DirectivePrefix) {
|
||||
return nil
|
||||
}
|
||||
|
||||
directive := line[len(DirectivePrefix):]
|
||||
split := strings.SplitN(directive, "=", 2)
|
||||
key := split[0]
|
||||
|
||||
if len(split) == 1 {
|
||||
return fmt.Errorf("invalid directive format in %q, should be '# +key=value'", line)
|
||||
}
|
||||
value := split[1]
|
||||
|
||||
switch key {
|
||||
case ExpiryTimeKey:
|
||||
expiryDate, err := time.Parse(time.RFC3339, strings.TrimSpace(value))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse expiry-date directive: %w", err)
|
||||
}
|
||||
opts.ExpiryTime = expiryDate
|
||||
default:
|
||||
return fmt.Errorf("unknown feature file directive %q", key)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseFeatures(lines [][]byte, fileName string) map[string]string {
|
||||
features := make(map[string]string)
|
||||
now := time.Now()
|
||||
parsingOpts := &parsingOpts{
|
||||
ExpiryTime: now,
|
||||
}
|
||||
|
||||
for _, l := range lines {
|
||||
line := strings.TrimSpace(string(l))
|
||||
if len(line) > 0 {
|
||||
// Skip comment lines
|
||||
if strings.HasPrefix(line, "#") {
|
||||
// Parse directives
|
||||
err := parseDirectives(line, parsingOpts)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "error while parsing directives", "fileName", fileName)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// handle expiration
|
||||
if parsingOpts.ExpiryTime.Before(now) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -197,7 +252,7 @@ func getFeaturesFromHooks() (map[string]string, error) {
|
|||
}
|
||||
|
||||
// Append features
|
||||
fileFeatures := parseFeatures(lines)
|
||||
fileFeatures := parseFeatures(lines, fileName)
|
||||
klog.V(4).InfoS("hook executed", "fileName", fileName, "features", utils.DelayedDumper(fileFeatures))
|
||||
for k, v := range fileFeatures {
|
||||
if old, ok := features[k]; ok {
|
||||
|
@ -273,7 +328,8 @@ func getFeaturesFromFiles() (map[string]string, error) {
|
|||
}
|
||||
|
||||
// Append features
|
||||
fileFeatures := parseFeatures(lines)
|
||||
fileFeatures := parseFeatures(lines, fileName)
|
||||
|
||||
klog.V(4).InfoS("feature file read", "fileName", fileName, "features", utils.DelayedDumper(fileFeatures))
|
||||
for k, v := range fileFeatures {
|
||||
if old, ok := features[k]; ok {
|
||||
|
|
|
@ -17,7 +17,11 @@ limitations under the License.
|
|||
package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -33,3 +37,48 @@ func TestLocalSource(t *testing.T) {
|
|||
assert.Empty(t, l)
|
||||
|
||||
}
|
||||
|
||||
func TestGetExpirationDate(t *testing.T) {
|
||||
expectedFeaturesLen := 5
|
||||
pwd, _ := os.Getwd()
|
||||
featureFilesDir = filepath.Join(pwd, "testdata/features.d")
|
||||
|
||||
features, err := getFeaturesFromFiles()
|
||||
fmt.Println(features)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedFeaturesLen, len(features))
|
||||
}
|
||||
|
||||
func TestParseDirectives(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
directive string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid directive",
|
||||
directive: "# +expiry-time=2080-07-28T11:22:33Z",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid directive",
|
||||
directive: "# +random-key=random-value",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid directive format",
|
||||
directive: "# + Something",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
parsingOpts := parsingOpts{
|
||||
ExpiryTime: time.Now(),
|
||||
}
|
||||
err := parseDirectives(tc.directive, &parsingOpts)
|
||||
assert.Equal(t, err != nil, tc.wantErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
2
source/local/testdata/features.d/expired_feature
vendored
Normal file
2
source/local/testdata/features.d/expired_feature
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# +expiry-time=2012-07-28T11:22:33Z
|
||||
featureKeyExpired=featureValue
|
2
source/local/testdata/features.d/feature_with_comments
vendored
Normal file
2
source/local/testdata/features.d/feature_with_comments
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Notes: foo bar
|
||||
featureKeyRandomComment=featureValue
|
11
source/local/testdata/features.d/multiple_expiration_dates
vendored
Normal file
11
source/local/testdata/features.d/multiple_expiration_dates
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# +expiry-time=2012-07-28T11:22:33Z
|
||||
featureKey=featureValue
|
||||
|
||||
# +expiry-time=2080-07-28T11:22:33Z
|
||||
featureKey2=featureValue2
|
||||
|
||||
# +expiry-time=2070-07-28T11:22:33Z
|
||||
featureKey3=featureValue3
|
||||
|
||||
# +expiry-time=2002-07-28T11:22:33Z
|
||||
featureKey4=featureValue4
|
2
source/local/testdata/features.d/unparsable_expiry_comment
vendored
Normal file
2
source/local/testdata/features.d/unparsable_expiry_comment
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# +expiry-time=2080-07-28T11:22:33X
|
||||
featureKeyUnparsable=featureValue
|
2
source/local/testdata/features.d/valid_feature
vendored
Normal file
2
source/local/testdata/features.d/valid_feature
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# +expiry-time=2080-07-28T11:22:33Z
|
||||
featureKeyValid=featureValue
|
Loading…
Reference in a new issue