1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-28 02:37:11 +00:00

nfd-master: change statusOp to a more generalized JSON patch

Generalize and rename 'statusOp' type to a more flexible 'JsonPatch'.
Move it to the apihelper package.
This commit is contained in:
Markus Lehtonen 2020-08-13 22:19:16 +03:00
parent bb1e4c60fb
commit 1ea301d272
3 changed files with 54 additions and 31 deletions

View file

@ -0,0 +1,34 @@
/*
Copyright 2020 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
import (
"path/filepath"
"strings"
)
// JsonPatch is a json marshaling helper used for patching API objects
type JsonPatch struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value,omitempty"`
}
// NewJsonPatch returns a new JsonPatch object
func NewJsonPatch(verb string, path string, key string, value string) JsonPatch {
return JsonPatch{verb, filepath.Join(path, strings.ReplaceAll(key, "/", "~1")), value}
}

View file

@ -189,14 +189,14 @@ func TestAddingExtResources(t *testing.T) {
Convey("When there are no matching labels", func() {
mockNode := newMockNode()
mockResourceLabels := ExtendedResources{}
resourceOps := getExtendedResourceOps(mockNode, mockResourceLabels)
resourceOps := createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(resourceOps), ShouldEqual, 0)
})
Convey("When there are matching labels", func() {
mockNode := newMockNode()
mockResourceLabels := ExtendedResources{LabelNs + "/feature-1": "1", LabelNs + "feature-2": "2"}
resourceOps := getExtendedResourceOps(mockNode, mockResourceLabels)
resourceOps := createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(resourceOps), ShouldBeGreaterThan, 0)
})
@ -204,7 +204,7 @@ func TestAddingExtResources(t *testing.T) {
mockNode := newMockNode()
mockNode.Status.Capacity[api.ResourceName(LabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI)
mockResourceLabels := ExtendedResources{LabelNs + "/feature-1": "1"}
resourceOps := getExtendedResourceOps(mockNode, mockResourceLabels)
resourceOps := createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(resourceOps), ShouldEqual, 0)
})
@ -212,7 +212,7 @@ func TestAddingExtResources(t *testing.T) {
mockNode := newMockNode()
mockNode.Status.Capacity[api.ResourceName(LabelNs+"/feature-1")] = *resource.NewQuantity(2, resource.BinarySI)
mockResourceLabels := ExtendedResources{LabelNs + "/feature-1": "1"}
resourceOps := getExtendedResourceOps(mockNode, mockResourceLabels)
resourceOps := createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(resourceOps), ShouldBeGreaterThan, 0)
})
})
@ -226,7 +226,7 @@ func TestRemovingExtResources(t *testing.T) {
mockNode.Annotations[AnnotationNs+"/extended-resources"] = "feature-1,feature-2"
mockNode.Status.Capacity[api.ResourceName(LabelNs+"/feature-1")] = *resource.NewQuantity(1, resource.BinarySI)
mockNode.Status.Capacity[api.ResourceName(LabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI)
resourceOps := getExtendedResourceOps(mockNode, mockResourceLabels)
resourceOps := createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(resourceOps), ShouldEqual, 0)
})
Convey("When the related label is gone", func() {
@ -235,7 +235,7 @@ func TestRemovingExtResources(t *testing.T) {
mockNode.Annotations[AnnotationNs+"/extended-resources"] = "feature-4,feature-2"
mockNode.Status.Capacity[api.ResourceName(LabelNs+"/feature-4")] = *resource.NewQuantity(4, resource.BinarySI)
mockNode.Status.Capacity[api.ResourceName(LabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI)
resourceOps := getExtendedResourceOps(mockNode, mockResourceLabels)
resourceOps := createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(resourceOps), ShouldBeGreaterThan, 0)
})
Convey("When the extended resource is no longer wanted", func() {
@ -244,7 +244,7 @@ func TestRemovingExtResources(t *testing.T) {
mockNode.Status.Capacity[api.ResourceName(LabelNs+"/feature-2")] = *resource.NewQuantity(2, resource.BinarySI)
mockResourceLabels := ExtendedResources{LabelNs + "/feature-2": "2"}
mockNode.Annotations[AnnotationNs+"/extended-resources"] = "feature-1,feature-2"
resourceOps := getExtendedResourceOps(mockNode, mockResourceLabels)
resourceOps := createExtendedResourcePatches(mockNode, mockResourceLabels)
So(len(resourceOps), ShouldBeGreaterThan, 0)
})
})

View file

@ -93,18 +93,6 @@ type nfdMaster struct {
apihelper apihelper.APIHelpers
}
// statusOp is a json marshaling helper used for patching node status
type statusOp struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value,omitempty"`
}
func createStatusOp(verb string, resource string, path string, value string) statusOp {
res := strings.ReplaceAll(resource, "/", "~1")
return statusOp{verb, "/status/" + path + "/" + res, value}
}
// Create new NfdMaster server instance.
func NewNfdMaster(args Args) (NfdMaster, error) {
nfd := &nfdMaster{args: args, ready: make(chan bool, 1)}
@ -397,7 +385,7 @@ func updateNodeFeatures(helper apihelper.APIHelpers, nodeName string, labels Lab
}
// Resolve publishable extended resources before node is modified
statusOps := getExtendedResourceOps(node, extendedResources)
patches := createExtendedResourcePatches(node, extendedResources)
// Remove old labels
if l, ok := node.Annotations[AnnotationNs+"/feature-labels"]; ok {
@ -427,8 +415,8 @@ func updateNodeFeatures(helper apihelper.APIHelpers, nodeName string, labels Lab
}
// patch node status with extended resource changes
if len(statusOps) > 0 {
err = helper.PatchStatus(cli, node.Name, statusOps)
if len(patches) > 0 {
err = helper.PatchStatus(cli, node.Name, patches)
if err != nil {
stderrLogger.Printf("error while patching extended resources: %s", err.Error())
return err
@ -454,9 +442,10 @@ func removeLabels(n *api.Node, labelNames []string) {
}
}
// getExtendedResourceOps returns a slice of operations to perform on the node status
func getExtendedResourceOps(n *api.Node, extendedResources ExtendedResources) []statusOp {
var statusOps []statusOp
// createExtendedResourcePatches returns a slice of operations to perform on
// the node status
func createExtendedResourcePatches(n *api.Node, extendedResources ExtendedResources) []apihelper.JsonPatch {
var patches []apihelper.JsonPatch
// Form a list of namespaced resource names managed by us
if old, ok := n.Annotations[AnnotationNs+"/extended-resources"]; ok {
@ -471,8 +460,8 @@ func getExtendedResourceOps(n *api.Node, extendedResources ExtendedResources) []
if _, ok := n.Status.Capacity[api.ResourceName(resource)]; ok {
// check if the ext resource is still needed
if _, extResNeeded := extendedResources[resource]; !extResNeeded {
statusOps = append(statusOps, createStatusOp("remove", resource, "capacity", ""))
statusOps = append(statusOps, createStatusOp("remove", resource, "allocatable", ""))
patches = append(patches, apihelper.NewJsonPatch("remove", "/status/capacity", resource, ""))
patches = append(patches, apihelper.NewJsonPatch("remove", "/status/allocatable", resource, ""))
}
}
}
@ -484,16 +473,16 @@ func getExtendedResourceOps(n *api.Node, extendedResources ExtendedResources) []
if quantity, ok := n.Status.Capacity[api.ResourceName(resource)]; ok {
val, _ := quantity.AsInt64()
if strconv.FormatInt(val, 10) != value {
statusOps = append(statusOps, createStatusOp("replace", resource, "capacity", value))
statusOps = append(statusOps, createStatusOp("replace", resource, "allocatable", value))
patches = append(patches, apihelper.NewJsonPatch("replace", "/status/capacity", resource, value))
patches = append(patches, apihelper.NewJsonPatch("replace", "/status/allocatable", resource, value))
}
} else {
statusOps = append(statusOps, createStatusOp("add", resource, "capacity", value))
patches = append(patches, apihelper.NewJsonPatch("add", "/status/capacity", resource, value))
// "allocatable" gets added implicitly after adding to capacity
}
}
return statusOps
return patches
}
// Add NFD labels to a Node object.