From d5ff7fac8df9f1aac5b0a7ac6f5661e96b72c495 Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Wed, 11 Dec 2024 16:41:53 +0100 Subject: [PATCH] [nad] Add GetJSONPathFromConfig Adds function to return the result of the jsonPath as string from the NetworkAttachmentDefinition config. If the NAD has no config, an empty string is returned. The jsonPath must be in the format e.g. ".ipam" Signed-off-by: Martin Schuppert --- .../networkattachment/networkattachment.go | 34 +++++++++ .../networkattachment_test.go | 76 +++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/modules/common/networkattachment/networkattachment.go b/modules/common/networkattachment/networkattachment.go index dcaa0e59..ce9102ee 100644 --- a/modules/common/networkattachment/networkattachment.go +++ b/modules/common/networkattachment/networkattachment.go @@ -204,3 +204,37 @@ func EnsureNetworksAnnotation( return annotationString, nil } + +// GetJSONPathFromConfig - returns the result of the jsonPath as string +// from the NetworkAttachmentDefinition config. +// if the NAD has no config, an empty string is returned. +// The jsonPath must be in the format e.g. ".ipam" +func GetJSONPathFromConfig(netAtt networkv1.NetworkAttachmentDefinition, path string) (string, error) { + var data interface{} + buf := new(bytes.Buffer) + + if netAtt.Spec.Config == "" { + return buf.String(), nil + } + + if err := json.Unmarshal([]byte(netAtt.Spec.Config), &data); err != nil { + return "", fmt.Errorf("failed to unmarshal JSON data: %w", err) + } + + // use jsonpath to parse the cni config + jp := jsonpath.New(netAtt.Name) + + // Parse the JSONPath template to get the ipam + err := jp.Parse(fmt.Sprintf(`{.%s}`, path)) + if err != nil { + return "", fmt.Errorf("parse template error: %w", err) + } + + // get the ipam from the config + err = jp.Execute(buf, data) + if err != nil { + return "", fmt.Errorf("parse execute template against nad %+v error: %w", netAtt.Spec.Config, err) + } + + return buf.String(), nil +} diff --git a/modules/common/networkattachment/networkattachment_test.go b/modules/common/networkattachment/networkattachment_test.go index ff558719..180f47be 100644 --- a/modules/common/networkattachment/networkattachment_test.go +++ b/modules/common/networkattachment/networkattachment_test.go @@ -291,3 +291,79 @@ func TestEnsureNetworksAnnotation(t *testing.T) { }) } } + +func TestGetJSONPathFromConfig(t *testing.T) { + + tests := []struct { + name string + nad networkv1.NetworkAttachmentDefinition + path string + want string + }{ + { + name: "No config", + nad: networkv1.NetworkAttachmentDefinition{}, + path: ".ipam", + want: "", + }, + { + name: "get .name", + nad: networkv1.NetworkAttachmentDefinition{ + ObjectMeta: metav1.ObjectMeta{Name: "one", Namespace: "foo"}, + Spec: networkv1.NetworkAttachmentDefinitionSpec{ + Config: ` + { + "cniVersion": "0.3.1", + "name": "internalapi", + "type": "macvlan", + "master": "internalapi", + "ipam": { + "type": "whereabouts", + "range": "172.17.0.0/24", + "range_start": "172.17.0.30", + "range_end": "172.17.0.70" + } + } + `, + }, + }, + path: ".name", + want: "internalapi", + }, + { + name: "get .ipam.range", + nad: networkv1.NetworkAttachmentDefinition{ + ObjectMeta: metav1.ObjectMeta{Name: "one", Namespace: "foo"}, + Spec: networkv1.NetworkAttachmentDefinitionSpec{ + Config: ` + { + "cniVersion": "0.3.1", + "name": "internalapi", + "type": "macvlan", + "master": "internalapi", + "ipam": { + "type": "whereabouts", + "range": "172.17.0.0/24", + "range_start": "172.17.0.30", + "range_end": "172.17.0.70" + } + } + `, + }, + }, + path: ".ipam.range", + want: "172.17.0.0/24", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + networkAnnotation, err := GetJSONPathFromConfig(tt.nad, tt.path) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(networkAnnotation).To(HaveLen(len(tt.want))) + g.Expect(networkAnnotation).To(BeEquivalentTo(tt.want)) + }) + } +}