github.phpd.cn/cilium/cilium@v1.6.12/test/k8sT/Services.go (about)

     1  // Copyright 2017-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package k8sTest
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"net"
    21  	"time"
    22  
    23  	. "github.com/cilium/cilium/test/ginkgo-ext"
    24  	"github.com/cilium/cilium/test/helpers"
    25  
    26  	"github.com/asaskevich/govalidator"
    27  	. "github.com/onsi/gomega"
    28  	"k8s.io/api/core/v1"
    29  )
    30  
    31  var _ = Describe("K8sServicesTest", func() {
    32  	var (
    33  		kubectl                *helpers.Kubectl
    34  		serviceName            = "app1-service"
    35  		microscopeErr          error
    36  		microscopeCancel                          = func() error { return nil }
    37  		backgroundCancel       context.CancelFunc = func() { return }
    38  		backgroundError        error
    39  		enableBackgroundReport = true
    40  		ciliumPodK8s1          string
    41  		testDSClient           = "zgroup=testDSClient"
    42  		testDS                 = "zgroup=testDS"
    43  		echoServiceName        = "echo"
    44  		echoPodLabel           = "name=echo"
    45  	)
    46  
    47  	applyPolicy := func(path string) {
    48  		By(fmt.Sprintf("Applying policy %s", path))
    49  		_, err := kubectl.CiliumPolicyAction(helpers.DefaultNamespace, path, helpers.KubectlApply, helpers.HelperTimeout)
    50  		ExpectWithOffset(1, err).Should(BeNil(), fmt.Sprintf("Error creating resource %s: %s", path, err))
    51  	}
    52  
    53  	BeforeAll(func() {
    54  		var err error
    55  
    56  		kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)
    57  		DeployCiliumAndDNS(kubectl)
    58  
    59  		ciliumPodK8s1, err = kubectl.GetCiliumPodOnNode(helpers.KubeSystemNamespace, helpers.K8s1)
    60  		Expect(err).Should(BeNil(), "Cannot get cilium pod on k8s1")
    61  	})
    62  
    63  	AfterFailed(func() {
    64  		kubectl.CiliumReport(helpers.KubeSystemNamespace,
    65  			"cilium service list",
    66  			"cilium endpoint list")
    67  	})
    68  
    69  	JustBeforeEach(func() {
    70  		microscopeErr, microscopeCancel = kubectl.MicroscopeStart()
    71  		Expect(microscopeErr).To(BeNil(), "Microscope cannot be started")
    72  		if enableBackgroundReport {
    73  			backgroundCancel, backgroundError = kubectl.BackgroundReport("uptime")
    74  			Expect(backgroundError).To(BeNil(), "Cannot start background report process")
    75  		}
    76  	})
    77  
    78  	JustAfterEach(func() {
    79  		kubectl.ValidateNoErrorsInLogs(CurrentGinkgoTestDescription().Duration)
    80  		Expect(microscopeCancel()).To(BeNil(), "cannot stop microscope")
    81  		backgroundCancel()
    82  	})
    83  
    84  	AfterEach(func() {
    85  		ExpectAllPodsTerminated(kubectl)
    86  	})
    87  
    88  	AfterAll(func() {
    89  		kubectl.CloseSSHClient()
    90  	})
    91  
    92  	testHTTPRequest := func(clientPodLabel, url string) {
    93  		pods, err := kubectl.GetPodNames(helpers.DefaultNamespace, clientPodLabel)
    94  		ExpectWithOffset(1, err).Should(BeNil(), "cannot retrieve pod names by filter %q", testDSClient)
    95  		// A DS with client is running in each node. So we try from each node
    96  		// that can connect to the service.  To make sure that the cross-node
    97  		// service connectivity is correct we tried 10 times, so balance in the
    98  		// two nodes
    99  		for _, pod := range pods {
   100  			By("Making ten HTTP requests from %q to %q", pod, url)
   101  			for i := 1; i <= 10; i++ {
   102  				res := kubectl.ExecPodCmd(
   103  					helpers.DefaultNamespace, pod,
   104  					helpers.CurlFail(url))
   105  				ExpectWithOffset(1, res).Should(helpers.CMDSuccess(),
   106  					"Pod %q can not connect to service %q", pod, url)
   107  			}
   108  		}
   109  	}
   110  
   111  	waitPodsDs := func() {
   112  		groups := []string{testDS, testDSClient}
   113  		for _, pod := range groups {
   114  			err := kubectl.WaitforPods(helpers.DefaultNamespace, fmt.Sprintf("-l %s", pod), helpers.HelperTimeout)
   115  			ExpectWithOffset(1, err).Should(BeNil())
   116  		}
   117  	}
   118  
   119  	Context("Checks ClusterIP Connectivity", func() {
   120  
   121  		var (
   122  			demoYAML    = helpers.ManifestGet("demo.yaml")
   123  			echoSVCYAML = helpers.ManifestGet("echo-svc.yaml")
   124  		)
   125  
   126  		BeforeEach(func() {
   127  			res := kubectl.ApplyDefault(demoYAML)
   128  			res.ExpectSuccess("unable to apply %s", demoYAML)
   129  			res = kubectl.ApplyDefault(echoSVCYAML)
   130  			res.ExpectSuccess("unable to apply %s", echoSVCYAML)
   131  		})
   132  
   133  		AfterEach(func() {
   134  			// Explicitly ignore result of deletion of resources to avoid incomplete
   135  			// teardown if any step fails.
   136  			_ = kubectl.Delete(demoYAML)
   137  			_ = kubectl.Delete(echoSVCYAML)
   138  		})
   139  
   140  		It("Checks service on same node", func() {
   141  			err := kubectl.WaitforPods(helpers.DefaultNamespace, "-l zgroup=testapp", helpers.HelperTimeout)
   142  			Expect(err).Should(BeNil())
   143  			clusterIP, _, err := kubectl.GetServiceHostPort(helpers.DefaultNamespace, serviceName)
   144  			Expect(err).Should(BeNil(), "Cannot get service %s", serviceName)
   145  			Expect(govalidator.IsIP(clusterIP)).Should(BeTrue(), "ClusterIP is not an IP")
   146  
   147  			By("testing connectivity via cluster IP %s", clusterIP)
   148  			monitorStop := kubectl.MonitorStart(helpers.KubeSystemNamespace, ciliumPodK8s1,
   149  				"cluster-ip-same-node.log")
   150  			status := kubectl.Exec(helpers.CurlFail("http://%s/", clusterIP))
   151  			monitorStop()
   152  			status.ExpectSuccess("cannot curl to service IP from host")
   153  			ciliumPods, err := kubectl.GetCiliumPods(helpers.KubeSystemNamespace)
   154  			Expect(err).To(BeNil(), "Cannot get cilium pods")
   155  			for _, pod := range ciliumPods {
   156  				service := kubectl.CiliumExec(pod, "cilium service list")
   157  				service.ExpectSuccess("Cannot retrieve services on cilium Pod")
   158  				service.ExpectContains(clusterIP, "ClusterIP is not present in the cilium service list")
   159  			}
   160  		}, 300)
   161  
   162  		It("Checks service accessing itself (hairpin flow)", func() {
   163  			err := kubectl.WaitforPods(helpers.DefaultNamespace, "-l name=echo", helpers.HelperTimeout)
   164  			Expect(err).Should(BeNil())
   165  			clusterIP, _, err := kubectl.GetServiceHostPort(helpers.DefaultNamespace, echoServiceName)
   166  			Expect(err).Should(BeNil(), "Cannot get service %q ClusterIP", echoServiceName)
   167  			Expect(govalidator.IsIP(clusterIP)).Should(BeTrue(), "ClusterIP is not an IP")
   168  
   169  			url := fmt.Sprintf("http://%s/", clusterIP)
   170  			testHTTPRequest(echoPodLabel, url)
   171  		}, 300)
   172  	})
   173  
   174  	Context("Checks service across nodes", func() {
   175  
   176  		var (
   177  			demoYAML = helpers.ManifestGet("demo_ds.yaml")
   178  		)
   179  
   180  		BeforeAll(func() {
   181  			res := kubectl.ApplyDefault(demoYAML)
   182  			res.ExpectSuccess("Unable to apply %s", demoYAML)
   183  		})
   184  
   185  		AfterAll(func() {
   186  			// Explicitly ignore result of deletion of resources to avoid incomplete
   187  			// teardown if any step fails.
   188  			_ = kubectl.Delete(demoYAML)
   189  			ExpectAllPodsTerminated(kubectl)
   190  		})
   191  
   192  		It("Checks ClusterIP Connectivity", func() {
   193  			waitPodsDs()
   194  			service := "testds-service"
   195  
   196  			clusterIP, _, err := kubectl.GetServiceHostPort(helpers.DefaultNamespace, service)
   197  			Expect(err).Should(BeNil(), "Cannot get service %s", service)
   198  			Expect(govalidator.IsIP(clusterIP)).Should(BeTrue(), "ClusterIP is not an IP")
   199  
   200  			url := fmt.Sprintf("http://%s/", clusterIP)
   201  			testHTTPRequest(testDSClient, url)
   202  		})
   203  
   204  		testNodePort := func(bpfNodePort bool) {
   205  			var data v1.Service
   206  			getURL := func(host string, port int32) string {
   207  				return fmt.Sprintf("http://%s",
   208  					net.JoinHostPort(host, fmt.Sprintf("%d", port)))
   209  			}
   210  			doRequests := func(url string, count int) {
   211  				By("Making %d HTTP requests from k8s1 to %q", count, url)
   212  				for i := 1; i <= count; i++ {
   213  					res := kubectl.Exec(helpers.CurlFail(url))
   214  					ExpectWithOffset(1, res).Should(helpers.CMDSuccess(),
   215  						"k8s1 host can not connect to service %q", url)
   216  				}
   217  			}
   218  
   219  			waitPodsDs()
   220  
   221  			err := kubectl.Get(helpers.DefaultNamespace, "service test-nodeport").Unmarshal(&data)
   222  			Expect(err).Should(BeNil(), "Can not retrieve service")
   223  			url := getURL(data.Spec.ClusterIP, data.Spec.Ports[0].Port)
   224  			testHTTPRequest(testDSClient, url)
   225  
   226  			// From host via localhost IP
   227  			// TODO: IPv6
   228  			count := 10
   229  			url = getURL("127.0.0.1", data.Spec.Ports[0].NodePort)
   230  			doRequests(url, count)
   231  
   232  			url = getURL(helpers.K8s1Ip, data.Spec.Ports[0].NodePort)
   233  			doRequests(url, count)
   234  
   235  			url = getURL(helpers.K8s2Ip, data.Spec.Ports[0].NodePort)
   236  			doRequests(url, count)
   237  
   238  			// From pod via node IPs
   239  			url = getURL(helpers.K8s1Ip, data.Spec.Ports[0].NodePort)
   240  			testHTTPRequest(testDSClient, url)
   241  			url = getURL(helpers.K8s2Ip, data.Spec.Ports[0].NodePort)
   242  			testHTTPRequest(testDSClient, url)
   243  
   244  			if bpfNodePort {
   245  				// From host via local cilium_host
   246  				localCiliumHostIPv4, err := kubectl.GetCiliumHostIPv4(context.TODO(), helpers.K8s1)
   247  				Expect(err).Should(BeNil(), "Cannot retrieve local cilium_host ipv4")
   248  				url = getURL(localCiliumHostIPv4, data.Spec.Ports[0].NodePort)
   249  				doRequests(url, count)
   250  
   251  				// From host via remote cilium_host
   252  				remoteCiliumHostIPv4, err := kubectl.GetCiliumHostIPv4(context.TODO(), helpers.K8s2)
   253  				Expect(err).Should(BeNil(), "Cannot retrieve remote cilium_host ipv4")
   254  				url = getURL(remoteCiliumHostIPv4, data.Spec.Ports[0].NodePort)
   255  				doRequests(url, count)
   256  
   257  				// From pod via loopback (host reachable services)
   258  				url = getURL("127.0.0.1", data.Spec.Ports[0].NodePort)
   259  				testHTTPRequest(testDSClient, url)
   260  
   261  				// From pod via local cilium_host
   262  				url = getURL(localCiliumHostIPv4, data.Spec.Ports[0].NodePort)
   263  				testHTTPRequest(testDSClient, url)
   264  
   265  				// From pod via remote cilium_host
   266  				url = getURL(remoteCiliumHostIPv4, data.Spec.Ports[0].NodePort)
   267  				testHTTPRequest(testDSClient, url)
   268  			}
   269  		}
   270  
   271  		It("Tests NodePort (kube-proxy)", func() {
   272  			testNodePort(false)
   273  		})
   274  
   275  		Context("with L7 policy", func() {
   276  			var (
   277  				demoPolicy = helpers.ManifestGet("l7-policy-demo.yaml")
   278  			)
   279  
   280  			AfterAll(func() {
   281  				// Explicitly ignore result of deletion of resources to avoid incomplete
   282  				// teardown if any step fails.
   283  				_ = kubectl.Delete(demoPolicy)
   284  			})
   285  
   286  			It("Tests NodePort with L7 Policy", func() {
   287  				applyPolicy(demoPolicy)
   288  				testNodePort(false)
   289  			})
   290  		})
   291  
   292  		SkipContextIf(helpers.DoesNotRunOnNetNext, "Tests NodePort BPF", func() {
   293  			// TODO(brb) Add with L7 policy test cases after GH#8864 has been merged
   294  
   295  			nativeDev := "enp0s8"
   296  
   297  			BeforeAll(func() {
   298  				enableBackgroundReport = false
   299  			})
   300  
   301  			AfterAll(func() {
   302  				enableBackgroundReport = true
   303  				// Remove NodePort programs (GH#8873)
   304  				pods, err := kubectl.GetCiliumPods(helpers.KubeSystemNamespace)
   305  				Expect(err).To(BeNil(), "Cannot retrieve Cilium pods")
   306  				for _, pod := range pods {
   307  					ret := kubectl.CiliumExec(pod, "tc filter del dev "+nativeDev+" ingress")
   308  					Expect(ret.WasSuccessful()).Should(BeTrue(), "Cannot remove ingress bpf_netdev on %s", pod)
   309  					ret = kubectl.CiliumExec(pod, "tc filter del dev "+nativeDev+" egress")
   310  					Expect(ret.WasSuccessful()).Should(BeTrue(), "Cannot remove egress bpf_netdev on %s", pod)
   311  				}
   312  				deleteCiliumDS(kubectl)
   313  				// Deploy Cilium as the next test expects it to be up and running
   314  				DeployCiliumAndDNS(kubectl)
   315  			})
   316  
   317  			It("Tests with vxlan", func() {
   318  				deleteCiliumDS(kubectl)
   319  
   320  				DeployCiliumOptionsAndDNS(kubectl, []string{
   321  					"--set global.nodePort.enabled=true",
   322  					"--set global.nodePort.device=" + nativeDev,
   323  				})
   324  
   325  				testNodePort(true)
   326  			})
   327  
   328  			It("Tests with direct routing", func() {
   329  				deleteCiliumDS(kubectl)
   330  				DeployCiliumOptionsAndDNS(kubectl, []string{
   331  					"--set global.nodePort.enabled=true",
   332  					"--set global.nodePort.device=" + nativeDev,
   333  					"--set global.tunnel=disabled",
   334  					"--set global.autoDirectNodeRoutes=true",
   335  				})
   336  
   337  				testNodePort(true)
   338  			})
   339  		})
   340  
   341  	})
   342  
   343  	//TODO: Check service with IPV6
   344  
   345  	Context("External services", func() {
   346  
   347  		var (
   348  			expectedCIDR = "198.49.23.144/32"
   349  			podName      = "toservices"
   350  
   351  			endpointPath      = helpers.ManifestGet("external_endpoint.yaml")
   352  			podPath           = helpers.ManifestGet("external_pod.yaml")
   353  			policyPath        = helpers.ManifestGet("external-policy.yaml")
   354  			policyLabeledPath = helpers.ManifestGet("external-policy-labeled.yaml")
   355  			servicePath       = helpers.ManifestGet("external_service.yaml")
   356  		)
   357  
   358  		BeforeAll(func() {
   359  			kubectl.ApplyDefault(servicePath).ExpectSuccess("cannot install external service")
   360  			kubectl.ApplyDefault(podPath).ExpectSuccess("cannot install pod path")
   361  
   362  			err := kubectl.WaitforPods(helpers.DefaultNamespace, "", helpers.HelperTimeout)
   363  			Expect(err).To(BeNil(), "Pods are not ready after timeout")
   364  
   365  			err = kubectl.CiliumEndpointWaitReady()
   366  			Expect(err).To(BeNil(), "Endpoints are not ready after timeout")
   367  		})
   368  
   369  		AfterAll(func() {
   370  			_ = kubectl.Delete(servicePath)
   371  			_ = kubectl.Delete(podPath)
   372  
   373  			ExpectAllPodsTerminated(kubectl)
   374  		})
   375  
   376  		AfterEach(func() {
   377  			_ = kubectl.Delete(policyLabeledPath)
   378  			_ = kubectl.Delete(policyPath)
   379  			_ = kubectl.Delete(endpointPath)
   380  		})
   381  
   382  		validateEgress := func() {
   383  			By("Checking that toServices CIDR is plumbed into CEP")
   384  			Eventually(func() string {
   385  				res := kubectl.Exec(fmt.Sprintf(
   386  					"%s -n %s get cep %s -o json",
   387  					helpers.KubectlCmd,
   388  					helpers.DefaultNamespace,
   389  					podName))
   390  				ExpectWithOffset(1, res).Should(helpers.CMDSuccess(), "cannot get Cilium endpoint")
   391  				data, err := res.Filter(`{.status.policy.egress}`)
   392  				ExpectWithOffset(1, err).To(BeNil(), "unable to get endpoint %s metadata", podName)
   393  				return data.String()
   394  			}, 2*time.Minute, 2*time.Second).Should(ContainSubstring(expectedCIDR))
   395  		}
   396  
   397  		validateEgressAfterDeletion := func() {
   398  			By("Checking that toServices CIDR is no longer plumbed into CEP")
   399  			Eventually(func() string {
   400  				res := kubectl.Exec(fmt.Sprintf(
   401  					"%s -n %s get cep %s -o json",
   402  					helpers.KubectlCmd,
   403  					helpers.DefaultNamespace,
   404  					podName))
   405  				ExpectWithOffset(1, res).Should(helpers.CMDSuccess(), "cannot get Cilium endpoint")
   406  				data, err := res.Filter(`{.status.policy.egress}`)
   407  				ExpectWithOffset(1, err).To(BeNil(), "unable to get endpoint %s metadata", podName)
   408  				return data.String()
   409  			}, 2*time.Minute, 2*time.Second).ShouldNot(ContainSubstring(expectedCIDR))
   410  		}
   411  
   412  		It("To Services first endpoint creation", func() {
   413  			res := kubectl.ApplyDefault(endpointPath)
   414  			res.ExpectSuccess()
   415  
   416  			applyPolicy(policyPath)
   417  			validateEgress()
   418  
   419  			kubectl.Delete(policyPath)
   420  			kubectl.Delete(endpointPath)
   421  			validateEgressAfterDeletion()
   422  		})
   423  
   424  		It("To Services first policy", func() {
   425  			applyPolicy(policyPath)
   426  			res := kubectl.ApplyDefault(endpointPath)
   427  			res.ExpectSuccess()
   428  
   429  			validateEgress()
   430  
   431  			kubectl.Delete(policyPath)
   432  			kubectl.Delete(endpointPath)
   433  			validateEgressAfterDeletion()
   434  		})
   435  
   436  		It("To Services first endpoint creation match service by labels", func() {
   437  			By("Creating Kubernetes Endpoint")
   438  			res := kubectl.ApplyDefault(endpointPath)
   439  			res.ExpectSuccess()
   440  
   441  			applyPolicy(policyLabeledPath)
   442  
   443  			validateEgress()
   444  
   445  			kubectl.Delete(policyLabeledPath)
   446  			kubectl.Delete(endpointPath)
   447  			validateEgressAfterDeletion()
   448  		})
   449  
   450  		It("To Services first policy, match service by labels", func() {
   451  			applyPolicy(policyLabeledPath)
   452  
   453  			By("Creating Kubernetes Endpoint")
   454  			res := kubectl.ApplyDefault(endpointPath)
   455  			res.ExpectSuccess()
   456  
   457  			validateEgress()
   458  
   459  			kubectl.Delete(policyLabeledPath)
   460  			kubectl.Delete(endpointPath)
   461  			validateEgressAfterDeletion()
   462  		})
   463  	})
   464  
   465  	Context("Bookinfo Demo", func() {
   466  
   467  		var (
   468  			bookinfoV1YAML, bookinfoV2YAML string
   469  			resourceYAMLs                  []string
   470  			policyPath                     string
   471  		)
   472  
   473  		BeforeEach(func() {
   474  
   475  			bookinfoV1YAML = helpers.ManifestGet("bookinfo-v1.yaml")
   476  			bookinfoV2YAML = helpers.ManifestGet("bookinfo-v2.yaml")
   477  			policyPath = helpers.ManifestGet("cnp-specs.yaml")
   478  
   479  			resourceYAMLs = []string{bookinfoV1YAML, bookinfoV2YAML}
   480  
   481  			for _, resourcePath := range resourceYAMLs {
   482  				By("Creating objects in file %q", resourcePath)
   483  				res := kubectl.Create(resourcePath)
   484  				res.ExpectSuccess("unable to create resource %q", resourcePath)
   485  			}
   486  		})
   487  
   488  		AfterEach(func() {
   489  
   490  			// Explicitly do not check result to avoid having assertions in AfterEach.
   491  			_ = kubectl.Delete(policyPath)
   492  
   493  			for _, resourcePath := range resourceYAMLs {
   494  				By("Deleting resource %s", resourcePath)
   495  				// Explicitly do not check result to avoid having assertions in AfterEach.
   496  				_ = kubectl.Delete(resourcePath)
   497  			}
   498  		})
   499  
   500  		It("Tests bookinfo demo", func() {
   501  
   502  			// We use wget in this test because the Istio apps do not provide curl.
   503  			wgetCommand := fmt.Sprintf("wget --tries=2 --connect-timeout %d", helpers.CurlConnectTimeout)
   504  
   505  			version := "version"
   506  			v1 := "v1"
   507  
   508  			productPage := "productpage"
   509  			reviews := "reviews"
   510  			ratings := "ratings"
   511  			details := "details"
   512  			dnsChecks := []string{productPage, reviews, ratings, details}
   513  			app := "app"
   514  			health := "health"
   515  			ratingsPath := "ratings/0"
   516  
   517  			apiPort := "9080"
   518  
   519  			podNameFilter := "{.items[*].metadata.name}"
   520  
   521  			// shouldConnect asserts that srcPod can connect to dst.
   522  			shouldConnect := func(srcPod, dst string) {
   523  				By("Checking that %q can connect to %q", srcPod, dst)
   524  				res := kubectl.ExecPodCmd(
   525  					helpers.DefaultNamespace, srcPod, fmt.Sprintf("%s %s", wgetCommand, dst))
   526  				res.ExpectSuccess("Unable to connect from %q to %q", srcPod, dst)
   527  			}
   528  
   529  			// shouldNotConnect asserts that srcPod cannot connect to dst.
   530  			shouldNotConnect := func(srcPod, dst string) {
   531  				By("Checking that %q cannot connect to %q", srcPod, dst)
   532  				res := kubectl.ExecPodCmd(
   533  					helpers.DefaultNamespace, srcPod, fmt.Sprintf("%s %s", wgetCommand, dst))
   534  				res.ExpectFail("Was able to connect from %q to %q, but expected no connection: %s", srcPod, dst, res.CombineOutput())
   535  			}
   536  
   537  			// formatLabelArgument formats the provided key-value pairs as labels for use in
   538  			// querying Kubernetes.
   539  			formatLabelArgument := func(firstKey, firstValue string, nextLabels ...string) string {
   540  				baseString := fmt.Sprintf("-l %s=%s", firstKey, firstValue)
   541  				if nextLabels == nil {
   542  					return baseString
   543  				} else if len(nextLabels)%2 != 0 {
   544  					Fail("must provide even number of arguments for label key-value pairings")
   545  				} else {
   546  					for i := 0; i < len(nextLabels); i += 2 {
   547  						baseString = fmt.Sprintf("%s,%s=%s", baseString, nextLabels[i], nextLabels[i+1])
   548  					}
   549  				}
   550  				return baseString
   551  			}
   552  
   553  			// formatAPI is a helper function which formats a URI to access.
   554  			formatAPI := func(service, port, resource string) string {
   555  				target := fmt.Sprintf(
   556  					"%s.%s.svc.cluster.local:%s",
   557  					service, helpers.DefaultNamespace, port)
   558  				if resource != "" {
   559  					return fmt.Sprintf("%s/%s", target, resource)
   560  				}
   561  				return target
   562  			}
   563  
   564  			By("Waiting for pods to be ready")
   565  			err := kubectl.WaitforPods(helpers.DefaultNamespace, "-l zgroup=bookinfo", helpers.HelperTimeout)
   566  			Expect(err).Should(BeNil(), "Pods are not ready after timeout")
   567  
   568  			err = kubectl.CiliumEndpointWaitReady()
   569  			ExpectWithOffset(1, err).To(BeNil(), "Endpoints are not ready after timeout")
   570  
   571  			By("Waiting for services to be ready")
   572  			for _, service := range []string{details, ratings, reviews, productPage} {
   573  				err = kubectl.WaitForServiceEndpoints(
   574  					helpers.DefaultNamespace, "", service,
   575  					helpers.HelperTimeout)
   576  				Expect(err).Should(BeNil(), "Service %q is not ready after timeout", service)
   577  			}
   578  			By("Validating DNS without Policy")
   579  			for _, name := range dnsChecks {
   580  				err = kubectl.WaitForKubeDNSEntry(name, helpers.DefaultNamespace)
   581  				Expect(err).To(BeNil(), "DNS entry is not ready after timeout")
   582  			}
   583  
   584  			By("All pods should be able to connect without policy")
   585  
   586  			reviewsPodV1, err := kubectl.GetPods(helpers.DefaultNamespace, formatLabelArgument(app, reviews, version, v1)).Filter(podNameFilter)
   587  			Expect(err).Should(BeNil(), "cannot get reviewsV1 pods")
   588  			productpagePodV1, err := kubectl.GetPods(helpers.DefaultNamespace, formatLabelArgument(app, productPage, version, v1)).Filter(podNameFilter)
   589  			Expect(err).Should(BeNil(), "cannot get productpageV1 pods")
   590  
   591  			shouldConnect(reviewsPodV1.String(), formatAPI(ratings, apiPort, health))
   592  			shouldConnect(reviewsPodV1.String(), formatAPI(ratings, apiPort, ratingsPath))
   593  
   594  			shouldConnect(productpagePodV1.String(), formatAPI(details, apiPort, health))
   595  			shouldConnect(productpagePodV1.String(), formatAPI(ratings, apiPort, health))
   596  			shouldConnect(productpagePodV1.String(), formatAPI(ratings, apiPort, ratingsPath))
   597  
   598  			policyCmd := "cilium policy get io.cilium.k8s.policy.name=cnp-specs"
   599  
   600  			By("Importing policy")
   601  
   602  			_, err = kubectl.CiliumPolicyAction(helpers.DefaultNamespace, policyPath, helpers.KubectlCreate, helpers.HelperTimeout)
   603  			Expect(err).Should(BeNil(), "Error creating policy %q", policyPath)
   604  
   605  			By("Checking that policies were correctly imported into Cilium")
   606  
   607  			ciliumPodK8s1, err = kubectl.GetCiliumPodOnNode(helpers.KubeSystemNamespace, helpers.K8s1)
   608  			Expect(err).Should(BeNil(), "Cannot get cilium pod on k8s1")
   609  			res := kubectl.ExecPodCmd(helpers.KubeSystemNamespace, ciliumPodK8s1, policyCmd)
   610  			res.ExpectSuccess("Policy %s is not imported", policyCmd)
   611  
   612  			By("Validating DNS with Policy loaded")
   613  			for _, name := range dnsChecks {
   614  				err = kubectl.WaitForKubeDNSEntry(name, helpers.DefaultNamespace)
   615  				Expect(err).To(BeNil(), "DNS entry is not ready after timeout")
   616  			}
   617  
   618  			By("After policy import")
   619  			shouldConnect(reviewsPodV1.String(), formatAPI(ratings, apiPort, health))
   620  			shouldNotConnect(reviewsPodV1.String(), formatAPI(ratings, apiPort, ratingsPath))
   621  
   622  			shouldConnect(productpagePodV1.String(), formatAPI(details, apiPort, health))
   623  
   624  			shouldNotConnect(productpagePodV1.String(), formatAPI(ratings, apiPort, health))
   625  			shouldNotConnect(productpagePodV1.String(), formatAPI(ratings, apiPort, ratingsPath))
   626  		})
   627  	})
   628  })