github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/verify-install/istio/istio_test.go (about)

     1  // Copyright (c) 2020, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package istio
     5  
     6  import (
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/Jeffail/gabs/v2"
    11  	. "github.com/onsi/ginkgo/v2"
    12  	. "github.com/onsi/gomega"
    13  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    14  	vzapi "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1"
    15  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    16  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework"
    17  	appsv1 "k8s.io/api/apps/v1"
    18  	corev1 "k8s.io/api/core/v1"
    19  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    20  	"k8s.io/apimachinery/pkg/labels"
    21  	"k8s.io/apimachinery/pkg/types"
    22  )
    23  
    24  const (
    25  	waitTimeout     = 3 * time.Minute
    26  	pollingInterval = 10 * time.Second
    27  )
    28  
    29  var t = framework.NewTestFramework("istio")
    30  
    31  var _ = t.AfterEach(func() {})
    32  
    33  var _ = t.Describe("Istio", Label("f:platform-lcm.install"), func() {
    34  	const istioNamespace = "istio-system"
    35  
    36  	t.It("has affinity configured on istiod pods", func() {
    37  		var pods []corev1.Pod
    38  		var err error
    39  		Eventually(func() bool {
    40  			pods, err = pkg.GetPodsFromSelector(&metav1.LabelSelector{MatchLabels: map[string]string{"app": "istiod"}}, istioNamespace)
    41  			if err != nil {
    42  				t.Logs.Error("Failed to get Istiod pods: %v", err)
    43  				return false
    44  			}
    45  			if len(pods) < 1 {
    46  				return false
    47  			}
    48  			return true
    49  		}, waitTimeout, pollingInterval).Should(BeTrue())
    50  		for _, pod := range pods {
    51  			affinity := pod.Spec.Affinity
    52  			Expect(affinity).ToNot(BeNil())
    53  			Expect(affinity.PodAffinity).To(BeNil())
    54  			Expect(affinity.NodeAffinity).To(BeNil())
    55  			Expect(affinity.PodAntiAffinity).ToNot(BeNil())
    56  			Expect(len(affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution)).To(Equal(1))
    57  		}
    58  	})
    59  
    60  	t.DescribeTable("namespace",
    61  		func(name string) {
    62  			Eventually(func() (bool, error) {
    63  				return pkg.DoesNamespaceExist(name)
    64  			}, waitTimeout, pollingInterval).Should(BeTrue())
    65  		},
    66  		t.Entry(fmt.Sprintf("%s namespace should exist", istioNamespace), istioNamespace),
    67  	)
    68  
    69  	expectedDeployments := []string{
    70  		"istio-egressgateway",
    71  		"istio-ingressgateway",
    72  		"istiod",
    73  	}
    74  
    75  	t.DescribeTable("deployments",
    76  		func(namespace string) {
    77  
    78  			deploymentNames := func(deploymentList *appsv1.DeploymentList) []string {
    79  				var deploymentNames []string
    80  				for _, deployment := range deploymentList.Items {
    81  					deploymentNames = append(deploymentNames, deployment.Name)
    82  				}
    83  				return deploymentNames
    84  			}
    85  
    86  			var deployments *appsv1.DeploymentList
    87  			Eventually(func() (*appsv1.DeploymentList, error) {
    88  				var err error
    89  				deployments, err = pkg.ListDeployments(namespace)
    90  				return deployments, err
    91  			}, waitTimeout, pollingInterval).ShouldNot(BeNil())
    92  
    93  			Expect(deployments).Should(WithTransform(deploymentNames, ContainElements(expectedDeployments)))
    94  		},
    95  		t.Entry(fmt.Sprintf("%s namespace should contain expected list of deployments", istioNamespace), istioNamespace),
    96  	)
    97  
    98  	t.DescribeTable("Verify expected replica counts",
    99  		func(namespace string) {
   100  
   101  			// Verify the correct number of pods for each deployment based on the profile & any overrides
   102  
   103  			kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
   104  			if err != nil {
   105  				Fail(err.Error())
   106  			}
   107  
   108  			vz, err := pkg.GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   109  			if err != nil {
   110  				Fail(err.Error())
   111  			}
   112  
   113  			deployments := []types.NamespacedName{
   114  				{Name: "istio-egressgateway", Namespace: namespace},
   115  				{Name: "istio-ingressgateway", Namespace: namespace},
   116  				{Name: "istiod", Namespace: namespace},
   117  			}
   118  			expectedPods := map[string]uint32{
   119  				deployments[0].String(): getEgressReplicaCount(vz),
   120  				deployments[1].String(): getIngressReplicaCount(vz),
   121  				deployments[2].String(): getPilotReplicaCount(vz),
   122  			}
   123  			t.Logs.Infof("Expected replica counts: %v", expectedPods)
   124  
   125  			Eventually(func() (map[string]uint32, error) {
   126  				return pkg.GetReplicaCounts(deployments, buildListOpts)
   127  			}, waitTimeout, pollingInterval).Should(Equal(expectedPods))
   128  		},
   129  		t.Entry(fmt.Sprintf("%s namespace should contain expected pod counts", istioNamespace), istioNamespace),
   130  	)
   131  })
   132  
   133  func buildListOpts(name types.NamespacedName) (metav1.ListOptions, error) {
   134  	selector := metav1.LabelSelector{
   135  		MatchLabels: map[string]string{
   136  			"app": name.Name,
   137  		},
   138  	}
   139  	labelMap, err := metav1.LabelSelectorAsMap(&selector)
   140  	if err != nil {
   141  		return metav1.ListOptions{}, err
   142  	}
   143  	listOpts := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labelMap).String()}
   144  	return listOpts, nil
   145  }
   146  
   147  func getIngressReplicaCount(vz *vzapi.Verrazzano) uint32 {
   148  	istio := vz.Spec.Components.Istio
   149  	if istio != nil {
   150  		if !isIstioEnabled(istio) {
   151  			return 0
   152  		}
   153  		return extractIstioSubComponentReplicas(istio.ValueOverrides, "spec.components.egressGateways.0.k8s.replicaCount")
   154  	}
   155  	return 1
   156  }
   157  
   158  func getEgressReplicaCount(vz *vzapi.Verrazzano) uint32 {
   159  	istio := vz.Spec.Components.Istio
   160  	if istio != nil {
   161  		if !isIstioEnabled(istio) {
   162  			return 0
   163  		}
   164  		return extractIstioSubComponentReplicas(istio.ValueOverrides, "spec.components.ingressGateways.0.k8s.replicaCount")
   165  	}
   166  	return 1
   167  }
   168  
   169  func getPilotReplicaCount(vz *vzapi.Verrazzano) uint32 {
   170  	istio := vz.Spec.Components.Istio
   171  	if istio != nil {
   172  		if !isIstioEnabled(istio) {
   173  			return 0
   174  		}
   175  		return extractIstioSubComponentReplicas(istio.ValueOverrides, "spec.components.pilot.k8s.replicaCount")
   176  	}
   177  	return 1
   178  }
   179  
   180  func extractIstioSubComponentReplicas(overrides []vzapi.Overrides, jsonPath string) uint32 {
   181  	for _, override := range overrides {
   182  		if override.Values != nil {
   183  			jsonString, err := gabs.ParseJSON(override.Values.Raw)
   184  			if err != nil {
   185  				return 1
   186  			}
   187  			if container := jsonString.Path(jsonPath); container != nil {
   188  				if val, ok := container.Data().(float64); ok {
   189  					return uint32(val)
   190  				}
   191  			}
   192  		}
   193  	}
   194  	return 1
   195  }
   196  
   197  func isIstioEnabled(istio *vzapi.IstioComponent) bool {
   198  	if istio.Enabled != nil {
   199  		return *istio.Enabled
   200  	}
   201  	return true
   202  }