mirror of
https://github.com/kubernetes-sigs/node-feature-discovery.git
synced 2025-03-15 04:57:56 +00:00
Refactor APIHelpers
Remove functionality that was not interacting with Kubernetes API. Makes the architecture a bit simpler and simplifies testing.
This commit is contained in:
parent
35d26001e4
commit
75a8f0c146
6 changed files with 123 additions and 185 deletions
|
@ -29,22 +29,6 @@ type APIHelpers interface {
|
||||||
// GetNode returns the Kubernetes node on which this container is running.
|
// GetNode returns the Kubernetes node on which this container is running.
|
||||||
GetNode(*k8sclient.Clientset, string) (*api.Node, error)
|
GetNode(*k8sclient.Clientset, string) (*api.Node, error)
|
||||||
|
|
||||||
// RemoveLabelsWithPrefix removes labels from the supplied node that contain the
|
|
||||||
// search string provided. In order to publish the changes, the node must
|
|
||||||
// subsequently be updated via the API server using the client library.
|
|
||||||
RemoveLabelsWithPrefix(*api.Node, string)
|
|
||||||
|
|
||||||
// RemoveLabels removes NFD labels from a node object
|
|
||||||
RemoveLabels(*api.Node, []string)
|
|
||||||
|
|
||||||
// AddLabels adds new NFD labels to the node object.
|
|
||||||
// In order to publish the labels, the node must be subsequently updated via the
|
|
||||||
// API server using the client library.
|
|
||||||
AddLabels(*api.Node, map[string]string)
|
|
||||||
|
|
||||||
// Add annotations
|
|
||||||
AddAnnotations(*api.Node, map[string]string)
|
|
||||||
|
|
||||||
// UpdateNode updates the node via the API server using a client.
|
// UpdateNode updates the node via the API server using a client.
|
||||||
UpdateNode(*k8sclient.Clientset, *api.Node) error
|
UpdateNode(*k8sclient.Clientset, *api.Node) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ limitations under the License.
|
||||||
package apihelper
|
package apihelper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
|
|
||||||
api "k8s.io/api/core/v1"
|
api "k8s.io/api/core/v1"
|
||||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
k8sclient "k8s.io/client-go/kubernetes"
|
k8sclient "k8s.io/client-go/kubernetes"
|
||||||
|
@ -54,36 +52,6 @@ func (h K8sHelpers) GetNode(cli *k8sclient.Clientset, nodeName string) (*api.Nod
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveLabelsWithPrefix searches through all labels on Node n and removes
|
|
||||||
// any where the key contain the search string.
|
|
||||||
func (h K8sHelpers) RemoveLabelsWithPrefix(n *api.Node, search string) {
|
|
||||||
for k := range n.Labels {
|
|
||||||
if strings.Contains(k, search) {
|
|
||||||
delete(n.Labels, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveLabels removes given NFD labels
|
|
||||||
func (h K8sHelpers) RemoveLabels(n *api.Node, labelNames []string) {
|
|
||||||
for _, l := range labelNames {
|
|
||||||
delete(n.Labels, h.LabelNs+l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h K8sHelpers) AddLabels(n *api.Node, labels map[string]string) {
|
|
||||||
for k, v := range labels {
|
|
||||||
n.Labels[h.LabelNs+k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Annotations to the Node object
|
|
||||||
func (h K8sHelpers) AddAnnotations(n *api.Node, annotations map[string]string) {
|
|
||||||
for k, v := range annotations {
|
|
||||||
n.Annotations[h.AnnotationNs+k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h K8sHelpers) UpdateNode(c *k8sclient.Clientset, n *api.Node) error {
|
func (h K8sHelpers) UpdateNode(c *k8sclient.Clientset, n *api.Node) error {
|
||||||
// Send the updated node to the apiserver.
|
// Send the updated node to the apiserver.
|
||||||
_, err := c.Core().Nodes().Update(n)
|
_, err := c.Core().Nodes().Update(n)
|
||||||
|
|
|
@ -1,90 +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 apihelper_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
|
||||||
api "k8s.io/api/core/v1"
|
|
||||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"sigs.k8s.io/node-feature-discovery/pkg/apihelper"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAddLabels(t *testing.T) {
|
|
||||||
Convey("When adding labels", t, func() {
|
|
||||||
labelNs := "test.nfd/"
|
|
||||||
helper := apihelper.K8sHelpers{LabelNs: labelNs}
|
|
||||||
labels := map[string]string{}
|
|
||||||
n := &api.Node{
|
|
||||||
ObjectMeta: meta_v1.ObjectMeta{
|
|
||||||
Labels: map[string]string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Convey("If no labels are passed", func() {
|
|
||||||
helper.AddLabels(n, labels)
|
|
||||||
|
|
||||||
Convey("None should be added", func() {
|
|
||||||
So(len(n.Labels), ShouldEqual, 0)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("They should be added to the node.Labels", func() {
|
|
||||||
test1 := "test1"
|
|
||||||
labels[test1] = "true"
|
|
||||||
helper.AddLabels(n, labels)
|
|
||||||
So(n.Labels, ShouldContainKey, labelNs+test1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRemoveLabelsWithPrefix(t *testing.T) {
|
|
||||||
Convey("When removing labels", t, func() {
|
|
||||||
helper := apihelper.K8sHelpers{}
|
|
||||||
n := &api.Node{
|
|
||||||
ObjectMeta: meta_v1.ObjectMeta{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"single": "123",
|
|
||||||
"multiple_A": "a",
|
|
||||||
"multiple_B": "b",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
Convey("a unique label should be removed", func() {
|
|
||||||
helper.RemoveLabelsWithPrefix(n, "single")
|
|
||||||
So(len(n.Labels), ShouldEqual, 2)
|
|
||||||
So(n.Labels, ShouldNotContainKey, "single")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("a non-unique search string should remove all matching keys", func() {
|
|
||||||
helper.RemoveLabelsWithPrefix(n, "multiple")
|
|
||||||
So(len(n.Labels), ShouldEqual, 1)
|
|
||||||
So(n.Labels, ShouldNotContainKey, "multiple_A")
|
|
||||||
So(n.Labels, ShouldNotContainKey, "multiple_B")
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("a search string with no matches should not alter labels", func() {
|
|
||||||
helper.RemoveLabelsWithPrefix(n, "unique")
|
|
||||||
So(n.Labels, ShouldContainKey, "single")
|
|
||||||
So(n.Labels, ShouldContainKey, "multiple_A")
|
|
||||||
So(n.Labels, ShouldContainKey, "multiple_B")
|
|
||||||
So(len(n.Labels), ShouldEqual, 3)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -13,16 +13,6 @@ type MockAPIHelpers struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAnnotations provides a mock function with given fields: _a0, _a1
|
|
||||||
func (_m *MockAPIHelpers) AddAnnotations(_a0 *v1.Node, _a1 map[string]string) {
|
|
||||||
_m.Called(_a0, _a1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddLabels provides a mock function with given fields: _a0, _a1
|
|
||||||
func (_m *MockAPIHelpers) AddLabels(_a0 *v1.Node, _a1 map[string]string) {
|
|
||||||
_m.Called(_a0, _a1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetClient provides a mock function with given fields:
|
// GetClient provides a mock function with given fields:
|
||||||
func (_m *MockAPIHelpers) GetClient() (*kubernetes.Clientset, error) {
|
func (_m *MockAPIHelpers) GetClient() (*kubernetes.Clientset, error) {
|
||||||
ret := _m.Called()
|
ret := _m.Called()
|
||||||
|
@ -69,16 +59,6 @@ func (_m *MockAPIHelpers) GetNode(_a0 *kubernetes.Clientset, _a1 string) (*v1.No
|
||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveLabels provides a mock function with given fields: _a0, _a1
|
|
||||||
func (_m *MockAPIHelpers) RemoveLabels(_a0 *v1.Node, _a1 []string) {
|
|
||||||
_m.Called(_a0, _a1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveLabelsWithPrefix provides a mock function with given fields: _a0, _a1
|
|
||||||
func (_m *MockAPIHelpers) RemoveLabelsWithPrefix(_a0 *v1.Node, _a1 string) {
|
|
||||||
_m.Called(_a0, _a1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateNode provides a mock function with given fields: _a0, _a1
|
// UpdateNode provides a mock function with given fields: _a0, _a1
|
||||||
func (_m *MockAPIHelpers) UpdateNode(_a0 *kubernetes.Clientset, _a1 *v1.Node) error {
|
func (_m *MockAPIHelpers) UpdateNode(_a0 *kubernetes.Clientset, _a1 *v1.Node) error {
|
||||||
ret := _m.Called(_a0, _a1)
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
|
@ -21,10 +21,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"github.com/vektra/errors"
|
"github.com/vektra/errors"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
api "k8s.io/api/core/v1"
|
api "k8s.io/api/core/v1"
|
||||||
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
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"
|
||||||
|
@ -39,6 +39,13 @@ func init() {
|
||||||
nodeName = mockNodeName
|
nodeName = mockNodeName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newMockNode() *api.Node {
|
||||||
|
n := api.Node{}
|
||||||
|
n.Labels = map[string]string{}
|
||||||
|
n.Annotations = map[string]string{}
|
||||||
|
return &n
|
||||||
|
}
|
||||||
|
|
||||||
func TestUpdateNodeFeatures(t *testing.T) {
|
func TestUpdateNodeFeatures(t *testing.T) {
|
||||||
Convey("When I update the node using fake client", t, func() {
|
Convey("When I update the node using fake client", t, func() {
|
||||||
fakeFeatureLabels := map[string]string{"source-feature.1": "val1", "source-feature.2": "val2", "source-feature.3": "val3"}
|
fakeFeatureLabels := map[string]string{"source-feature.1": "val1", "source-feature.2": "val2", "source-feature.3": "val3"}
|
||||||
|
@ -50,23 +57,31 @@ func TestUpdateNodeFeatures(t *testing.T) {
|
||||||
fakeAnnotations["feature-labels"] = strings.Join(fakeFeatureLabelNames, ",")
|
fakeAnnotations["feature-labels"] = strings.Join(fakeFeatureLabelNames, ",")
|
||||||
|
|
||||||
mockAPIHelper := new(apihelper.MockAPIHelpers)
|
mockAPIHelper := new(apihelper.MockAPIHelpers)
|
||||||
mockNode := &api.Node{}
|
|
||||||
mockClient := &k8sclient.Clientset{}
|
mockClient := &k8sclient.Clientset{}
|
||||||
|
// Mock node with old features
|
||||||
|
mockNode := newMockNode()
|
||||||
|
mockNode.Labels[labelNs+"old-feature"] = "old-value"
|
||||||
|
mockNode.Annotations[annotationNs+"feature-labels"] = "old-feature"
|
||||||
|
|
||||||
Convey("When I successfully update the node with feature labels", func() {
|
Convey("When I successfully update the node with feature labels", func() {
|
||||||
mockAPIHelper.On("GetClient").Return(mockClient, nil)
|
mockAPIHelper.On("GetClient").Return(mockClient, nil)
|
||||||
mockAPIHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil).Once()
|
mockAPIHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil).Once()
|
||||||
mockAPIHelper.On("AddLabels", mockNode, fakeFeatureLabels).Return().Once()
|
|
||||||
mockAPIHelper.On("RemoveLabelsWithPrefix", mockNode, labelNs).Return().Once()
|
|
||||||
mockAPIHelper.On("RemoveLabelsWithPrefix", mockNode, "node.alpha.kubernetes-incubator.io/nfd").Return().Once()
|
|
||||||
mockAPIHelper.On("RemoveLabelsWithPrefix", mockNode, "node.alpha.kubernetes-incubator.io/node-feature-discovery").Return().Once()
|
|
||||||
mockAPIHelper.On("AddAnnotations", mockNode, fakeAnnotations).Return().Once()
|
|
||||||
mockAPIHelper.On("UpdateNode", mockClient, mockNode).Return(nil).Once()
|
mockAPIHelper.On("UpdateNode", mockClient, mockNode).Return(nil).Once()
|
||||||
err := updateNodeFeatures(mockAPIHelper, mockNodeName, fakeFeatureLabels, fakeAnnotations)
|
err := updateNodeFeatures(mockAPIHelper, mockNodeName, fakeFeatureLabels, fakeAnnotations)
|
||||||
|
|
||||||
Convey("Error is nil", func() {
|
Convey("Error is nil", func() {
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
Convey("Node object should have updated with labels and annotations", func() {
|
||||||
|
So(len(mockNode.Labels), ShouldEqual, len(fakeFeatureLabels))
|
||||||
|
for k, v := range fakeFeatureLabels {
|
||||||
|
So(mockNode.Labels[labelNs+k], ShouldEqual, v)
|
||||||
|
}
|
||||||
|
So(len(mockNode.Annotations), ShouldEqual, len(fakeAnnotations))
|
||||||
|
for k, v := range fakeFeatureLabels {
|
||||||
|
So(mockNode.Labels[labelNs+k], ShouldEqual, v)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("When I fail to update the node with feature labels", func() {
|
Convey("When I fail to update the node with feature labels", func() {
|
||||||
|
@ -104,11 +119,6 @@ func TestUpdateNodeFeatures(t *testing.T) {
|
||||||
expectedError := errors.New("fake error")
|
expectedError := errors.New("fake error")
|
||||||
mockAPIHelper.On("GetClient").Return(mockClient, nil)
|
mockAPIHelper.On("GetClient").Return(mockClient, nil)
|
||||||
mockAPIHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil).Once()
|
mockAPIHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil).Once()
|
||||||
mockAPIHelper.On("RemoveLabelsWithPrefix", mockNode, labelNs).Return().Once()
|
|
||||||
mockAPIHelper.On("RemoveLabelsWithPrefix", mockNode, "node.alpha.kubernetes-incubator.io/nfd").Return().Once()
|
|
||||||
mockAPIHelper.On("RemoveLabelsWithPrefix", mockNode, "node.alpha.kubernetes-incubator.io/node-feature-discovery").Return().Once()
|
|
||||||
mockAPIHelper.On("AddLabels", mockNode, fakeFeatureLabels).Return().Once()
|
|
||||||
mockAPIHelper.On("AddAnnotations", mockNode, fakeAnnotations).Return().Once()
|
|
||||||
mockAPIHelper.On("UpdateNode", mockClient, mockNode).Return(expectedError).Once()
|
mockAPIHelper.On("UpdateNode", mockClient, mockNode).Return(expectedError).Once()
|
||||||
err := updateNodeFeatures(mockAPIHelper, mockNodeName, fakeFeatureLabels, fakeAnnotations)
|
err := updateNodeFeatures(mockAPIHelper, mockNodeName, fakeFeatureLabels, fakeAnnotations)
|
||||||
|
|
||||||
|
@ -124,11 +134,10 @@ func TestUpdateMasterNode(t *testing.T) {
|
||||||
Convey("When updating the nfd-master node", t, func() {
|
Convey("When updating the nfd-master node", t, func() {
|
||||||
mockHelper := &apihelper.MockAPIHelpers{}
|
mockHelper := &apihelper.MockAPIHelpers{}
|
||||||
mockClient := &k8sclient.Clientset{}
|
mockClient := &k8sclient.Clientset{}
|
||||||
mockNode := &api.Node{}
|
mockNode := newMockNode()
|
||||||
Convey("When update operation succeeds", func() {
|
Convey("When update operation succeeds", func() {
|
||||||
mockHelper.On("GetClient").Return(mockClient, nil)
|
mockHelper.On("GetClient").Return(mockClient, nil)
|
||||||
mockHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil)
|
mockHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil)
|
||||||
mockHelper.On("AddAnnotations", mockNode, map[string]string{"master.version": version.Get()})
|
|
||||||
mockHelper.On("UpdateNode", mockClient, mockNode).Return(nil)
|
mockHelper.On("UpdateNode", mockClient, mockNode).Return(nil)
|
||||||
err := updateMasterNode(mockHelper)
|
err := updateMasterNode(mockHelper)
|
||||||
Convey("No error should be returned", func() {
|
Convey("No error should be returned", func() {
|
||||||
|
@ -157,7 +166,6 @@ func TestUpdateMasterNode(t *testing.T) {
|
||||||
Convey("When updating node object fails", func() {
|
Convey("When updating node object fails", func() {
|
||||||
mockHelper.On("GetClient").Return(mockClient, nil)
|
mockHelper.On("GetClient").Return(mockClient, nil)
|
||||||
mockHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil)
|
mockHelper.On("GetNode", mockClient, mockNodeName).Return(mockNode, nil)
|
||||||
mockHelper.On("AddAnnotations", mock.Anything, mock.Anything)
|
|
||||||
mockHelper.On("UpdateNode", mockClient, mockNode).Return(mockErr)
|
mockHelper.On("UpdateNode", mockClient, mockNode).Return(mockErr)
|
||||||
err := updateMasterNode(mockHelper)
|
err := updateMasterNode(mockHelper)
|
||||||
Convey("An error should be returned", func() {
|
Convey("An error should be returned", func() {
|
||||||
|
@ -173,7 +181,7 @@ func TestSetLabels(t *testing.T) {
|
||||||
const workerVer = "0.1-test"
|
const workerVer = "0.1-test"
|
||||||
mockHelper := &apihelper.MockAPIHelpers{}
|
mockHelper := &apihelper.MockAPIHelpers{}
|
||||||
mockClient := &k8sclient.Clientset{}
|
mockClient := &k8sclient.Clientset{}
|
||||||
mockNode := &api.Node{}
|
mockNode := newMockNode()
|
||||||
mockServer := labelerServer{args: Args{}, apiHelper: mockHelper}
|
mockServer := labelerServer{args: Args{}, apiHelper: mockHelper}
|
||||||
mockCtx := context.Background()
|
mockCtx := context.Background()
|
||||||
mockReq := &labeler.SetLabelsRequest{NodeName: workerName, NfdVersion: workerVer, Labels: map[string]string{"feature-1": "val-1"}}
|
mockReq := &labeler.SetLabelsRequest{NodeName: workerName, NfdVersion: workerVer, Labels: map[string]string{"feature-1": "val-1"}}
|
||||||
|
@ -181,9 +189,6 @@ func TestSetLabels(t *testing.T) {
|
||||||
Convey("When node update succeeds", func() {
|
Convey("When node update succeeds", func() {
|
||||||
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("RemoveLabelsWithPrefix", mockNode, mock.Anything).Return()
|
|
||||||
mockHelper.On("AddLabels", mockNode, mock.Anything).Return()
|
|
||||||
mockHelper.On("AddAnnotations", mockNode, map[string]string{"worker.version": workerVer, "feature-labels": "feature-1"})
|
|
||||||
mockHelper.On("UpdateNode", mockClient, mockNode).Return(nil)
|
mockHelper.On("UpdateNode", mockClient, mockNode).Return(nil)
|
||||||
_, err := mockServer.SetLabels(mockCtx, mockReq)
|
_, err := mockServer.SetLabels(mockCtx, mockReq)
|
||||||
Convey("No error should be returned", func() {
|
Convey("No error should be returned", func() {
|
||||||
|
@ -209,3 +214,64 @@ func TestSetLabels(t *testing.T) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddLabels(t *testing.T) {
|
||||||
|
Convey("When adding labels", t, func() {
|
||||||
|
labels := map[string]string{}
|
||||||
|
n := &api.Node{
|
||||||
|
ObjectMeta: meta_v1.ObjectMeta{
|
||||||
|
Labels: map[string]string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("If no labels are passed", func() {
|
||||||
|
addLabels(n, labels)
|
||||||
|
|
||||||
|
Convey("None should be added", func() {
|
||||||
|
So(len(n.Labels), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("They should be added to the node.Labels", func() {
|
||||||
|
test1 := "test1"
|
||||||
|
labels[test1] = "true"
|
||||||
|
addLabels(n, labels)
|
||||||
|
So(n.Labels, ShouldContainKey, labelNs+test1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveLabelsWithPrefix(t *testing.T) {
|
||||||
|
Convey("When removing labels", t, func() {
|
||||||
|
n := &api.Node{
|
||||||
|
ObjectMeta: meta_v1.ObjectMeta{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"single-label": "123",
|
||||||
|
"multiple_A": "a",
|
||||||
|
"multiple_B": "b",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("a unique label should be removed", func() {
|
||||||
|
removeLabelsWithPrefix(n, "single")
|
||||||
|
So(len(n.Labels), ShouldEqual, 2)
|
||||||
|
So(n.Labels, ShouldNotContainKey, "single")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("a non-unique search string should remove all matching keys", func() {
|
||||||
|
removeLabelsWithPrefix(n, "multiple")
|
||||||
|
So(len(n.Labels), ShouldEqual, 1)
|
||||||
|
So(n.Labels, ShouldNotContainKey, "multiple_A")
|
||||||
|
So(n.Labels, ShouldNotContainKey, "multiple_B")
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("a search string with no matches should not alter labels", func() {
|
||||||
|
removeLabelsWithPrefix(n, "unique")
|
||||||
|
So(n.Labels, ShouldContainKey, "single-label")
|
||||||
|
So(n.Labels, ShouldContainKey, "multiple_A")
|
||||||
|
So(n.Labels, ShouldContainKey, "multiple_B")
|
||||||
|
So(len(n.Labels), ShouldEqual, 3)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/peer"
|
"google.golang.org/grpc/peer"
|
||||||
|
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/version"
|
"sigs.k8s.io/node-feature-discovery/pkg/version"
|
||||||
|
@ -109,8 +110,7 @@ func (m *nfdMaster) Run() error {
|
||||||
stdoutLogger.Printf("NodeName: '%s'", nodeName)
|
stdoutLogger.Printf("NodeName: '%s'", nodeName)
|
||||||
|
|
||||||
// Initialize Kubernetes API helpers
|
// Initialize Kubernetes API helpers
|
||||||
helper := apihelper.APIHelpers(apihelper.K8sHelpers{AnnotationNs: annotationNs,
|
helper := apihelper.APIHelpers(apihelper.K8sHelpers{})
|
||||||
LabelNs: labelNs})
|
|
||||||
|
|
||||||
if !m.args.NoPublish {
|
if !m.args.NoPublish {
|
||||||
err := updateMasterNode(helper)
|
err := updateMasterNode(helper)
|
||||||
|
@ -192,7 +192,7 @@ func updateMasterNode(helper apihelper.APIHelpers) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advertise NFD version as an annotation
|
// Advertise NFD version as an annotation
|
||||||
helper.AddAnnotations(node, Annotations{"master.version": version.Get()})
|
addAnnotations(node, Annotations{"master.version": version.Get()})
|
||||||
err = helper.UpdateNode(cli, node)
|
err = helper.UpdateNode(cli, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stderrLogger.Printf("can't update node: %s", err.Error())
|
stderrLogger.Printf("can't update node: %s", err.Error())
|
||||||
|
@ -282,18 +282,18 @@ func updateNodeFeatures(helper apihelper.APIHelpers, nodeName string, labels Lab
|
||||||
// Remove old labels
|
// Remove old labels
|
||||||
if l, ok := node.Annotations[annotationNs+"feature-labels"]; ok {
|
if l, ok := node.Annotations[annotationNs+"feature-labels"]; ok {
|
||||||
oldLabels := strings.Split(l, ",")
|
oldLabels := strings.Split(l, ",")
|
||||||
helper.RemoveLabels(node, oldLabels)
|
removeLabels(node, oldLabels)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also, remove all labels with the old prefix, and the old version label
|
// Also, remove all labels with the old prefix, and the old version label
|
||||||
helper.RemoveLabelsWithPrefix(node, "node.alpha.kubernetes-incubator.io/nfd")
|
removeLabelsWithPrefix(node, "node.alpha.kubernetes-incubator.io/nfd")
|
||||||
helper.RemoveLabelsWithPrefix(node, "node.alpha.kubernetes-incubator.io/node-feature-discovery")
|
removeLabelsWithPrefix(node, "node.alpha.kubernetes-incubator.io/node-feature-discovery")
|
||||||
|
|
||||||
// Add labels to the node object.
|
// Add labels to the node object.
|
||||||
helper.AddLabels(node, labels)
|
addLabels(node, labels)
|
||||||
|
|
||||||
// Add annotations
|
// Add annotations
|
||||||
helper.AddAnnotations(node, annotations)
|
addAnnotations(node, annotations)
|
||||||
|
|
||||||
// Send the updated node to the apiserver.
|
// Send the updated node to the apiserver.
|
||||||
err = helper.UpdateNode(cli, node)
|
err = helper.UpdateNode(cli, node)
|
||||||
|
@ -304,3 +304,33 @@ func updateNodeFeatures(helper apihelper.APIHelpers, nodeName string, labels Lab
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove any labels having the given prefix
|
||||||
|
func removeLabelsWithPrefix(n *api.Node, search string) {
|
||||||
|
for k := range n.Labels {
|
||||||
|
if strings.HasPrefix(k, search) {
|
||||||
|
delete(n.Labels, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes NFD labels from a Node object
|
||||||
|
func removeLabels(n *api.Node, labelNames []string) {
|
||||||
|
for _, l := range labelNames {
|
||||||
|
delete(n.Labels, labelNs+l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add NFD labels to a Node object.
|
||||||
|
func addLabels(n *api.Node, labels map[string]string) {
|
||||||
|
for k, v := range labels {
|
||||||
|
n.Labels[labelNs+k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Annotations to a Node object
|
||||||
|
func addAnnotations(n *api.Node, annotations map[string]string) {
|
||||||
|
for k, v := range annotations {
|
||||||
|
n.Annotations[annotationNs+k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue