From c3656643e9225882b4eb067e41cc345cd69fc254 Mon Sep 17 00:00:00 2001
From: Shriram Sharma <shriram_sharma@intuit.com>
Date: Thu, 19 May 2022 16:01:04 -0700
Subject: [PATCH] Fixes #104 (#217)

exposed outlierDetection configuration through GTP

Signed-off-by: Shriram Sharma <shriram_sharma@intuit.com>
Signed-off-by: sa <sushanth_a@intuit.com>
---
 .../apis/admiral/model/globalrouting.pb.go    | 129 +++++++++---
 .../apis/admiral/model/globalrouting.proto    |  17 ++
 admiral/pkg/clusters/handler.go               |  31 ++-
 admiral/pkg/clusters/handler_test.go          | 185 ++++++++++++++----
 go.mod                                        |   2 +-
 5 files changed, 295 insertions(+), 69 deletions(-)

diff --git a/admiral/pkg/apis/admiral/model/globalrouting.pb.go b/admiral/pkg/apis/admiral/model/globalrouting.pb.go
index 12257ede0..33b4dbf92 100644
--- a/admiral/pkg/apis/admiral/model/globalrouting.pb.go
+++ b/admiral/pkg/apis/admiral/model/globalrouting.pb.go
@@ -111,10 +111,12 @@ type TrafficPolicy struct {
 	Target []*TrafficGroup `protobuf:"bytes,3,rep,name=target,proto3" json:"target,omitempty"`
 	//REQUIRED: dnsPrefix that will be prefixed for the service names being generated with this traffic policy
 	//Ex: dnsPrefix = west => generated service name = west.stage.servicename.global
-	DnsPrefix            string   `protobuf:"bytes,4,opt,name=dnsPrefix,proto3" json:"dnsPrefix,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
+	DnsPrefix string `protobuf:"bytes,4,opt,name=dnsPrefix,proto3" json:"dnsPrefix,omitempty"`
+	//OPTIONAL: to configure the outlierDetection in DestinationRule
+	OutlierDetection     *TrafficPolicy_OutlierDetection `protobuf:"bytes,5,opt,name=outlier_detection,json=outlierDetection,proto3" json:"outlier_detection,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}                        `json:"-"`
+	XXX_unrecognized     []byte                          `json:"-"`
+	XXX_sizecache        int32                           `json:"-"`
 }
 
 func (m *TrafficPolicy) Reset()         { *m = TrafficPolicy{} }
@@ -171,6 +173,71 @@ func (m *TrafficPolicy) GetDnsPrefix() string {
 	return ""
 }
 
+func (m *TrafficPolicy) GetOutlierDetection() *TrafficPolicy_OutlierDetection {
+	if m != nil {
+		return m.OutlierDetection
+	}
+	return nil
+}
+
+type TrafficPolicy_OutlierDetection struct {
+	//REQUIRED: Minimum duration of time in seconds, the endpoint will be ejected
+	BaseEjectionTime int64 `protobuf:"varint,1,opt,name=base_ejection_time,json=baseEjectionTime,proto3" json:"base_ejection_time,omitempty"`
+	//REQUIRED: No. of consecutive failures in specified interval after which the endpoint will be ejected
+	ConsecutiveGatewayErrors uint32 `protobuf:"varint,2,opt,name=consecutive_gateway_errors,json=consecutiveGatewayErrors,proto3" json:"consecutive_gateway_errors,omitempty"`
+	//REQUIRED: Time interval between ejection sweep analysis
+	Interval             int64    `protobuf:"varint,3,opt,name=interval,proto3" json:"interval,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *TrafficPolicy_OutlierDetection) Reset()         { *m = TrafficPolicy_OutlierDetection{} }
+func (m *TrafficPolicy_OutlierDetection) String() string { return proto.CompactTextString(m) }
+func (*TrafficPolicy_OutlierDetection) ProtoMessage()    {}
+func (*TrafficPolicy_OutlierDetection) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a5c0dc509add6f4f, []int{1, 0}
+}
+
+func (m *TrafficPolicy_OutlierDetection) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_TrafficPolicy_OutlierDetection.Unmarshal(m, b)
+}
+func (m *TrafficPolicy_OutlierDetection) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_TrafficPolicy_OutlierDetection.Marshal(b, m, deterministic)
+}
+func (m *TrafficPolicy_OutlierDetection) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_TrafficPolicy_OutlierDetection.Merge(m, src)
+}
+func (m *TrafficPolicy_OutlierDetection) XXX_Size() int {
+	return xxx_messageInfo_TrafficPolicy_OutlierDetection.Size(m)
+}
+func (m *TrafficPolicy_OutlierDetection) XXX_DiscardUnknown() {
+	xxx_messageInfo_TrafficPolicy_OutlierDetection.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_TrafficPolicy_OutlierDetection proto.InternalMessageInfo
+
+func (m *TrafficPolicy_OutlierDetection) GetBaseEjectionTime() int64 {
+	if m != nil {
+		return m.BaseEjectionTime
+	}
+	return 0
+}
+
+func (m *TrafficPolicy_OutlierDetection) GetConsecutiveGatewayErrors() uint32 {
+	if m != nil {
+		return m.ConsecutiveGatewayErrors
+	}
+	return 0
+}
+
+func (m *TrafficPolicy_OutlierDetection) GetInterval() int64 {
+	if m != nil {
+		return m.Interval
+	}
+	return 0
+}
+
 type TrafficGroup struct {
 	//region for the traffic
 	Region string `protobuf:"bytes,1,opt,name=region,proto3" json:"region,omitempty"`
@@ -225,33 +292,41 @@ func init() {
 	proto.RegisterType((*GlobalTrafficPolicy)(nil), "admiral.global.v1alpha.GlobalTrafficPolicy")
 	proto.RegisterMapType((map[string]string)(nil), "admiral.global.v1alpha.GlobalTrafficPolicy.SelectorEntry")
 	proto.RegisterType((*TrafficPolicy)(nil), "admiral.global.v1alpha.TrafficPolicy")
+	proto.RegisterType((*TrafficPolicy_OutlierDetection)(nil), "admiral.global.v1alpha.TrafficPolicy.OutlierDetection")
 	proto.RegisterType((*TrafficGroup)(nil), "admiral.global.v1alpha.TrafficGroup")
 }
 
 func init() { proto.RegisterFile("globalrouting.proto", fileDescriptor_a5c0dc509add6f4f) }
 
 var fileDescriptor_a5c0dc509add6f4f = []byte{
-	// 346 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4f, 0x4b, 0xeb, 0x40,
-	0x14, 0xc5, 0x5f, 0x92, 0xd7, 0xbc, 0xf6, 0xbe, 0x56, 0xca, 0xb4, 0x94, 0x20, 0x2e, 0x24, 0x54,
-	0xe8, 0x42, 0x02, 0xd6, 0x8d, 0xff, 0xc1, 0x62, 0x2d, 0x42, 0x21, 0x65, 0xac, 0x82, 0xee, 0xa6,
-	0xcd, 0x34, 0x1d, 0x9c, 0x66, 0xc2, 0x74, 0x5a, 0xed, 0x37, 0x76, 0xe3, 0x77, 0x90, 0x4c, 0x06,
-	0xb5, 0x50, 0xd1, 0xdd, 0x3d, 0xe7, 0x72, 0x7e, 0x37, 0x27, 0x0c, 0xd4, 0x62, 0x2e, 0x46, 0x84,
-	0x4b, 0xb1, 0x50, 0x2c, 0x89, 0x83, 0x54, 0x0a, 0x25, 0x50, 0x83, 0x44, 0x33, 0x26, 0x09, 0x0f,
-	0xf2, 0x65, 0xb0, 0x3c, 0x20, 0x3c, 0x9d, 0x12, 0xff, 0xd5, 0x82, 0x5a, 0x4f, 0x5b, 0x43, 0x49,
-	0x26, 0x13, 0x36, 0x1e, 0x08, 0xce, 0xc6, 0x2b, 0x74, 0x0e, 0x6e, 0xaa, 0x27, 0xcf, 0xda, 0x75,
-	0x5a, 0xff, 0xdb, 0x7b, 0xc1, 0x66, 0x40, 0xb0, 0x16, 0xc3, 0x26, 0x84, 0xee, 0xa0, 0x38, 0xa7,
-	0x9c, 0x8e, 0x95, 0x90, 0x9e, 0xad, 0x01, 0xc7, 0xdf, 0x01, 0x36, 0x5c, 0x0f, 0x6e, 0x4d, 0xb6,
-	0x9b, 0x28, 0xb9, 0xc2, 0x1f, 0xa8, 0xed, 0x53, 0xa8, 0xac, 0xad, 0x50, 0x15, 0x9c, 0x27, 0x9a,
-	0x7d, 0xa3, 0xd5, 0x2a, 0xe1, 0x6c, 0x44, 0x75, 0x28, 0x2c, 0x09, 0x5f, 0x50, 0xcf, 0xd6, 0x5e,
-	0x2e, 0x4e, 0xec, 0x23, 0xcb, 0x7f, 0xb3, 0xa0, 0xb2, 0x5e, 0xb2, 0x0e, 0x4e, 0x94, 0xcc, 0xf3,
-	0x74, 0xc7, 0xf6, 0x2c, 0x9c, 0x49, 0x74, 0x05, 0x2e, 0x1f, 0x0d, 0x57, 0x69, 0x8e, 0xd8, 0x6a,
-	0xef, 0xff, 0xaa, 0x7a, 0xd0, 0xd7, 0x19, 0x6c, 0xb2, 0xe8, 0x0c, 0x5c, 0x45, 0x64, 0x4c, 0x95,
-	0xe7, 0xe8, 0xfe, 0xcd, 0x1f, 0x28, 0x3d, 0x29, 0x16, 0x29, 0x36, 0x19, 0xb4, 0x03, 0xa5, 0x28,
-	0x99, 0x0f, 0x24, 0x9d, 0xb0, 0x17, 0xef, 0xaf, 0x6e, 0xf2, 0x69, 0xf8, 0x4d, 0x70, 0xf3, 0x6b,
-	0xa8, 0x0c, 0xc5, 0x61, 0x38, 0x08, 0xfb, 0x61, 0xef, 0xa1, 0xfa, 0x27, 0x53, 0xd7, 0x97, 0x37,
-	0xfd, 0xf0, 0xbe, 0x8b, 0xab, 0x96, 0x7f, 0x01, 0xe5, 0xaf, 0x6c, 0xd4, 0x00, 0x57, 0xd2, 0x98,
-	0x89, 0xc4, 0xfc, 0x2e, 0xa3, 0x32, 0xff, 0x99, 0xb2, 0x78, 0xaa, 0x74, 0xdf, 0x02, 0x36, 0xaa,
-	0xf3, 0xef, 0xb1, 0x30, 0x13, 0x11, 0xe5, 0x23, 0x57, 0x3f, 0xa1, 0xc3, 0xf7, 0x00, 0x00, 0x00,
-	0xff, 0xff, 0x22, 0x4e, 0xd6, 0x22, 0x59, 0x02, 0x00, 0x00,
+	// 463 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x5d, 0x6b, 0xdb, 0x30,
+	0x14, 0x9d, 0xe3, 0xc5, 0x4b, 0x6f, 0x9b, 0xe1, 0xa9, 0xa5, 0x88, 0xb0, 0x87, 0x12, 0x3a, 0xc8,
+	0x43, 0x31, 0x2c, 0x83, 0xb1, 0x6f, 0x58, 0x69, 0x16, 0x06, 0x81, 0x04, 0x2d, 0x1b, 0x6c, 0x2f,
+	0x46, 0xb1, 0x6f, 0x5c, 0x6d, 0x8a, 0x65, 0x64, 0x39, 0x5d, 0xfe, 0xca, 0x7e, 0xe1, 0xde, 0xf6,
+	0x17, 0x86, 0x25, 0xaf, 0x6b, 0x4a, 0xc7, 0xfa, 0xa6, 0x73, 0x8e, 0xce, 0xd1, 0xbd, 0x07, 0x1b,
+	0xf6, 0x33, 0xa9, 0x16, 0x5c, 0x6a, 0x55, 0x19, 0x91, 0x67, 0x51, 0xa1, 0x95, 0x51, 0xe4, 0x90,
+	0xa7, 0x2b, 0xa1, 0xb9, 0x8c, 0x9c, 0x18, 0xad, 0x1f, 0x73, 0x59, 0x9c, 0xf3, 0xfe, 0x4f, 0x0f,
+	0xf6, 0xc7, 0x96, 0x9a, 0x6b, 0xbe, 0x5c, 0x8a, 0x64, 0xa6, 0xa4, 0x48, 0x36, 0xe4, 0x35, 0x04,
+	0x85, 0x3d, 0x51, 0xef, 0xc8, 0x1f, 0xec, 0x0e, 0x1f, 0x45, 0x37, 0x07, 0x44, 0x5b, 0x36, 0xd6,
+	0x98, 0xc8, 0x47, 0xe8, 0x94, 0x28, 0x31, 0x31, 0x4a, 0xd3, 0x96, 0x0d, 0x78, 0xfe, 0xaf, 0x80,
+	0x1b, 0x5e, 0x8f, 0x3e, 0x34, 0xde, 0x51, 0x6e, 0xf4, 0x86, 0x5d, 0x46, 0xf5, 0x5e, 0x42, 0x77,
+	0x4b, 0x22, 0x21, 0xf8, 0xdf, 0xb0, 0x9e, 0xd1, 0x1b, 0xec, 0xb0, 0xfa, 0x48, 0x0e, 0xa0, 0xbd,
+	0xe6, 0xb2, 0x42, 0xda, 0xb2, 0x9c, 0x03, 0x2f, 0x5a, 0xcf, 0xbc, 0xfe, 0x2f, 0x1f, 0xba, 0xdb,
+	0x4b, 0x1e, 0x80, 0x9f, 0xe6, 0xa5, 0x73, 0x9f, 0xb6, 0xa8, 0xc7, 0x6a, 0x48, 0xce, 0x20, 0x90,
+	0x8b, 0xf9, 0xa6, 0x70, 0x11, 0xf7, 0x87, 0x27, 0xb7, 0x5a, 0x3d, 0x9a, 0x58, 0x0f, 0x6b, 0xbc,
+	0xe4, 0x15, 0x04, 0x86, 0xeb, 0x0c, 0x0d, 0xf5, 0xed, 0xfe, 0xc7, 0xff, 0x49, 0x19, 0x6b, 0x55,
+	0x15, 0xac, 0xf1, 0x90, 0x87, 0xb0, 0x93, 0xe6, 0xe5, 0x4c, 0xe3, 0x52, 0x7c, 0xa7, 0x77, 0xed,
+	0x26, 0x7f, 0x09, 0x92, 0xc0, 0x03, 0x55, 0x19, 0x29, 0x50, 0xc7, 0x29, 0x1a, 0x4c, 0x8c, 0x50,
+	0x39, 0x6d, 0x1f, 0x79, 0x83, 0xdd, 0xe1, 0xd3, 0xdb, 0x0d, 0x3b, 0x75, 0xf6, 0xb3, 0x3f, 0x6e,
+	0x16, 0xaa, 0x6b, 0x4c, 0xef, 0x87, 0x07, 0xe1, 0xf5, 0x6b, 0xe4, 0x04, 0xc8, 0x82, 0x97, 0x18,
+	0xe3, 0x57, 0x47, 0xc4, 0x46, 0xac, 0xd0, 0x16, 0xe8, 0xb3, 0xb0, 0x56, 0x46, 0x8d, 0x30, 0x17,
+	0xab, 0xba, 0x83, 0x5e, 0xa2, 0xf2, 0x12, 0x93, 0xca, 0x88, 0x35, 0xc6, 0x19, 0x37, 0x78, 0xc1,
+	0x37, 0x31, 0x6a, 0xad, 0x74, 0x69, 0xdb, 0xed, 0x32, 0x7a, 0xe5, 0xc6, 0xd8, 0x5d, 0x18, 0x59,
+	0x9d, 0xf4, 0xa0, 0x23, 0x72, 0x83, 0x7a, 0xcd, 0x25, 0xf5, 0xed, 0x0b, 0x97, 0xb8, 0x7f, 0x0c,
+	0x81, 0xeb, 0x9b, 0xec, 0x41, 0x67, 0x3e, 0x9d, 0x4d, 0x27, 0xd3, 0xf1, 0xe7, 0xf0, 0x4e, 0x8d,
+	0xde, 0xbd, 0x7d, 0x3f, 0x99, 0x7e, 0x1a, 0xb1, 0xd0, 0xeb, 0xbf, 0x81, 0xbd, 0xab, 0xed, 0x92,
+	0x43, 0x08, 0x34, 0x66, 0x75, 0x59, 0xee, 0x83, 0x69, 0x50, 0xcd, 0x5f, 0xa0, 0xc8, 0xce, 0x8d,
+	0x9d, 0xa9, 0xcd, 0x1a, 0x74, 0x7a, 0xef, 0x4b, 0x7b, 0xa5, 0x52, 0x94, 0x8b, 0xc0, 0xfe, 0x44,
+	0x4f, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0xde, 0xb6, 0x59, 0xbf, 0x5b, 0x03, 0x00, 0x00,
 }
diff --git a/admiral/pkg/apis/admiral/model/globalrouting.proto b/admiral/pkg/apis/admiral/model/globalrouting.proto
index 9c9706c3f..e5b07f595 100644
--- a/admiral/pkg/apis/admiral/model/globalrouting.proto
+++ b/admiral/pkg/apis/admiral/model/globalrouting.proto
@@ -33,6 +33,10 @@ option go_package = "model";
 //       weight: 10
 //     - region: us-east2
 //       weight: 90
+//     outlier_detection:
+//       base_ejection_time: 180
+//       consecutive_gateway_errors: 100
+//       interval: 60
 //
 // ```
 
@@ -74,6 +78,19 @@ message TrafficPolicy {
     //REQUIRED: dnsPrefix that will be prefixed for the service names being generated with this traffic policy
     //Ex: dnsPrefix = west => generated service name = west.stage.servicename.global
     string dnsPrefix = 4;
+
+   message OutlierDetection {
+       //REQUIRED: Minimum duration of time in seconds, the endpoint will be ejected
+       int64 base_ejection_time = 1;
+       //REQUIRED: No. of consecutive failures in specified interval after which the endpoint will be ejected
+       uint32 consecutive_gateway_errors = 2;
+       //REQUIRED: Time interval between ejection sweep analysis
+       int64 interval = 3;
+   }
+
+   //OPTIONAL: to configure the outlierDetection in DestinationRule
+    OutlierDetection outlier_detection = 5;
+
 }
 
 message TrafficGroup {
diff --git a/admiral/pkg/clusters/handler.go b/admiral/pkg/clusters/handler.go
index e7148dbda..c93bd2eec 100644
--- a/admiral/pkg/clusters/handler.go
+++ b/admiral/pkg/clusters/handler.go
@@ -24,7 +24,12 @@ import (
 	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-const ROLLOUT_POD_HASH_LABEL string = "rollouts-pod-template-hash"
+const (
+	ROLLOUT_POD_HASH_LABEL          string = "rollouts-pod-template-hash"
+	DefaultBaseEjectionTime         int64  = 300
+	DefaultConsecutiveGatewayErrors uint32 = 50
+	DefaultInterval                 int64  = 60
+)
 
 type ServiceEntryHandler struct {
 	RemoteRegistry *RemoteRegistry
@@ -106,9 +111,27 @@ func getDestinationRule(se *v1alpha32.ServiceEntry, locality string, gtpTrafficP
 func getOutlierDetection(se *v1alpha32.ServiceEntry, locality string, gtpTrafficPolicy *model.TrafficPolicy) *v1alpha32.OutlierDetection {
 
 	outlierDetection := &v1alpha32.OutlierDetection{
-		BaseEjectionTime:      &types.Duration{Seconds: 300},
-		ConsecutiveGatewayErrors: &types.UInt32Value{Value: uint32(50)},
-		Interval:              &types.Duration{Seconds: 60},
+		BaseEjectionTime:         &types.Duration{Seconds: DefaultBaseEjectionTime},
+		ConsecutiveGatewayErrors: &types.UInt32Value{Value: DefaultConsecutiveGatewayErrors},
+		Interval:                 &types.Duration{Seconds: DefaultInterval},
+	}
+
+	if gtpTrafficPolicy != nil && gtpTrafficPolicy.OutlierDetection != nil {
+		if gtpTrafficPolicy.OutlierDetection.BaseEjectionTime > 0 {
+			outlierDetection.BaseEjectionTime = &types.Duration{
+				Seconds: gtpTrafficPolicy.OutlierDetection.BaseEjectionTime,
+			}
+		}
+		if gtpTrafficPolicy.OutlierDetection.ConsecutiveGatewayErrors > 0 {
+			outlierDetection.ConsecutiveGatewayErrors = &types.UInt32Value{
+				Value: gtpTrafficPolicy.OutlierDetection.ConsecutiveGatewayErrors,
+			}
+		}
+		if gtpTrafficPolicy.OutlierDetection.Interval > 0 {
+			outlierDetection.Interval = &types.Duration{
+				Seconds: gtpTrafficPolicy.OutlierDetection.Interval,
+			}
+		}
 	}
 
 	//Scenario 1: Only one endpoint present and is local service (ends in svc.cluster.local) - no outlier detection (optimize this for headless services in future?)
diff --git a/admiral/pkg/clusters/handler_test.go b/admiral/pkg/clusters/handler_test.go
index 455849b27..d8472dad8 100644
--- a/admiral/pkg/clusters/handler_test.go
+++ b/admiral/pkg/clusters/handler_test.go
@@ -175,15 +175,14 @@ func TestIgnoreIstioResource(t *testing.T) {
 func TestGetDestinationRule(t *testing.T) {
 	//Do setup here
 	outlierDetection := &v1alpha3.OutlierDetection{
-		BaseEjectionTime:      &types.Duration{Seconds: 300},
+		BaseEjectionTime:         &types.Duration{Seconds: 300},
 		ConsecutiveGatewayErrors: &types.UInt32Value{Value: 50},
-		Interval:              &types.Duration{Seconds: 60},
-		MaxEjectionPercent: 100,
+		Interval:                 &types.Duration{Seconds: 60},
+		MaxEjectionPercent:       100,
 	}
 	mTLS := &v1alpha3.TrafficPolicy{Tls: &v1alpha3.TLSSettings{Mode: v1alpha3.TLSSettings_ISTIO_MUTUAL}, OutlierDetection: outlierDetection}
 
-
-	se := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"},Endpoints:[]*v1alpha3.ServiceEntry_Endpoint{
+	se := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"}, Endpoints: []*v1alpha3.ServiceEntry_Endpoint{
 		{Address: "east.com", Locality: "us-east-2"}, {Address: "west.com", Locality: "us-west-2"},
 	}}
 	noGtpDr := v1alpha3.DestinationRule{
@@ -298,17 +297,17 @@ func TestGetDestinationRule(t *testing.T) {
 func TestGetOutlierDetection(t *testing.T) {
 	//Do setup here
 	outlierDetection := &v1alpha3.OutlierDetection{
-		BaseEjectionTime:      &types.Duration{Seconds: 300},
-		ConsecutiveGatewayErrors: &types.UInt32Value{Value: 50},
-		Interval:              &types.Duration{Seconds: 60},
-		MaxEjectionPercent: 100,
+		BaseEjectionTime:         &types.Duration{Seconds: DefaultBaseEjectionTime},
+		ConsecutiveGatewayErrors: &types.UInt32Value{Value: DefaultConsecutiveGatewayErrors},
+		Interval:                 &types.Duration{Seconds: DefaultInterval},
+		MaxEjectionPercent:       100,
 	}
 
 	outlierDetectionOneHostRemote := &v1alpha3.OutlierDetection{
-		BaseEjectionTime:      &types.Duration{Seconds: 300},
-		ConsecutiveGatewayErrors: &types.UInt32Value{Value: 50},
-		Interval:              &types.Duration{Seconds: 60},
-		MaxEjectionPercent: 34,
+		BaseEjectionTime:         &types.Duration{Seconds: DefaultBaseEjectionTime},
+		ConsecutiveGatewayErrors: &types.UInt32Value{Value: DefaultConsecutiveGatewayErrors},
+		Interval:                 &types.Duration{Seconds: DefaultInterval},
+		MaxEjectionPercent:       34,
 	}
 
 	topologyGTPPolicy := &model.TrafficPolicy{
@@ -321,58 +320,170 @@ func TestGetOutlierDetection(t *testing.T) {
 		},
 	}
 
-	se := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"},Endpoints:[]*v1alpha3.ServiceEntry_Endpoint{
+	se := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"}, Endpoints: []*v1alpha3.ServiceEntry_Endpoint{
 		{Address: "east.com", Locality: "us-east-2"}, {Address: "west.com", Locality: "us-west-2"},
 	}}
 
-	seOneHostRemote := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"},Endpoints:[]*v1alpha3.ServiceEntry_Endpoint{
+	seOneHostRemote := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"}, Endpoints: []*v1alpha3.ServiceEntry_Endpoint{
 		{Address: "east.com", Locality: "us-east-2"},
 	}}
 
-	seOneHostLocal := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"},Endpoints:[]*v1alpha3.ServiceEntry_Endpoint{
+	seOneHostLocal := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"}, Endpoints: []*v1alpha3.ServiceEntry_Endpoint{
 		{Address: "hello.ns.svc.cluster.local", Locality: "us-east-2"},
 	}}
 
-	seOneHostRemoteIp := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"},Endpoints:[]*v1alpha3.ServiceEntry_Endpoint{
+	seOneHostRemoteIp := &v1alpha3.ServiceEntry{Hosts: []string{"qa.myservice.global"}, Endpoints: []*v1alpha3.ServiceEntry_Endpoint{
 		{Address: "95.45.25.34", Locality: "us-east-2"},
 	}}
 
 	//Struct of test case info. Name is required.
 	testCases := []struct {
-		name            string
-		se              *v1alpha3.ServiceEntry
-		locality        string
-		gtpPolicy       *model.TrafficPolicy
+		name             string
+		se               *v1alpha3.ServiceEntry
+		locality         string
+		gtpPolicy        *model.TrafficPolicy
 		outlierDetection *v1alpha3.OutlierDetection
 	}{
+
 		{
-			name:            "Should return nil for cluster local only endpoint",
-			se:              seOneHostLocal,
-			locality:        "uswest2",
-			gtpPolicy:       topologyGTPPolicy,
+			name:             "Should return nil for cluster local only endpoint",
+			se:               seOneHostLocal,
+			locality:         "uswest2",
+			gtpPolicy:        topologyGTPPolicy,
 			outlierDetection: nil,
 		},
 		{
-			name:            "Should return nil for one IP endpoint",
-			se:              seOneHostRemoteIp,
-			locality:        "uswest2",
-			gtpPolicy:       topologyGTPPolicy,
+			name:             "Should return nil for one IP endpoint",
+			se:               seOneHostRemoteIp,
+			locality:         "uswest2",
+			gtpPolicy:        topologyGTPPolicy,
 			outlierDetection: nil,
 		},
 		{
-			name:            "Should return 34% ejection for remote endpoint with one entry",
-			se:              seOneHostRemote,
-			locality:        "uswest2",
-			gtpPolicy:       topologyGTPPolicy,
+			name:             "Should return 34% ejection for remote endpoint with one entry",
+			se:               seOneHostRemote,
+			locality:         "uswest2",
+			gtpPolicy:        topologyGTPPolicy,
 			outlierDetection: outlierDetectionOneHostRemote,
 		},
 		{
-			name:            "Should return 100% ejection for two remote endpoints",
-			se:              se,
-			locality:        "uswest2",
-			gtpPolicy:       topologyGTPPolicy,
+			name:             "Should return 100% ejection for two remote endpoints",
+			se:               se,
+			locality:         "uswest2",
+			gtpPolicy:        topologyGTPPolicy,
+			outlierDetection: outlierDetection,
+		},
+		{
+			name:             "Should use the default outlier detection if gtpPolicy is nil",
+			se:               se,
+			locality:         "uswest2",
+			gtpPolicy:        nil,
 			outlierDetection: outlierDetection,
 		},
+		{
+			name:             "Should use the default outlier detection if OutlierDetection is nil inside gtpPolicy",
+			se:               se,
+			locality:         "uswest2",
+			gtpPolicy:        topologyGTPPolicy,
+			outlierDetection: outlierDetection,
+		},
+		{
+			name:     "Should apply the default BaseEjectionTime if it is not configured in the outlier detection config",
+			se:       se,
+			locality: "uswest2",
+			gtpPolicy: &model.TrafficPolicy{
+				LbType: model.TrafficPolicy_TOPOLOGY,
+				Target: []*model.TrafficGroup{
+					{
+						Region: "us-west-2",
+						Weight: 100,
+					},
+				},
+				OutlierDetection: &model.TrafficPolicy_OutlierDetection{
+					ConsecutiveGatewayErrors: 10,
+					Interval:                 60,
+				},
+			},
+			outlierDetection: &v1alpha3.OutlierDetection{
+				BaseEjectionTime:         &types.Duration{Seconds: DefaultBaseEjectionTime},
+				ConsecutiveGatewayErrors: &types.UInt32Value{Value: 10},
+				Interval:                 &types.Duration{Seconds: 60},
+				MaxEjectionPercent:       100,
+			},
+		},
+		{
+			name:     "Should apply the default ConsecutiveGatewayErrors if it is not configured in the outlier detection config",
+			se:       se,
+			locality: "uswest2",
+			gtpPolicy: &model.TrafficPolicy{
+				LbType: model.TrafficPolicy_TOPOLOGY,
+				Target: []*model.TrafficGroup{
+					{
+						Region: "us-west-2",
+						Weight: 100,
+					},
+				},
+				OutlierDetection: &model.TrafficPolicy_OutlierDetection{
+					BaseEjectionTime: 600,
+					Interval:         60,
+				},
+			},
+			outlierDetection: &v1alpha3.OutlierDetection{
+				BaseEjectionTime:         &types.Duration{Seconds: 600},
+				ConsecutiveGatewayErrors: &types.UInt32Value{Value: DefaultConsecutiveGatewayErrors},
+				Interval:                 &types.Duration{Seconds: 60},
+				MaxEjectionPercent:       100,
+			},
+		},
+		{
+			name:     "Should apply the default Interval if it is not configured in the outlier detection config",
+			se:       se,
+			locality: "uswest2",
+			gtpPolicy: &model.TrafficPolicy{
+				LbType: model.TrafficPolicy_TOPOLOGY,
+				Target: []*model.TrafficGroup{
+					{
+						Region: "us-west-2",
+						Weight: 100,
+					},
+				},
+				OutlierDetection: &model.TrafficPolicy_OutlierDetection{
+					BaseEjectionTime:         600,
+					ConsecutiveGatewayErrors: 50,
+				},
+			},
+			outlierDetection: &v1alpha3.OutlierDetection{
+				BaseEjectionTime:         &types.Duration{Seconds: 600},
+				ConsecutiveGatewayErrors: &types.UInt32Value{Value: 50},
+				Interval:                 &types.Duration{Seconds: DefaultInterval},
+				MaxEjectionPercent:       100,
+			},
+		},
+		{
+			name:     "Default outlier detection config should be overriden by the outlier detection config specified in the TrafficPolicy",
+			se:       se,
+			locality: "uswest2",
+			gtpPolicy: &model.TrafficPolicy{
+				LbType: model.TrafficPolicy_TOPOLOGY,
+				Target: []*model.TrafficGroup{
+					{
+						Region: "us-west-2",
+						Weight: 100,
+					},
+				},
+				OutlierDetection: &model.TrafficPolicy_OutlierDetection{
+					BaseEjectionTime:         600,
+					ConsecutiveGatewayErrors: 10,
+					Interval:                 60,
+				},
+			},
+			outlierDetection: &v1alpha3.OutlierDetection{
+				BaseEjectionTime:         &types.Duration{Seconds: 600},
+				ConsecutiveGatewayErrors: &types.UInt32Value{Value: 10},
+				Interval:                 &types.Duration{Seconds: 60},
+				MaxEjectionPercent:       100,
+			},
+		},
 	}
 
 	//Run the test for every provided case
diff --git a/go.mod b/go.mod
index dd417423e..58730ba94 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
 	github.com/onsi/ginkgo v1.10.2 // indirect
 	github.com/onsi/gomega v1.7.0
 	github.com/prometheus/client_golang v1.5.0
-	github.com/prometheus/client_model v0.2.0 // indirect
+	github.com/prometheus/client_model v0.2.0
 	github.com/prometheus/common v0.9.1
 	github.com/sirupsen/logrus v1.4.2
 	github.com/spf13/cobra v0.0.5