test: [WIN-NPM] dataplane test framework (#1652)

* wip with StrictlyHasSetPolicies approach

* better approaching of getting all set policies

* wip for rigorous win dp UTs

* marshal setpolicies in hns mock and dont short circuit in UTs

* policy stuff and update test cases

* marshal ACLs in hns mock

* more UTs and minor refinements

* option to apply dp or not

* address cmp.Equal and t.Helper comments

* dpEvent returns error and better defined concurrency

* remove unnecessary logic in concurrent test code

* approach #3 emulating cyclonus

* namespace method for podmetadata

* refactor Action structure and TestCase wait group behavior

* hnsactions and renaming a file

* refactor to Serial and ThreadedTestCase structs, and move files to dp pkg

* hns latency hard coded to be the same for all threaded test cases

* fix build error after rebasing

* export fake hns network id

* address comments on multierr and terminology

* add comment about pod metadata in controller

* pod update and delete actions

* move ApplyDPAction to top

* namespace actions and rename some fields of UpdatePod

* adding code comments

* reconcile action

* fix bug in key-val ipsets

* implement all previous test cases

* fix incorrect error wrapping in dataplane.go

* multi-job tests are working. updated terminology from routine to job

* MultiErrManager instead of dependency for multierr

* return to the channel approach for multierr, now using FailNow instead of asserting on channel length

* fix some lints

* fix more lints
This commit is contained in:
Hunter Gregory 2022-10-31 09:20:39 -07:00 коммит произвёл GitHub
Родитель b231f0f2e3
Коммит e3ffab843d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 1272 добавлений и 27 удалений

Просмотреть файл

@ -9,6 +9,8 @@ import (
utilexec "k8s.io/utils/exec"
)
const FakeHNSNetworkID = "1234"
type IOShim struct {
Exec utilexec.Interface
Hns hnswrapper.HnsV2WrapperInterface
@ -24,7 +26,7 @@ func NewIOShim() *IOShim {
func NewMockIOShim(calls []testutils.TestCmd) *IOShim {
hns := hnswrapper.NewHnsv2wrapperFake()
network := &hcn.HostComputeNetwork{
Id: "1234",
Id: FakeHNSNetworkID,
Name: "azure",
}

Просмотреть файл

@ -317,10 +317,13 @@ func (f Hnsv2wrapperFake) GetEndpointByName(endpointName string) (*hcn.HostCompu
}
type FakeHNSCache struct {
networks map[string]*FakeHostComputeNetwork
// networks maps network name to network object
networks map[string]*FakeHostComputeNetwork
// endpoints maps endpoint ID to endpoint object
endpoints map[string]*FakeHostComputeEndpoint
}
// SetPolicy returns the first SetPolicy found with this ID in any network.
func (fCache FakeHNSCache) SetPolicy(setID string) *hcn.SetPolicySetting {
for _, network := range fCache.networks {
for _, policy := range network.Policies {
@ -332,6 +335,35 @@ func (fCache FakeHNSCache) SetPolicy(setID string) *hcn.SetPolicySetting {
return nil
}
func (fCache FakeHNSCache) PrettyString() string {
networkStrings := make([]string, 0, len(fCache.networks))
for _, network := range fCache.networks {
networkStrings = append(networkStrings, fmt.Sprintf("[%+v]", network.PrettyString()))
}
endpointStrings := make([]string, 0, len(fCache.endpoints))
for _, endpoint := range fCache.endpoints {
endpointStrings = append(endpointStrings, fmt.Sprintf("[%+v]", endpoint.PrettyString()))
}
return fmt.Sprintf("networks: %s\nendpoints: %s", strings.Join(networkStrings, ","), strings.Join(endpointStrings, ","))
}
// AllSetPolicies returns all SetPolicies in a given network as a map of SetPolicy ID to SetPolicy object.
func (fCache FakeHNSCache) AllSetPolicies(networkID string) map[string]*hcn.SetPolicySetting {
setPolicies := make(map[string]*hcn.SetPolicySetting)
for _, network := range fCache.networks {
if network.ID == networkID {
for _, setPolicy := range network.Policies {
setPolicies[setPolicy.Id] = setPolicy
}
break
}
}
return setPolicies
}
// ACLPolicies returns a map of the inputed Endpoint IDs to Policies with the given policyID.
func (fCache FakeHNSCache) ACLPolicies(epList map[string]string, policyID string) (map[string][]*FakeEndpointPolicy, error) {
aclPols := make(map[string][]*FakeEndpointPolicy)
for ip, epID := range epList {
@ -354,6 +386,7 @@ func (fCache FakeHNSCache) ACLPolicies(epList map[string]string, policyID string
return aclPols, nil
}
// GetAllACLs maps all Endpoint IDs to ACLs
func (fCache FakeHNSCache) GetAllACLs() map[string][]*FakeEndpointPolicy {
aclPols := make(map[string][]*FakeEndpointPolicy)
for _, ep := range fCache.endpoints {
@ -362,9 +395,20 @@ func (fCache FakeHNSCache) GetAllACLs() map[string][]*FakeEndpointPolicy {
return aclPols
}
// EndpointIP returns the Endpoint's IP or an empty string if the Endpoint doesn't exist.
func (fCache FakeHNSCache) EndpointIP(id string) string {
for _, ep := range fCache.endpoints {
if ep.ID == id {
return ep.IPConfiguration
}
}
return ""
}
type FakeHostComputeNetwork struct {
ID string
Name string
ID string
Name string
// Policies maps SetPolicy ID to SetPolicy object
Policies map[string]*hcn.SetPolicySetting
}
@ -376,10 +420,33 @@ func NewFakeHostComputeNetwork(network *hcn.HostComputeNetwork) *FakeHostCompute
}
}
func (fNetwork *FakeHostComputeNetwork) PrettyString() string {
setPolicyStrings := make([]string, 0, len(fNetwork.Policies))
for _, setPolicy := range fNetwork.Policies {
setPolicyStrings = append(setPolicyStrings, fmt.Sprintf("[%+v]", setPolicy))
}
return fmt.Sprintf("ID: %s, Name: %s, SetPolicies: [%s]", fNetwork.ID, fNetwork.Name, strings.Join(setPolicyStrings, ","))
}
func (fNetwork *FakeHostComputeNetwork) GetHCNObj() *hcn.HostComputeNetwork {
setPolicies := make([]hcn.NetworkPolicy, 0)
for _, setPolicy := range fNetwork.Policies {
rawSettings, err := json.Marshal(setPolicy)
if err != nil {
fmt.Printf("FakeHostComputeNetwork: error marshalling SetPolicy: %+v. err: %s\n", setPolicy, err.Error())
continue
}
policy := hcn.NetworkPolicy{
Type: hcn.SetPolicy,
Settings: rawSettings,
}
setPolicies = append(setPolicies, policy)
}
return &hcn.HostComputeNetwork{
Id: fNetwork.ID,
Name: fNetwork.Name,
Id: fNetwork.ID,
Name: fNetwork.Name,
Policies: setPolicies,
}
}
@ -404,29 +471,41 @@ func NewFakeHostComputeEndpoint(endpoint *hcn.HostComputeEndpoint) *FakeHostComp
}
}
func (fEndpoint *FakeHostComputeEndpoint) PrettyString() string {
aclStrings := make([]string, 0, len(fEndpoint.Policies))
for _, acl := range fEndpoint.Policies {
aclStrings = append(aclStrings, fmt.Sprintf("[%+v]", acl))
}
return fmt.Sprintf("ID: %s, Name: %s, IP: %s, ACLs: [%s]",
fEndpoint.ID, fEndpoint.Name, fEndpoint.IPConfiguration, strings.Join(aclStrings, ","))
}
func (fEndpoint *FakeHostComputeEndpoint) GetHCNObj() *hcn.HostComputeEndpoint {
// NOTE: not including other policy types like perhaps SetPolicies
hcnEndpoint := &hcn.HostComputeEndpoint{
acls := make([]hcn.EndpointPolicy, 0)
for _, acl := range fEndpoint.Policies {
rawSettings, err := json.Marshal(acl)
if err != nil {
fmt.Printf("FakeHostComputeEndpoint: error marshalling ACL: %+v. err: %s\n", acl, err.Error())
continue
}
policy := hcn.EndpointPolicy{
Type: hcn.ACL,
Settings: rawSettings,
}
acls = append(acls, policy)
}
return &hcn.HostComputeEndpoint{
Id: fEndpoint.ID,
Name: fEndpoint.Name,
HostComputeNetwork: fEndpoint.HostComputeNetwork,
Policies: make([]hcn.EndpointPolicy, 0),
IpConfigurations: []hcn.IpConfig{
{
IpAddress: fEndpoint.IPConfiguration,
},
},
Policies: acls,
}
for _, fakeEndpointPol := range fEndpoint.Policies {
rawJSON, err := json.Marshal(fakeEndpointPol)
if err != nil {
fmt.Printf("FAILURE marshalling fake endpoint policy: %s\n", err.Error())
} else {
hcnPolicy := hcn.EndpointPolicy{
Type: hcn.ACL,
Settings: rawJSON,
}
hcnEndpoint.Policies = append(hcnEndpoint.Policies, hcnPolicy)
}
}
return hcnEndpoint
}
func (fEndpoint *FakeHostComputeEndpoint) RemovePolicy(toRemovePol *FakeEndpointPolicy) error {

Просмотреть файл

@ -573,6 +573,8 @@ func (c *PodController) cleanUpDeletedPod(cachedNpmPodKey string) error {
func (c *PodController) manageNamedPortIpsets(portList []corev1.ContainerPort, podKey,
podIP, nodeName string, namedPortOperation NamedPortOperation) error {
if util.IsWindowsDP() {
// NOTE: if we support namedport operations, need to be careful of implications of including the node name in the pod metadata below
// since we say the node name is "" in cleanUpDeletedPod
klog.Warningf("Windows Dataplane does not support NamedPort operations. Operation: %s portList is %+v", namedPortOperation, portList)
return nil
}

Просмотреть файл

@ -0,0 +1,448 @@
package dataplane
import (
"github.com/Azure/azure-container-networking/network/hnswrapper"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/policies"
dptestutils "github.com/Azure/azure-container-networking/npm/pkg/dataplane/testutils"
"github.com/Microsoft/hcsshim/hcn"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// tags
const (
podCrudTag Tag = "pod-crud"
nsCrudTag Tag = "namespace-crud"
netpolCrudTag Tag = "netpol-crud"
)
const (
thisNode = "this-node"
otherNode = "other-node"
ip1 = "10.0.0.1"
ip2 = "10.0.0.2"
endpoint1 = "test1"
endpoint2 = "test2"
)
// IPSet constants
var (
podK1Set = ipsets.NewIPSetMetadata("k1", ipsets.KeyLabelOfPod)
podK1V1Set = ipsets.NewIPSetMetadata("k1:v1", ipsets.KeyValueLabelOfPod)
podK2Set = ipsets.NewIPSetMetadata("k2", ipsets.KeyLabelOfPod)
podK2V2Set = ipsets.NewIPSetMetadata("k2:v2", ipsets.KeyValueLabelOfPod)
// emptySet is a member of a list if enabled in the dp Config
// in Windows, this Config option is actually forced to be enabled in NewDataPlane()
emptySet = ipsets.NewIPSetMetadata("emptyhashset", ipsets.EmptyHashSet)
allNamespaces = ipsets.NewIPSetMetadata("all-namespaces", ipsets.KeyLabelOfNamespace)
nsXSet = ipsets.NewIPSetMetadata("x", ipsets.Namespace)
nsYSet = ipsets.NewIPSetMetadata("y", ipsets.Namespace)
nsK1Set = ipsets.NewIPSetMetadata("k1", ipsets.KeyLabelOfNamespace)
nsK1V1Set = ipsets.NewIPSetMetadata("k1:v1", ipsets.KeyValueLabelOfNamespace)
nsK2Set = ipsets.NewIPSetMetadata("k2", ipsets.KeyLabelOfNamespace)
nsK2V2Set = ipsets.NewIPSetMetadata("k2:v2", ipsets.KeyValueLabelOfNamespace)
)
// DP Configs
var (
defaultWindowsDPCfg = &Config{
IPSetManagerCfg: &ipsets.IPSetManagerCfg{
IPSetMode: ipsets.ApplyAllIPSets,
AddEmptySetToLists: true,
},
PolicyManagerCfg: &policies.PolicyManagerCfg{
PolicyMode: policies.IPSetPolicyMode,
},
}
)
func policyXBaseOnK1V1() *networkingv1.NetworkPolicy {
return &networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "base",
Namespace: "x",
},
Spec: networkingv1.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{
"k1": "v1",
},
},
Ingress: []networkingv1.NetworkPolicyIngressRule{
{},
},
Egress: []networkingv1.NetworkPolicyEgressRule{
{},
},
PolicyTypes: []networkingv1.PolicyType{
networkingv1.PolicyTypeIngress,
networkingv1.PolicyTypeEgress,
},
},
}
}
func getAllSerialTests() []*SerialTestCase {
return []*SerialTestCase{
{
Description: "pod created",
Actions: []*Action{
CreateEndpoint(endpoint1, ip1),
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
ApplyDP(),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet, ip1),
dptestutils.SetPolicy(podK1Set, ip1),
dptestutils.SetPolicy(podK1V1Set, ip1),
},
ExpectedEnpdointACLs: map[string][]*hnswrapper.FakeEndpointPolicy{
endpoint1: {},
},
},
},
{
Description: "pod created, then pod deleted",
Actions: []*Action{
CreateEndpoint(endpoint1, ip1),
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
ApplyDP(),
DeleteEndpoint(endpoint1),
DeletePod("x", "a", ip1, map[string]string{"k1": "v1"}),
ApplyDP(),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet),
dptestutils.SetPolicy(podK1Set),
dptestutils.SetPolicy(podK1V1Set),
},
ExpectedEnpdointACLs: nil,
},
},
{
Description: "pod created, then pod deleted, then ipsets garbage collected",
Actions: []*Action{
CreateEndpoint(endpoint1, ip1),
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
ApplyDP(),
DeleteEndpoint(endpoint1),
DeletePod("x", "a", ip1, map[string]string{"k1": "v1"}),
ApplyDP(),
ReconcileDP(),
ApplyDP(),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet),
},
ExpectedEnpdointACLs: nil,
},
},
{
Description: "policy created with no pods",
Actions: []*Action{
UpdatePolicy(policyXBaseOnK1V1()),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
netpolCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
// will not be an all-namespaces IPSet unless there's a Pod/Namespace event
dptestutils.SetPolicy(nsXSet),
// Policies do not create the KeyLabelOfPod type IPSet if the selector has a key-value requirement
dptestutils.SetPolicy(podK1V1Set),
},
},
},
{
Description: "pod created on node, then relevant policy created",
Actions: []*Action{
CreateEndpoint(endpoint1, ip1),
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
// will apply dirty ipsets from CreatePod
UpdatePolicy(policyXBaseOnK1V1()),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
netpolCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet, ip1),
dptestutils.SetPolicy(podK1Set, ip1),
dptestutils.SetPolicy(podK1V1Set, ip1),
},
ExpectedEnpdointACLs: map[string][]*hnswrapper.FakeEndpointPolicy{
endpoint1: {
{
ID: "azure-acl-x-base",
Protocols: "",
Action: "Allow",
Direction: "In",
LocalAddresses: "",
RemoteAddresses: "",
LocalPorts: "",
RemotePorts: "",
Priority: 222,
},
{
ID: "azure-acl-x-base",
Protocols: "",
Action: "Allow",
Direction: "Out",
LocalAddresses: "",
RemoteAddresses: "",
LocalPorts: "",
RemotePorts: "",
Priority: 222,
},
},
},
},
},
{
Description: "pod created on node, then relevant policy created, then policy deleted",
Actions: []*Action{
CreateEndpoint(endpoint1, ip1),
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
// will apply dirty ipsets from CreatePod
UpdatePolicy(policyXBaseOnK1V1()),
DeletePolicyByObject(policyXBaseOnK1V1()),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
netpolCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet, ip1),
dptestutils.SetPolicy(podK1Set, ip1),
dptestutils.SetPolicy(podK1V1Set, ip1),
},
ExpectedEnpdointACLs: map[string][]*hnswrapper.FakeEndpointPolicy{
endpoint1: {},
},
},
},
{
Description: "pod created off node (no local endpoint), then relevant policy created",
Actions: []*Action{
CreatePod("x", "a", ip1, otherNode, map[string]string{"k1": "v1"}),
// will apply dirty ipsets from CreatePod
UpdatePolicy(policyXBaseOnK1V1()),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
netpolCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet, ip1),
dptestutils.SetPolicy(podK1Set, ip1),
dptestutils.SetPolicy(podK1V1Set, ip1),
},
ExpectedEnpdointACLs: nil,
},
},
{
Description: "policy created, then pod created which satisfies policy",
Actions: []*Action{
UpdatePolicy(policyXBaseOnK1V1()),
CreateEndpoint(endpoint1, ip1),
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
ApplyDP(),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
netpolCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet, ip1),
dptestutils.SetPolicy(podK1Set, ip1),
dptestutils.SetPolicy(podK1V1Set, ip1),
},
ExpectedEnpdointACLs: map[string][]*hnswrapper.FakeEndpointPolicy{
endpoint1: {
{
ID: "azure-acl-x-base",
Protocols: "",
Action: "Allow",
Direction: "In",
LocalAddresses: "",
RemoteAddresses: "",
LocalPorts: "",
RemotePorts: "",
Priority: 222,
},
{
ID: "azure-acl-x-base",
Protocols: "",
Action: "Allow",
Direction: "Out",
LocalAddresses: "",
RemoteAddresses: "",
LocalPorts: "",
RemotePorts: "",
Priority: 222,
},
},
},
},
},
{
Description: "policy created, then pod created which satisfies policy, then pod relabeled and no longer satisfies policy",
Actions: []*Action{
UpdatePolicy(policyXBaseOnK1V1()),
CreateEndpoint(endpoint1, ip1),
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
ApplyDP(),
UpdatePodLabels("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}, map[string]string{"k2": "v2"}),
ApplyDP(),
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
podCrudTag,
netpolCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: nil,
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet, ip1),
// old labels (not yet garbage collected)
dptestutils.SetPolicy(podK1Set),
dptestutils.SetPolicy(podK1V1Set),
// new labels
dptestutils.SetPolicy(podK2Set, ip1),
dptestutils.SetPolicy(podK2V2Set, ip1),
},
ExpectedEnpdointACLs: map[string][]*hnswrapper.FakeEndpointPolicy{
endpoint1: {},
},
},
},
}
}
func getAllMultiJobTests() []*MultiJobTestCase {
return []*MultiJobTestCase{
{
Description: "create namespaces, pods, and a policy which applies to a pod",
Jobs: map[string][]*Action{
"namespace_controller": {
CreateNamespace("x", map[string]string{"k1": "v1"}),
CreateNamespace("y", map[string]string{"k2": "v2"}),
ApplyDP(),
},
"pod_controller": {
CreatePod("x", "a", ip1, thisNode, map[string]string{"k1": "v1"}),
CreatePod("y", "a", ip2, otherNode, map[string]string{"k1": "v1"}),
ApplyDP(),
},
"policy_controller": {
UpdatePolicy(policyXBaseOnK1V1()),
},
},
TestCaseMetadata: &TestCaseMetadata{
Tags: []Tag{
nsCrudTag,
podCrudTag,
netpolCrudTag,
},
DpCfg: defaultWindowsDPCfg,
InitialEndpoints: []*hcn.HostComputeEndpoint{
dptestutils.Endpoint(endpoint1, ip1),
dptestutils.Endpoint(endpoint2, ip2),
},
ExpectedSetPolicies: []*hcn.SetPolicySetting{
dptestutils.SetPolicy(emptySet),
dptestutils.SetPolicy(allNamespaces, emptySet.GetHashedName(), nsXSet.GetHashedName(), nsYSet.GetHashedName()),
dptestutils.SetPolicy(nsXSet, ip1),
dptestutils.SetPolicy(nsYSet, ip2),
dptestutils.SetPolicy(nsK1Set, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsK1V1Set, emptySet.GetHashedName(), nsXSet.GetHashedName()),
dptestutils.SetPolicy(nsK2Set, emptySet.GetHashedName(), nsYSet.GetHashedName()),
dptestutils.SetPolicy(nsK2V2Set, emptySet.GetHashedName(), nsYSet.GetHashedName()),
dptestutils.SetPolicy(podK1Set, ip1, ip2),
dptestutils.SetPolicy(podK1V1Set, ip1, ip2),
},
ExpectedEnpdointACLs: map[string][]*hnswrapper.FakeEndpointPolicy{
endpoint1: {
{
ID: "azure-acl-x-base",
Protocols: "",
Action: "Allow",
Direction: "In",
LocalAddresses: "",
RemoteAddresses: "",
LocalPorts: "",
RemotePorts: "",
Priority: 222,
},
{
ID: "azure-acl-x-base",
Protocols: "",
Action: "Allow",
Direction: "Out",
LocalAddresses: "",
RemoteAddresses: "",
LocalPorts: "",
RemotePorts: "",
Priority: 222,
},
},
endpoint2: {},
},
},
},
}
}

Просмотреть файл

@ -240,7 +240,7 @@ func (dp *DataPlane) ApplyDataPlane() error {
delete(dp.updatePodCache.cache, podKey)
}
if aggregateErr != nil {
return fmt.Errorf("[DataPlane] error while updating pods: %w", err)
return fmt.Errorf("[DataPlane] error while updating pods: %w", aggregateErr)
}
}
return nil

Просмотреть файл

@ -0,0 +1,113 @@
package dataplane
import (
"fmt"
"sync"
"testing"
"time"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
dptestutils "github.com/Azure/azure-container-networking/npm/pkg/dataplane/testutils"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
const (
defaultHNSLatency = time.Duration(0)
threadedHNSLatency = time.Duration(1 * time.Second)
)
func TestAllSerialCases(t *testing.T) {
tests := getAllSerialTests()
for i, tt := range tests {
i := i
tt := tt
t.Run(tt.Description, func(t *testing.T) {
t.Logf("beginning test #%d. Description: [%s]. Tags: %+v", i, tt.Description, tt.Tags)
hns := ipsets.GetHNSFake(t)
hns.Delay = defaultHNSLatency
io := common.NewMockIOShimWithFakeHNS(hns)
for _, ep := range tt.InitialEndpoints {
_, err := hns.CreateEndpoint(ep)
require.Nil(t, err, "failed to create initial endpoint %+v", ep)
}
dp, err := NewDataPlane(thisNode, io, tt.DpCfg, nil)
require.NoError(t, err, "failed to initialize dp")
for j, a := range tt.Actions {
var err error
if a.HNSAction != nil {
err = a.HNSAction.Do(hns)
} else if a.DPAction != nil {
err = a.DPAction.Do(dp)
}
require.Nil(t, err, "failed to run action %d", j)
}
dptestutils.VerifyHNSCache(t, hns, tt.ExpectedSetPolicies, tt.ExpectedEnpdointACLs)
})
}
}
func TestAllMultiJobCases(t *testing.T) {
tests := getAllMultiJobTests()
for i, tt := range tests {
i := i
tt := tt
t.Run(tt.Description, func(t *testing.T) {
t.Logf("beginning test #%d. Description: [%s]. Tags: %+v", i, tt.Description, tt.Tags)
hns := ipsets.GetHNSFake(t)
hns.Delay = threadedHNSLatency
io := common.NewMockIOShimWithFakeHNS(hns)
for _, ep := range tt.InitialEndpoints {
_, err := hns.CreateEndpoint(ep)
require.Nil(t, err, "failed to create initial endpoint %+v", ep)
}
// the dp is necessary for NPM tests
dp, err := NewDataPlane(thisNode, io, tt.DpCfg, nil)
require.NoError(t, err, "failed to initialize dp")
backgroundErrors := make(chan error, len(tt.Jobs))
wg := new(sync.WaitGroup)
wg.Add(len(tt.Jobs))
for jobName, job := range tt.Jobs {
jobName := jobName
job := job
go func() {
defer wg.Done()
for k, a := range job {
var err error
if a.HNSAction != nil {
err = a.HNSAction.Do(hns)
} else if a.DPAction != nil {
err = a.DPAction.Do(dp)
}
if err != nil {
backgroundErrors <- errors.Wrapf(err, "failed to run action %d in job %s", k, jobName)
break
}
}
}()
}
wg.Wait()
close(backgroundErrors)
if len(backgroundErrors) > 0 {
errStrings := make([]string, 0)
for err := range backgroundErrors {
errStrings = append(errStrings, fmt.Sprintf("[%s]", err.Error()))
}
require.FailNow(t, "encountered errors in multi-job test: %+v", errStrings)
}
dptestutils.VerifyHNSCache(t, hns, tt.ExpectedSetPolicies, tt.ExpectedEnpdointACLs)
})
}
}

Просмотреть файл

@ -3,16 +3,17 @@ package ipsets
import (
"testing"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/network/hnswrapper"
testutils "github.com/Azure/azure-container-networking/test/utils"
"github.com/stretchr/testify/require"
"github.com/Microsoft/hcsshim/hcn"
"github.com/stretchr/testify/require"
)
func GetHNSFake(t *testing.T) *hnswrapper.Hnsv2wrapperFake {
hns := hnswrapper.NewHnsv2wrapperFake()
network := &hcn.HostComputeNetwork{
Id: "1234",
Id: common.FakeHNSNetworkID,
Name: "azure",
}

Просмотреть файл

@ -0,0 +1,148 @@
package dptestutils
import (
"fmt"
"sort"
"strings"
"testing"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
"github.com/Microsoft/hcsshim/hcn"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/klog"
)
func PrefixNames(sets []*ipsets.IPSetMetadata) []string {
a := make([]string, len(sets))
for k, s := range sets {
a[k] = s.GetPrefixName()
}
return a
}
func Endpoint(epID, ip string) *hcn.HostComputeEndpoint {
return &hcn.HostComputeEndpoint{
Id: epID,
Name: epID,
HostComputeNetwork: common.FakeHNSNetworkID,
IpConfigurations: []hcn.IpConfig{
{
IpAddress: ip,
},
},
}
}
func SetPolicy(setMetadata *ipsets.IPSetMetadata, members ...string) *hcn.SetPolicySetting {
pType := hcn.SetPolicyType("")
switch setMetadata.GetSetKind() {
case ipsets.ListSet:
pType = hcn.SetPolicyTypeNestedIpSet
case ipsets.HashSet:
pType = hcn.SetPolicyTypeIpSet
case ipsets.UnknownKind:
pType = hcn.SetPolicyType("")
}
// sort for easier comparison
sort.Strings(members)
return &hcn.SetPolicySetting{
Id: setMetadata.GetHashedName(),
Name: setMetadata.GetPrefixName(),
PolicyType: pType,
Values: strings.Join(members, ","),
}
}
// VerifyHNSCache asserts that HNS has the correct state.
func VerifyHNSCache(t *testing.T, hns *hnswrapper.Hnsv2wrapperFake, expectedSetPolicies []*hcn.SetPolicySetting, expectedEndpointACLs map[string][]*hnswrapper.FakeEndpointPolicy) {
t.Helper()
PrintGetAllOutput(hns)
// we want to evaluate both verify functions even if one fails, so don't write as verifySetPolicies() && verifyACLs() in case of short-circuiting
success := VerifySetPolicies(t, hns, expectedSetPolicies)
success = VerifyACLs(t, hns, expectedEndpointACLs) && success
if !success {
require.FailNow(t, fmt.Sprintf("hns cache had unexpected state. printing hns cache...\n%s", hns.Cache.PrettyString()))
}
}
// VerifySetPolicies is true if HNS strictly has the expected SetPolicies.
func VerifySetPolicies(t *testing.T, hns *hnswrapper.Hnsv2wrapperFake, expectedSetPolicies []*hcn.SetPolicySetting) bool {
t.Helper()
cachedSetPolicies := hns.Cache.AllSetPolicies(common.FakeHNSNetworkID)
success := assert.Equal(t, len(expectedSetPolicies), len(cachedSetPolicies), "unexpected number of SetPolicies")
for _, expectedSetPolicy := range expectedSetPolicies {
cachedSetPolicy, ok := cachedSetPolicies[expectedSetPolicy.Id]
success = assert.True(t, ok, fmt.Sprintf("expected SetPolicy not found. ID %s, name: %s", expectedSetPolicy.Id, expectedSetPolicy.Name)) && success
if !ok {
continue
}
members := strings.Split(cachedSetPolicy.Values, ",")
sort.Strings(members)
copyOfCachedSetPolicy := *cachedSetPolicy
copyOfCachedSetPolicy.Values = strings.Join(members, ",")
// required that the expectedSetPolicy already has sorted members
success = assert.Equal(t, expectedSetPolicy, &copyOfCachedSetPolicy, fmt.Sprintf("SetPolicy has unexpected contents. ID %s, name: %s", expectedSetPolicy.Id, expectedSetPolicy.Name)) && success
}
return success
}
// verifyACLs is true if HNS strictly has the expected Endpoints and ACLs.
func VerifyACLs(t *testing.T, hns *hnswrapper.Hnsv2wrapperFake, expectedEndpointACLs map[string][]*hnswrapper.FakeEndpointPolicy) bool {
t.Helper()
cachedEndpointACLs := hns.Cache.GetAllACLs()
success := assert.Equal(t, len(expectedEndpointACLs), len(cachedEndpointACLs), "unexpected number of Endpoints")
for epID, expectedACLs := range expectedEndpointACLs {
cachedACLs, ok := cachedEndpointACLs[epID]
success = assert.True(t, ok, fmt.Sprintf("expected ACL not found for endpoint %s", epID)) && success
if !ok {
continue
}
success = assert.Equal(t, len(expectedACLs), len(cachedACLs), fmt.Sprintf("unexpected number of ACLs for Endpoint with ID: %s", epID)) && success
for _, expectedACL := range expectedACLs {
foundACL := false
for _, cacheACL := range cachedACLs {
if expectedACL.ID == cacheACL.ID {
if cmp.Equal(expectedACL, cacheACL) {
foundACL = true
break
}
}
}
success = assert.True(t, foundACL, fmt.Sprintf("missing expected ACL. ID: %s, full ACL: %+v", expectedACL.ID, expectedACL)) && success
}
}
return success
}
// helpful for debugging if there's a discrepancy between GetAll functions and the HNS PrettyString
func PrintGetAllOutput(hns *hnswrapper.Hnsv2wrapperFake) {
klog.Info("SETPOLICIES...")
for _, setPol := range hns.Cache.AllSetPolicies(common.FakeHNSNetworkID) {
klog.Infof("%+v", setPol)
}
klog.Info("Endpoint ACLs...")
for id, acls := range hns.Cache.GetAllACLs() {
a := make([]string, len(acls))
for k, v := range acls {
a[k] = fmt.Sprintf("%+v", v)
}
klog.Infof("%s: %s", id, strings.Join(a, ","))
}
}

Просмотреть файл

@ -1,6 +1,8 @@
package dataplane
import (
"strings"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/policies"
"github.com/Azure/azure-container-networking/npm/util"
@ -51,6 +53,10 @@ func NewPodMetadata(podKey, podIP, nodeName string) *PodMetadata {
}
}
func (p *PodMetadata) Namespace() string {
return strings.Split(p.PodKey, "/")[0]
}
func newUpdateNPMPod(podMetadata *PodMetadata) *updateNPMPod {
return &updateNPMPod{
PodMetadata: podMetadata,

Просмотреть файл

@ -0,0 +1,446 @@
package dataplane
import (
"fmt"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"github.com/Azure/azure-container-networking/npm/pkg/controlplane/translation"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
dptestutils "github.com/Azure/azure-container-networking/npm/pkg/dataplane/testutils"
"github.com/Microsoft/hcsshim/hcn"
"github.com/pkg/errors"
networkingv1 "k8s.io/api/networking/v1"
)
type Tag string
type SerialTestCase struct {
Description string
Actions []*Action
*TestCaseMetadata
}
type MultiJobTestCase struct {
Description string
Jobs map[string][]*Action
*TestCaseMetadata
}
type TestCaseMetadata struct {
Tags []Tag
InitialEndpoints []*hcn.HostComputeEndpoint
DpCfg *Config
ExpectedSetPolicies []*hcn.SetPolicySetting
ExpectedEnpdointACLs map[string][]*hnswrapper.FakeEndpointPolicy
}
// Action represents a single action (either an HNSAction or a DPAction).
// Exactly one of HNSAction or DPAction should be non-nil.
type Action struct {
HNSAction
DPAction
}
type HNSAction interface {
// Do models events in HNS
Do(hns *hnswrapper.Hnsv2wrapperFake) error
}
type EndpointCreateAction struct {
ID string
IP string
}
func CreateEndpoint(id, ip string) *Action {
return &Action{
HNSAction: &EndpointCreateAction{
ID: id,
IP: ip,
},
}
}
// Do models endpoint creation in HNS
func (e *EndpointCreateAction) Do(hns *hnswrapper.Hnsv2wrapperFake) error {
ep := dptestutils.Endpoint(e.ID, e.IP)
_, err := hns.CreateEndpoint(ep)
if err != nil {
return errors.Wrapf(err, "[EndpointCreateAction] failed to create endpoint. ep: [%+v]", ep)
}
return nil
}
type EndpointDeleteAction struct {
ID string
}
func DeleteEndpoint(id string) *Action {
return &Action{
HNSAction: &EndpointDeleteAction{
ID: id,
},
}
}
// Do models endpoint deletion in HNS
func (e *EndpointDeleteAction) Do(hns *hnswrapper.Hnsv2wrapperFake) error {
ep := &hcn.HostComputeEndpoint{
Id: e.ID,
}
if err := hns.DeleteEndpoint(ep); err != nil {
return errors.Wrapf(err, "[EndpointDeleteAction] failed to delete endpoint. ep: [%+v]", ep)
}
return nil
}
type DPAction interface {
// Do models interactions with the DataPlane
Do(dp *DataPlane) error
}
type ApplyDPAction struct{}
func ApplyDP() *Action {
return &Action{
DPAction: &ApplyDPAction{},
}
}
// Do applies the dataplane
func (*ApplyDPAction) Do(dp *DataPlane) error {
if err := dp.ApplyDataPlane(); err != nil {
return errors.Wrapf(err, "[ApplyDPAction] failed to apply")
}
return nil
}
type ReconcileDPAction struct{}
func ReconcileDP() *Action {
return &Action{
DPAction: &ReconcileDPAction{},
}
}
// Do reconciles the IPSetManager and PolicyManager
func (*ReconcileDPAction) Do(dp *DataPlane) error {
dp.ipsetMgr.Reconcile()
// currently does nothing in windows
dp.policyMgr.Reconcile()
return nil
}
type PodCreateAction struct {
Pod *PodMetadata
Labels map[string]string
}
func CreatePod(namespace, name, ip, node string, labels map[string]string) *Action {
podKey := fmt.Sprintf("%s/%s", namespace, name)
return &Action{
DPAction: &PodCreateAction{
Pod: NewPodMetadata(podKey, ip, node),
Labels: labels,
},
}
}
// Do models pod creation in the PodController
func (p *PodCreateAction) Do(dp *DataPlane) error {
context := fmt.Sprintf("create context: [pod: %+v. labels: %+v]", p.Pod, p.Labels)
nsIPSet := []*ipsets.IPSetMetadata{ipsets.NewIPSetMetadata(p.Pod.Namespace(), ipsets.Namespace)}
// PodController technically wouldn't call this if the namespace already existed
if err := dp.AddToLists([]*ipsets.IPSetMetadata{allNamespaces}, nsIPSet); err != nil {
return errors.Wrapf(err, "[PodCreateAction] failed to add ns set to all-namespaces list. %s", context)
}
if err := dp.AddToSets(nsIPSet, p.Pod); err != nil {
return errors.Wrapf(err, "[PodCreateAction] failed to add pod ip to ns set. %s", context)
}
for key, val := range p.Labels {
keyVal := fmt.Sprintf("%s:%s", key, val)
labelIPSets := []*ipsets.IPSetMetadata{
ipsets.NewIPSetMetadata(key, ipsets.KeyLabelOfPod),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfPod),
}
if err := dp.AddToSets(labelIPSets, p.Pod); err != nil {
return errors.Wrapf(err, "[PodCreateAction] failed to add pod ip to label sets %+v. %s", labelIPSets, context)
}
}
return nil
}
type PodUpdateAction struct {
OldPod *PodMetadata
NewPod *PodMetadata
LabelsToRemove map[string]string
LabelsToAdd map[string]string
}
func UpdatePod(namespace, name, oldIP, oldNode, newIP, newNode string, labelsToRemove, labelsToAdd map[string]string) *Action {
podKey := fmt.Sprintf("%s/%s", namespace, name)
return &Action{
DPAction: &PodUpdateAction{
OldPod: NewPodMetadata(podKey, oldIP, oldNode),
NewPod: NewPodMetadata(podKey, newIP, newNode),
LabelsToRemove: labelsToRemove,
LabelsToAdd: labelsToAdd,
},
}
}
func UpdatePodLabels(namespace, name, ip, node string, labelsToRemove, labelsToAdd map[string]string) *Action {
return UpdatePod(namespace, name, ip, node, ip, node, labelsToRemove, labelsToAdd)
}
// Do models pod updates in the PodController
func (p *PodUpdateAction) Do(dp *DataPlane) error {
context := fmt.Sprintf("update context: [old pod: %+v. current IP: %+v. old labels: %+v. new labels: %+v]", p.OldPod, p.NewPod.PodIP, p.LabelsToRemove, p.LabelsToAdd)
// think it's impossible for this to be called on an UPDATE
// dp.AddToLists([]*ipsets.IPSetMetadata{allNamespaces}, []*ipsets.IPSetMetadata{nsIPSet})
for k, v := range p.LabelsToRemove {
keyVal := fmt.Sprintf("%s:%s", k, v)
sets := []*ipsets.IPSetMetadata{
ipsets.NewIPSetMetadata(k, ipsets.KeyLabelOfPod),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfPod),
}
for _, toRemoveSet := range sets {
if err := dp.RemoveFromSets([]*ipsets.IPSetMetadata{toRemoveSet}, p.OldPod); err != nil {
return errors.Wrapf(err, "[PodUpdateAction] failed to remove old pod ip from set %s. %s", toRemoveSet.GetPrefixName(), context)
}
}
}
for k, v := range p.LabelsToAdd {
keyVal := fmt.Sprintf("%s:%s", k, v)
sets := []*ipsets.IPSetMetadata{
ipsets.NewIPSetMetadata(k, ipsets.KeyLabelOfPod),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfPod),
}
for _, toAddSet := range sets {
if err := dp.AddToSets([]*ipsets.IPSetMetadata{toAddSet}, p.NewPod); err != nil {
return errors.Wrapf(err, "[PodUpdateAction] failed to add new pod ip to set %s. %s", toAddSet.GetPrefixName(), context)
}
}
}
return nil
}
type PodDeleteAction struct {
Pod *PodMetadata
Labels map[string]string
}
func DeletePod(namespace, name, ip string, labels map[string]string) *Action {
podKey := fmt.Sprintf("%s/%s", namespace, name)
return &Action{
DPAction: &PodDeleteAction{
// currently, the PodController doesn't share the node name
Pod: NewPodMetadata(podKey, ip, ""),
Labels: labels,
},
}
}
// Do models pod deletion in the PodController
func (p *PodDeleteAction) Do(dp *DataPlane) error {
context := fmt.Sprintf("delete context: [pod: %+v. labels: %+v]", p.Pod, p.Labels)
nsIPSet := []*ipsets.IPSetMetadata{ipsets.NewIPSetMetadata(p.Pod.Namespace(), ipsets.Namespace)}
if err := dp.RemoveFromSets(nsIPSet, p.Pod); err != nil {
return errors.Wrapf(err, "[PodDeleteAction] failed to remove pod ip from ns set. %s", context)
}
for key, val := range p.Labels {
keyVal := fmt.Sprintf("%s:%s", key, val)
labelIPSets := []*ipsets.IPSetMetadata{
ipsets.NewIPSetMetadata(key, ipsets.KeyLabelOfPod),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfPod),
}
if err := dp.RemoveFromSets(labelIPSets, p.Pod); err != nil {
return errors.Wrapf(err, "[PodDeleteAction] failed to remove pod ip from label set %+v. %s", labelIPSets, context)
}
}
return nil
}
type NamespaceCreateAction struct {
NS string
Labels map[string]string
}
func CreateNamespace(ns string, labels map[string]string) *Action {
return &Action{
DPAction: &NamespaceCreateAction{
NS: ns,
Labels: labels,
},
}
}
// Do models namespace creation in the NamespaceController
func (n *NamespaceCreateAction) Do(dp *DataPlane) error {
nsIPSet := []*ipsets.IPSetMetadata{ipsets.NewIPSetMetadata(n.NS, ipsets.Namespace)}
listsToAddTo := []*ipsets.IPSetMetadata{allNamespaces}
for k, v := range n.Labels {
keyVal := fmt.Sprintf("%s:%s", k, v)
listsToAddTo = append(listsToAddTo,
ipsets.NewIPSetMetadata(k, ipsets.KeyLabelOfNamespace),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfNamespace))
}
if err := dp.AddToLists(listsToAddTo, nsIPSet); err != nil {
return errors.Wrapf(err, "[NamespaceCreateAction] failed to add ns ipset to all lists. Action: %+v", n)
}
return nil
}
type NamespaceUpdateAction struct {
NS string
LabelsToRemove map[string]string
LabelsToAdd map[string]string
}
func UpdateNamespace(ns string, labelsToRemove, labelsToAdd map[string]string) *Action {
return &Action{
DPAction: &NamespaceUpdateAction{
NS: ns,
LabelsToRemove: labelsToRemove,
LabelsToAdd: labelsToAdd,
},
}
}
// Do models namespace updates in the NamespaceController
func (n *NamespaceUpdateAction) Do(dp *DataPlane) error {
nsIPSet := []*ipsets.IPSetMetadata{ipsets.NewIPSetMetadata(n.NS, ipsets.Namespace)}
for k, v := range n.LabelsToRemove {
keyVal := fmt.Sprintf("%s:%s", k, v)
lists := []*ipsets.IPSetMetadata{
ipsets.NewIPSetMetadata(k, ipsets.KeyLabelOfNamespace),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfNamespace),
}
for _, listToRemoveFrom := range lists {
if err := dp.RemoveFromList(listToRemoveFrom, nsIPSet); err != nil {
return errors.Wrapf(err, "[NamespaceUpdateAction] failed to remove ns ipset from list %s. Action: %+v", listToRemoveFrom.GetPrefixName(), n)
}
}
}
for k, v := range n.LabelsToAdd {
keyVal := fmt.Sprintf("%s:%s", k, v)
lists := []*ipsets.IPSetMetadata{
ipsets.NewIPSetMetadata(k, ipsets.KeyLabelOfNamespace),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfNamespace),
}
for _, listToAddTo := range lists {
if err := dp.RemoveFromList(listToAddTo, nsIPSet); err != nil {
return errors.Wrapf(err, "[NamespaceUpdateAction] failed to add ns ipset to list %s. Action: %+v", listToAddTo.GetPrefixName(), n)
}
}
}
return nil
}
type NamespaceDeleteAction struct {
NS string
Labels map[string]string
}
func DeleteNamespace(ns string, labels map[string]string) *Action {
return &Action{
DPAction: &NamespaceDeleteAction{
NS: ns,
Labels: labels,
},
}
}
// Do models namespace deletion in the NamespaceController
func (n *NamespaceDeleteAction) Do(dp *DataPlane) error {
nsIPSet := []*ipsets.IPSetMetadata{ipsets.NewIPSetMetadata(n.NS, ipsets.Namespace)}
for k, v := range n.Labels {
keyVal := fmt.Sprintf("%s:%s", k, v)
lists := []*ipsets.IPSetMetadata{
ipsets.NewIPSetMetadata(k, ipsets.KeyLabelOfNamespace),
ipsets.NewIPSetMetadata(keyVal, ipsets.KeyValueLabelOfNamespace),
}
for _, listToRemoveFrom := range lists {
if err := dp.RemoveFromList(listToRemoveFrom, nsIPSet); err != nil {
return errors.Wrapf(err, "[NamespaceDeleteAction] failed to remove ns ipset from list %s. Action: %+v", listToRemoveFrom.GetPrefixName(), n)
}
}
}
if err := dp.RemoveFromList(allNamespaces, nsIPSet); err != nil {
return errors.Wrapf(err, "[NamespaceDeleteAction] failed to remove ns ipset from all-namespaces list. Action: %+v", n)
}
return nil
}
type PolicyUpdateAction struct {
Policy *networkingv1.NetworkPolicy
}
func UpdatePolicy(policy *networkingv1.NetworkPolicy) *Action {
return &Action{
DPAction: &PolicyUpdateAction{
Policy: policy,
},
}
}
// Do models policy updates in the NetworkPolicyController
func (p *PolicyUpdateAction) Do(dp *DataPlane) error {
npmNetPol, err := translation.TranslatePolicy(p.Policy)
if err != nil {
return errors.Wrapf(err, "[PolicyUpdateAction] failed to translate policy with key %s/%s", p.Policy.Namespace, p.Policy.Name)
}
if err := dp.UpdatePolicy(npmNetPol); err != nil {
return errors.Wrapf(err, "[PolicyUpdateAction] failed to update policy with key %s/%s", p.Policy.Namespace, p.Policy.Name)
}
return nil
}
type PolicyDeleteAction struct {
Namespace string
Name string
}
func DeletePolicy(namespace, name string) *Action {
return &Action{
DPAction: &PolicyDeleteAction{
Namespace: namespace,
Name: name,
},
}
}
func DeletePolicyByObject(policy *networkingv1.NetworkPolicy) *Action {
return DeletePolicy(policy.Namespace, policy.Name)
}
// Do models policy deletion in the NetworkPolicyController
func (p *PolicyDeleteAction) Do(dp *DataPlane) error {
policyKey := fmt.Sprintf("%s/%s", p.Namespace, p.Name)
if err := dp.RemovePolicy(policyKey); err != nil {
return errors.Wrapf(err, "[PolicyDeleteAction] failed to update policy with key %s", policyKey)
}
return nil
}