Skip to content

Commit ef37aaf

Browse files
committed
feat: add ability to export features for static node
For the HPC use case, we want to be able to export static features to the terminal or JSON path. Signed-off-by: vsoch <[email protected]>
1 parent 310a390 commit ef37aaf

File tree

4 files changed

+176
-0
lines changed

4 files changed

+176
-0
lines changed

cmd/nfd/subcmd/export/export.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package export
18+
19+
import (
20+
"fmt"
21+
"os"
22+
23+
"github.com/spf13/cobra"
24+
)
25+
26+
var ExportCmd = &cobra.Command{
27+
Use: "export",
28+
Short: "Export features commands",
29+
}
30+
31+
func Execute() {
32+
if err := ExportCmd.Execute(); err != nil {
33+
fmt.Println(err)
34+
os.Exit(1)
35+
}
36+
}

cmd/nfd/subcmd/export/features.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package export
18+
19+
import (
20+
"encoding/json"
21+
"fmt"
22+
"os"
23+
24+
"github.com/spf13/cobra"
25+
26+
"sigs.k8s.io/node-feature-discovery/source"
27+
)
28+
29+
var (
30+
outputJSON bool
31+
outputPath string
32+
)
33+
34+
func NewExportCmd() *cobra.Command {
35+
cmd := &cobra.Command{
36+
Use: "features",
37+
Short: "Export features for given node",
38+
RunE: func(cmd *cobra.Command, args []string) error {
39+
sources := map[string]source.FeatureSource{}
40+
for k, v := range source.GetAllFeatureSources() {
41+
if ts, ok := v.(source.SupplementalSource); ok && ts.DisableByDefault() {
42+
continue
43+
}
44+
sources[k] = v
45+
}
46+
47+
// Discover all feature sources
48+
for _, s := range sources {
49+
if err := s.Discover(); err != nil {
50+
fmt.Errorf("error during discovery of source %s: %w", s.Name(), err)
51+
return err
52+
}
53+
}
54+
55+
// Make into flat format.
56+
features := source.GetAllFeatures()
57+
featureListing := map[string]string{}
58+
59+
// A flag's presence == true
60+
for flagName := range features.Flags {
61+
featureListing[flagName] = "true"
62+
}
63+
64+
// Attributes are sets of elements (key value pairs)
65+
for featureName, featureSet := range features.Attributes {
66+
for elementName, elementValue := range featureSet.Elements {
67+
featureListing[fmt.Sprintf("%s.%s", featureName, elementName)] = elementValue
68+
}
69+
}
70+
71+
for featureName, featureSet := range features.Instances {
72+
for _, element := range featureSet.Elements {
73+
for attrName, attrValue := range element.Attributes {
74+
featureListing[fmt.Sprintf("%s.%s", featureName, attrName)] = attrValue
75+
}
76+
}
77+
}
78+
exportedLabels, err := json.MarshalIndent(featureListing, "", " ")
79+
if err != nil {
80+
return err
81+
}
82+
83+
if outputPath != "" {
84+
fd, err := os.Create(outputPath)
85+
if err != nil {
86+
return err
87+
}
88+
defer fd.Close()
89+
_, err = fmt.Fprint(fd, string(exportedLabels))
90+
return err
91+
} else {
92+
fmt.Println(string(exportedLabels))
93+
}
94+
return nil
95+
},
96+
}
97+
cmd.Flags().StringVar(&outputPath, "path", "", "export to this JSON path")
98+
return cmd
99+
}
100+
101+
func init() {
102+
ExportCmd.AddCommand(NewExportCmd())
103+
}

cmd/nfd/subcmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/spf13/cobra"
2424

2525
"sigs.k8s.io/node-feature-discovery/cmd/nfd/subcmd/compat"
26+
"sigs.k8s.io/node-feature-discovery/cmd/nfd/subcmd/export"
2627
)
2728

2829
// RootCmd represents the base command when called without any subcommands
@@ -33,6 +34,7 @@ var RootCmd = &cobra.Command{
3334

3435
func init() {
3536
RootCmd.AddCommand(compat.CompatCmd)
37+
RootCmd.AddCommand(export.ExportCmd)
3638
}
3739

3840
// Execute adds all child commands to the root command and sets flags appropriately.

docs/usage/nfd-export.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
title: "Feature Export"
3+
layout: default
4+
sort: 12
5+
---
6+
7+
# Feature Export
8+
{: .no_toc}
9+
10+
## Table of contents
11+
{: .no_toc .text-delta}
12+
13+
1. TOC
14+
{:toc}
15+
16+
---
17+
18+
## Feature Export
19+
20+
**Feature export is in the experimental `v1alpha1` version.**
21+
22+
If you are interested in exporting features in a generic context, the nfd client supports an export mode, where features can be derived without requiring a Kubernetes context.
23+
This addresses use cases such as high performance computing (HPC) and other environments with compute nodes that warrant assessment, but may not have Kubernetes running, or may not be able to or want to run a central daemon service for data.
24+
To use export, you can use `nfd export features`:
25+
26+
```bash
27+
nfd export features
28+
```
29+
30+
By default, JSON structure with parsed key value pairs will appear in the terminal.
31+
To save to a file path:
32+
33+
```bash
34+
nfd export features --path features.json
35+
```

0 commit comments

Comments
 (0)