...

Source file src/k8s.io/kubernetes/test/e2e/network/netpol/network_policy_api.go

Documentation: k8s.io/kubernetes/test/e2e/network/netpol

     1  /*
     2  Copyright 2021 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package netpol
    18  
    19  import (
    20  	"context"
    21  	"time"
    22  
    23  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    24  	"k8s.io/apimachinery/pkg/types"
    25  	"k8s.io/apimachinery/pkg/util/intstr"
    26  	"k8s.io/apimachinery/pkg/util/wait"
    27  	"k8s.io/apimachinery/pkg/watch"
    28  	admissionapi "k8s.io/pod-security-admission/api"
    29  
    30  	"github.com/onsi/ginkgo/v2"
    31  	"github.com/onsi/gomega"
    32  
    33  	networkingv1 "k8s.io/api/networking/v1"
    34  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    35  	"k8s.io/kubernetes/test/e2e/framework"
    36  	"k8s.io/kubernetes/test/e2e/network/common"
    37  )
    38  
    39  var _ = common.SIGDescribe("Netpol API", func() {
    40  	f := framework.NewDefaultFramework("netpol")
    41  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    42  	/*
    43  		Release: v1.20
    44  		Testname: NetworkPolicies API
    45  		Description:
    46  		- The networking.k8s.io API group MUST exist in the /apis discovery document.
    47  		- The networking.k8s.io/v1 API group/version MUST exist in the /apis/networking.k8s.io discovery document.
    48  		- The NetworkPolicies resources MUST exist in the /apis/networking.k8s.io/v1 discovery document.
    49  		- The NetworkPolicies resource must support create, get, list, watch, update, patch, delete, and deletecollection.
    50  	*/
    51  
    52  	ginkgo.It("should support creating NetworkPolicy API operations", func(ctx context.Context) {
    53  		// Setup
    54  		ns := f.Namespace.Name
    55  		npVersion := "v1"
    56  		npClient := f.ClientSet.NetworkingV1().NetworkPolicies(ns)
    57  
    58  		namespaceSelector := &metav1.LabelSelector{
    59  			MatchLabels: map[string]string{
    60  				"ns-name": "pod-b",
    61  			},
    62  		}
    63  		podSelector := &metav1.LabelSelector{
    64  			MatchLabels: map[string]string{
    65  				"pod-name": "client-a",
    66  			},
    67  		}
    68  		ingressRule := networkingv1.NetworkPolicyIngressRule{}
    69  		ingressRule.From = append(ingressRule.From, networkingv1.NetworkPolicyPeer{PodSelector: podSelector, NamespaceSelector: namespaceSelector})
    70  		npTemplate := GenNetworkPolicy(SetGenerateName("e2e-example-netpol"),
    71  			SetObjectMetaLabel(map[string]string{"special-label": f.UniqueName}),
    72  			SetSpecPodSelectorMatchLabels(map[string]string{"pod-name": "test-pod"}),
    73  			SetSpecIngressRules(ingressRule))
    74  
    75  		// Discovery
    76  		ginkgo.By("getting /apis")
    77  		{
    78  			discoveryGroups, err := f.ClientSet.Discovery().ServerGroups()
    79  			framework.ExpectNoError(err)
    80  			found := false
    81  			for _, group := range discoveryGroups.Groups {
    82  				if group.Name == networkingv1.GroupName {
    83  					for _, version := range group.Versions {
    84  						if version.Version == npVersion {
    85  							found = true
    86  							break
    87  						}
    88  					}
    89  				}
    90  			}
    91  			if !found {
    92  				framework.Failf("expected networking API group/version, got %#v", discoveryGroups.Groups)
    93  			}
    94  		}
    95  		ginkgo.By("getting /apis/networking.k8s.io")
    96  		{
    97  			group := &metav1.APIGroup{}
    98  			err := f.ClientSet.Discovery().RESTClient().Get().AbsPath("/apis/networking.k8s.io").Do(ctx).Into(group)
    99  			framework.ExpectNoError(err)
   100  			found := false
   101  			for _, version := range group.Versions {
   102  				if version.Version == npVersion {
   103  					found = true
   104  					break
   105  				}
   106  			}
   107  			if !found {
   108  				framework.Failf("expected networking API version, got %#v", group.Versions)
   109  			}
   110  		}
   111  		ginkgo.By("getting /apis/networking.k8s.io" + npVersion)
   112  		{
   113  			resources, err := f.ClientSet.Discovery().ServerResourcesForGroupVersion(networkingv1.SchemeGroupVersion.String())
   114  			framework.ExpectNoError(err)
   115  			foundNetPol := false
   116  			for _, resource := range resources.APIResources {
   117  				switch resource.Name {
   118  				case "networkpolicies":
   119  					foundNetPol = true
   120  				}
   121  			}
   122  			if !foundNetPol {
   123  				framework.Failf("expected networkpolicies, got %#v", resources.APIResources)
   124  			}
   125  		}
   126  		// NetPol resource create/read/update/watch verbs
   127  		ginkgo.By("creating")
   128  		_, err := npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   129  		framework.ExpectNoError(err)
   130  		_, err = npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   131  		framework.ExpectNoError(err)
   132  		createdNetPol, err := npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   133  		framework.ExpectNoError(err)
   134  
   135  		ginkgo.By("getting")
   136  		gottenNetPol, err := npClient.Get(ctx, createdNetPol.Name, metav1.GetOptions{})
   137  		framework.ExpectNoError(err)
   138  		gomega.Expect(gottenNetPol.UID).To(gomega.Equal(createdNetPol.UID))
   139  
   140  		ginkgo.By("listing")
   141  		nps, err := npClient.List(ctx, metav1.ListOptions{LabelSelector: "special-label=" + f.UniqueName})
   142  		framework.ExpectNoError(err)
   143  		gomega.Expect(nps.Items).To(gomega.HaveLen(3), "filtered list should have 3 items")
   144  
   145  		ginkgo.By("watching")
   146  		framework.Logf("starting watch")
   147  		npWatch, err := npClient.Watch(ctx, metav1.ListOptions{ResourceVersion: nps.ResourceVersion, LabelSelector: "special-label=" + f.UniqueName})
   148  		framework.ExpectNoError(err)
   149  		// Test cluster-wide list and watch
   150  		clusterNPClient := f.ClientSet.NetworkingV1().NetworkPolicies("")
   151  		ginkgo.By("cluster-wide listing")
   152  		clusterNPs, err := clusterNPClient.List(ctx, metav1.ListOptions{LabelSelector: "special-label=" + f.UniqueName})
   153  		framework.ExpectNoError(err)
   154  		gomega.Expect(clusterNPs.Items).To(gomega.HaveLen(3), "filtered list should have 3 items")
   155  
   156  		ginkgo.By("cluster-wide watching")
   157  		framework.Logf("starting watch")
   158  		_, err = clusterNPClient.Watch(ctx, metav1.ListOptions{ResourceVersion: nps.ResourceVersion, LabelSelector: "special-label=" + f.UniqueName})
   159  		framework.ExpectNoError(err)
   160  
   161  		ginkgo.By("patching")
   162  		patchedNetPols, err := npClient.Patch(ctx, createdNetPol.Name, types.MergePatchType, []byte(`{"metadata":{"annotations":{"patched":"true"}}}`), metav1.PatchOptions{})
   163  		framework.ExpectNoError(err)
   164  		gomega.Expect(patchedNetPols.Annotations).To(gomega.HaveKeyWithValue("patched", "true"), "patched object should have the applied annotation")
   165  
   166  		ginkgo.By("updating")
   167  		npToUpdate := patchedNetPols.DeepCopy()
   168  		npToUpdate.Annotations["updated"] = "true"
   169  		updatedNetPols, err := npClient.Update(ctx, npToUpdate, metav1.UpdateOptions{})
   170  		framework.ExpectNoError(err)
   171  		gomega.Expect(updatedNetPols.Annotations).To(gomega.HaveKeyWithValue("updated", "true"), "updated object should have the applied annotation")
   172  
   173  		framework.Logf("waiting for watch events with expected annotations")
   174  		for sawAnnotations := false; !sawAnnotations; {
   175  			select {
   176  			case evt, ok := <-npWatch.ResultChan():
   177  				if !ok {
   178  					framework.Fail("watch channel should not close")
   179  				}
   180  				gomega.Expect(evt.Type).To(gomega.Equal(watch.Modified))
   181  				watchedNetPol, isNetPol := evt.Object.(*networkingv1.NetworkPolicy)
   182  				if !isNetPol {
   183  					framework.Failf("expected NetworkPolicy, got %T", evt.Object)
   184  				}
   185  				if watchedNetPol.Annotations["patched"] == "true" && watchedNetPol.Annotations["updated"] == "true" {
   186  					framework.Logf("saw patched and updated annotations")
   187  					sawAnnotations = true
   188  					npWatch.Stop()
   189  				} else {
   190  					framework.Logf("missing expected annotations, waiting: %#v", watchedNetPol.Annotations)
   191  				}
   192  			case <-time.After(wait.ForeverTestTimeout):
   193  				framework.Fail("timed out waiting for watch event")
   194  			}
   195  		}
   196  		// NetPol resource delete operations
   197  		ginkgo.By("deleting")
   198  		err = npClient.Delete(ctx, createdNetPol.Name, metav1.DeleteOptions{})
   199  		framework.ExpectNoError(err)
   200  		_, err = npClient.Get(ctx, createdNetPol.Name, metav1.GetOptions{})
   201  		if !apierrors.IsNotFound(err) {
   202  			framework.Failf("expected 404, got %#v", err)
   203  		}
   204  		nps, err = npClient.List(ctx, metav1.ListOptions{LabelSelector: "special-label=" + f.UniqueName})
   205  		framework.ExpectNoError(err)
   206  		gomega.Expect(nps.Items).To(gomega.HaveLen(2), "filtered list should have 2 items")
   207  
   208  		ginkgo.By("deleting a collection")
   209  		err = npClient.DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "special-label=" + f.UniqueName})
   210  		framework.ExpectNoError(err)
   211  		nps, err = npClient.List(ctx, metav1.ListOptions{LabelSelector: "special-label=" + f.UniqueName})
   212  		framework.ExpectNoError(err)
   213  		gomega.Expect(nps.Items).To(gomega.BeEmpty(), "filtered list should have 0 items")
   214  	})
   215  
   216  	/*
   217  		Release: v1.21
   218  		Testname: NetworkPolicy support EndPort Field
   219  		Description:
   220  		- EndPort field cannot be defined if the Port field is not defined
   221  		- EndPort field cannot be defined if the Port field is defined as a named (string) port.
   222  		- EndPort field must be equal or greater than port.
   223  	*/
   224  	ginkgo.It("should support creating NetworkPolicy API with endport field", func(ctx context.Context) {
   225  		ns := f.Namespace.Name
   226  		npClient := f.ClientSet.NetworkingV1().NetworkPolicies(ns)
   227  
   228  		ginkgo.By("EndPort field cannot be defined if the Port field is not defined.")
   229  		var endport int32 = 20000
   230  		egressRule := networkingv1.NetworkPolicyEgressRule{}
   231  		egressRule.Ports = append(egressRule.Ports, networkingv1.NetworkPolicyPort{EndPort: &endport})
   232  		npTemplate := GenNetworkPolicy(SetGenerateName("e2e-example-netpol-endport-validate"),
   233  			SetObjectMetaLabel(map[string]string{"special-label": f.UniqueName}),
   234  			SetSpecPodSelectorMatchLabels(map[string]string{"pod-name": "test-pod"}),
   235  			SetSpecEgressRules(egressRule))
   236  		_, err := npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   237  		gomega.Expect(err).To(gomega.HaveOccurred(), "request template:%v", npTemplate)
   238  
   239  		ginkgo.By("EndPort field cannot be defined if the Port field is defined as a named (string) port.")
   240  		egressRule = networkingv1.NetworkPolicyEgressRule{}
   241  		egressRule.Ports = append(egressRule.Ports, networkingv1.NetworkPolicyPort{Port: &intstr.IntOrString{Type: intstr.String, StrVal: "serve-80"}, EndPort: &endport})
   242  		npTemplate.Spec.Egress = []networkingv1.NetworkPolicyEgressRule{egressRule}
   243  		_, err = npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   244  		gomega.Expect(err).To(gomega.HaveOccurred(), "request template:%v", npTemplate)
   245  
   246  		ginkgo.By("EndPort field must be equal or greater than port.")
   247  		ginkgo.By("When EndPort field is smaller than port, it will failed")
   248  		egressRule = networkingv1.NetworkPolicyEgressRule{}
   249  		egressRule.Ports = append(egressRule.Ports, networkingv1.NetworkPolicyPort{Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 30000}, EndPort: &endport})
   250  		npTemplate.Spec.Egress = []networkingv1.NetworkPolicyEgressRule{egressRule}
   251  		_, err = npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   252  		gomega.Expect(err).To(gomega.HaveOccurred(), "request template:%v", npTemplate)
   253  
   254  		ginkgo.By("EndPort field is equal with port.")
   255  		egressRule.Ports[0].Port = &intstr.IntOrString{Type: intstr.Int, IntVal: 20000}
   256  		npTemplate.Spec.Egress = []networkingv1.NetworkPolicyEgressRule{egressRule}
   257  		_, err = npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   258  		framework.ExpectNoError(err, "request template:%v", npTemplate)
   259  
   260  		ginkgo.By("EndPort field is greater than port.")
   261  		egressRule = networkingv1.NetworkPolicyEgressRule{}
   262  		egressRule.Ports = append(egressRule.Ports, networkingv1.NetworkPolicyPort{Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 10000}, EndPort: &endport})
   263  		npTemplate.Spec.Egress = []networkingv1.NetworkPolicyEgressRule{egressRule}
   264  		_, err = npClient.Create(ctx, npTemplate, metav1.CreateOptions{})
   265  		framework.ExpectNoError(err, "request template:%v", npTemplate)
   266  
   267  		ginkgo.By("deleting all test collection")
   268  		err = npClient.DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: "special-label=" + f.UniqueName})
   269  		framework.ExpectNoError(err)
   270  		nps, err := npClient.List(ctx, metav1.ListOptions{LabelSelector: "special-label=" + f.UniqueName})
   271  		framework.ExpectNoError(err)
   272  		gomega.Expect(nps.Items).To(gomega.BeEmpty(), "filtered list should be 0 items")
   273  	})
   274  })
   275  

View as plain text