k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/network/netpol/network_policy_api.go (about) 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 })