github.com/solo-io/service-mesh-hub@v0.9.2/test/e2e/istio/failover_service_test.go (about)

     1  package istio_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	. "github.com/onsi/gomega"
     9  	networkingv1alpha2 "github.com/solo-io/service-mesh-hub/pkg/api/networking.smh.solo.io/v1alpha2"
    10  	"github.com/solo-io/service-mesh-hub/test/e2e"
    11  	"github.com/solo-io/service-mesh-hub/test/utils"
    12  	v1 "github.com/solo-io/skv2/pkg/api/core.skv2.solo.io/v1"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  )
    15  
    16  var _ = Describe("FailoverService", func() {
    17  	var (
    18  		err                    error
    19  		manifest               utils.Manifest
    20  		ctx                    = context.Background()
    21  		failoverServiceObjMeta = metav1.ObjectMeta{
    22  			Name:      "reviews-failover",
    23  			Namespace: BookinfoNamespace,
    24  		}
    25  	)
    26  
    27  	AfterEach(func() {
    28  		manifest.Cleanup(BookinfoNamespace)
    29  		// Ensure restoring bookinfo containers if test fails.
    30  		env := e2e.GetEnv()
    31  		env.Management.EnableContainer(ctx, BookinfoNamespace, "reviews-v1")
    32  		env.Management.EnableContainer(ctx, BookinfoNamespace, "reviews-v2")
    33  		env.Management.WaitForRollout(ctx, BookinfoNamespace, "reviews-v1")
    34  		env.Management.WaitForRollout(ctx, BookinfoNamespace, "reviews-v2")
    35  	})
    36  
    37  	It("should create a failover service", func() {
    38  		manifest, err = utils.NewManifest("failover_service_test_manifest.yaml")
    39  		Expect(err).ToNot(HaveOccurred())
    40  		env := e2e.GetEnv()
    41  
    42  		failoverServiceHostname := "reviews-failover.bookinfo.global"
    43  		curlFailoverService := func() string {
    44  			return curlFromProductpage(fmt.Sprintf("http://%s:9080/reviews/1", failoverServiceHostname))
    45  		}
    46  
    47  		By("creating a new FailoverService with the prerequisite TrafficPolicy and VirtualMesh", func() {
    48  			trafficPolicy := &networkingv1alpha2.TrafficPolicy{
    49  				TypeMeta: metav1.TypeMeta{
    50  					Kind:       "TrafficPolicy",
    51  					APIVersion: networkingv1alpha2.SchemeGroupVersion.String(),
    52  				},
    53  				ObjectMeta: metav1.ObjectMeta{
    54  					Name:      "reviews-outlier-detection",
    55  					Namespace: BookinfoNamespace,
    56  				},
    57  				Spec: networkingv1alpha2.TrafficPolicySpec{
    58  					DestinationSelector: []*networkingv1alpha2.TrafficTargetSelector{
    59  						{
    60  							KubeServiceRefs: &networkingv1alpha2.TrafficTargetSelector_KubeServiceRefs{
    61  								Services: []*v1.ClusterObjectRef{
    62  									{
    63  										Name:        "reviews",
    64  										Namespace:   BookinfoNamespace,
    65  										ClusterName: mgmtClusterName,
    66  									},
    67  									{
    68  										Name:        "reviews",
    69  										Namespace:   BookinfoNamespace,
    70  										ClusterName: remoteClusterName,
    71  									},
    72  								},
    73  							},
    74  						},
    75  					},
    76  					OutlierDetection: &networkingv1alpha2.TrafficPolicySpec_OutlierDetection{
    77  						ConsecutiveErrors: 1,
    78  					},
    79  				},
    80  			}
    81  			failoverService := &networkingv1alpha2.FailoverService{
    82  				TypeMeta: metav1.TypeMeta{
    83  					Kind:       "FailoverService",
    84  					APIVersion: networkingv1alpha2.SchemeGroupVersion.String(),
    85  				},
    86  				ObjectMeta: failoverServiceObjMeta,
    87  				Spec: networkingv1alpha2.FailoverServiceSpec{
    88  					Hostname: failoverServiceHostname,
    89  					Port: &networkingv1alpha2.FailoverServiceSpec_Port{
    90  						Number:   9080,
    91  						Protocol: "http",
    92  					},
    93  					Meshes: []*v1.ObjectRef{
    94  						masterMesh,
    95  					},
    96  					BackingServices: []*networkingv1alpha2.FailoverServiceSpec_BackingService{
    97  						{
    98  							BackingServiceType: &networkingv1alpha2.FailoverServiceSpec_BackingService_KubeService{
    99  								KubeService: &v1.ClusterObjectRef{
   100  									Name:        "reviews",
   101  									Namespace:   BookinfoNamespace,
   102  									ClusterName: mgmtClusterName,
   103  								},
   104  							},
   105  						},
   106  						{
   107  							BackingServiceType: &networkingv1alpha2.FailoverServiceSpec_BackingService_KubeService{
   108  								KubeService: &v1.ClusterObjectRef{
   109  									Name:        "reviews",
   110  									Namespace:   BookinfoNamespace,
   111  									ClusterName: remoteClusterName,
   112  								},
   113  							},
   114  						},
   115  					},
   116  				},
   117  			}
   118  
   119  			err := manifest.AppendResources(trafficPolicy)
   120  			Expect(err).NotTo(HaveOccurred())
   121  			err = manifest.KubeApply(BookinfoNamespace)
   122  			Expect(err).NotTo(HaveOccurred())
   123  			// Wait for TrafficPolicy with outlier detection to be processed before creating FailoverService.
   124  			utils.AssertTrafficPolicyStatuses(dynamicClient, BookinfoNamespace)
   125  
   126  			err = manifest.AppendResources(failoverService)
   127  			Expect(err).NotTo(HaveOccurred())
   128  			err = manifest.KubeApply(BookinfoNamespace)
   129  			Expect(err).NotTo(HaveOccurred())
   130  
   131  			// Make it failover to remote cluster with reviews-v3, disable all master cluster reviews pods to prove
   132  			// that request is being served by remote cluster
   133  			env.Management.DisableContainer(ctx, BookinfoNamespace, "reviews-v1", "reviews")
   134  			env.Management.DisableContainer(ctx, BookinfoNamespace, "reviews-v2", "reviews")
   135  			env.Management.WaitForRollout(ctx, BookinfoNamespace, "reviews-v1")
   136  			env.Management.WaitForRollout(ctx, BookinfoNamespace, "reviews-v2")
   137  
   138  			// first check that we have a response to reduce flakiness
   139  			Eventually(curlFailoverService, "1m", "1s").Should(ContainSubstring("200 OK"))
   140  		})
   141  
   142  		By("setting a TrafficShift to redirect traffic to the FailoverService", func() {
   143  			trafficPolicy := &networkingv1alpha2.TrafficPolicy{
   144  				TypeMeta: metav1.TypeMeta{
   145  					Kind:       "TrafficPolicy",
   146  					APIVersion: networkingv1alpha2.SchemeGroupVersion.String(),
   147  				},
   148  				ObjectMeta: metav1.ObjectMeta{
   149  					Name:      "reviews-shift-failover",
   150  					Namespace: BookinfoNamespace,
   151  				},
   152  				Spec: networkingv1alpha2.TrafficPolicySpec{
   153  					DestinationSelector: []*networkingv1alpha2.TrafficTargetSelector{
   154  						{
   155  							KubeServiceRefs: &networkingv1alpha2.TrafficTargetSelector_KubeServiceRefs{
   156  								Services: []*v1.ClusterObjectRef{
   157  									{
   158  										Name:        "reviews",
   159  										Namespace:   BookinfoNamespace,
   160  										ClusterName: mgmtClusterName,
   161  									},
   162  								},
   163  							},
   164  						},
   165  					},
   166  					TrafficShift: &networkingv1alpha2.TrafficPolicySpec_MultiDestination{
   167  						Destinations: []*networkingv1alpha2.TrafficPolicySpec_MultiDestination_WeightedDestination{
   168  							{
   169  								DestinationType: &networkingv1alpha2.TrafficPolicySpec_MultiDestination_WeightedDestination_FailoverService{
   170  									FailoverService: &networkingv1alpha2.TrafficPolicySpec_MultiDestination_WeightedDestination_FailoverServiceDestination{
   171  										Name:      failoverServiceObjMeta.Name,
   172  										Namespace: failoverServiceObjMeta.Namespace,
   173  									},
   174  								},
   175  							},
   176  						},
   177  					},
   178  				},
   179  			}
   180  			err := manifest.AppendResources(trafficPolicy)
   181  			Expect(err).NotTo(HaveOccurred())
   182  			err = manifest.KubeApply(BookinfoNamespace)
   183  			Expect(err).NotTo(HaveOccurred())
   184  			utils.AssertTrafficPolicyStatuses(dynamicClient, BookinfoNamespace)
   185  
   186  			// reviews-v3 is only deployed on remote cluster, so receiving a response proves that the FailoverService is working
   187  			Eventually(curlReviews, "1m", "1s").Should(ContainSubstring(`"color": "red"`))
   188  		})
   189  
   190  		By("re-enable management-plane reviews deployments", func() {
   191  			err := manifest.KubeDelete(BookinfoNamespace)
   192  			Expect(err).NotTo(HaveOccurred())
   193  
   194  			env.Management.EnableContainer(ctx, BookinfoNamespace, "reviews-v1")
   195  			env.Management.EnableContainer(ctx, BookinfoNamespace, "reviews-v2")
   196  			env.Management.WaitForRollout(ctx, BookinfoNamespace, "reviews-v1")
   197  			env.Management.WaitForRollout(ctx, BookinfoNamespace, "reviews-v2")
   198  			Eventually(curlReviews, "1m", "1s").Should(ContainSubstring("200 OK"))
   199  		})
   200  	})
   201  })