diff --git a/npm/cache/npmCache.go b/npm/cache/npmCache.go deleted file mode 100644 index 291bb0e12b..0000000000 --- a/npm/cache/npmCache.go +++ /dev/null @@ -1,59 +0,0 @@ -package cache - -import ( - "encoding/json" - "fmt" - "io" - - "github.com/Azure/azure-container-networking/npm" - "github.com/Azure/azure-container-networking/npm/ipsm" -) - -type NPMCache struct { - Nodename string - NsMap map[string]*npm.Namespace - PodMap map[string]*npm.NpmPod - ListMap map[string]*ipsm.Ipset - SetMap map[string]*ipsm.Ipset -} - -// Decode returns NPMCache object after decoding data. -// TODO(jungukcho): This Decode has tight ordering for decoding data due to dependency with Encode function. -// It needs to find a way of relaxing this strong ordering. -func Decode(reader io.Reader) (*NPMCache, error) { - cache := &NPMCache{} - dec := json.NewDecoder(reader) - - if err := dec.Decode(&cache.Nodename); err != nil { - return nil, fmt.Errorf("failed to decode Nodename : %w", err) - } - - if err := dec.Decode(&cache.NsMap); err != nil { - return nil, fmt.Errorf("failed to decode NsMap : %w", err) - } - - if err := dec.Decode(&cache.PodMap); err != nil { - return nil, fmt.Errorf("failed to decode PodMap : %w", err) - } - - if err := dec.Decode(&cache.ListMap); err != nil { - return nil, fmt.Errorf("failed to decode ListMap : %w", err) - } - - if err := dec.Decode(&cache.SetMap); err != nil { - return nil, fmt.Errorf("failed to decode SetMap : %w", err) - } - - return cache, nil -} - -// Encode returns encoded NPMCache data. -// TODO(jungukcho): This Encode has tight ordering for encoding data due to dependency with Decode function. -// It needs to find a way of relaxing this strong ordering. -func Encode(writer io.Writer, npmEncoder npm.NetworkPolicyManagerEncoder) error { - if err := npmEncoder.Encode(writer); err != nil { - return fmt.Errorf("cannot encode NPMCache %w", err) - } - - return nil -} diff --git a/npm/cache/npmCache_test.go b/npm/cache/npmCache_test.go deleted file mode 100644 index 934e5a6258..0000000000 --- a/npm/cache/npmCache_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package cache - -import ( - "bytes" - "reflect" - "strings" - "testing" - "time" - - "github.com/Azure/azure-container-networking/npm" - "github.com/Azure/azure-container-networking/npm/ipsm" - k8sversion "k8s.io/apimachinery/pkg/version" - kubeinformers "k8s.io/client-go/informers" - k8sfake "k8s.io/client-go/kubernetes/fake" - fakeexec "k8s.io/utils/exec/testing" -) - -func NPMEncoder(nodeName string) npm.NetworkPolicyManagerEncoder { - noResyncPeriodFunc := func() time.Duration { return 0 } - kubeclient := k8sfake.NewSimpleClientset() - kubeInformer := kubeinformers.NewSharedInformerFactory(kubeclient, noResyncPeriodFunc()) - fakeK8sVersion := &k8sversion.Info{ - GitVersion: "v1.20.2", - } - exec := &fakeexec.FakeExec{} - npmVersion := "npm-ut-test" - - npMgr := npm.NewNetworkPolicyManager(kubeInformer, exec, npmVersion, fakeK8sVersion) - npMgr.NodeName = nodeName - return npMgr -} - -func TestDecode(t *testing.T) { - encodedNPMCacheData := "\"nodename\"\n{}\n{}\n{}\n{}\n" - reader := strings.NewReader(encodedNPMCacheData) - decodedNPMCache, err := Decode(reader) - if err != nil { - t.Errorf("failed to decode %s to NPMCache", encodedNPMCacheData) - } - - expected := &NPMCache{ - Nodename: "nodename", - NsMap: make(map[string]*npm.Namespace), - PodMap: make(map[string]*npm.NpmPod), - ListMap: make(map[string]*ipsm.Ipset), - SetMap: make(map[string]*ipsm.Ipset), - } - - if !reflect.DeepEqual(decodedNPMCache, expected) { - t.Errorf("got '%+v', expected '%+v'", decodedNPMCache, expected) - } -} - -func TestEncode(t *testing.T) { - nodeName := "nodename" - npmEncoder := NPMEncoder(nodeName) - var buf bytes.Buffer - if err := Encode(&buf, npmEncoder); err != nil { - t.Errorf("failed to encode NPMCache") - } - encodedNPMCache := buf.String() - - expected := "\"nodename\"\n{}\n{}\n{}\n{}\n" - if encodedNPMCache != expected { - t.Errorf("got '%+v', expected '%+v'", encodedNPMCache, expected) - } -} diff --git a/npm/http/server/server.go b/npm/http/server/server.go index 56706959d9..4568fbdd17 100644 --- a/npm/http/server/server.go +++ b/npm/http/server/server.go @@ -1,18 +1,18 @@ package server import ( + "encoding/json" "fmt" "net/http" "net/http/pprof" _ "net/http/pprof" - "github.com/Azure/azure-container-networking/npm/cache" + "github.com/Azure/azure-container-networking/log" npmconfig "github.com/Azure/azure-container-networking/npm/config" "github.com/Azure/azure-container-networking/npm/http/api" "github.com/Azure/azure-container-networking/npm/metrics" "k8s.io/klog" - "github.com/Azure/azure-container-networking/npm" "github.com/gorilla/mux" ) @@ -21,7 +21,7 @@ type NPMRestServer struct { router *mux.Router } -func NPMRestServerListenAndServe(config npmconfig.Config, npmEncoder npm.NetworkPolicyManagerEncoder) { +func NPMRestServerListenAndServe(config npmconfig.Config, npmEncoder json.Marshaler) { rs := NPMRestServer{} rs.router = mux.NewRouter() @@ -60,12 +60,16 @@ func NPMRestServerListenAndServe(config npmconfig.Config, npmEncoder npm.Network klog.Errorf("Failed to start NPM HTTP Server with error: %+v", srv.ListenAndServe()) } -func (n *NPMRestServer) npmCacheHandler(npmEncoder npm.NetworkPolicyManagerEncoder) http.Handler { +func (n *NPMRestServer) npmCacheHandler(npmCacheEncoder json.Marshaler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - err := cache.Encode(w, npmEncoder) + b, err := json.Marshal(npmCacheEncoder) if err != nil { http.Error(w, err.Error(), 500) return } + _, err = w.Write(b) + if err != nil { + log.Errorf("failed to write resp: %w", err) + } }) } diff --git a/npm/http/server/server_test.go b/npm/http/server/server_test.go index cba2a2e71a..35badb204e 100644 --- a/npm/http/server/server_test.go +++ b/npm/http/server/server_test.go @@ -1,44 +1,26 @@ package server import ( + "encoding/json" + "io/ioutil" "net/http" "net/http/httptest" - "os" "testing" - "time" - "github.com/Azure/azure-container-networking/npm/cache" "github.com/Azure/azure-container-networking/npm/http/api" "github.com/Azure/azure-container-networking/npm/ipsm" "github.com/stretchr/testify/assert" "github.com/Azure/azure-container-networking/npm" - k8sversion "k8s.io/apimachinery/pkg/version" - kubeinformers "k8s.io/client-go/informers" - k8sfake "k8s.io/client-go/kubernetes/fake" - fakeexec "k8s.io/utils/exec/testing" ) -func NPMEncoder() npm.NetworkPolicyManagerEncoder { - noResyncPeriodFunc := func() time.Duration { return 0 } - kubeclient := k8sfake.NewSimpleClientset() - kubeInformer := kubeinformers.NewSharedInformerFactory(kubeclient, noResyncPeriodFunc()) - fakeK8sVersion := &k8sversion.Info{ - GitVersion: "v1.20.2", - } - exec := &fakeexec.FakeExec{} - npmVersion := "npm-ut-test" - - npmEncoder := npm.NewNetworkPolicyManager(kubeInformer, exec, npmVersion, fakeK8sVersion) - return npmEncoder -} - func TestGetNPMCacheHandler(t *testing.T) { assert := assert.New(t) - npmEncoder := NPMEncoder() + nodeName := "nodename" + npmCacheEncoder := npm.CacheEncoder(nodeName) n := &NPMRestServer{} - handler := n.npmCacheHandler(npmEncoder) + handler := n.npmCacheHandler(npmCacheEncoder) req, err := http.NewRequest(http.MethodGet, api.NPMMgrPath, nil) if err != nil { @@ -53,14 +35,19 @@ func TestGetNPMCacheHandler(t *testing.T) { status, http.StatusOK) } - var actual *cache.NPMCache - actual, err = cache.Decode(rr.Body) + byteArray, err := ioutil.ReadAll(rr.Body) if err != nil { - t.Fatal(err) + t.Errorf("failed to read response's data : %w", err) + } + + actual := &npm.Cache{} + err = json.Unmarshal(byteArray, actual) + if err != nil { + t.Fatalf("failed to unmarshal %s due to %v", string(byteArray), err) } - expected := &cache.NPMCache{ - Nodename: os.Getenv("HOSTNAME"), + expected := &npm.Cache{ + NodeName: nodeName, NsMap: make(map[string]*npm.Namespace), PodMap: make(map[string]*npm.NpmPod), ListMap: make(map[string]*ipsm.Ipset), diff --git a/npm/ipsm/ipsm.go b/npm/ipsm/ipsm.go index 5e00846e88..9b566ecd4f 100644 --- a/npm/ipsm/ipsm.go +++ b/npm/ipsm/ipsm.go @@ -15,6 +15,7 @@ import ( "github.com/Azure/azure-container-networking/log" "github.com/Azure/azure-container-networking/npm/metrics" "github.com/Azure/azure-container-networking/npm/util" + "github.com/pkg/errors" utilexec "k8s.io/utils/exec" ) @@ -75,22 +76,28 @@ func NewIpsetManager(exec utilexec.Interface) *IpsetManager { } } -// Encode encodes listmap and setmap. -// The ordering to encode them is important. -// Do encode listMap first and then setMap. -func (ipsMgr *IpsetManager) Encode(enc *json.Encoder) error { +func (ipsMgr *IpsetManager) MarshalListMapJSON() ([]byte, error) { ipsMgr.Lock() defer ipsMgr.Unlock() - if err := enc.Encode(ipsMgr.listMap); err != nil { - return fmt.Errorf("failed to encode listMap %w", err) + listMapRaw, err := json.Marshal(ipsMgr.listMap) + if err != nil { + return nil, errors.Errorf("failed to marshal ListMap due to %v", err) } - if err := enc.Encode(ipsMgr.setMap); err != nil { - return fmt.Errorf("failed to encode setMap %w", err) + return listMapRaw, nil +} + +func (ipsMgr *IpsetManager) MarshalSetMapJSON() ([]byte, error) { + ipsMgr.Lock() + defer ipsMgr.Unlock() + + setMapRaw, err := json.Marshal(ipsMgr.setMap) + if err != nil { + return nil, errors.Errorf("failed to marshal SetMap due to %v", err) } - return nil + return setMapRaw, nil } // Exists checks if an element exists in setMap/listMap. diff --git a/npm/ipsm/ipsm_test.go b/npm/ipsm/ipsm_test.go index e99ad5faaf..51c34ac52c 100644 --- a/npm/ipsm/ipsm_test.go +++ b/npm/ipsm/ipsm_test.go @@ -11,6 +11,7 @@ import ( "github.com/Azure/azure-container-networking/npm/metrics/promutil" "github.com/Azure/azure-container-networking/npm/util" testutils "github.com/Azure/azure-container-networking/test/utils" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/utils/exec" ) @@ -531,6 +532,54 @@ func TestDestroyNpmIpsets(t *testing.T) { } } +func TestMarshalListMapJSON(t *testing.T) { + testListSet := "test-list" + calls := []testutils.TestCmd{ + {Cmd: []string{"ipset", "-N", "-exist", util.GetHashedName(testListSet), "setlist"}}, + } + + fexec := testutils.GetFakeExecWithScripts(calls) + ipsMgr := NewIpsetManager(fexec) + defer testutils.VerifyCalls(t, fexec, calls) + + err := ipsMgr.createList(testListSet) + require.NoError(t, err) + + listMapRaw, err := ipsMgr.MarshalListMapJSON() + require.NoError(t, err) + fmt.Println(string(listMapRaw)) + + expect := []byte(`{"test-list":{}}`) + + fmt.Printf("%v\n", ipsMgr.listMap) + assert.ElementsMatch(t, expect, listMapRaw) +} + +func TestMarshalSetMapJSON(t *testing.T) { + testSet := "test-set" + calls := []testutils.TestCmd{ + {Cmd: []string{"ipset", "-N", "-exist", util.GetHashedName(testSet), "nethash"}}, + } + + fexec := testutils.GetFakeExecWithScripts(calls) + ipsMgr := NewIpsetManager(fexec) + defer testutils.VerifyCalls(t, fexec, calls) + + err := ipsMgr.createSet(testSet, []string{util.IpsetNetHashFlag}) + require.NoError(t, err) + + setMapRaw, err := ipsMgr.MarshalSetMapJSON() + require.NoError(t, err) + fmt.Println(string(setMapRaw)) + + expect := []byte(`{"test-set":{}}`) + for key, val := range ipsMgr.setMap { + fmt.Printf("key: %s value: %+v\n", key, val) + } + + assert.ElementsMatch(t, expect, setMapRaw) +} + // Enable these tests once the the changes for ipsm are enabled /* const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" diff --git a/npm/npm.go b/npm/npm.go index 74db53e8ec..403b94fb86 100644 --- a/npm/npm.go +++ b/npm/npm.go @@ -5,7 +5,6 @@ package npm import ( "encoding/json" "fmt" - "io" "os" "sync" "time" @@ -16,6 +15,7 @@ import ( "github.com/Azure/azure-container-networking/npm/ipsm" "github.com/Azure/azure-container-networking/npm/metrics" "github.com/Azure/azure-container-networking/npm/util" + "github.com/pkg/errors" "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/informers" coreinformers "k8s.io/client-go/informers/core/v1" @@ -41,8 +41,16 @@ type npmNamespaceCache struct { nsMap map[string]*Namespace // Key is ns- } -type NetworkPolicyManagerEncoder interface { - Encode(writer io.Writer) error +func (n *npmNamespaceCache) MarshalJSON() ([]byte, error) { + n.Lock() + defer n.Unlock() + + nsMapRaw, err := json.Marshal(n.nsMap) + if err != nil { + return nil, errors.Errorf("failed to marshal nsMap due to %v", err) + } + + return nsMapRaw, nil } // NetworkPolicyManager contains informers for pod, namespace and networkpolicy. @@ -97,39 +105,47 @@ func NewNetworkPolicyManager(informerFactory informers.SharedInformerFactory, ex return npMgr } -func (npMgr *NetworkPolicyManager) encode(enc *json.Encoder) error { - if err := enc.Encode(npMgr.NodeName); err != nil { - return fmt.Errorf("failed to encode nodename %w", err) +func (npMgr *NetworkPolicyManager) MarshalJSON() ([]byte, error) { + m := map[CacheKey]json.RawMessage{} + + npmNamespaceCacheRaw, err := json.Marshal(npMgr.npmNamespaceCache) + if err != nil { + return nil, errors.Errorf("%s: %v", errMarshalNPMCache, err) } + m[NsMap] = npmNamespaceCacheRaw - npMgr.npmNamespaceCache.Lock() - defer npMgr.npmNamespaceCache.Unlock() - if err := enc.Encode(npMgr.npmNamespaceCache.nsMap); err != nil { - return fmt.Errorf("failed to encode npm namespace cache %w", err) + podControllerRaw, err := json.Marshal(npMgr.podController) + if err != nil { + return nil, errors.Errorf("%s: %v", errMarshalNPMCache, err) } + m[PodMap] = podControllerRaw - return nil -} + if npMgr.ipsMgr != nil { + listMapRaw, listMapMarshalErr := npMgr.ipsMgr.MarshalListMapJSON() + if listMapMarshalErr != nil { + return nil, errors.Errorf("%s: %v", errMarshalNPMCache, listMapMarshalErr) + } + m[ListMap] = listMapRaw -// Encode returns all information of pod, namespace, ipsm map information. -// TODO(jungukcho): While this approach is beneficial to hold separate lock instead of global lock, -// it has strict ordering limitation between encoding and decoding. -// Will find flexible way by maintaining performance benefit. -func (npMgr *NetworkPolicyManager) Encode(writer io.Writer) error { - enc := json.NewEncoder(writer) - if err := npMgr.encode(enc); err != nil { - return err + setMapRaw, setMapMarshalErr := npMgr.ipsMgr.MarshalSetMapJSON() + if setMapMarshalErr != nil { + return nil, errors.Errorf("%s: %v", errMarshalNPMCache, setMapMarshalErr) + } + m[SetMap] = setMapRaw } - if err := npMgr.podController.Encode(enc); err != nil { - return err + nodeNameRaw, err := json.Marshal(npMgr.NodeName) + if err != nil { + return nil, errors.Errorf("%s: %v", errMarshalNPMCache, err) } + m[NodeName] = nodeNameRaw - if err := npMgr.ipsMgr.Encode(enc); err != nil { - return fmt.Errorf("failed to encode ipsm cache %w", err) + npmCacheRaw, err := json.Marshal(m) + if err != nil { + return nil, errors.Errorf("%s: %v", errMarshalNPMCache, err) } - return nil + return npmCacheRaw, nil } // GetAppVersion returns network policy manager app version diff --git a/npm/npmCache.go b/npm/npmCache.go new file mode 100644 index 0000000000..c5cba29e1c --- /dev/null +++ b/npm/npmCache.go @@ -0,0 +1,52 @@ +// Copyright 2018 Microsoft. All rights reserved. +// MIT License +package npm + +import ( + "encoding/json" + "time" + + "github.com/Azure/azure-container-networking/npm/ipsm" + "github.com/pkg/errors" + k8sversion "k8s.io/apimachinery/pkg/version" + kubeinformers "k8s.io/client-go/informers" + k8sfake "k8s.io/client-go/kubernetes/fake" + fakeexec "k8s.io/utils/exec/testing" +) + +type CacheKey string + +// NPMCache Key Contract for Json marshal and unmarshal +const ( + NodeName CacheKey = "NodeName" + NsMap CacheKey = "NsMap" + PodMap CacheKey = "PodMap" + ListMap CacheKey = "ListMap" + SetMap CacheKey = "SetMap" +) + +type Cache struct { + NodeName string + NsMap map[string]*Namespace + PodMap map[string]*NpmPod + ListMap map[string]*ipsm.Ipset + SetMap map[string]*ipsm.Ipset +} + +var errMarshalNPMCache = errors.New("failed to marshal NPM Cache") + +// CacheEncoder is used only for unit tests to test encoding and decoding Cache. +func CacheEncoder(nodeName string) json.Marshaler { + noResyncPeriodFunc := func() time.Duration { return 0 } + kubeclient := k8sfake.NewSimpleClientset() + kubeInformer := kubeinformers.NewSharedInformerFactory(kubeclient, noResyncPeriodFunc()) + fakeK8sVersion := &k8sversion.Info{ + GitVersion: "v1.20.2", + } + exec := &fakeexec.FakeExec{} + npmVersion := "npm-ut-test" + + npMgr := NewNetworkPolicyManager(kubeInformer, exec, npmVersion, fakeK8sVersion) + npMgr.NodeName = nodeName + return npMgr +} diff --git a/npm/npm_test.go b/npm/npm_test.go index e195421db7..378e30753e 100644 --- a/npm/npm_test.go +++ b/npm/npm_test.go @@ -1,12 +1,16 @@ package npm import ( + "encoding/json" "os" + "reflect" "testing" "github.com/Azure/azure-container-networking/npm/ipsm" "github.com/Azure/azure-container-networking/npm/iptm" "github.com/Azure/azure-container-networking/npm/metrics" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "k8s.io/client-go/tools/cache" "k8s.io/utils/exec" ) @@ -28,6 +32,69 @@ func getKey(obj interface{}, t *testing.T) string { return key } +func TestNSMapMarshalJSON(t *testing.T) { + npmNSCache := &npmNamespaceCache{nsMap: make(map[string]*Namespace)} + nsName := "ns-test" + ns := &Namespace{ + name: nsName, + LabelsMap: map[string]string{ + "test-key": "test-value", + }, + } + + npmNSCache.nsMap[nsName] = ns + nsMapRaw, err := npmNSCache.MarshalJSON() + require.NoError(t, err) + + expect := []byte(`{"ns-test":{"LabelsMap":{"test-key":"test-value"}}}`) + assert.ElementsMatch(t, expect, nsMapRaw) +} + +func TestMarshalJSONForNilValues(t *testing.T) { + npMgr := &NetworkPolicyManager{} + npmCacheRaw, err := npMgr.MarshalJSON() + assert.NoError(t, err) + + expect := []byte(`{"NodeName":"","NsMap":null,"PodMap":null}`) + assert.ElementsMatch(t, expect, npmCacheRaw) +} + +func TestMarshalJSON(t *testing.T) { + nodeName := "test-nodename" + npmCacheEncoder := CacheEncoder(nodeName) + npmCacheRaw, err := npmCacheEncoder.MarshalJSON() + assert.NoError(t, err) + + // "test-nodename" in "NodeName" should be the same as nodeName variable. + expect := []byte(`{"ListMap":{},"NodeName":"test-nodename","NsMap":{},"PodMap":{},"SetMap":{}}`) + assert.ElementsMatch(t, expect, npmCacheRaw) +} + +func TestMarshalUnMarshalJSON(t *testing.T) { + nodeName := "test-nodename" + npmCacheEncoder := CacheEncoder(nodeName) + + npmCacheRaw, err := npmCacheEncoder.MarshalJSON() + assert.NoError(t, err) + + decodedNPMCache := Cache{} + if err := json.Unmarshal(npmCacheRaw, &decodedNPMCache); err != nil { + t.Errorf("failed to decode %s to NPMCache", npmCacheRaw) + } + + expected := Cache{ + ListMap: make(map[string]*ipsm.Ipset), + NodeName: nodeName, + NsMap: make(map[string]*Namespace), + PodMap: make(map[string]*NpmPod), + SetMap: make(map[string]*ipsm.Ipset), + } + + if !reflect.DeepEqual(decodedNPMCache, expected) { + t.Errorf("got '%+v', expected '%+v'", decodedNPMCache, expected) + } +} + func TestMain(m *testing.M) { metrics.InitializeAll() exec := exec.New() diff --git a/npm/pkg/dataplane/debug/const.go b/npm/pkg/dataplane/debug/const.go index 9a8a274299..fe36085c27 100644 --- a/npm/pkg/dataplane/debug/const.go +++ b/npm/pkg/dataplane/debug/const.go @@ -41,9 +41,7 @@ var ( // To test paser, converter, and trafficAnalyzer with stored files. const ( - iptableSaveFile = "../testfiles/iptablesave" + iptableSaveFile = "../testdata/iptablesave" // stored file with json compatible form (i.e., can call json.Unmarshal) - // npmCacheFile = ".../testfiles/npmCache.json" - // stored file with custom encoding in Encode function in npmCache.go - npmCacheWithCustomFormatFile = "../testfiles/npmCacheWithCustomFormat.json" + npmCacheFile = "../testdata/npmcache.json" ) diff --git a/npm/pkg/dataplane/debug/converter.go b/npm/pkg/dataplane/debug/converter.go index 81a6ab1151..a44a3f0beb 100644 --- a/npm/pkg/dataplane/debug/converter.go +++ b/npm/pkg/dataplane/debug/converter.go @@ -1,18 +1,18 @@ package dataplane import ( - "bufio" "bytes" "context" + "encoding/json" "fmt" + "io/ioutil" "log" "net/http" - "os" "os/exec" "strconv" "strings" - "github.com/Azure/azure-container-networking/npm/cache" + "github.com/Azure/azure-container-networking/npm" "github.com/Azure/azure-container-networking/npm/http/api" NPMIPtable "github.com/Azure/azure-container-networking/npm/pkg/dataplane/iptables" "github.com/Azure/azure-container-networking/npm/pkg/dataplane/parse" @@ -26,20 +26,20 @@ type Converter struct { ListMap map[string]string // key: hash(value), value: one of namespace, label of namespace, multiple values SetMap map[string]string // key: hash(value), value: one of label of pods, cidr, namedport AzureNPMChains map[string]bool - NPMCache *cache.NPMCache + NPMCache *npm.Cache } // NpmCacheFromFile initialize NPM cache from file. func (c *Converter) NpmCacheFromFile(npmCacheJSONFile string) error { - file, err := os.Open(npmCacheJSONFile) + byteArray, err := ioutil.ReadFile(npmCacheJSONFile) if err != nil { - return fmt.Errorf("failed to open file : %w", err) + return fmt.Errorf("failed to read %s file : %w", npmCacheJSONFile, err) } - defer file.Close() - c.NPMCache, err = cache.Decode(bufio.NewReader(file)) + c.NPMCache = &npm.Cache{} + err = json.Unmarshal(byteArray, c.NPMCache) if err != nil { - return fmt.Errorf("failed to decode npm cache due to : %w", err) + return fmt.Errorf("failed to unmarshal %s due to %w", string(byteArray), err) } return nil } @@ -60,12 +60,15 @@ func (c *Converter) NpmCache() error { return fmt.Errorf("failed to request NPM Cache : %w", err) } defer resp.Body.Close() - - c.NPMCache, err = cache.Decode(resp.Body) + byteArray, err := ioutil.ReadAll(resp.Body) if err != nil { - return fmt.Errorf("cannot decode NPM Cache : %w", err) + return fmt.Errorf("failed to read response's data : %w", err) + } + c.NPMCache = &npm.Cache{} + err = json.Unmarshal(byteArray, c.NPMCache) + if err != nil { + return fmt.Errorf("failed to unmarshal %s due to %w", string(byteArray), err) } - return nil } diff --git a/npm/pkg/dataplane/debug/converter_test.go b/npm/pkg/dataplane/debug/converter_test.go index 055ec94b42..dc0258c30d 100644 --- a/npm/pkg/dataplane/debug/converter_test.go +++ b/npm/pkg/dataplane/debug/converter_test.go @@ -14,11 +14,11 @@ func TestGetJSONRulesFromIptableFile(t *testing.T) { c := &Converter{} _, err := c.GetJSONRulesFromIptableFile( util.IptablesFilterTable, - npmCacheWithCustomFormatFile, + npmCacheFile, iptableSaveFile, ) if err != nil { - t.Errorf("error during TestGetJSONRulesFromIptable : %w", err) + t.Errorf("failed to test GetJSONRulesFromIptable : %w", err) } } @@ -26,7 +26,7 @@ func TestGetProtobufRulesFromIptableFile(t *testing.T) { c := &Converter{} _, err := c.GetProtobufRulesFromIptableFile( util.IptablesFilterTable, - npmCacheWithCustomFormatFile, + npmCacheFile, iptableSaveFile, ) if err != nil { @@ -36,9 +36,9 @@ func TestGetProtobufRulesFromIptableFile(t *testing.T) { func TestNpmCacheFromFile(t *testing.T) { c := &Converter{} - err := c.NpmCacheFromFile(npmCacheWithCustomFormatFile) + err := c.NpmCacheFromFile(npmCacheFile) if err != nil { - t.Errorf("Failed to decode NPMCache from %s file : %w", npmCacheWithCustomFormatFile, err) + t.Errorf("Failed to decode NPMCache from %s file : %w", npmCacheFile, err) } } @@ -91,7 +91,7 @@ func TestGetSetType(t *testing.T) { } c := &Converter{} - err := c.initConverterFile(npmCacheWithCustomFormatFile) + err := c.initConverterFile(npmCacheFile) if err != nil { t.Errorf("error during initilizing converter : %w", err) } @@ -313,7 +313,7 @@ func TestGetRulesFromChain(t *testing.T) { } c := &Converter{} - err := c.initConverterFile(npmCacheWithCustomFormatFile) + err := c.initConverterFile(npmCacheFile) if err != nil { t.Errorf("error during initilizing converter : %w", err) } @@ -502,7 +502,7 @@ func TestGetModulesFromRule(t *testing.T) { } c := &Converter{} - err := c.initConverterFile(npmCacheWithCustomFormatFile) + err := c.initConverterFile(npmCacheFile) if err != nil { t.Errorf("error during initilizing converter : %w", err) } diff --git a/npm/pkg/dataplane/debug/trafficanalyzer.go b/npm/pkg/dataplane/debug/trafficanalyzer.go index 5e15407624..193c284a31 100644 --- a/npm/pkg/dataplane/debug/trafficanalyzer.go +++ b/npm/pkg/dataplane/debug/trafficanalyzer.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/Azure/azure-container-networking/npm" - "github.com/Azure/azure-container-networking/npm/cache" "github.com/Azure/azure-container-networking/npm/pkg/dataplane/pb" "github.com/Azure/azure-container-networking/npm/util" "google.golang.org/protobuf/encoding/protojson" @@ -78,7 +77,7 @@ func GetNetworkTupleFile( // Common function. func getNetworkTupleCommon( src, dst *Input, - npmCache *cache.NPMCache, + npmCache *npm.Cache, allRules []*pb.RuleResponse, ) ([][]byte, []*Tuple, error) { @@ -130,7 +129,7 @@ func getNetworkTupleCommon( return ruleResListJSON, resTupleList, nil } -func getNPMPod(input *Input, npmCache *cache.NPMCache) (*npm.NpmPod, error) { +func getNPMPod(input *Input, npmCache *npm.Cache) (*npm.NpmPod, error) { switch input.Type { case PODNAME: if pod, ok := npmCache.PodMap[input.Content]; ok { @@ -209,7 +208,7 @@ func generateTuple(src, dst *npm.NpmPod, rule *pb.RuleResponse) *Tuple { func getHitRules( src, dst *npm.NpmPod, rules []*pb.RuleResponse, - npmCache *cache.NPMCache, + npmCache *npm.Cache, ) ([]*pb.RuleResponse, error) { res := make([]*pb.RuleResponse, 0) @@ -267,7 +266,7 @@ func evaluateSetInfo( setInfo *pb.RuleResponse_SetInfo, pod *npm.NpmPod, rule *pb.RuleResponse, - npmCache *cache.NPMCache, + npmCache *npm.Cache, ) (bool, error) { switch setInfo.Type { @@ -292,7 +291,7 @@ func evaluateSetInfo( } } -func matchKEYVALUELABELOFNAMESPACE(pod *npm.NpmPod, npmCache *cache.NPMCache, setInfo *pb.RuleResponse_SetInfo) bool { +func matchKEYVALUELABELOFNAMESPACE(pod *npm.NpmPod, npmCache *npm.Cache, setInfo *pb.RuleResponse_SetInfo) bool { srcNamespace := util.NamespacePrefix + pod.Namespace key, expectedValue := processKeyValueLabelOfNameSpace(setInfo.Name) actualValue := npmCache.NsMap[srcNamespace].LabelsMap[key] @@ -331,7 +330,7 @@ func matchNESTEDLABELOFPOD(pod *npm.NpmPod, setInfo *pb.RuleResponse_SetInfo) bo return true } -func matchKEYLABELOFNAMESPACE(pod *npm.NpmPod, npmCache *cache.NPMCache, setInfo *pb.RuleResponse_SetInfo) bool { +func matchKEYLABELOFNAMESPACE(pod *npm.NpmPod, npmCache *npm.Cache, setInfo *pb.RuleResponse_SetInfo) bool { srcNamespace := util.NamespacePrefix + pod.Namespace key := strings.TrimPrefix(setInfo.Name, util.NamespacePrefix) if _, ok := npmCache.NsMap[srcNamespace].LabelsMap[key]; ok { diff --git a/npm/pkg/dataplane/debug/trafficanalyzer_test.go b/npm/pkg/dataplane/debug/trafficanalyzer_test.go index 9a942afdda..35b97294a5 100644 --- a/npm/pkg/dataplane/debug/trafficanalyzer_test.go +++ b/npm/pkg/dataplane/debug/trafficanalyzer_test.go @@ -233,7 +233,7 @@ func TestGetNetworkTuple(t *testing.T) { _, actualTupleList, err := GetNetworkTupleFile( test.input.src, test.input.dst, - npmCacheWithCustomFormatFile, + npmCacheFile, iptableSaveFile, ) if err != nil { diff --git a/npm/pkg/dataplane/parse/parser_test.go b/npm/pkg/dataplane/parse/parser_test.go index 320a96ef24..bd526ea0a7 100644 --- a/npm/pkg/dataplane/parse/parser_test.go +++ b/npm/pkg/dataplane/parse/parser_test.go @@ -11,7 +11,7 @@ import ( ) func TestParseIptablesObjectFile(t *testing.T) { - _, err := IptablesFile(util.IptablesFilterTable, "../testfiles/iptablesave") + _, err := IptablesFile(util.IptablesFilterTable, "../testdata/iptablesave") if err != nil { t.Fatal(err) } diff --git a/npm/pkg/dataplane/testfiles/iptablesave b/npm/pkg/dataplane/testdata/iptablesave similarity index 100% rename from npm/pkg/dataplane/testfiles/iptablesave rename to npm/pkg/dataplane/testdata/iptablesave diff --git a/npm/pkg/dataplane/testdata/npmcache.json b/npm/pkg/dataplane/testdata/npmcache.json new file mode 100644 index 0000000000..6d167b74a5 --- /dev/null +++ b/npm/pkg/dataplane/testdata/npmcache.json @@ -0,0 +1,656 @@ +{ + "NodeName":"aks-nodepool1-25107630-vmss000001", + "NsMap": { + "ns-acn": { + "LabelsMap": {} + }, + "ns-dangerous": { + "LabelsMap": {} + }, + "ns-default": { + "LabelsMap": {} + }, + "ns-kube-node-lease": { + "LabelsMap": { + "all": "namespaces" + } + }, + "ns-kube-public": { + "LabelsMap": { + "all": "namespaces" + } + }, + "ns-kube-system": { + "LabelsMap": { + "addonmanager.kubernetes.io/mode": "Reconcile", + "all": "namespaces", + "control-plane": "true", + "kubernetes.io/cluster-service": "true", + "networking/namespace": "kube-system" + } + }, + "ns-monitoring": { + "LabelsMap": {} + }, + "ns-netpol-4537-x": { + "LabelsMap": {} + }, + "ns-test": { + "LabelsMap": {} + }, + "ns-project": { + "LabelsMap": { + "project": "myproject" + } + }, + "ns-testnamespace": { + "LabelsMap": {} + }, + "ns-unsafe": { + "LabelsMap": {} + }, + "ns-x": { + "LabelsMap": { + "ns": "x" + } + }, + "ns-y": { + "LabelsMap": { + "ns": "y" + } + }, + "ns-z": { + "LabelsMap": { + "ns": "z" + } + } + }, + "PodMap": { + "default/ubuntu-proxy-6zg9f": { + "Name": "ubuntu-proxy-6zg9f", + "Namespace": "default", + "PodIP": "10.240.0.17", + "Labels": { + "app.kubernetes.io/tier": "metrics", + "tier": "frontend" + }, + "ContainerPorts": [], + "Phase": "Running" + }, + "default/ubuntu-proxy-vwtx8": { + "Name": "ubuntu-proxy-vwtx8", + "Namespace": "default", + "PodIP": "10.240.0.68", + "Labels": { + "app.kubernetes.io/tier": "metrics", + "tier": "frontend" + }, + "ContainerPorts": [], + "Phase": "Running" + }, + "default/db": { + "Name": "ubuntu-proxy-vwtx8", + "Namespace": "default", + "PodIP": "10.240.0.69", + "Labels": { + "role": "db" + }, + "ContainerPorts": [], + "Phase": "Running" + }, + "kube-system/coredns-77b8db5487-r6ctd": { + "Name": "coredns-77b8db5487-r6ctd", + "Namespace": "kube-system", + "PodIP": "10.240.0.82", + "Labels": { + "k8s-app": "kube-dns", + "kubernetes.io/cluster-service": "true", + "pod-template-hash": "77b8db5487", + "version": "v20" + }, + "ContainerPorts": [ + { + "name": "dns", + "containerPort": 53, + "protocol": "UDP" + }, + { + "name": "dns-tcp", + "containerPort": 53, + "protocol": "TCP" + }, + { + "name": "metrics", + "containerPort": 9153, + "protocol": "TCP" + } + ], + "Phase": "Running" + }, + "kube-system/coredns-77b8db5487-tfxk4": { + "Name": "coredns-77b8db5487-tfxk4", + "Namespace": "kube-system", + "PodIP": "10.240.0.14", + "Labels": { + "k8s-app": "kube-dns", + "kubernetes.io/cluster-service": "true", + "pod-template-hash": "77b8db5487", + "version": "v20" + }, + "ContainerPorts": [ + { + "name": "dns", + "containerPort": 53, + "protocol": "UDP" + }, + { + "name": "dns-tcp", + "containerPort": 53, + "protocol": "TCP" + }, + { + "name": "metrics", + "containerPort": 9153, + "protocol": "TCP" + } + ], + "Phase": "Running" + }, + "kube-system/coredns-autoscaler-cb5bc68df-xjbhc": { + "Name": "coredns-autoscaler-cb5bc68df-xjbhc", + "Namespace": "kube-system", + "PodIP": "10.240.0.10", + "Labels": { + "k8s-app": "coredns-autoscaler", + "pod-template-hash": "cb5bc68df" + }, + "ContainerPorts": [], + "Phase": "Running" + }, + "kube-system/metrics-server-58fdc875d5-rv42s": { + "Name": "metrics-server-58fdc875d5-rv42s", + "Namespace": "kube-system", + "PodIP": "10.240.0.15", + "Labels": { + "k8s-app": "metrics-server", + "pod-template-hash": "58fdc875d5" + }, + "ContainerPorts": [], + "Phase": "Running" + }, + "kube-system/omsagent-4c47t": { + "Name": "omsagent-4c47t", + "Namespace": "kube-system", + "PodIP": "10.240.0.85", + "Labels": { + "component": "oms-agent", + "controller-revision-hash": "799857d4bc", + "kubernetes.azure.com/managedby": "aks", + "pod-template-generation": "7", + "tier": "node" + }, + "ContainerPorts": [ + { + "containerPort": 25225, + "protocol": "TCP" + }, + { + "containerPort": 25224, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "kube-system/omsagent-r9bmf": { + "Name": "omsagent-r9bmf", + "Namespace": "kube-system", + "PodIP": "10.240.0.25", + "Labels": { + "component": "oms-agent", + "controller-revision-hash": "799857d4bc", + "kubernetes.azure.com/managedby": "aks", + "pod-template-generation": "7", + "tier": "node" + }, + "ContainerPorts": [ + { + "containerPort": 25225, + "protocol": "TCP" + }, + { + "containerPort": 25224, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "kube-system/omsagent-rs-6f8864d65f-8pc8b": { + "Name": "omsagent-rs-6f8864d65f-8pc8b", + "Namespace": "kube-system", + "PodIP": "10.240.0.60", + "Labels": { + "kubernetes.azure.com/managedby": "aks", + "pod-template-hash": "6f8864d65f", + "rsName": "omsagent-rs" + }, + "ContainerPorts": [ + { + "containerPort": 25225, + "protocol": "TCP" + }, + { + "containerPort": 25224, + "protocol": "UDP" + }, + { + "name": "in-rs-tcp", + "containerPort": 25227, + "protocol": "TCP" + } + ], + "Phase": "Running" + }, + "kube-system/omsagent-zmmd5": { + "Name": "omsagent-zmmd5", + "Namespace": "kube-system", + "PodIP": "10.240.0.58", + "Labels": { + "component": "oms-agent", + "controller-revision-hash": "799857d4bc", + "kubernetes.azure.com/managedby": "aks", + "pod-template-generation": "7", + "tier": "node" + }, + "ContainerPorts": [ + { + "containerPort": 25225, + "protocol": "TCP" + }, + { + "containerPort": 25224, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "monitoring/prometheus-deployment-54686956bd-89m2j": { + "Name": "prometheus-deployment-54686956bd-89m2j", + "Namespace": "monitoring", + "PodIP": "10.240.0.33", + "Labels": { + "app": "prometheus-server", + "pod-template-hash": "54686956bd" + }, + "ContainerPorts": [ + { + "containerPort": 9090, + "protocol": "TCP" + } + ], + "Phase": "Running" + }, + "test/server": { + "Name": "server", + "Namespace": "test", + "PodIP": "10.240.0.38", + "Labels": { + "app": "server" + }, + "ContainerPorts": [ + { + "name": "serve-80", + "containerPort": 80, + "protocol": "TCP" + } + ], + "Phase": "Running" + }, + "x/a": { + "Name": "a", + "Namespace": "x", + "PodIP": "10.240.0.38", + "Labels": { + "pod": "a" + }, + "ContainerPorts": [ + { + "name": "serve-80", + "containerPort": 80, + "protocol": "UDP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "x/b": { + "Name": "b", + "Namespace": "x", + "PodIP": "10.240.0.59", + "Labels": { + "pod": "b" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "x/c": { + "Name": "c", + "Namespace": "x", + "PodIP": "10.240.0.46", + "Labels": { + "pod": "c" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "testnamespace/a": { + "Name": "a", + "Namespace": "testnamespace", + "PodIP": "10.240.0.12", + "Labels": { + "pod": "a", + "app": "frontend" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "y/b": { + "Name": "b", + "Namespace": "y", + "PodIP": "10.240.0.42", + "Labels": { + "pod": "b" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "y/c": { + "Name": "c", + "Namespace": "y", + "PodIP": "10.240.0.84", + "Labels": { + "pod": "c" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "netpol-4537-x/a": { + "Name": "a", + "Namespace": "netpol-4537-x", + "PodIP": "10.240.0.13", + "Labels": { + "pod": "a" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "z/b": { + "Name": "b", + "Namespace": "z", + "PodIP": "10.240.0.70", + "Labels": { + "pod": "b", + "app": "int" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "z/c": { + "Name": "c", + "Namespace": "z", + "PodIP": "10.240.0.37", + "Labels": { + "pod": "c" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "myproject/frontend1": { + "Name": "frontend1", + "Namespace": "project", + "PodIP": "172.17.0.0", + "Labels": { + "project": "myproject" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + }, + "myproject/frontend2": { + "Name": "frontend", + "Namespace": "project", + "PodIP": "172.17.1.0", + "Labels": { + "project": "myproject" + }, + "ContainerPorts": [ + { + "name": "serve-80-tcp", + "containerPort": 80, + "protocol": "TCP" + }, + { + "name": "serve-80-udp", + "containerPort": 80, + "protocol": "UDP" + } + ], + "Phase": "Running" + } + }, + "ListMap": { + "all-namespaces": {}, + "app:test:int": {}, + "k1:v0:v1": {}, + "ns-addonmanager.kubernetes.io/mode": {}, + "ns-addonmanager.kubernetes.io/mode:Reconcile": {}, + "ns-all": {}, + "ns-all:namespaces": {}, + "ns-control-plane": {}, + "ns-control-plane:true": {}, + "ns-kubernetes.io/cluster-service": {}, + "ns-kubernetes.io/cluster-service:true": {}, + "ns-namespace:dev": {}, + "ns-namespace:test0": {}, + "ns-namespace:test1": {}, + "ns-networking/namespace": {}, + "ns-networking/namespace:kube-system": {}, + "ns-ns": {}, + "ns-ns:dev": {}, + "ns-ns:netpol-4537-x": {}, + "ns-ns:netpol-4537-y": {}, + "ns-ns:x": {}, + "ns-ns:y": {}, + "ns-ns:z": {}, + "ns-project:myproject": {}, + "pod:a:x": {}, + "pod:b:c": {} + }, + "SetMap": { + "allow-backend-to-frontend-on-port-53-policy-in-ns-testnamespace-1out": {}, + "allow-backend-to-frontend-on-port-8000-policy-in-ns-testnamespace-0in": {}, + "allow-multiple-labels-to-multiple-labels-in-ns-acn-0in": {}, + "allow-ns-dev-to-app-frontend-in-ns-testnamespace-0in": {}, + "allow-ns-y-z-pod-b-c-in-ns-netpol-4537-x-0in": {}, + "app": {}, + "app.kubernetes.io/tier": {}, + "app.kubernetes.io/tier:metrics": {}, + "app:backdoor": {}, + "app:backend": {}, + "app:frontend": {}, + "app:int": {}, + "app:k8s": {}, + "app:konnectivity-agent": {}, + "app:prometheus-server": {}, + "app:server": {}, + "app:test": {}, + "binary:cns": {}, + "component": {}, + "component:oms-agent": {}, + "controller-revision-hash": {}, + "controller-revision-hash:799857d4bc": {}, + "deny-all-policy-in-ns-testnamespace-0in": {}, + "group:container": {}, + "k0": {}, + "k1:v0": {}, + "k1:v1": {}, + "k8s-app": {}, + "k8s-app:coredns-autoscaler": {}, + "k8s-app:kube-dns": {}, + "k8s-app:metrics-server": {}, + "k8s-example-policy-in-ns-default-0in": {}, + "k8s-example-policy-in-ns-default-0out": {}, + "kube-system": {}, + "kubernetes.azure.com/managedby": {}, + "kubernetes.azure.com/managedby:aks": {}, + "kubernetes.io/cluster-service": {}, + "kubernetes.io/cluster-service:true": {}, + "namedport:dns": {}, + "namedport:dns-tcp": {}, + "namedport:in-rs-tcp": {}, + "namedport:metrics": {}, + "namedport:serve-80": {}, + "namedport:serve-80-tcp": {}, + "namedport:serve-80-udp": {}, + "ns-acn": {}, + "ns-dangerous": {}, + "ns-default": {}, + "ns-kube-node-lease": {}, + "ns-kube-public": {}, + "ns-kube-system": {}, + "ns-monitoring": {}, + "ns-netpol-4537-x": {}, + "ns-test": {}, + "ns-testnamespace": {}, + "ns-unsafe": {}, + "ns-x": {}, + "ns-y": {}, + "ns-z": {}, + "pod": {}, + "pod-template-generation": {}, + "pod-template-generation:7": {}, + "pod-template-hash": {}, + "pod-template-hash:54686956bd": {}, + "pod-template-hash:58fdc875d5": {}, + "pod-template-hash:6f8864d65f": {}, + "pod-template-hash:77b8db5487": {}, + "pod-template-hash:cb5bc68df": {}, + "pod:a": {}, + "pod:b": {}, + "pod:c": {}, + "pod:x": {}, + "program:cni": {}, + "role:db": {}, + "role:frontend": {}, + "rsName": {}, + "rsName:omsagent-rs": {}, + "team:acn": {}, + "team:aks": {}, + "tier": {}, + "tier:frontend": {}, + "tier:node": {}, + "version": {}, + "version:v20": {} + } +} \ No newline at end of file diff --git a/npm/pkg/dataplane/testfiles/npmcache.json b/npm/pkg/dataplane/testdata/npmgr.json similarity index 100% rename from npm/pkg/dataplane/testfiles/npmcache.json rename to npm/pkg/dataplane/testdata/npmgr.json diff --git a/npm/pkg/dataplane/testfiles/npmCacheWithCustomFormat.json b/npm/pkg/dataplane/testfiles/npmCacheWithCustomFormat.json deleted file mode 100644 index 238b533403..0000000000 --- a/npm/pkg/dataplane/testfiles/npmCacheWithCustomFormat.json +++ /dev/null @@ -1,654 +0,0 @@ -"aks-nodepool1-25107630-vmss000001" -{ - "ns-acn": { - "LabelsMap": {} - }, - "ns-dangerous": { - "LabelsMap": {} - }, - "ns-default": { - "LabelsMap": {} - }, - "ns-kube-node-lease": { - "LabelsMap": { - "all": "namespaces" - } - }, - "ns-kube-public": { - "LabelsMap": { - "all": "namespaces" - } - }, - "ns-kube-system": { - "LabelsMap": { - "addonmanager.kubernetes.io/mode": "Reconcile", - "all": "namespaces", - "control-plane": "true", - "kubernetes.io/cluster-service": "true", - "networking/namespace": "kube-system" - } - }, - "ns-monitoring": { - "LabelsMap": {} - }, - "ns-netpol-4537-x": { - "LabelsMap": {} - }, - "ns-test": { - "LabelsMap": {} - }, - "ns-project": { - "LabelsMap": { - "project": "myproject" - } - }, - "ns-testnamespace": { - "LabelsMap": {} - }, - "ns-unsafe": { - "LabelsMap": {} - }, - "ns-x": { - "LabelsMap": { - "ns": "x" - } - }, - "ns-y": { - "LabelsMap": { - "ns": "y" - } - }, - "ns-z": { - "LabelsMap": { - "ns": "z" - } - } -} -{ - "default/ubuntu-proxy-6zg9f": { - "Name": "ubuntu-proxy-6zg9f", - "Namespace": "default", - "PodIP": "10.240.0.17", - "Labels": { - "app.kubernetes.io/tier": "metrics", - "tier": "frontend" - }, - "ContainerPorts": [], - "Phase": "Running" - }, - "default/ubuntu-proxy-vwtx8": { - "Name": "ubuntu-proxy-vwtx8", - "Namespace": "default", - "PodIP": "10.240.0.68", - "Labels": { - "app.kubernetes.io/tier": "metrics", - "tier": "frontend" - }, - "ContainerPorts": [], - "Phase": "Running" - }, - "default/db": { - "Name": "ubuntu-proxy-vwtx8", - "Namespace": "default", - "PodIP": "10.240.0.69", - "Labels": { - "role": "db" - }, - "ContainerPorts": [], - "Phase": "Running" - }, - "kube-system/coredns-77b8db5487-r6ctd": { - "Name": "coredns-77b8db5487-r6ctd", - "Namespace": "kube-system", - "PodIP": "10.240.0.82", - "Labels": { - "k8s-app": "kube-dns", - "kubernetes.io/cluster-service": "true", - "pod-template-hash": "77b8db5487", - "version": "v20" - }, - "ContainerPorts": [ - { - "name": "dns", - "containerPort": 53, - "protocol": "UDP" - }, - { - "name": "dns-tcp", - "containerPort": 53, - "protocol": "TCP" - }, - { - "name": "metrics", - "containerPort": 9153, - "protocol": "TCP" - } - ], - "Phase": "Running" - }, - "kube-system/coredns-77b8db5487-tfxk4": { - "Name": "coredns-77b8db5487-tfxk4", - "Namespace": "kube-system", - "PodIP": "10.240.0.14", - "Labels": { - "k8s-app": "kube-dns", - "kubernetes.io/cluster-service": "true", - "pod-template-hash": "77b8db5487", - "version": "v20" - }, - "ContainerPorts": [ - { - "name": "dns", - "containerPort": 53, - "protocol": "UDP" - }, - { - "name": "dns-tcp", - "containerPort": 53, - "protocol": "TCP" - }, - { - "name": "metrics", - "containerPort": 9153, - "protocol": "TCP" - } - ], - "Phase": "Running" - }, - "kube-system/coredns-autoscaler-cb5bc68df-xjbhc": { - "Name": "coredns-autoscaler-cb5bc68df-xjbhc", - "Namespace": "kube-system", - "PodIP": "10.240.0.10", - "Labels": { - "k8s-app": "coredns-autoscaler", - "pod-template-hash": "cb5bc68df" - }, - "ContainerPorts": [], - "Phase": "Running" - }, - "kube-system/metrics-server-58fdc875d5-rv42s": { - "Name": "metrics-server-58fdc875d5-rv42s", - "Namespace": "kube-system", - "PodIP": "10.240.0.15", - "Labels": { - "k8s-app": "metrics-server", - "pod-template-hash": "58fdc875d5" - }, - "ContainerPorts": [], - "Phase": "Running" - }, - "kube-system/omsagent-4c47t": { - "Name": "omsagent-4c47t", - "Namespace": "kube-system", - "PodIP": "10.240.0.85", - "Labels": { - "component": "oms-agent", - "controller-revision-hash": "799857d4bc", - "kubernetes.azure.com/managedby": "aks", - "pod-template-generation": "7", - "tier": "node" - }, - "ContainerPorts": [ - { - "containerPort": 25225, - "protocol": "TCP" - }, - { - "containerPort": 25224, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "kube-system/omsagent-r9bmf": { - "Name": "omsagent-r9bmf", - "Namespace": "kube-system", - "PodIP": "10.240.0.25", - "Labels": { - "component": "oms-agent", - "controller-revision-hash": "799857d4bc", - "kubernetes.azure.com/managedby": "aks", - "pod-template-generation": "7", - "tier": "node" - }, - "ContainerPorts": [ - { - "containerPort": 25225, - "protocol": "TCP" - }, - { - "containerPort": 25224, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "kube-system/omsagent-rs-6f8864d65f-8pc8b": { - "Name": "omsagent-rs-6f8864d65f-8pc8b", - "Namespace": "kube-system", - "PodIP": "10.240.0.60", - "Labels": { - "kubernetes.azure.com/managedby": "aks", - "pod-template-hash": "6f8864d65f", - "rsName": "omsagent-rs" - }, - "ContainerPorts": [ - { - "containerPort": 25225, - "protocol": "TCP" - }, - { - "containerPort": 25224, - "protocol": "UDP" - }, - { - "name": "in-rs-tcp", - "containerPort": 25227, - "protocol": "TCP" - } - ], - "Phase": "Running" - }, - "kube-system/omsagent-zmmd5": { - "Name": "omsagent-zmmd5", - "Namespace": "kube-system", - "PodIP": "10.240.0.58", - "Labels": { - "component": "oms-agent", - "controller-revision-hash": "799857d4bc", - "kubernetes.azure.com/managedby": "aks", - "pod-template-generation": "7", - "tier": "node" - }, - "ContainerPorts": [ - { - "containerPort": 25225, - "protocol": "TCP" - }, - { - "containerPort": 25224, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "monitoring/prometheus-deployment-54686956bd-89m2j": { - "Name": "prometheus-deployment-54686956bd-89m2j", - "Namespace": "monitoring", - "PodIP": "10.240.0.33", - "Labels": { - "app": "prometheus-server", - "pod-template-hash": "54686956bd" - }, - "ContainerPorts": [ - { - "containerPort": 9090, - "protocol": "TCP" - } - ], - "Phase": "Running" - }, - "test/server": { - "Name": "server", - "Namespace": "test", - "PodIP": "10.240.0.38", - "Labels": { - "app": "server" - }, - "ContainerPorts": [ - { - "name": "serve-80", - "containerPort": 80, - "protocol": "TCP" - } - ], - "Phase": "Running" - }, - "x/a": { - "Name": "a", - "Namespace": "x", - "PodIP": "10.240.0.38", - "Labels": { - "pod": "a" - }, - "ContainerPorts": [ - { - "name": "serve-80", - "containerPort": 80, - "protocol": "UDP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "x/b": { - "Name": "b", - "Namespace": "x", - "PodIP": "10.240.0.59", - "Labels": { - "pod": "b" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "x/c": { - "Name": "c", - "Namespace": "x", - "PodIP": "10.240.0.46", - "Labels": { - "pod": "c" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "testnamespace/a": { - "Name": "a", - "Namespace": "testnamespace", - "PodIP": "10.240.0.12", - "Labels": { - "pod": "a", - "app": "frontend" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "y/b": { - "Name": "b", - "Namespace": "y", - "PodIP": "10.240.0.42", - "Labels": { - "pod": "b" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "y/c": { - "Name": "c", - "Namespace": "y", - "PodIP": "10.240.0.84", - "Labels": { - "pod": "c" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "netpol-4537-x/a": { - "Name": "a", - "Namespace": "netpol-4537-x", - "PodIP": "10.240.0.13", - "Labels": { - "pod": "a" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "z/b": { - "Name": "b", - "Namespace": "z", - "PodIP": "10.240.0.70", - "Labels": { - "pod": "b", - "app": "int" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "z/c": { - "Name": "c", - "Namespace": "z", - "PodIP": "10.240.0.37", - "Labels": { - "pod": "c" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "myproject/frontend1": { - "Name": "frontend1", - "Namespace": "project", - "PodIP": "172.17.0.0", - "Labels": { - "project": "myproject" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - }, - "myproject/frontend2": { - "Name": "frontend", - "Namespace": "project", - "PodIP": "172.17.1.0", - "Labels": { - "project": "myproject" - }, - "ContainerPorts": [ - { - "name": "serve-80-tcp", - "containerPort": 80, - "protocol": "TCP" - }, - { - "name": "serve-80-udp", - "containerPort": 80, - "protocol": "UDP" - } - ], - "Phase": "Running" - } -} -{ - "all-namespaces": {}, - "app:test:int": {}, - "k1:v0:v1": {}, - "ns-addonmanager.kubernetes.io/mode": {}, - "ns-addonmanager.kubernetes.io/mode:Reconcile": {}, - "ns-all": {}, - "ns-all:namespaces": {}, - "ns-control-plane": {}, - "ns-control-plane:true": {}, - "ns-kubernetes.io/cluster-service": {}, - "ns-kubernetes.io/cluster-service:true": {}, - "ns-namespace:dev": {}, - "ns-namespace:test0": {}, - "ns-namespace:test1": {}, - "ns-networking/namespace": {}, - "ns-networking/namespace:kube-system": {}, - "ns-ns": {}, - "ns-ns:dev": {}, - "ns-ns:netpol-4537-x": {}, - "ns-ns:netpol-4537-y": {}, - "ns-ns:x": {}, - "ns-ns:y": {}, - "ns-ns:z": {}, - "ns-project:myproject": {}, - "pod:a:x": {}, - "pod:b:c": {} -} -{ - "allow-backend-to-frontend-on-port-53-policy-in-ns-testnamespace-1out": {}, - "allow-backend-to-frontend-on-port-8000-policy-in-ns-testnamespace-0in": {}, - "allow-multiple-labels-to-multiple-labels-in-ns-acn-0in": {}, - "allow-ns-dev-to-app-frontend-in-ns-testnamespace-0in": {}, - "allow-ns-y-z-pod-b-c-in-ns-netpol-4537-x-0in": {}, - "app": {}, - "app.kubernetes.io/tier": {}, - "app.kubernetes.io/tier:metrics": {}, - "app:backdoor": {}, - "app:backend": {}, - "app:frontend": {}, - "app:int": {}, - "app:k8s": {}, - "app:konnectivity-agent": {}, - "app:prometheus-server": {}, - "app:server": {}, - "app:test": {}, - "binary:cns": {}, - "component": {}, - "component:oms-agent": {}, - "controller-revision-hash": {}, - "controller-revision-hash:799857d4bc": {}, - "deny-all-policy-in-ns-testnamespace-0in": {}, - "group:container": {}, - "k0": {}, - "k1:v0": {}, - "k1:v1": {}, - "k8s-app": {}, - "k8s-app:coredns-autoscaler": {}, - "k8s-app:kube-dns": {}, - "k8s-app:metrics-server": {}, - "k8s-example-policy-in-ns-default-0in": {}, - "k8s-example-policy-in-ns-default-0out": {}, - "kube-system": {}, - "kubernetes.azure.com/managedby": {}, - "kubernetes.azure.com/managedby:aks": {}, - "kubernetes.io/cluster-service": {}, - "kubernetes.io/cluster-service:true": {}, - "namedport:dns": {}, - "namedport:dns-tcp": {}, - "namedport:in-rs-tcp": {}, - "namedport:metrics": {}, - "namedport:serve-80": {}, - "namedport:serve-80-tcp": {}, - "namedport:serve-80-udp": {}, - "ns-acn": {}, - "ns-dangerous": {}, - "ns-default": {}, - "ns-kube-node-lease": {}, - "ns-kube-public": {}, - "ns-kube-system": {}, - "ns-monitoring": {}, - "ns-netpol-4537-x": {}, - "ns-test": {}, - "ns-testnamespace": {}, - "ns-unsafe": {}, - "ns-x": {}, - "ns-y": {}, - "ns-z": {}, - "pod": {}, - "pod-template-generation": {}, - "pod-template-generation:7": {}, - "pod-template-hash": {}, - "pod-template-hash:54686956bd": {}, - "pod-template-hash:58fdc875d5": {}, - "pod-template-hash:6f8864d65f": {}, - "pod-template-hash:77b8db5487": {}, - "pod-template-hash:cb5bc68df": {}, - "pod:a": {}, - "pod:b": {}, - "pod:c": {}, - "pod:x": {}, - "program:cni": {}, - "role:db": {}, - "role:frontend": {}, - "rsName": {}, - "rsName:omsagent-rs": {}, - "team:acn": {}, - "team:aks": {}, - "tier": {}, - "tier:frontend": {}, - "tier:node": {}, - "version": {}, - "version:v20": {} -} \ No newline at end of file diff --git a/npm/podController.go b/npm/podController.go index 958bdb0dad..8e7f30f64c 100644 --- a/npm/podController.go +++ b/npm/podController.go @@ -13,8 +13,9 @@ import ( "github.com/Azure/azure-container-networking/npm/metrics" "github.com/Azure/azure-container-networking/npm/util" + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" coreinformer "k8s.io/client-go/informers/core/v1" @@ -109,15 +110,16 @@ func NewPodController(podInformer coreinformer.PodInformer, ipsMgr *ipsm.IpsetMa return podController } -func (c *podController) Encode(enc *json.Encoder) error { +func (c *podController) MarshalJSON() ([]byte, error) { c.Lock() defer c.Unlock() - if err := enc.Encode(c.podMap); err != nil { - return fmt.Errorf("failed to encode podMap %w", err) + podMapRaw, err := json.Marshal(c.podMap) + if err != nil { + return nil, errors.Errorf("failed to marshal podMap due to %v", err) } - return nil + return podMapRaw, nil } func (c *podController) lengthOfPodMap() int { @@ -307,7 +309,7 @@ func (c *podController) syncPod(key string) error { defer c.Unlock() if err != nil { - if errors.IsNotFound(err) { + if apierrors.IsNotFound(err) { klog.Infof("pod %s not found, may be it is deleted", key) // cleanUpDeletedPod will check if the pod exists in cache, if it does then proceeds with deletion // if it does not exists, then event will be no-op diff --git a/npm/podController_test.go b/npm/podController_test.go index d4107290fa..f7f59f166a 100644 --- a/npm/podController_test.go +++ b/npm/podController_test.go @@ -11,8 +11,10 @@ import ( "github.com/Azure/azure-container-networking/npm/ipsm" "github.com/Azure/azure-container-networking/npm/util" testutils "github.com/Azure/azure-container-networking/test/utils" + "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" utilexec "k8s.io/utils/exec" + fakeexec "k8s.io/utils/exec/testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -635,6 +637,31 @@ func TestPodStatusUpdatePod(t *testing.T) { } } +func TestPodMapMarshalJSON(t *testing.T) { + fexec := &fakeexec.FakeExec{} + f := newFixture(t, fexec) + stopCh := make(chan struct{}) + defer close(stopCh) + f.newPodController(stopCh) + + labels := map[string]string{ + "app": "test-pod", + } + pod := createPod("test-pod", "test-namespace", "0", "1.2.3.4", labels, NonHostNetwork, corev1.PodRunning) + podKey, err := cache.MetaNamespaceKeyFunc(pod) + assert.NoError(t, err) + + npmPod := newNpmPod(pod) + f.podController.podMap[podKey] = npmPod + + npMapRaw, err := f.podController.MarshalJSON() + assert.NoError(t, err) + + expect := []byte(`{"test-namespace/test-pod":{"Name":"test-pod","Namespace":"test-namespace","PodIP":"1.2.3.4","Labels":{},"ContainerPorts":[],"Phase":"Running"}}`) + fmt.Printf("%s\n", string(npMapRaw)) + assert.ElementsMatch(t, expect, npMapRaw) +} + func TestHasValidPodIP(t *testing.T) { podObj := &corev1.Pod{ Status: corev1.PodStatus{