1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-15 04:57:56 +00:00

nfd-master: parse kubeconfig even with NoPublish set

Don't try to be too smart when kubeconfig is needed. In practice, the
nfd-master really doesn't work anymore (with the NodeFeature API
enabled) without a kubeconfig set. This patch fixes crashes happening
when NoPublish is enabled, e.g. in listing all nodes in the nfd api
handler and in getting single node objects in the node updater pool.

This patch changes the kubeconfig parsing to happen at the creation of
the nfd-master instance. We don't need to do that at reconfigure time as
none of the dynamic config options affect it. Unit tests are adjusted,
accordingly.
This commit is contained in:
Markus Lehtonen 2024-04-04 17:48:47 +03:00
parent 8f5830f3c6
commit 8709cccf71
4 changed files with 47 additions and 34 deletions

View file

@ -40,7 +40,6 @@ import (
fakecorev1client "k8s.io/client-go/kubernetes/typed/core/v1/fake" fakecorev1client "k8s.io/client-go/kubernetes/typed/core/v1/fake"
clienttesting "k8s.io/client-go/testing" clienttesting "k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1" nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
"sigs.k8s.io/node-feature-discovery/pkg/features" "sigs.k8s.io/node-feature-discovery/pkg/features"
@ -115,6 +114,7 @@ func newFakeMaster(opts ...NfdMasterOption) *nfdMaster {
defaultOpts := []NfdMasterOption{ defaultOpts := []NfdMasterOption{
withNodeName(testNodeName), withNodeName(testNodeName),
withConfig(&NFDConfig{}), withConfig(&NFDConfig{}),
WithKubernetesClient(fakeclient.NewSimpleClientset()),
} }
m, err := NewNfdMaster(append(defaultOpts, opts...)...) m, err := NewNfdMaster(append(defaultOpts, opts...)...)
if err != nil { if err != nil {
@ -664,6 +664,10 @@ leaderElection:
func TestDynamicConfig(t *testing.T) { func TestDynamicConfig(t *testing.T) {
Convey("When running nfd-master", t, func() { Convey("When running nfd-master", t, func() {
// Add feature gates as running nfd-master depends on that
err := features.NFDMutableFeatureGate.Add(features.DefaultNFDFeatureGates)
So(err, ShouldBeNil)
tmpDir, err := os.MkdirTemp("", "*.nfd-test") tmpDir, err := os.MkdirTemp("", "*.nfd-test")
So(err, ShouldBeNil) So(err, ShouldBeNil)
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
@ -674,7 +678,7 @@ func TestDynamicConfig(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
// Create config file // Create config file
configFile := filepath.Join(configDir, "master.conf") configFile := filepath.Clean(filepath.Join(configDir, "master.conf"))
writeConfig := func(data string) { writeConfig := func(data string) {
f, err := os.Create(configFile) f, err := os.Create(configFile)
@ -685,25 +689,22 @@ func TestDynamicConfig(t *testing.T) {
So(err, ShouldBeNil) So(err, ShouldBeNil)
} }
writeConfig(` writeConfig(`
klog:
v: "4"
extraLabelNs: ["added.ns.io"] extraLabelNs: ["added.ns.io"]
`) `)
noPublish := true master := newFakeMaster(
// Add FeatureGates flag WithArgs(&Args{ConfigFile: configFile}),
if err := features.NFDMutableFeatureGate.Add(features.DefaultNFDFeatureGates); err != nil { WithKubernetesClient(fakeclient.NewSimpleClientset(newTestNode())))
klog.ErrorS(err, "failed to add default feature gates")
os.Exit(1)
}
_ = features.NFDMutableFeatureGate.OverrideDefault(features.NodeFeatureAPI, false)
master := newFakeMaster(WithArgs(&Args{
ConfigFile: configFile,
Overrides: ConfigOverrideArgs{
NoPublish: &noPublish,
},
}))
Convey("config file updates should take effect", func() { Convey("config file updates should take effect", func() {
go func() { _ = master.Run() }() go func() {
Convey("nfd-master should exit gracefully", t, func() {
err = master.Run()
So(err, ShouldBeNil)
})
}()
defer master.Stop() defer master.Stop()
// Check initial config // Check initial config
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)

View file

@ -194,6 +194,19 @@ func NewNfdMaster(opts ...NfdMasterOption) (NfdMaster, error) {
nfd.configFilePath = filepath.Clean(nfd.args.ConfigFile) nfd.configFilePath = filepath.Clean(nfd.args.ConfigFile)
} }
// k8sClient might've been set via opts by tests
if nfd.k8sClient == nil {
kubeconfig, err := utils.GetKubeconfig(nfd.args.Kubeconfig)
if err != nil {
return nfd, err
}
cli, err := k8sclient.NewForConfig(kubeconfig)
if err != nil {
return nfd, err
}
nfd.k8sClient = cli
}
nfd.nodeUpdaterPool = newNodeUpdaterPool(nfd) nfd.nodeUpdaterPool = newNodeUpdaterPool(nfd)
return nfd, nil return nfd, nil
@ -770,10 +783,6 @@ func (m *nfdMaster) nfdAPIUpdateOneNode(node *corev1.Node) error {
return objs[i].Namespace < objs[j].Namespace return objs[i].Namespace < objs[j].Namespace
}) })
if m.config.NoPublish {
return nil
}
klog.V(1).InfoS("processing of node initiated by NodeFeature API", "nodeName", node.Name) klog.V(1).InfoS("processing of node initiated by NodeFeature API", "nodeName", node.Name)
features := nfdv1alpha1.NewNodeFeatureSpec() features := nfdv1alpha1.NewNodeFeatureSpec()
@ -875,6 +884,11 @@ func (m *nfdMaster) refreshNodeFeatures(node *corev1.Node, labels map[string]str
taints = filterTaints(crTaints) taints = filterTaints(crTaints)
} }
if m.config.NoPublish {
klog.V(1).InfoS("node update skipped, NoPublish=true", "nodeName", node.Name)
return nil
}
err := m.updateNodeObject(node, labels, annotations, extendedResources, taints) err := m.updateNodeObject(node, labels, annotations, extendedResources, taints)
if err != nil { if err != nil {
klog.ErrorS(err, "failed to update node", "nodeName", node.Name) klog.ErrorS(err, "failed to update node", "nodeName", node.Name)
@ -1250,18 +1264,6 @@ func (m *nfdMaster) configure(filepath string, overrides string) error {
return err return err
} }
if !c.NoPublish {
kubeconfig, err := utils.GetKubeconfig(m.args.Kubeconfig)
if err != nil {
return err
}
cli, err := k8sclient.NewForConfig(kubeconfig)
if err != nil {
return err
}
m.k8sClient = cli
}
// Pre-process DenyLabelNS into 2 lists: one for normal ns, and the other for wildcard ns // Pre-process DenyLabelNS into 2 lists: one for normal ns, and the other for wildcard ns
normalDeniedNs, wildcardDeniedNs := preProcessDeniedNamespaces(c.DenyLabelNs) normalDeniedNs, wildcardDeniedNs := preProcessDeniedNamespaces(c.DenyLabelNs)
m.deniedNs.normal = normalDeniedNs m.deniedNs.normal = normalDeniedNs

View file

@ -20,6 +20,7 @@ import (
"testing" "testing"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
fakeclient "k8s.io/client-go/kubernetes/fake"
m "sigs.k8s.io/node-feature-discovery/pkg/nfd-master" m "sigs.k8s.io/node-feature-discovery/pkg/nfd-master"
) )
@ -36,7 +37,13 @@ func TestNewNfdMaster(t *testing.T) {
}) })
}) })
Convey("When -config is supplied", func() { Convey("When -config is supplied", func() {
_, err := m.NewNfdMaster(m.WithArgs(&m.Args{CertFile: "crt", KeyFile: "key", CaFile: "ca", ConfigFile: "master-config.yaml"})) _, err := m.NewNfdMaster(
m.WithArgs(&m.Args{
CertFile: "crt",
KeyFile: "key",
CaFile: "ca",
ConfigFile: "master-config.yaml"}),
m.WithKubernetesClient(fakeclient.NewSimpleClientset()))
Convey("An error should not be returned", func() { Convey("An error should not be returned", func() {
So(err, ShouldBeNil) So(err, ShouldBeNil)
}) })

View file

@ -24,6 +24,7 @@ import (
"time" "time"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
fakeclient "k8s.io/client-go/kubernetes/fake"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"sigs.k8s.io/node-feature-discovery/pkg/features" "sigs.k8s.io/node-feature-discovery/pkg/features"
@ -52,7 +53,9 @@ func setupTest(args *master.Args) testContext {
os.Exit(1) os.Exit(1)
} }
_ = features.NFDMutableFeatureGate.OverrideDefault(features.NodeFeatureAPI, false) _ = features.NFDMutableFeatureGate.OverrideDefault(features.NodeFeatureAPI, false)
m, err := master.NewNfdMaster(master.WithArgs(args)) m, err := master.NewNfdMaster(
master.WithArgs(args),
master.WithKubernetesClient(fakeclient.NewSimpleClientset()))
if err != nil { if err != nil {
fmt.Printf("Test setup failed: %v\n", err) fmt.Printf("Test setup failed: %v\n", err)
os.Exit(1) os.Exit(1)