diff --git a/ako-gateway-api/k8s/ako_init.go b/ako-gateway-api/k8s/ako_init.go index 571e6b86c..582aa9bb2 100644 --- a/ako-gateway-api/k8s/ako_init.go +++ b/ako-gateway-api/k8s/ako_init.go @@ -274,7 +274,7 @@ func (c *GatewayController) FullSyncK8s(sync bool) error { resVer := meta.GetResourceVersion() objects.SharedResourceVerInstanceLister().Save(key, resVer) } - if IsValidGateway(key, gatewayObj) { + if valid, _ := IsValidGateway(key, gatewayObj); valid { filteredGateways = append(filteredGateways, gatewayObj) } } @@ -304,7 +304,7 @@ func (c *GatewayController) FullSyncK8s(sync bool) error { resVer := meta.GetResourceVersion() objects.SharedResourceVerInstanceLister().Save(key, resVer) } - if IsHTTPRouteValid(key, httpRouteObj) { + if IsHTTPRouteConfigValid(key, httpRouteObj) { filteredHTTPRoutes = append(filteredHTTPRoutes, httpRouteObj) } } diff --git a/ako-gateway-api/k8s/gateway_controller.go b/ako-gateway-api/k8s/gateway_controller.go index b9367aaa0..4991e3b63 100644 --- a/ako-gateway-api/k8s/gateway_controller.go +++ b/ako-gateway-api/k8s/gateway_controller.go @@ -17,11 +17,14 @@ package k8s import ( "fmt" "reflect" + "sort" "sync" "time" corev1 "k8s.io/api/core/v1" discovery "k8s.io/api/discovery/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" @@ -500,13 +503,23 @@ func (c *GatewayController) SetupGatewayApiEventHandlers(numWorkers uint32) { utils.AviLog.Debugf("key: %s, msg: same resource version returning", key) return } - if !IsValidGateway(key, gw) { + valid, allowedRoutesAll := IsValidGateway(key, gw) + if !valid { return } + listRoutes, err := validateReferredHTTPRoute(key, allowedRoutesAll, *gw) + if err != nil { + utils.AviLog.Errorf("Validation of Referred HTTPRoutes Failed due to error : %s", err.Error()) + } namespace, _, _ := cache.SplitMetaNamespaceKey(utils.ObjKey(gw)) bkt := utils.Bkt(namespace, numWorkers) c.workqueue[bkt].AddRateLimited(key) utils.AviLog.Debugf("key: %s, msg: ADD", key) + for _, route := range listRoutes { + key := lib.HTTPRoute + "/" + utils.ObjKey(route) + c.workqueue[bkt].AddRateLimited(key) + utils.AviLog.Debugf("key: %s, msg: UPDATE", key) + } }, DeleteFunc: func(obj interface{}) { if c.DisableSync { @@ -542,13 +555,23 @@ func (c *GatewayController) SetupGatewayApiEventHandlers(numWorkers uint32) { gw := obj.(*gatewayv1.Gateway) if IsGatewayUpdated(oldGw, gw) { key := lib.Gateway + "/" + utils.ObjKey(gw) - if !IsValidGateway(key, gw) { + valid, allowedRoutesAll := IsValidGateway(key, gw) + if !valid { return } + listRoutes, err := validateReferredHTTPRoute(key, allowedRoutesAll, *gw) + if err != nil { + utils.AviLog.Errorf("Validation of Referred HTTPRoutes Failed due to error : %s", err.Error()) + } namespace, _, _ := cache.SplitMetaNamespaceKey(utils.ObjKey(gw)) bkt := utils.Bkt(namespace, numWorkers) c.workqueue[bkt].AddRateLimited(key) utils.AviLog.Debugf("key: %s, msg: UPDATE", key) + for _, route := range listRoutes { + key := lib.HTTPRoute + "/" + utils.ObjKey(route) + c.workqueue[bkt].AddRateLimited(key) + utils.AviLog.Debugf("key: %s, msg: UPDATE", key) + } } }, } @@ -635,7 +658,7 @@ func (c *GatewayController) SetupGatewayApiEventHandlers(numWorkers uint32) { utils.AviLog.Debugf("key: %s, msg: same resource version returning", key) return } - if !IsHTTPRouteValid(key, httpRoute) { + if !IsHTTPRouteConfigValid(key, httpRoute) { return } namespace, _, _ := cache.SplitMetaNamespaceKey(utils.ObjKey(httpRoute)) @@ -676,7 +699,7 @@ func (c *GatewayController) SetupGatewayApiEventHandlers(numWorkers uint32) { newHTTPRoute := obj.(*gatewayv1.HTTPRoute) if IsHTTPRouteUpdated(oldHTTPRoute, newHTTPRoute) { key := lib.HTTPRoute + "/" + utils.ObjKey(newHTTPRoute) - if !IsHTTPRouteValid(key, newHTTPRoute) { + if !IsHTTPRouteConfigValid(key, newHTTPRoute) { return } namespace, _, _ := cache.SplitMetaNamespaceKey(utils.ObjKey(newHTTPRoute)) @@ -714,3 +737,32 @@ func validateAviConfigMap(obj interface{}) (*corev1.ConfigMap, bool) { } return nil, false } +func validateReferredHTTPRoute(key string, allowedRoutesAll bool, gateway gatewayv1.Gateway) ([]*gatewayv1.HTTPRoute, error) { + + namespace := gateway.Namespace + if allowedRoutesAll { + namespace = metav1.NamespaceAll + } + hrObjs, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().HTTPRouteInformer.Lister().HTTPRoutes(namespace).List(labels.Set(nil).AsSelector()) + httpRoutes := make([]*gatewayv1.HTTPRoute, 0) + if err != nil { + return nil, err + } + for _, httpRoute := range hrObjs { + for _, parentRef := range httpRoute.Spec.ParentRefs { + if parentRef.Name == gatewayv1.ObjectName(gateway.Name) { + if IsHTTPRouteConfigValid(key, httpRoute) { + httpRoutes = append(httpRoutes, httpRoute) + } + break + } + } + } + sort.Slice(httpRoutes, func(i, j int) bool { + if httpRoutes[i].GetCreationTimestamp().Unix() == httpRoutes[j].GetCreationTimestamp().Unix() { + return httpRoutes[i].Namespace+"/"+httpRoutes[i].Name < httpRoutes[j].Namespace+"/"+httpRoutes[j].Name + } + return httpRoutes[i].GetCreationTimestamp().Unix() < httpRoutes[j].GetCreationTimestamp().Unix() + }) + return httpRoutes, nil +} diff --git a/ako-gateway-api/k8s/validator.go b/ako-gateway-api/k8s/validator.go index 0c5542739..134e23e39 100644 --- a/ako-gateway-api/k8s/validator.go +++ b/ako-gateway-api/k8s/validator.go @@ -15,36 +15,20 @@ package k8s import ( + "context" "fmt" - "regexp" - "strings" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" "k8s.io/apimachinery/pkg/labels" akogatewayapilib "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/lib" - akogatewayapiobjects "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/objects" akogatewayapistatus "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/status" - "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/internal/lib" "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/internal/status" "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/pkg/utils" ) -func isRegexMatch(stringWithWildCard string, stringToBeMatched string, key string) bool { - // replace the wildcard character with a regex - replacedHostname := strings.Replace(stringWithWildCard, utils.WILDCARD, utils.FQDN_LABEL_REGEX, 1) - // create the expression for pattern matching - pattern := fmt.Sprintf("^%s$", replacedHostname) - expr, err := regexp.Compile(pattern) - if err != nil { - utils.AviLog.Warnf("key: %s, msg: unable to compile wildcard string to regex object. Err: %s", key, err) - } - return expr.MatchString(stringToBeMatched) -} - func IsGatewayClassValid(key string, gatewayClass *gatewayv1.GatewayClass) bool { controllerName := string(gatewayClass.Spec.ControllerName) @@ -66,14 +50,20 @@ func IsGatewayClassValid(key string, gatewayClass *gatewayv1.GatewayClass) bool return true } -func IsValidGateway(key string, gateway *gatewayv1.Gateway) bool { +func IsValidGateway(key string, gateway *gatewayv1.Gateway) (bool, bool) { spec := gateway.Spec - + allowedRoutesAll := false defaultCondition := akogatewayapistatus.NewCondition(). Type(string(gatewayv1.GatewayConditionAccepted)). Reason(string(gatewayv1.GatewayReasonInvalid)). Status(metav1.ConditionFalse). ObservedGeneration(gateway.ObjectMeta.Generation) + programmedCondition := akogatewayapistatus.NewCondition(). + Type(string(gatewayv1.GatewayConditionProgrammed)). + Reason(string(gatewayv1.GatewayReasonInvalid)). + Status(metav1.ConditionFalse). + ObservedGeneration(gateway.ObjectMeta.Generation). + Message("Gateway not programmed") gatewayStatus := gateway.Status.DeepCopy() @@ -83,8 +73,10 @@ func IsValidGateway(key string, gateway *gatewayv1.Gateway) bool { defaultCondition. Message("No listeners found"). SetIn(&gatewayStatus.Conditions) + programmedCondition. + SetIn(&gatewayStatus.Conditions) akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) - return false + return false, allowedRoutesAll } // has 1 or none addresses @@ -93,37 +85,62 @@ func IsValidGateway(key string, gateway *gatewayv1.Gateway) bool { defaultCondition. Message("More than one address is not supported"). SetIn(&gatewayStatus.Conditions) + programmedCondition. + Reason(string(gatewayv1.GatewayReasonAddressNotUsable)). + SetIn(&gatewayStatus.Conditions) akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) - return false + return false, allowedRoutesAll } if len(spec.Addresses) == 1 && *spec.Addresses[0].Type != "IPAddress" { utils.AviLog.Errorf("key: %s, msg: gateway address is not of type IPAddress %+v", key, gateway.Name) defaultCondition. + Reason(string(gatewayv1.GatewayReasonUnsupportedAddress)). Message("Only IPAddress as AddressType is supported"). SetIn(&gatewayStatus.Conditions) + programmedCondition. + Reason(string(gatewayv1.GatewayReasonAddressNotUsable)). + SetIn(&gatewayStatus.Conditions) akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) - return false + return false, allowedRoutesAll } gatewayStatus.Listeners = make([]gatewayv1.ListenerStatus, len(gateway.Spec.Listeners)) - var invalidListenerCount int + var validListenerCount int for index := range spec.Listeners { - if !isValidListener(key, gateway, gatewayStatus, index) { - invalidListenerCount++ + if isValidListener(key, gateway, gatewayStatus, index) { + if !allowedRoutesAll { + if spec.Listeners[index].AllowedRoutes != nil && spec.Listeners[index].AllowedRoutes.Namespaces != nil && spec.Listeners[index].AllowedRoutes.Namespaces.From != nil { + if string(*spec.Listeners[index].AllowedRoutes.Namespaces.From) == akogatewayapilib.AllowedRoutesNamespaceFromAll { + allowedRoutesAll = true + } + } + } + validListenerCount++ } } - if invalidListenerCount > 0 { - utils.AviLog.Errorf("key: %s, msg: Gateway %s contains %d invalid listeners", key, gateway.Name, invalidListenerCount) + if validListenerCount == 0 { + utils.AviLog.Errorf("key: %s, msg: Gateway %s does not contain any valid listener", key, gateway.Name) defaultCondition. Type(string(gatewayv1.GatewayConditionAccepted)). Reason(string(gatewayv1.GatewayReasonListenersNotValid)). - Message(fmt.Sprintf("Gateway contains %d invalid listener(s)", invalidListenerCount)). + Message("Gateway does not contain any valid listener"). + SetIn(&gatewayStatus.Conditions) + programmedCondition. SetIn(&gatewayStatus.Conditions) akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) - return false + gateway.Status = *gatewayStatus.DeepCopy() + return false, allowedRoutesAll + } else if validListenerCount < len(spec.Listeners) { + defaultCondition. + Reason(string(gatewayv1.GatewayReasonListenersNotValid)). + Status(metav1.ConditionTrue). + Message("Gateway contains atleast one valid listener"). + SetIn(&gatewayStatus.Conditions) + akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) + utils.AviLog.Infof("key: %s, msg: Gateway %s contains atleast one valid listener", key, gateway.Name) } defaultCondition. @@ -133,7 +150,7 @@ func IsValidGateway(key string, gateway *gatewayv1.Gateway) bool { SetIn(&gatewayStatus.Conditions) akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) utils.AviLog.Infof("key: %s, msg: Gateway %s is valid", key, gateway.Name) - return true + return true, allowedRoutesAll } func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gatewayv1.GatewayStatus, index int) bool { @@ -144,8 +161,16 @@ func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gate gatewayStatus.Listeners[index].AttachedRoutes = akogatewayapilib.ZeroAttachedRoutes defaultCondition := akogatewayapistatus.NewCondition(). - Type(string(gatewayv1.GatewayConditionAccepted)). - Reason(string(gatewayv1.GatewayReasonListenersNotValid)). + Type(string(gatewayv1.ListenerConditionAccepted)). + Reason(string(gatewayv1.ListenerReasonInvalid)). + Message("Listener is Invalid"). + Status(metav1.ConditionFalse). + ObservedGeneration(gateway.ObjectMeta.Generation) + + programmedCondition := akogatewayapistatus.NewCondition(). + Type(string(gatewayv1.ListenerConditionProgrammed)). + Reason(string(gatewayv1.ListenerReasonInvalid)). + Message("Virtual service not configured/updated for this listener"). Status(metav1.ConditionFalse). ObservedGeneration(gateway.ObjectMeta.Generation) @@ -166,6 +191,7 @@ func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gate defaultCondition. Message("Hostname is same as an existing gateway hostname"). SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) return false } } @@ -177,6 +203,7 @@ func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gate defaultCondition. Message(fmt.Sprintf("Didn't find match for hostname :%s in available sub-domains", string(*listener.Hostname))). SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) return false } } @@ -189,18 +216,24 @@ func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gate Reason(string(gatewayv1.ListenerReasonUnsupportedProtocol)). Message("Unsupported protocol"). SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) gatewayStatus.Listeners[index].SupportedKinds = akogatewayapilib.SupportedKinds[gatewayv1.HTTPSProtocolType] return false } + resolvedRefCondition := akogatewayapistatus.NewCondition(). + Type(string(gatewayv1.ListenerConditionResolvedRefs)). + Status(metav1.ConditionFalse). + ObservedGeneration(gateway.ObjectMeta.Generation) // has valid TLS config if listener.TLS != nil { if (listener.TLS.Mode != nil && *listener.TLS.Mode != gatewayv1.TLSModeTerminate) || len(listener.TLS.CertificateRefs) == 0 { utils.AviLog.Errorf("key: %s, msg: tls mode/ref not valid %+v/%+v", key, gateway.Name, listener.Name) - defaultCondition. - Reason(string(gatewayv1.ListenerReasonInvalidCertificateRef)). + defaultCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) + resolvedRefCondition.Reason(string(gatewayv1.ListenerReasonInvalidCertificateRef)). Message("TLS mode or reference not valid"). SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) return false } for _, certRef := range listener.TLS.CertificateRefs { @@ -208,13 +241,26 @@ func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gate if (certRef.Group != nil && string(*certRef.Group) != "") || certRef.Kind != nil && string(*certRef.Kind) != utils.Secret { utils.AviLog.Errorf("key: %s, msg: CertificateRef is not valid %+v/%+v, must be Secret", key, gateway.Name, listener.Name) - defaultCondition. - Reason(string(gatewayv1.ListenerReasonInvalidCertificateRef)). + defaultCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) + resolvedRefCondition.Reason(string(gatewayv1.ListenerReasonInvalidCertificateRef)). Message("TLS mode or reference not valid"). SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) + return false + } + name := string(certRef.Name) + cs := utils.GetInformers().ClientSet + secretObj, err := cs.CoreV1().Secrets(gateway.ObjectMeta.Namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil || secretObj == nil { + utils.AviLog.Errorf("key: %s, msg: Secret specified in CertificateRef does not exist %+v/%+v", key, gateway.Name, listener.Name) + defaultCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) + resolvedRefCondition. + Reason(string(gatewayv1.ListenerReasonInvalidCertificateRef)). + Message("Secret does not exist"). + SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) return false } - } } @@ -224,20 +270,22 @@ func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gate for _, kindInAllowedRoute := range listener.AllowedRoutes.Kinds { if kindInAllowedRoute.Kind != "" && string(kindInAllowedRoute.Kind) != utils.HTTPRoute { utils.AviLog.Errorf("key: %s, msg: AllowedRoute kind is invalid %+v/%+v. Supported AllowedRoute kind is HTTPRoute.", key, gateway.Name, listener.Name) - defaultCondition. - Type(string(gatewayv1.ListenerConditionResolvedRefs)). + defaultCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) + resolvedRefCondition. Reason(string(gatewayv1.ListenerReasonInvalidRouteKinds)). Message("AllowedRoute kind is invalid. Only HTTPRoute is supported currently"). SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) return false } if kindInAllowedRoute.Group != nil && *kindInAllowedRoute.Group != "" && string(*kindInAllowedRoute.Group) != gatewayv1.GroupName { utils.AviLog.Errorf("key: %s, msg: AllowedRoute Group is invalid %+v/%+v.", key, gateway.Name, listener.Name) - defaultCondition. - Type(string(gatewayv1.ListenerConditionResolvedRefs)). + defaultCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) + resolvedRefCondition. Reason(string(gatewayv1.ListenerReasonInvalidRouteKinds)). Message("AllowedRoute Group is invalid."). SetIn(&gatewayStatus.Listeners[index].Conditions) + programmedCondition.SetIn(&gatewayStatus.Listeners[index].Conditions) return false } } @@ -246,235 +294,28 @@ func isValidListener(key string, gateway *gatewayv1.Gateway, gatewayStatus *gate // Valid listener defaultCondition. - Reason(string(gatewayv1.GatewayReasonAccepted)). + Reason(string(gatewayv1.ListenerReasonAccepted)). Status(metav1.ConditionTrue). Message("Listener is valid"). SetIn(&gatewayStatus.Listeners[index].Conditions) + + // Setting the resolvedRef condition + resolvedRefCondition. + Status(metav1.ConditionTrue). + Reason(string(gatewayv1.ListenerReasonResolvedRefs)). + Message("All the references are valid"). + SetIn(&gatewayStatus.Listeners[index].Conditions) + utils.AviLog.Infof("key: %s, msg: Listener %s/%s is valid", key, gateway.Name, listener.Name) return true } -func IsHTTPRouteValid(key string, obj *gatewayv1.HTTPRoute) bool { +func IsHTTPRouteConfigValid(key string, obj *gatewayv1.HTTPRoute) bool { httpRoute := obj.DeepCopy() if len(httpRoute.Spec.ParentRefs) == 0 { utils.AviLog.Errorf("key: %s, msg: Parent Reference is empty for the HTTPRoute %s", key, httpRoute.Name) return false } - - httpRouteStatus := obj.Status.DeepCopy() - httpRouteStatus.Parents = make([]gatewayv1.RouteParentStatus, 0, len(httpRoute.Spec.ParentRefs)) - var invalidParentRefCount int - parentRefIndexInHttpRouteStatus := 0 - for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs { - err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus) - if err != nil { - invalidParentRefCount++ - parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name - utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err) - } - } - akogatewayapistatus.Record(key, httpRoute, &status.Status{HTTPRouteStatus: httpRouteStatus}) - - // No valid attachment, we can't proceed with this HTTPRoute object. - if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) { - utils.AviLog.Errorf("key: %s, msg: HTTPRoute object %s is not valid", key, httpRoute.Name) - akogatewayapilib.AKOControlConfig().EventRecorder().Eventf(httpRoute, corev1.EventTypeWarning, - lib.Detached, "HTTPRoute object %s is not valid", httpRoute.Name) - return false - } - utils.AviLog.Infof("key: %s, msg: HTTPRoute object %s is valid", key, httpRoute.Name) return true } - -func validateParentReference(key string, httpRoute *gatewayv1.HTTPRoute, httpRouteStatus *gatewayv1.HTTPRouteStatus, parentRefIndexFromSpec int, parentRefIndexInHttpRouteStatus *int) error { - - name := string(httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name) - namespace := httpRoute.Namespace - if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Namespace != nil { - namespace = string(*httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Namespace) - } - gwNsName := namespace + "/" + name - obj, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().GatewayInformer.Lister().Gateways(namespace).Get(name) - if err != nil { - utils.AviLog.Errorf("key: %s, msg: unable to get the gateway object. err: %s", key, err) - return err - } - gateway := obj.DeepCopy() - - gwClass := string(gateway.Spec.GatewayClassName) - _, isAKOCtrl := akogatewayapiobjects.GatewayApiLister().IsGatewayClassControllerAKO(gwClass) - if !isAKOCtrl { - utils.AviLog.Warnf("key: %s, msg: controller for the parent reference %s of HTTPRoute object %s is not ako", key, name, httpRoute.Name) - return fmt.Errorf("controller for the parent reference %s of HTTPRoute object %s is not ako", name, httpRoute.Name) - } - // creates the Parent status only when the AKO is the gateway controller - httpRouteStatus.Parents = append(httpRouteStatus.Parents, gatewayv1.RouteParentStatus{}) - httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ControllerName = akogatewayapilib.GatewayController - httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ParentRef.Name = gatewayv1.ObjectName(name) - httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ParentRef.Namespace = (*gatewayv1.Namespace)(&namespace) - if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName != nil { - httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ParentRef.SectionName = httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName - } - - defaultCondition := akogatewayapistatus.NewCondition(). - Type(string(gatewayv1.GatewayConditionAccepted)). - Reason(string(gatewayv1.GatewayReasonInvalid)). - Status(metav1.ConditionFalse). - ObservedGeneration(httpRoute.ObjectMeta.Generation) - - gwStatus := akogatewayapiobjects.GatewayApiLister().GetGatewayToGatewayStatusMapping(gwNsName) - if len(gwStatus.Conditions) == 0 { - // Gateway processing by AKO has not started. - utils.AviLog.Errorf("key: %s, msg: AKO is yet to process Gateway %s for parent reference %s.", key, gateway.Name, name) - err := fmt.Errorf("AKO is yet to process Gateway %s for parent reference %s", gateway.Name, name) - defaultCondition. - Message(err.Error()). - SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) - *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 - return err - } - - // Attach only when gateway configuration is valid - currentGatewayStatusCondition := gwStatus.Conditions[0] - if currentGatewayStatusCondition.Status != metav1.ConditionTrue { - // Gateway is not in an expected state. - utils.AviLog.Errorf("key: %s, msg: Gateway %s for parent reference %s is in Invalid State", key, gateway.Name, name) - err := fmt.Errorf("Gateway %s is in Invalid State", gateway.Name) - defaultCondition. - Message(err.Error()). - SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) - *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 - return err - } - - //section name is optional - var listenersForRoute []gatewayv1.Listener - if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName != nil { - listenerName := *httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName - i := akogatewayapilib.FindListenerByName(string(listenerName), gateway.Spec.Listeners) - if i == -1 { - // listener is not present in gateway - utils.AviLog.Errorf("key: %s, msg: unable to find the listener from the Section Name %s in Parent Reference %s", key, name, listenerName) - err := fmt.Errorf("Invalid listener name provided") - defaultCondition. - Message(err.Error()). - SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) - *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 - return err - } - listenersForRoute = append(listenersForRoute, gateway.Spec.Listeners[i]) - } else { - listenersForRoute = append(listenersForRoute, gateway.Spec.Listeners...) - } - - // TODO: Validation for hostname (those being fqdns) need to validate as per the K8 gateway req. - var listenersMatchedToRoute []gatewayv1.Listener - for _, listenerObj := range listenersForRoute { - // check from store - hostInListener := listenerObj.Hostname - isListenerFqdnWildcard := false - matched := false - // TODO: - // Use case to handle for validations of hostname: - // USe case 1: Shouldn't contain mor than 1 * - // USe case 2: * should be at the beginning only - if hostInListener == nil || *hostInListener == "" || *hostInListener == utils.WILDCARD { - matched = true - } else { - // mark listener fqdn if it has * - if strings.HasPrefix(string(*hostInListener), utils.WILDCARD) { - isListenerFqdnWildcard = true - } - for _, host := range httpRoute.Spec.Hostnames { - // casese to consider: - // Case 1: hostname of gateway is wildcard(empty) and hostname from httproute is not wild card - // Case 2: hostname of gateway is not wild card and hostname from httproute is wildcard - // case 3: hostname of gateway is wildcard(empty) and hostname from httproute is wildcard - // case 4: hostname of gateway is not wildcard and hostname from httproute is not wildcard - isHttpRouteHostFqdnWildcard := false - if strings.HasPrefix(string(host), utils.WILDCARD) { - isHttpRouteHostFqdnWildcard = true - } - if isHttpRouteHostFqdnWildcard && isListenerFqdnWildcard { - // both are true. Match nonwildcard part - // Use case: 1. GW: *.avi.internal HttpRoute: *.bar.avi.internal - // USe case: 2. GW: *.bar.avi.internal HttpRoute: *.avi.internal - if utils.CheckSubdomainOverlapping(string(host), string(*hostInListener)) { - matched = true - break - } - - } else if !isHttpRouteHostFqdnWildcard && !isListenerFqdnWildcard { - // both are complete fqdn - if string(host) == string(*hostInListener) { - matched = true - break - } - } else { - if isHttpRouteHostFqdnWildcard { - // httpRoute hostFqdn is wildcard - matched = matched || isRegexMatch(string(host), string(*hostInListener), key) - } else if isListenerFqdnWildcard { - // listener fqdn is wildcard - matched = matched || isRegexMatch(string(*hostInListener), string(host), key) - } - - } - - } - // if there are no hostnames specified, all parent listneres should be matched. - if len(httpRoute.Spec.Hostnames) == 0 { - matched = true - } - } - if !matched { - utils.AviLog.Warnf("key: %s, msg: Gateway object %s don't have any listeners that matches the hostnames in HTTPRoute %s", key, gateway.Name, httpRoute.Name) - continue - } - listenersMatchedToRoute = append(listenersMatchedToRoute, listenerObj) - } - if len(listenersMatchedToRoute) == 0 { - err := fmt.Errorf("Hostname in Gateway Listener doesn't match with any of the hostnames in HTTPRoute") - defaultCondition. - Message(err.Error()). - SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) - *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 - gwRouteNsName := fmt.Sprintf("%s/%s/%s/%s", gwNsName, lib.HTTPRoute, httpRoute.Namespace, httpRoute.Name) - found, hosts := akogatewayapiobjects.GatewayApiLister().GetGatewayRouteToHostname(gwRouteNsName) - if found { - utils.AviLog.Warnf("key: %s, msg: Hostname in Gateway Listener doesn't match with any of the hostnames in HTTPRoute", key) - utils.AviLog.Debugf("key: %s, msg: %d hosts mapped to the route %s/%s/%s", key, len(hosts), "HTTPRoute", httpRoute.Namespace, httpRoute.Name) - return nil - } - return err - } - gatewayStatus := gwStatus.DeepCopy() - for _, listenerObj := range listenersMatchedToRoute { - listenerName := listenerObj.Name - // Increment the attached routes of the listener in the Gateway object - - i := akogatewayapilib.FindListenerStatusByName(string(listenerName), gatewayStatus.Listeners) - if i == -1 { - utils.AviLog.Errorf("key: %s, msg: Gateway status is missing for the listener with name %s", key, listenerName) - err := fmt.Errorf("Couldn't find the listener %s in the Gateway status", listenerName) - defaultCondition. - Message(err.Error()). - SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) - *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 - return err - } - - gatewayStatus.Listeners[i].AttachedRoutes += 1 - } - akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) - - defaultCondition. - Reason(string(gatewayv1.GatewayReasonAccepted)). - Status(metav1.ConditionTrue). - Message("Parent reference is valid"). - SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) - utils.AviLog.Infof("key: %s, msg: Parent Reference %s of HTTPRoute object %s is valid", key, name, httpRoute.Name) - *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 - return nil -} diff --git a/ako-gateway-api/nodes/dequeue_ingestion.go b/ako-gateway-api/nodes/dequeue_ingestion.go index 90f36a1f1..9283b8273 100644 --- a/ako-gateway-api/nodes/dequeue_ingestion.go +++ b/ako-gateway-api/nodes/dequeue_ingestion.go @@ -36,6 +36,15 @@ func DequeueIngestion(key string, fullsync bool) { if !valid { return } + if objType == lib.HTTPRoute { + httpRoute, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().HTTPRouteInformer.Lister().HTTPRoutes(namespace).Get(name) + if err == nil { + utils.AviLog.Debugf("key: %s, msg: Successfully retrieved the HTTPRoute object %s", key, name) + if !IsHTTPRouteValid(key, httpRoute) { + return + } + } + } gatewayNsNameList, found := schema.GetGateways(namespace, name, key) if !found { diff --git a/ako-gateway-api/nodes/gateway_model.go b/ako-gateway-api/nodes/gateway_model.go index f574daa03..099f35d92 100644 --- a/ako-gateway-api/nodes/gateway_model.go +++ b/ako-gateway-api/nodes/gateway_model.go @@ -23,6 +23,7 @@ import ( gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" akogatewayapilib "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/lib" + akogatewayapiobjects "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/objects" "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/internal/lib" "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/internal/nodes" "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/pkg/utils" @@ -77,8 +78,12 @@ func (o *AviObjectGraph) BuildGatewayParent(gateway *gatewayv1.Gateway, key stri func BuildPortProtocols(gateway *gatewayv1.Gateway, key string) []nodes.AviPortHostProtocol { var portProtocols []nodes.AviPortHostProtocol - for _, listener := range gateway.Spec.Listeners { + gatewayStatus := akogatewayapiobjects.GatewayApiLister().GetGatewayToGatewayStatusMapping(utils.ObjKey(gateway.GetNamespace() + "/" + gateway.GetName())) + for i, listener := range gateway.Spec.Listeners { + if gatewayStatus.Listeners[i].Conditions[0].Type == string(gatewayv1.ListenerConditionAccepted) && gatewayStatus.Listeners[i].Conditions[0].Status == "False" { + continue + } pp := nodes.AviPortHostProtocol{Port: int32(listener.Port), Protocol: string(listener.Protocol)} //TLS config on listener is present if listener.TLS != nil && len(listener.TLS.CertificateRefs) > 0 { @@ -96,7 +101,11 @@ func BuildTLSNodesForGateway(gateway *gatewayv1.Gateway, key string) []*nodes.Av var tlsNodes []*nodes.AviTLSKeyCertNode var ns, name string cs := utils.GetInformers().ClientSet - for _, listener := range gateway.Spec.Listeners { + gatewayStatus := akogatewayapiobjects.GatewayApiLister().GetGatewayToGatewayStatusMapping(utils.ObjKey(gateway.GetNamespace() + "/" + gateway.GetName())) + for i, listener := range gateway.Spec.Listeners { + if gatewayStatus.Listeners[i].Conditions[0].Type == string(gatewayv1.ListenerConditionAccepted) && gatewayStatus.Listeners[i].Conditions[0].Status == "False" { + continue + } if listener.TLS != nil { for _, certRef := range listener.TLS.CertificateRefs { //kind is validated at ingestion @@ -161,7 +170,11 @@ func DeleteTLSNode(key string, object *AviObjectGraph, gateway *gatewayv1.Gatewa var tlsNodes []*nodes.AviTLSKeyCertNode _, _, secretName := lib.ExtractTypeNameNamespace(key) evhVsCertRefs := object.GetAviEvhVS()[0].SSLKeyCertRefs - for _, listener := range gateway.Spec.Listeners { + gatewayStatus := akogatewayapiobjects.GatewayApiLister().GetGatewayToGatewayStatusMapping(utils.ObjKey(gateway.GetNamespace() + "/" + gateway.GetName())) + for i, listener := range gateway.Spec.Listeners { + if gatewayStatus.Listeners[i].Conditions[0].Type == string(gatewayv1.ListenerConditionAccepted) && gatewayStatus.Listeners[i].Conditions[0].Status == "False" { + continue + } if listener.TLS != nil { for _, certRef := range listener.TLS.CertificateRefs { name := string(certRef.Name) @@ -188,7 +201,11 @@ func AddTLSNode(key string, object *AviObjectGraph, gateway *gatewayv1.Gateway, var tlsNodes []*nodes.AviTLSKeyCertNode _, _, secretName := lib.ExtractTypeNameNamespace(key) evhVsCertRefs := object.GetAviEvhVS()[0].SSLKeyCertRefs - for _, listener := range gateway.Spec.Listeners { + gatewayStatus := akogatewayapiobjects.GatewayApiLister().GetGatewayToGatewayStatusMapping(utils.ObjKey(gateway.GetNamespace() + "/" + gateway.GetName())) + for i, listener := range gateway.Spec.Listeners { + if gatewayStatus.Listeners[i].Conditions[0].Type == string(gatewayv1.ListenerConditionAccepted) && gatewayStatus.Listeners[i].Conditions[0].Status == "False" { + continue + } if listener.TLS != nil { for _, certRef := range listener.TLS.CertificateRefs { name := string(certRef.Name) diff --git a/ako-gateway-api/nodes/gateway_model_rel.go b/ako-gateway-api/nodes/gateway_model_rel.go index bd5856337..af73c9d6f 100644 --- a/ako-gateway-api/nodes/gateway_model_rel.go +++ b/ako-gateway-api/nodes/gateway_model_rel.go @@ -19,7 +19,9 @@ import ( "fmt" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" akogatewayapilib "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/lib" akogatewayapiobjects "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/objects" @@ -126,8 +128,12 @@ func GatewayGetGw(namespace, name, key string) ([]string, bool) { hostnames := make(map[string]string, 0) var gwHostnames []string //var hostnames map[string]string + gatewayStatus := akogatewayapiobjects.GatewayApiLister().GetGatewayToGatewayStatusMapping(utils.ObjKey(gwNsName)) - for _, listenerObj := range gwObj.Spec.Listeners { + for i, listenerObj := range gwObj.Spec.Listeners { + if gatewayStatus.Listeners[i].Conditions[0].Type == string(gatewayv1.ListenerConditionAccepted) && gatewayStatus.Listeners[i].Conditions[0].Status != "True" { + continue + } gwListener := akogatewayapiobjects.GatewayListenerStore{} gwListener.Name = string(listenerObj.Name) gwListener.Gateway = gwNsName @@ -258,7 +264,20 @@ func HTTPRouteToGateway(namespace, name, key string) ([]string, bool) { var gatewayList []string var gwNsNameList []string parentNameToHostnameMap := make(map[string][]string) + statusIndex := 0 for _, parentRef := range hrObj.Spec.ParentRefs { + if statusIndex >= len(hrObj.Status.Parents) { + break + } + if hrObj.Status.RouteStatus.Parents[statusIndex].ParentRef.Name != parentRef.Name { + continue + } + for statusIndex < len(hrObj.Status.Parents) && (parentRef.SectionName != nil && *hrObj.Status.RouteStatus.Parents[statusIndex].ParentRef.SectionName != *parentRef.SectionName) { + statusIndex += 1 + } + if hrObj.Status.Parents[statusIndex].Conditions[0].Type == string(gatewayv1.RouteConditionAccepted) && hrObj.Status.Parents[statusIndex].Conditions[0].Status == metav1.ConditionFalse { + continue + } hostnameIntersection, _ := parentNameToHostnameMap[string(parentRef.Name)] ns := namespace if parentRef.Namespace != nil { @@ -332,6 +351,7 @@ func HTTPRouteToGateway(namespace, name, key string) ([]string, bool) { gwNsNameList = append(gwNsNameList, gwNsName) } parentNameToHostnameMap[string(parentRef.Name)] = hostnameIntersection + statusIndex += 1 } utils.AviLog.Debugf("key: %s, msg: Gateways retrieved %s", key, gwNsNameList) @@ -343,7 +363,7 @@ func HTTPRouteChanges(namespace, name, key string) ([]string, bool) { hrObj, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().HTTPRouteInformer.Lister().HTTPRoutes(namespace).Get(name) if err != nil { if !errors.IsNotFound(err) { - utils.AviLog.Errorf("key: %s, msg: got error while getting gateway: %v", key, err) + utils.AviLog.Errorf("key: %s, msg: got error while getting httproute: %v", key, err) return []string{}, false } // httproute must be deleted so remove mappings diff --git a/ako-gateway-api/nodes/route_validator.go b/ako-gateway-api/nodes/route_validator.go new file mode 100644 index 000000000..374091ed5 --- /dev/null +++ b/ako-gateway-api/nodes/route_validator.go @@ -0,0 +1,283 @@ +/* + * Copyright 2023-2024 VMware, Inc. + * All Rights Reserved. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* http://www.apache.org/licenses/LICENSE-2.0 +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package nodes + +import ( + "fmt" + "regexp" + "strings" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + + "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/internal/status" + + akogatewayapilib "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/lib" + akogatewayapiobjects "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/objects" + akogatewayapistatus "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/ako-gateway-api/status" + "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/internal/lib" + "github.com/vmware/load-balancer-and-ingress-services-for-kubernetes/pkg/utils" +) + +func isRegexMatch(stringWithWildCard string, stringToBeMatched string, key string) bool { + // replace the wildcard character with a regex + replacedHostname := strings.Replace(stringWithWildCard, utils.WILDCARD, utils.FQDN_LABEL_REGEX, 1) + // create the expression for pattern matching + pattern := fmt.Sprintf("^%s$", replacedHostname) + expr, err := regexp.Compile(pattern) + if err != nil { + utils.AviLog.Warnf("key: %s, msg: unable to compile wildcard string to regex object. Err: %s", key, err) + } + return expr.MatchString(stringToBeMatched) +} + +func IsHTTPRouteValid(key string, obj *gatewayv1.HTTPRoute) bool { + + httpRoute := obj.DeepCopy() + httpRouteStatus := obj.Status.DeepCopy() + httpRouteStatus.Parents = make([]gatewayv1.RouteParentStatus, 0, len(httpRoute.Spec.ParentRefs)) + var invalidParentRefCount int + parentRefIndexInHttpRouteStatus := 0 + for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs { + err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus) + if err != nil { + invalidParentRefCount++ + parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name + utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err) + } + } + akogatewayapistatus.Record(key, httpRoute, &status.Status{HTTPRouteStatus: httpRouteStatus}) + + // No valid attachment, we can't proceed with this HTTPRoute object. + if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) { + utils.AviLog.Errorf("key: %s, msg: HTTPRoute object %s is not valid", key, httpRoute.Name) + akogatewayapilib.AKOControlConfig().EventRecorder().Eventf(httpRoute, corev1.EventTypeWarning, + lib.Detached, "HTTPRoute object %s is not valid", httpRoute.Name) + return false + } + utils.AviLog.Infof("key: %s, msg: HTTPRoute object %s is valid", key, httpRoute.Name) + return true +} + +func validateParentReference(key string, httpRoute *gatewayv1.HTTPRoute, httpRouteStatus *gatewayv1.HTTPRouteStatus, parentRefIndexFromSpec int, parentRefIndexInHttpRouteStatus *int) error { + + name := string(httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name) + namespace := httpRoute.Namespace + if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Namespace != nil { + namespace = string(*httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Namespace) + } + gwNsName := namespace + "/" + name + obj, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().GatewayInformer.Lister().Gateways(namespace).Get(name) + if err != nil { + utils.AviLog.Errorf("key: %s, msg: unable to get the gateway object. err: %s", key, err) + return err + } + gateway := obj.DeepCopy() + + gwClass := string(gateway.Spec.GatewayClassName) + _, isAKOCtrl := akogatewayapiobjects.GatewayApiLister().IsGatewayClassControllerAKO(gwClass) + if !isAKOCtrl { + utils.AviLog.Warnf("key: %s, msg: controller for the parent reference %s of HTTPRoute object %s is not ako", key, name, httpRoute.Name) + return fmt.Errorf("controller for the parent reference %s of HTTPRoute object %s is not ako", name, httpRoute.Name) + } + // creates the Parent status only when the AKO is the gateway controller + httpRouteStatus.Parents = append(httpRouteStatus.Parents, gatewayv1.RouteParentStatus{}) + httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ControllerName = akogatewayapilib.GatewayController + httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ParentRef.Name = gatewayv1.ObjectName(name) + httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ParentRef.Namespace = (*gatewayv1.Namespace)(&namespace) + if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName != nil { + httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].ParentRef.SectionName = httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName + } + + defaultCondition := akogatewayapistatus.NewCondition(). + Type(string(gatewayv1.RouteConditionAccepted)). + Status(metav1.ConditionFalse). + ObservedGeneration(httpRoute.ObjectMeta.Generation) + + gatewayStatus := akogatewayapiobjects.GatewayApiLister().GetGatewayToGatewayStatusMapping(utils.ObjKey(gateway.GetNamespace() + "/" + gateway.GetName())) + + if len(gatewayStatus.Conditions) == 0 { + // Gateway processing by AKO has not started. + utils.AviLog.Errorf("key: %s, msg: AKO is yet to process Gateway %s for parent reference %s.", key, gateway.Name, name) + err := fmt.Errorf("AKO is yet to process Gateway %s for parent reference %s", gateway.Name, name) + defaultCondition. + Reason(string(gatewayv1.RouteReasonPending)). + Message(err.Error()). + SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) + *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 + return err + } + + // Attach only when gateway configuration is valid + currentGatewayStatusCondition := gatewayStatus.Conditions[0] + if currentGatewayStatusCondition.Status != metav1.ConditionTrue { + // Gateway is not in an expected state. + utils.AviLog.Errorf("key: %s, msg: Gateway %s for parent reference %s is in Invalid State", key, gateway.Name, name) + err := fmt.Errorf("Gateway %s is in Invalid State", gateway.Name) + defaultCondition. + Reason(string(gatewayv1.RouteReasonPending)). + Message(err.Error()). + SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) + *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 + return err + } + + //section name is optional + var listenersForRoute []gatewayv1.Listener + if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName != nil { + listenerName := *httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName + i := akogatewayapilib.FindListenerByName(string(listenerName), gateway.Spec.Listeners) + if i == -1 { + // listener is not present in gateway + utils.AviLog.Errorf("key: %s, msg: unable to find the listener from the Section Name %s in Parent Reference %s", key, name, listenerName) + err := fmt.Errorf("Invalid listener name provided") + defaultCondition. + Reason(string(gatewayv1.RouteReasonNoMatchingParent)). + Message(err.Error()). + SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) + *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 + return err + } + if gatewayStatus.Listeners[i].Conditions[0].Type == string(gatewayv1.GatewayConditionAccepted) && gatewayStatus.Listeners[i].Conditions[0].Status == metav1.ConditionFalse { + // listener is present in gateway but is in invalid state + utils.AviLog.Errorf("key: %s, msg: Matching gateway listener %s in Parent Reference is in invalid state", key, listenerName) + err := fmt.Errorf("Matching gateway listener is in Invalid state") + defaultCondition. + Reason(string(gatewayv1.RouteReasonPending)). + Message(err.Error()). + SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) + *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 + return err + } + listenersForRoute = append(listenersForRoute, gateway.Spec.Listeners[i]) + } else { + listenersForRoute = append(listenersForRoute, gateway.Spec.Listeners...) + } + + // TODO: Validation for hostname (those being fqdns) need to validate as per the K8 gateway req. + var listenersMatchedToRoute []gatewayv1.Listener + for _, listenerObj := range listenersForRoute { + // check from store + hostInListener := listenerObj.Hostname + isListenerFqdnWildcard := false + matched := false + // TODO: + // Use case to handle for validations of hostname: + // USe case 1: Shouldn't contain mor than 1 * + // USe case 2: * should be at the beginning only + if hostInListener == nil || *hostInListener == "" || *hostInListener == utils.WILDCARD { + matched = true + } else { + // mark listener fqdn if it has * + if strings.HasPrefix(string(*hostInListener), utils.WILDCARD) { + isListenerFqdnWildcard = true + } + for _, host := range httpRoute.Spec.Hostnames { + // casese to consider: + // Case 1: hostname of gateway is wildcard(empty) and hostname from httproute is not wild card + // Case 2: hostname of gateway is not wild card and hostname from httproute is wildcard + // case 3: hostname of gateway is wildcard(empty) and hostname from httproute is wildcard + // case 4: hostname of gateway is not wildcard and hostname from httproute is not wildcard + isHttpRouteHostFqdnWildcard := false + if strings.HasPrefix(string(host), utils.WILDCARD) { + isHttpRouteHostFqdnWildcard = true + } + if isHttpRouteHostFqdnWildcard && isListenerFqdnWildcard { + // both are true. Match nonwildcard part + // Use case: 1. GW: *.avi.internal HttpRoute: *.bar.avi.internal + // USe case: 2. GW: *.bar.avi.internal HttpRoute: *.avi.internal + if utils.CheckSubdomainOverlapping(string(host), string(*hostInListener)) { + matched = true + break + } + + } else if !isHttpRouteHostFqdnWildcard && !isListenerFqdnWildcard { + // both are complete fqdn + if string(host) == string(*hostInListener) { + matched = true + break + } + } else { + if isHttpRouteHostFqdnWildcard { + // httpRoute hostFqdn is wildcard + matched = matched || isRegexMatch(string(host), string(*hostInListener), key) + } else if isListenerFqdnWildcard { + // listener fqdn is wildcard + matched = matched || isRegexMatch(string(*hostInListener), string(host), key) + } + + } + + } + // if there are no hostnames specified, all parent listneres should be matched. + if len(httpRoute.Spec.Hostnames) == 0 { + matched = true + } + } + if !matched { + utils.AviLog.Warnf("key: %s, msg: Gateway object %s don't have any listeners that matches the hostnames in HTTPRoute %s", key, gateway.Name, httpRoute.Name) + continue + } + listenersMatchedToRoute = append(listenersMatchedToRoute, listenerObj) + } + if len(listenersMatchedToRoute) == 0 { + err := fmt.Errorf("Hostname in Gateway Listener doesn't match with any of the hostnames in HTTPRoute") + defaultCondition. + Reason(string(gatewayv1.RouteReasonNoMatchingListenerHostname)). + Message(err.Error()). + SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) + *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 + gwRouteNsName := fmt.Sprintf("%s/%s/%s/%s", gwNsName, lib.HTTPRoute, httpRoute.Namespace, httpRoute.Name) + found, hosts := akogatewayapiobjects.GatewayApiLister().GetGatewayRouteToHostname(gwRouteNsName) + if found { + utils.AviLog.Warnf("key: %s, msg: Hostname in Gateway Listener doesn't match with any of the hostnames in HTTPRoute", key) + utils.AviLog.Debugf("key: %s, msg: %d hosts mapped to the route %s/%s/%s", key, len(hosts), "HTTPRoute", httpRoute.Namespace, httpRoute.Name) + return nil + } + return err + } + + //TODO: Add a condition to check whether this route is allowed by the parent gateways allowedroute field and set gatewayv1.RouteReasonNotAllowedByListeners reason while implemenating gateway->listener->allowedRoutes->Selector + + for _, listenerObj := range listenersMatchedToRoute { + listenerName := listenerObj.Name + // Increment the attached routes of the listener in the Gateway object + + i := akogatewayapilib.FindListenerStatusByName(string(listenerName), gatewayStatus.Listeners) + if i == -1 { + utils.AviLog.Errorf("key: %s, msg: Gateway status is missing for the listener with name %s", key, listenerName) + err := fmt.Errorf("Couldn't find the listener %s in the Gateway status", listenerName) + defaultCondition. + Reason(string(gatewayv1.RouteReasonNoMatchingParent)). + Message(err.Error()). + SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) + *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 + return err + } + + gatewayStatus.Listeners[i].AttachedRoutes += 1 + } + akogatewayapistatus.Record(key, gateway, &status.Status{GatewayStatus: gatewayStatus}) + + defaultCondition. + Reason(string(gatewayv1.RouteReasonAccepted)). + Status(metav1.ConditionTrue). + Message("Parent reference is valid"). + SetIn(&httpRouteStatus.Parents[*parentRefIndexInHttpRouteStatus].Conditions) + utils.AviLog.Infof("key: %s, msg: Parent Reference %s of HTTPRoute object %s is valid", key, name, httpRoute.Name) + *parentRefIndexInHttpRouteStatus = *parentRefIndexInHttpRouteStatus + 1 + return nil +} diff --git a/ako-gateway-api/status/gateway_status.go b/ako-gateway-api/status/gateway_status.go index 83b7121a5..d602af737 100644 --- a/ako-gateway-api/status/gateway_status.go +++ b/ako-gateway-api/status/gateway_status.go @@ -17,6 +17,7 @@ package status import ( "context" "encoding/json" + "errors" "reflect" "strings" @@ -159,13 +160,12 @@ func (o *gateway) Update(key string, option status.StatusOptions) { conditionStatus := metav1.ConditionTrue if option.Options.Message != "" { - conditionType = string(gatewayv1.GatewayConditionAccepted) + conditionType = string(gatewayv1.GatewayConditionProgrammed) conditionStatus = metav1.ConditionFalse reason = string(gatewayv1.GatewayReasonInvalid) message = option.Options.Message } else { conditionType = string(gatewayv1.GatewayConditionProgrammed) - conditionStatus = metav1.ConditionTrue reason = string(gatewayv1.GatewayReasonProgrammed) message = "Virtual service configured/updated" } @@ -177,15 +177,25 @@ func (o *gateway) Update(key string, option status.StatusOptions) { Message(message). SetIn(&gatewaystatus.Conditions) - for i := range gatewaystatus.Listeners { + for i, listener := range gatewaystatus.Listeners { listenerCondition := NewCondition() - listenerCondition. - Type(conditionType). - Status(conditionStatus). - Reason(reason). - ObservedGeneration(gw.ObjectMeta.Generation). - Message(message). - SetIn(&gatewaystatus.Listeners[i].Conditions) + if listener.Conditions[0].Type == string(gatewayv1.ListenerConditionAccepted) && listener.Conditions[0].Status == metav1.ConditionTrue && listener.Conditions[1].Type == string(gatewayv1.ListenerConditionResolvedRefs) && listener.Conditions[1].Status == metav1.ConditionTrue { + listenerCondition. + Type(string(gatewayv1.ListenerConditionProgrammed)). + Status(conditionStatus). + Reason(string(gatewayv1.ListenerReasonProgrammed)). + ObservedGeneration(gw.ObjectMeta.Generation). + Message(message). + SetIn(&gatewaystatus.Listeners[i].Conditions) + } else { + listenerCondition. + Type(string(gatewayv1.ListenerConditionProgrammed)). + Status(metav1.ConditionFalse). + Reason(string(gatewayv1.ListenerReasonInvalid)). + ObservedGeneration(gw.ObjectMeta.Generation). + Message("Virtual service not configured/updated for this listener"). + SetIn(&gatewaystatus.Listeners[i].Conditions) + } } o.Patch(key, gw, &status.Status{GatewayStatus: gatewaystatus}) @@ -219,37 +229,37 @@ func (o *gateway) BulkUpdate(key string, options []status.StatusOptions) { } } -func (o *gateway) Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) { +func (o *gateway) Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) (runtime.Object, error) { retry := 0 if len(retryNum) > 0 { retry = retryNum[0] if retry >= 5 { utils.AviLog.Errorf("key: %s, msg: Patch retried 5 times, aborting", key) - return + return obj, errors.New("Patch retried 5 times, aborting") } } gw := obj.(*gatewayv1.Gateway) if o.isStatusEqual(&gw.Status, status.GatewayStatus) { - return + return obj, nil } patchPayload, _ := json.Marshal(map[string]interface{}{ "status": status.GatewayStatus, }) - _, err := akogatewayapilib.AKOControlConfig().GatewayAPIClientset().GatewayV1().Gateways(gw.Namespace).Patch(context.TODO(), gw.Name, types.MergePatchType, patchPayload, metav1.PatchOptions{}, "status") + updatedGateway, err := akogatewayapilib.AKOControlConfig().GatewayAPIClientset().GatewayV1().Gateways(gw.Namespace).Patch(context.TODO(), gw.Name, types.MergePatchType, patchPayload, metav1.PatchOptions{}, "status") if err != nil { utils.AviLog.Warnf("key: %s, msg: there was an error in updating the gateway status. err: %+v, retry: %d", key, err, retry) updatedGW, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().GatewayInformer.Lister().Gateways(gw.Namespace).Get(gw.Name) if err != nil { utils.AviLog.Warnf("gateway not found %v", err) - return + return updatedGW, err } - o.Patch(key, updatedGW, status, retry+1) - return + return o.Patch(key, updatedGW, status, retry+1) } utils.AviLog.Infof("key: %s, msg: Successfully updated the gateway %s/%s status %+v", key, gw.Namespace, gw.Name, utils.Stringify(status)) + return updatedGateway, nil } func (o *gateway) isStatusEqual(old, new *gatewayv1.GatewayStatus) bool { diff --git a/ako-gateway-api/status/gatewayclass_status.go b/ako-gateway-api/status/gatewayclass_status.go index ebd23e610..27c8f88e9 100644 --- a/ako-gateway-api/status/gatewayclass_status.go +++ b/ako-gateway-api/status/gatewayclass_status.go @@ -17,6 +17,7 @@ package status import ( "context" "encoding/json" + "errors" "reflect" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -72,37 +73,36 @@ func (o *gatewayClass) BulkUpdate(key string, options []status.StatusOptions) { // TODO: Add this code when we publish the status from the rest layer } -func (o *gatewayClass) Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) { +func (o *gatewayClass) Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) (runtime.Object, error) { retry := 0 if len(retryNum) > 0 { retry = retryNum[0] if retry >= 5 { utils.AviLog.Errorf("key: %s, msg: Patch retried 5 times, aborting", key) - return + return obj, errors.New("Patch retried 5 times, aborting") } } gatewayClass := obj.(*gatewayv1.GatewayClass) if o.isStatusEqual(&gatewayClass.Status, status.GatewayClassStatus) { - return + return obj, nil } patchPayload, _ := json.Marshal(map[string]interface{}{ "status": status.GatewayClassStatus, }) - _, err := akogatewayapilib.AKOControlConfig().GatewayAPIClientset().GatewayV1().GatewayClasses().Patch(context.TODO(), gatewayClass.Name, types.MergePatchType, patchPayload, metav1.PatchOptions{}, "status") + updatedObject, err := akogatewayapilib.AKOControlConfig().GatewayAPIClientset().GatewayV1().GatewayClasses().Patch(context.TODO(), gatewayClass.Name, types.MergePatchType, patchPayload, metav1.PatchOptions{}, "status") if err != nil { utils.AviLog.Warnf("key: %s, msg: there was an error in updating the GatewayClass status. err: %+v, retry: %d", key, err, retry) updatedObj, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().GatewayClassInformer.Lister().Get(gatewayClass.Name) if err != nil { utils.AviLog.Warnf("GatewayClass not found %v", err) - return + return updatedObj, err } - o.Patch(key, updatedObj, status, retry+1) - return + return o.Patch(key, updatedObj, status, retry+1) } - utils.AviLog.Infof("key: %s, msg: Successfully updated the GatewayClass %s status %+v %v", key, gatewayClass.Name, utils.Stringify(status), err) + return updatedObject, nil } func (o *gatewayClass) isStatusEqual(old, new *gatewayv1.GatewayClassStatus) bool { diff --git a/ako-gateway-api/status/httproute_status.go b/ako-gateway-api/status/httproute_status.go index ee46c8e70..a5157c7b5 100644 --- a/ako-gateway-api/status/httproute_status.go +++ b/ako-gateway-api/status/httproute_status.go @@ -17,6 +17,7 @@ package status import ( "context" "encoding/json" + "errors" "reflect" "strings" @@ -83,37 +84,37 @@ func (o *httproute) BulkUpdate(key string, options []status.StatusOptions) { // TODO: Add this code when we publish the status from the rest layer } -func (o *httproute) Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) { +func (o *httproute) Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) (runtime.Object, error) { retry := 0 if len(retryNum) > 0 { retry = retryNum[0] if retry >= 5 { utils.AviLog.Errorf("key: %s, msg: Patch retried 5 times, aborting", key) - return + return obj, errors.New("Patch retried 5 times, aborting") } } httpRoute := obj.(*gatewayv1.HTTPRoute) if o.isStatusEqual(&httpRoute.Status, status.HTTPRouteStatus) { - return + return obj, nil } patchPayload, _ := json.Marshal(map[string]interface{}{ "status": status.HTTPRouteStatus, }) - _, err := akogatewayapilib.AKOControlConfig().GatewayAPIClientset().GatewayV1().HTTPRoutes(httpRoute.Namespace).Patch(context.TODO(), httpRoute.Name, types.MergePatchType, patchPayload, metav1.PatchOptions{}, "status") + updatedObject, err := akogatewayapilib.AKOControlConfig().GatewayAPIClientset().GatewayV1().HTTPRoutes(httpRoute.Namespace).Patch(context.TODO(), httpRoute.Name, types.MergePatchType, patchPayload, metav1.PatchOptions{}, "status") if err != nil { utils.AviLog.Warnf("key: %s, msg: there was an error in updating the HTTPRoute status. err: %+v, retry: %d", key, err, retry) updatedObj, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().HTTPRouteInformer.Lister().HTTPRoutes(httpRoute.Namespace).Get(httpRoute.Name) if err != nil { utils.AviLog.Warnf("HTTPRoute not found %v", err) - return + return updatedObj, err } - o.Patch(key, updatedObj, status, retry+1) - return + return o.Patch(key, updatedObj, status, retry+1) } utils.AviLog.Infof("key: %s, msg: Successfully updated the HTTPRoute %s/%s status %+v", key, httpRoute.Namespace, httpRoute.Name, utils.Stringify(status)) + return updatedObject, nil } func (o *httproute) isStatusEqual(old, new *gatewayv1.HTTPRouteStatus) bool { diff --git a/ako-gateway-api/status/status.go b/ako-gateway-api/status/status.go index 42bc5585e..07eabbf84 100644 --- a/ako-gateway-api/status/status.go +++ b/ako-gateway-api/status/status.go @@ -27,7 +27,7 @@ import ( type StatusUpdater interface { Update(key string, option status.StatusOptions) BulkUpdate(key string, options []status.StatusOptions) - Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) + Patch(key string, obj runtime.Object, status *status.Status, retryNum ...int) (runtime.Object, error) Delete(key string, option status.StatusOptions) } @@ -74,7 +74,6 @@ func BulkUpdate(key string, objectType string, options []status.StatusOptions) e utils.AviLog.Debugf("key: %s, msg: Bulk update successful for object %s", key, objectType) return nil } - func Record(key string, obj runtime.Object, objStatus *status.Status) { var objectType string var statusOption status.StatusOptions diff --git a/internal/lib/constants.go b/internal/lib/constants.go index 6bd462cfb..9edd03680 100644 --- a/internal/lib/constants.go +++ b/internal/lib/constants.go @@ -222,6 +222,7 @@ const ( Synced = "Synced" Attached = "Attached" Detached = "Detached" + PatchFailed = "PatchFailed" InvalidConfiguration = "InvalidConfiguration" AKODeleteConfigSet = "AKODeleteConfigSet" AKODeleteConfigUnset = "AKODeleteConfigUnset" diff --git a/internal/rest/dequeue_nodes.go b/internal/rest/dequeue_nodes.go index 03192a74f..83b5e4bf7 100644 --- a/internal/rest/dequeue_nodes.go +++ b/internal/rest/dequeue_nodes.go @@ -1805,7 +1805,9 @@ func (rest *RestOperations) SSLKeyCertDelete(ssl_to_delete []avicache.NamespaceN for _, del_ssl := range ssl_to_delete { // Skip SSL cert deletion if it maps to the Default Router Cert if del_ssl.Name == defaultRouteCertName || del_ssl.Name == defaultRouteAltCertName { - continue + if !strings.HasSuffix(key, lib.DummyVSForStaleData) { + continue + } } ssl_key := avicache.NamespaceName{Namespace: namespace, Name: del_ssl.Name} ssl_cache, ok := rest.cache.SSLKeyCache.AviCacheGet(ssl_key) diff --git a/tests/gatewayapitests/graphlayer/gateway_test.go b/tests/gatewayapitests/graphlayer/gateway_test.go index 9eee5d3a7..954b6dea9 100644 --- a/tests/gatewayapitests/graphlayer/gateway_test.go +++ b/tests/gatewayapitests/graphlayer/gateway_test.go @@ -427,19 +427,17 @@ func TestSecretCreateDelete(t *testing.T) { g.Eventually(func() bool { found, _ := objects.SharedAviGraphLister().Get(modelName) return found - }, 30*time.Second).Should(gomega.Equal(true)) + }, 30*time.Second).Should(gomega.Equal(false)) _, aviModel := objects.SharedAviGraphLister().Get(modelName) - nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() - g.Expect(nodes).To(gomega.HaveLen(1)) - g.Expect(nodes[0].SSLKeyCertRefs).To(gomega.HaveLen(0)) + g.Expect(aviModel).To(gomega.BeNil()) integrationtest.AddSecret(secrets[0], DEFAULT_NAMESPACE, "cert", "key") g.Eventually(func() bool { found, aviModel := objects.SharedAviGraphLister().Get(modelName) if found { - nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() g.Expect(nodes).To(gomega.HaveLen(1)) g.Expect(nodes[0].SSLKeyCertRefs).To(gomega.HaveLen(1)) return true @@ -453,7 +451,7 @@ func TestSecretCreateDelete(t *testing.T) { g.Eventually(func() bool { found, aviModel := objects.SharedAviGraphLister().Get(modelName) if found { - nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() g.Expect(nodes).To(gomega.HaveLen(1)) g.Expect(nodes[0].SSLKeyCertRefs).To(gomega.HaveLen(0)) return true diff --git a/tests/gatewayapitests/graphlayer/httproute_test.go b/tests/gatewayapitests/graphlayer/httproute_test.go index 930fa2782..3580c2f49 100644 --- a/tests/gatewayapitests/graphlayer/httproute_test.go +++ b/tests/gatewayapitests/graphlayer/httproute_test.go @@ -1256,6 +1256,7 @@ func TestHTTPRouteWithMultipleGateways(t *testing.T) { integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName) integrationtest.DelEPorEPS(t, DEFAULT_NAMESPACE, svcName) akogatewayapitests.TeardownGateway(t, gatewayName1, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName2, DEFAULT_NAMESPACE) akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) } @@ -1416,3 +1417,986 @@ func TestHTTPRouteParentFQDN(t *testing.T) { akogatewayapitests.TeardownGateway(t, gatewayName1, DEFAULT_NAMESPACE) akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) } +func TestHttpRouteWithValidAndInvalidGatewayListeners(t *testing.T) { + gatewayName := "gateway-hr-08" + gatewayClassName := "gateway-class-hr-08" + httpRouteName := "http-route-hr-08" + svcName1 := "avisvc-hr-08-a" + svcName2 := "avisvc-hr-08-b" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + + g.Eventually(func() bool { + found, _ := objects.SharedAviGraphLister().Get(modelName) + return found + }, 25*time.Second).Should(gomega.Equal(true)) + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName1, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName1, false, false, "1.2.3") + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName2, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName2, false, false, "1.2.3") + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName1, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName2, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules := []gatewayv1.HTTPRouteRule{rule1, rule2} + + hostnames := []gatewayv1.Hostname{"foo-8080.com", "foo-8081.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(2)) + + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + childNode2 := nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName2) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName2) + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} + +func TestMultipleHttpRoutesWithValidAndInvalidGatewayListeners(t *testing.T) { + gatewayName := "gateway-hr-09" + gatewayClassName := "gateway-class-hr-09" + httpRouteName1 := "http-route-hr-09-a" + httpRouteName2 := "http-route-hr-09-b" + svcName := "avisvc-hr-09" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + + g.Eventually(func() bool { + found, _ := objects.SharedAviGraphLister().Get(modelName) + return found + }, 25*time.Second).Should(gomega.Equal(true)) + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName, false, false, "1.2.3") + + parentRefs1 := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, []int32{ports[0]}) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rules1 := []gatewayv1.HTTPRouteRule{rule1} + hostnames1 := []gatewayv1.Hostname{"foo-8080.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRouteName1, DEFAULT_NAMESPACE, parentRefs1, hostnames1, rules1) + + parentRefs2 := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, []int32{ports[1]}) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules2 := []gatewayv1.HTTPRouteRule{rule2} + hostnames2 := []gatewayv1.Hostname{"foo-8081.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRouteName2, DEFAULT_NAMESPACE, parentRefs2, hostnames2, rules2) + + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 30*time.Second).Should(gomega.Equal(1)) + + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName) + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName1, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName2, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} +func TestTransitionsHttpRouteWithPartiallyValidGatewayToValidGateway(t *testing.T) { + //1: One HTTPRoute with partially valid gateway + gatewayName := "gateway-hr-10" + gatewayClassName := "gateway-class-hr-10" + httpRouteName := "http-route-hr-10" + svcName1 := "avisvc-hr-10-a" + svcName2 := "avisvc-hr-10-b" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + + g.Eventually(func() bool { + found, _ := objects.SharedAviGraphLister().Get(modelName) + return found + }, 25*time.Second).Should(gomega.Equal(true)) + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName1, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName1, false, false, "1.2.3") + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName2, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName2, false, false, "1.2.3") + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName1, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName2, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules := []gatewayv1.HTTPRouteRule{rule1, rule2} + + hostnames := []gatewayv1.Hostname{"foo-8080.com", "foo-8081.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(2)) + + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + childNode2 := nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + listeners[1].Protocol = "HTTPS" + akogatewayapitests.UpdateGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + if len(gateway.Status.Listeners) < 2 { + return false + } + return gateway.Status.Listeners[1].Conditions[0].Status == metav1.ConditionTrue + //apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + gateway, _ := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + g.Expect(gateway.Status.Listeners[1].Conditions[0].Status).To(gomega.Equal(metav1.ConditionTrue)) + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + if len(nodes[0].EvhNodes) != 2 { + return 0 + } + return len(nodes[0].EvhNodes[0].VHMatches) + }, 30*time.Second).Should(gomega.Equal(2)) + + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + if len(nodes[0].EvhNodes) != 2 { + return 0 + } + return len(nodes[0].EvhNodes[1].VHMatches) + }, 30*time.Second).Should(gomega.Equal(2)) + time.Sleep(20 * time.Second) + + _, aviModel = objects.SharedAviGraphLister().Get(modelName) + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 = nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(2)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + g.Expect(*childNode1.VHMatches[1].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode1.VHMatches[1].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + + childNode2 = nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(2)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + g.Expect(*childNode2.VHMatches[1].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode2.VHMatches[1].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName2) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName2) + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} + +func TestTransitionsHttpRouteWithPartiallyValidGatewayToInvalidGateway(t *testing.T) { + t.Skip("Skipping since current implementation is not supporting partially Valid to Invalid gateway transition") + gatewayName := "gateway-hr-11" + gatewayClassName := "gateway-class-hr-11" + httpRouteName := "http-route-hr-11" + svcName1 := "avisvc-hr-11-a" + svcName2 := "avisvc-hr-11-b" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + + g.Eventually(func() bool { + found, _ := objects.SharedAviGraphLister().Get(modelName) + return found + }, 25*time.Second).Should(gomega.Equal(true)) + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName1, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName1, false, false, "1.2.3") + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName2, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName2, false, false, "1.2.3") + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName1, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName2, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules := []gatewayv1.HTTPRouteRule{rule1, rule2} + + hostnames := []gatewayv1.Hostname{"foo-8080.com", "foo-8081.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(2)) + + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + childNode2 := nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + listeners[0].Protocol = "TCP" + akogatewayapitests.UpdateGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + return apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + gateway, _ := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + g.Expect(gateway.Status.Listeners[1].Conditions[0].Status).To(gomega.Equal(metav1.ConditionTrue)) + + g.Eventually(func() int { + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes[0].VHMatches) + }, 50*time.Second).Should(gomega.Equal(2)) + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName2) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName2) + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) + +} + +func TestTransitionsHttpRouteWithInvalidGatewayToPartiallyValidGateway(t *testing.T) { + gatewayName := "gateway-hr-12" + gatewayClassName := "gateway-class-hr-12" + httpRouteName := "http-route-hr-12" + svcName1 := "avisvc-hr-12-a" + svcName2 := "avisvc-hr-12-b" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + listeners[0].Protocol = "TCP" + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + + g.Eventually(func() bool { + found, _ := objects.SharedAviGraphLister().Get(modelName) + return found + }, 25*time.Second).Should(gomega.Equal(false)) + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName1, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName1, false, false, "1.2.3") + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName2, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName2, false, false, "1.2.3") + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName1, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName2, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules := []gatewayv1.HTTPRouteRule{rule1, rule2} + + hostnames := []gatewayv1.Hostname{"foo-8080.com", "foo-8081.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + time.Sleep(10 * time.Second) + listeners[1].Protocol = "HTTPS" + akogatewayapitests.UpdateGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + return apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + gateway, _ := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + g.Expect(gateway.Status.Listeners[1].Conditions[0].Status).To(gomega.Equal(metav1.ConditionTrue)) + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(2)) + + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8081))) + + childNode2 := nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8081))) + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName2) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName2) + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) + +} + +func TestTransitionsHttpRouteWithValidGatewayToPartiallyValidGateway(t *testing.T) { + t.Skip("Skipping since current implementation is not supporting Valid to partially valid gateway transition") + gatewayName := "gateway-hr-13" + gatewayClassName := "gateway-class-hr-13" + httpRouteName := "http-route-hr-13" + svcName1 := "avisvc-hr-13-a" + svcName2 := "avisvc-hr-13-b" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + + g.Eventually(func() bool { + found, _ := objects.SharedAviGraphLister().Get(modelName) + return found + }, 25*time.Second).Should(gomega.Equal(true)) + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName1, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName1, false, false, "1.2.3") + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName2, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName2, false, false, "1.2.3") + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName1, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName2, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules := []gatewayv1.HTTPRouteRule{rule1, rule2} + + hostnames := []gatewayv1.Hostname{"foo-8080.com", "foo-8081.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(2)) + + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(2)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + g.Expect(*childNode1.VHMatches[1].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode1.VHMatches[1].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + + childNode2 := nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(2)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + g.Expect(*childNode2.VHMatches[1].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode2.VHMatches[1].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + + listeners[1].Protocol = "TCP" + akogatewayapitests.UpdateGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + return apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + gateway, _ := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + g.Expect(gateway.Status.Listeners[1].Conditions[0].Status).To(gomega.Equal(metav1.ConditionFalse)) + + g.Eventually(func() int { + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes[0].VHMatches) + }, 50*time.Second).Should(gomega.Equal(1)) + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + + childNode1 = nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(2)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + g.Expect(*childNode1.VHMatches[1].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode1.VHMatches[1].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode1.VHMatches[1].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + + childNode2 = nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(2)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + g.Expect(*childNode2.VHMatches[1].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode2.VHMatches[1].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(2)) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + g.Expect(childNode2.VHMatches[1].Rules[0].Matches.VsPort.Ports[1]).To(gomega.Equal(int64(8081))) + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName2) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName2) + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} + +func TestTransitionsMultipleHttpRoutesWithPartiallyValidGatewayToValidGateway(t *testing.T) { + // 1: Two HTTPRoute with partially valid gateway + gatewayName := "gateway-hr-14" + gatewayClassName := "gateway-class-hr-14" + httpRoute1Name := "http-route-hr-14a" + httpRoute2Name := "http-route-hr-14b" + svcName1 := "avisvc-hr-14-a" + svcName2 := "avisvc-hr-14-b" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + + g.Eventually(func() bool { + found, _ := objects.SharedAviGraphLister().Get(modelName) + return found + }, 25*time.Second).Should(gomega.Equal(true)) + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName1, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName1, false, false, "1.2.3") + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName2, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName2, false, false, "1.2.3") + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, []int32{ports[0]}) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName1, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName2, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules := []gatewayv1.HTTPRouteRule{rule1, rule2} + + hostnames := []gatewayv1.Hostname{"foo-8080.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRoute1Name, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + hostnames = []gatewayv1.Hostname{"foo-8081.com"} + parentRefs = akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, []int32{ports[1]}) + akogatewayapitests.SetupHTTPRoute(t, httpRoute2Name, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(2)) + + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + childNode2 := nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + listeners[1].Protocol = "HTTPS" + akogatewayapitests.UpdateGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + return apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + gateway, _ := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + g.Expect(gateway.Status.Listeners[1].Conditions[0].Status).To(gomega.Equal(metav1.ConditionTrue)) + g.Eventually(func() int { + _, aviModel = objects.SharedAviGraphLister().Get(modelName) + nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(4)) + + childNode1 = nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + childNode2 = nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + childNode3 := nodes[0].EvhNodes[2] + g.Expect(childNode3.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode3.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode3.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode3.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode3.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode3.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode3.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode3.VHMatches[0].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode3.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode3.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode3.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode3.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8081))) + + childNode4 := nodes[0].EvhNodes[3] + g.Expect(childNode4.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode4.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode4.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode4.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode4.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode4.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode4.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode4.VHMatches[0].Host).To(gomega.Equal("foo-8081.com")) + g.Expect(len(childNode4.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode4.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode4.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode4.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8081))) + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName2) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName2) + akogatewayapitests.TeardownHTTPRoute(t, httpRoute1Name, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownHTTPRoute(t, httpRoute2Name, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} +func TestTransitionsMultipleHttpRouteWithInvalidGatewayToPartiallyValidGateway(t *testing.T) { + // 1: Two HTTPRoute with invalid gateway + gatewayName := "gateway-hr-16" + gatewayClassName := "gateway-class-hr-16" + httpRoute1Name := "http-route-hr-16a" + httpRoute2Name := "http-route-hr-16b" + svcName1 := "avisvc-hr-16-a" + svcName2 := "avisvc-hr-16-b" + ports := []int32{8080, 8081} + modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName) + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[0].Protocol = "TCP" + listeners[1].Protocol = "TCP" + akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g := gomega.NewGomegaWithT(t) + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName1, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName1, false, false, "1.2.3") + + integrationtest.CreateSVC(t, DEFAULT_NAMESPACE, svcName2, corev1.ProtocolTCP, corev1.ServiceTypeClusterIP, false) + integrationtest.CreateEP(t, DEFAULT_NAMESPACE, svcName2, false, false, "1.2.3") + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, []int32{ports[0]}) + rule1 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/foo"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName1, DEFAULT_NAMESPACE, "8080", "1"}}, nil) + rule2 := akogatewayapitests.GetHTTPRouteRuleV1([]string{"/bar"}, []string{}, + map[string][]string{"RequestHeaderModifier": {"add", "remove", "replace"}}, + [][]string{{svcName2, DEFAULT_NAMESPACE, "8081", "1"}}, nil) + rules := []gatewayv1.HTTPRouteRule{rule1, rule2} + hostnames := []gatewayv1.Hostname{"foo-8080.com"} + akogatewayapitests.SetupHTTPRoute(t, httpRoute1Name, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + hostnames = []gatewayv1.Hostname{"foo-8081.com"} + parentRefs = akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, []int32{ports[1]}) + akogatewayapitests.SetupHTTPRoute(t, httpRoute2Name, DEFAULT_NAMESPACE, parentRefs, hostnames, rules) + listeners[0].Protocol = "HTTPS" + time.Sleep(10 * time.Second) + akogatewayapitests.UpdateGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners) + + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + return apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + gateway, _ := akogatewayapitests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + g.Expect(gateway.Status.Listeners[0].Conditions[0].Status).To(gomega.Equal(metav1.ConditionTrue)) + g.Eventually(func() int { + found, aviModel := objects.SharedAviGraphLister().Get(modelName) + if !found { + return 0 + } + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + return len(nodes[0].EvhNodes) + }, 50*time.Second).Should(gomega.Equal(2)) + _, aviModel := objects.SharedAviGraphLister().Get(modelName) + nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS() + childNode1 := nodes[0].EvhNodes[0] + g.Expect(childNode1.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode1.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode1.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode1.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode1.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode1.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode1.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode1.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/foo")) + g.Expect(len(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode1.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + childNode2 := nodes[0].EvhNodes[1] + g.Expect(childNode2.PoolGroupRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolGroupRefs[0].Members).To(gomega.HaveLen(1)) + g.Expect(childNode2.DefaultPoolGroup).NotTo(gomega.Equal("")) + g.Expect(childNode2.PoolRefs).To(gomega.HaveLen(1)) + g.Expect(childNode2.PoolRefs[0].Port).To(gomega.Equal(int32(8080))) + g.Expect(len(childNode2.PoolRefs[0].Servers)).To(gomega.Equal(1)) + g.Expect(len(childNode2.VHMatches)).To(gomega.Equal(1)) + g.Expect(*childNode2.VHMatches[0].Host).To(gomega.Equal("foo-8080.com")) + g.Expect(len(childNode2.VHMatches[0].Rules)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.Path.MatchStr[0]).To(gomega.Equal("/bar")) + g.Expect(len(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports)).To(gomega.Equal(1)) + g.Expect(childNode2.VHMatches[0].Rules[0].Matches.VsPort.Ports[0]).To(gomega.Equal(int64(8080))) + + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName1) + integrationtest.DelSVC(t, DEFAULT_NAMESPACE, svcName2) + integrationtest.DelEP(t, DEFAULT_NAMESPACE, svcName2) + akogatewayapitests.TeardownHTTPRoute(t, httpRoute1Name, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownHTTPRoute(t, httpRoute2Name, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} diff --git a/tests/gatewayapitests/ingestion/httproute_test.go b/tests/gatewayapitests/ingestion/httproute_test.go index 863267c57..98b0fa93a 100644 --- a/tests/gatewayapitests/ingestion/httproute_test.go +++ b/tests/gatewayapitests/ingestion/httproute_test.go @@ -83,7 +83,7 @@ func TestHTTPRouteHostnameInvalid(t *testing.T) { parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, namespace, ports) hostnames := []gatewayv1.Hostname{"*.example.com"} akogatewayapitests.SetupHTTPRoute(t, httpRouteName, namespace, parentRefs, hostnames, nil) - waitAndverify(t, "") + waitAndverify(t, key) // update hostnames = []gatewayv1.Hostname{"foo-8080.com"} @@ -117,7 +117,7 @@ func TestHTTPRouteGatewayNotPresent(t *testing.T) { parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, namespace, ports) hostnames := []gatewayv1.Hostname{"foo-8080.com", "foo-8081.com"} akogatewayapitests.SetupHTTPRoute(t, httpRouteName, namespace, parentRefs, hostnames, nil) - waitAndverify(t, "") + waitAndverify(t, key) // update listeners := akogatewayapitests.GetListenersV1(ports, false, false) diff --git a/tests/gatewayapitests/status/gateway_test.go b/tests/gatewayapitests/status/gateway_test.go index 5ee759832..f32a1225b 100644 --- a/tests/gatewayapitests/status/gateway_test.go +++ b/tests/gatewayapitests/status/gateway_test.go @@ -164,7 +164,7 @@ func TestGatewayWithValidListenersAndGatewayClass(t *testing.T) { Reason: string(gatewayv1.GatewayReasonProgrammed), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, true), } gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) @@ -210,7 +210,7 @@ func TestGatewayWithTLSListeners(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) @@ -256,7 +256,7 @@ func TestGatewayListenerUpdate(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0, 0}, true, false), } gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) @@ -280,7 +280,7 @@ func TestGatewayListenerUpdate(t *testing.T) { return len(gateway.Status.Listeners) == len(ports) }, 30*time.Second).Should(gomega.Equal(true)) - expectedStatus.Listeners = tests.GetListenerStatusV1(ports, []int32{0, 0}) + expectedStatus.Listeners = tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false) gateway, err = tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { t.Fatalf("Couldn't get the gateway, err: %+v", err) @@ -299,7 +299,7 @@ Transition test cases * - Non AKO gateway controller to AKO gateway controller * - AKO gateway controller to non AKO gateway controller */ -func TestGatewayTransitionFromValidToInvalid(t *testing.T) { +func TestGatewayTransitionFromValidToPartiallyValid(t *testing.T) { t.Skip("This is invalid test case as Hostname in listener can not be *.") gatewayName := "gateway-trans-01" @@ -330,7 +330,7 @@ func TestGatewayTransitionFromValidToInvalid(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) @@ -354,13 +354,27 @@ func TestGatewayTransitionFromValidToInvalid(t *testing.T) { return len(gateway.Status.Listeners) == len(ports) }, 30*time.Second).Should(gomega.Equal(true)) - expectedStatus.Conditions[0].Status = metav1.ConditionFalse - expectedStatus.Conditions[0].Reason = string(gatewayv1.GatewayReasonListenersNotValid) - expectedStatus.Conditions[0].Message = "Gateway contains 1 invalid listener(s)" - expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.GatewayReasonListenersNotValid) + expectedStatus = &gatewayv1.GatewayStatus{ + Conditions: []metav1.Condition{ + { + Type: string(gatewayv1.GatewayConditionAccepted), + Status: metav1.ConditionTrue, + Message: "Gateway contains atleast one valid listener", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonListenersNotValid), + }, + }, + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), + } + expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalid) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionFalse expectedStatus.Listeners[0].Conditions[0].Message = "Hostname not found or Hostname has invalid configuration" + expectedStatus.Listeners[0].Conditions[1].Type = string(gatewayv1.ListenerConditionProgrammed) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerReasonInvalid) + expectedStatus.Listeners[0].Conditions[1].Message = "Virtual service not configured/updated for this listener" + gateway, err = tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { t.Fatalf("Couldn't get the gateway, err: %+v", err) @@ -370,7 +384,7 @@ func TestGatewayTransitionFromValidToInvalid(t *testing.T) { tests.TeardownGatewayClass(t, gatewayClassName) } -func TestGatewayTransitionFromInvalidToValid(t *testing.T) { +func TestGatewayTransitionFromPartiallyValidToValid(t *testing.T) { gatewayName := "gateway-trans-02" gatewayClassName := "gateway-class-trans-02" @@ -424,7 +438,7 @@ func TestGatewayTransitionFromInvalidToValid(t *testing.T) { expectedStatus.Conditions[0].Status = metav1.ConditionTrue expectedStatus.Conditions[0].Reason = string(gatewayv1.GatewayReasonAccepted) expectedStatus.Conditions[0].Message = "Gateway configuration is valid" - expectedStatus.Listeners = tests.GetListenerStatusV1(ports, []int32{0, 0}) + expectedStatus.Listeners = tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false) gateway, err = tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { @@ -479,7 +493,7 @@ func TestGatewayTransitionFromNonAKOControllerToAKOController(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) @@ -522,7 +536,7 @@ func TestGatewayTransitionFromAKOControllerToNonAKOController(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) @@ -584,6 +598,13 @@ func TestGatewayWithNoListeners(t *testing.T) { ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonInvalid), }, + { + Type: string(gatewayv1.GatewayConditionProgrammed), + Status: metav1.ConditionFalse, + Message: "Gateway not programmed", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonInvalid), + }, }, } @@ -629,6 +650,13 @@ func TestGatewayWithMoreThanOneAddress(t *testing.T) { ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonInvalid), }, + { + Type: string(gatewayv1.GatewayConditionProgrammed), + Status: metav1.ConditionFalse, + Message: "Gateway not programmed", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonAddressNotUsable), + }, }, } @@ -668,12 +696,12 @@ func TestGatewayWithUnsupportedProtocolInListeners(t *testing.T) { { Type: string(gatewayv1.GatewayConditionAccepted), Status: metav1.ConditionFalse, - Message: "Gateway contains 1 invalid listener(s)", + Message: "Gateway contains atleast one valid listener", ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonListenersNotValid), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonUnsupportedProtocol) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionFalse @@ -715,18 +743,23 @@ func TestGatewayWithInvalidHostnameInListeners(t *testing.T) { Conditions: []metav1.Condition{ { Type: string(gatewayv1.GatewayConditionAccepted), - Status: metav1.ConditionFalse, - Message: "Gateway contains 1 invalid listener(s)", + Status: metav1.ConditionTrue, + Message: "Gateway contains atleast one valid listener", ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonListenersNotValid), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } - expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.GatewayReasonListenersNotValid) + expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalid) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionFalse expectedStatus.Listeners[0].Conditions[0].Message = "Hostname not found or Hostname has invalid configuration" + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerReasonInvalid) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[1].Type = string(gatewayv1.GatewayConditionProgrammed) + expectedStatus.Listeners[0].Conditions[1].Message = "Virtual service not configured/updated for this listener" + gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { t.Fatalf("Couldn't get the gateway, err: %+v", err) @@ -767,16 +800,24 @@ func TestGatewayWithInvalidTLSConfigInListeners(t *testing.T) { { Type: string(gatewayv1.GatewayConditionAccepted), Status: metav1.ConditionFalse, - Message: "Gateway contains 1 invalid listener(s)", + Message: "Gateway contains atleast one valid listener", ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonListenersNotValid), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, true), } - expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalidCertificateRef) + expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalid) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionFalse - expectedStatus.Listeners[0].Conditions[0].Message = "TLS mode or reference not valid" + expectedStatus.Listeners[0].Conditions[0].Message = "Listener is Invalid" + + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerReasonInvalidCertificateRef) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[1].Message = "TLS mode or reference not valid" + + expectedStatus.Listeners[0].Conditions[2].Reason = string(gatewayv1.ListenerReasonInvalid) + expectedStatus.Listeners[0].Conditions[2].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[2].Message = "Virtual service not configured/updated for this listener" gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { @@ -824,17 +865,33 @@ func TestGatewayWithInvalidAllowedRoute(t *testing.T) { { Type: string(gatewayv1.GatewayConditionAccepted), Status: metav1.ConditionFalse, - Message: "Gateway contains 1 invalid listener(s)", + Message: "Gateway does not contain any valid listener", ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonListenersNotValid), }, + { + Type: string(gatewayv1.GatewayConditionProgrammed), + Status: metav1.ConditionFalse, + Message: "Gateway not programmed", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonInvalid), + }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, true), } - expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalidRouteKinds) + expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalid) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionFalse - expectedStatus.Listeners[0].Conditions[0].Message = "AllowedRoute kind is invalid. Only HTTPRoute is supported currently" - expectedStatus.Listeners[0].Conditions[0].Type = string(gatewayv1.ListenerConditionResolvedRefs) + expectedStatus.Listeners[0].Conditions[0].Message = "Listener is Invalid" + //expectedStatus.Listeners[0].Conditions[0].Type = string(gatewayv1.ListenerConditionAccepted) + + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerReasonInvalidRouteKinds) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[1].Message = "AllowedRoute kind is invalid. Only HTTPRoute is supported currently" + //expectedStatus.Listeners[0].Conditions[1].Type = string(gatewayv1.ListenerConditionResolvedRefs) + + expectedStatus.Listeners[0].Conditions[2].Message = "Virtual service not configured/updated for this listener" + expectedStatus.Listeners[0].Conditions[2].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[2].Reason = string(gatewayv1.ListenerReasonInvalid) gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { @@ -866,17 +923,34 @@ func TestGatewayWithInvalidAllowedRoute(t *testing.T) { { Type: string(gatewayv1.GatewayConditionAccepted), Status: metav1.ConditionFalse, - Message: "Gateway contains 1 invalid listener(s)", + Message: "Gateway does not contain any valid listener", ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonListenersNotValid), }, + { + Type: string(gatewayv1.GatewayConditionProgrammed), + Status: metav1.ConditionFalse, + Message: "Gateway not programmed", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonInvalid), + }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, true), } - expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalidRouteKinds) + + expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalid) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionFalse - expectedStatus.Listeners[0].Conditions[0].Message = "AllowedRoute Group is invalid." - expectedStatus.Listeners[0].Conditions[0].Type = string(gatewayv1.ListenerConditionResolvedRefs) + expectedStatus.Listeners[0].Conditions[0].Message = "Listener is Invalid" + expectedStatus.Listeners[0].Conditions[0].Type = string(gatewayv1.ListenerConditionAccepted) + + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerReasonInvalidRouteKinds) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[1].Message = "AllowedRoute Group is invalid." + expectedStatus.Listeners[0].Conditions[1].Type = string(gatewayv1.ListenerConditionResolvedRefs) + + expectedStatus.Listeners[0].Conditions[2].Message = "Virtual service not configured/updated for this listener" + expectedStatus.Listeners[0].Conditions[2].Reason = string(gatewayv1.ListenerReasonInvalid) + expectedStatus.Listeners[0].Conditions[2].Status = metav1.ConditionFalse gateway, err = tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { @@ -927,12 +1001,16 @@ func TestGatewayWithValidAllowedRoute(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerConditionAccepted) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionTrue expectedStatus.Listeners[0].Conditions[0].Message = "Listener is valid" + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerConditionResolvedRefs) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionTrue + expectedStatus.Listeners[0].Conditions[1].Message = "All the references are valid" + gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName, metav1.GetOptions{}) if err != nil || gateway == nil { t.Fatalf("Couldn't get the gateway, err: %+v", err) @@ -971,7 +1049,7 @@ func TestGatewayWithValidAllowedRoute(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonAccepted) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionTrue @@ -1010,7 +1088,7 @@ func TestGatewayWithValidAllowedRoute(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonAccepted) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionTrue @@ -1048,8 +1126,15 @@ func TestGatewayWithValidAllowedRoute(t *testing.T) { ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonAccepted), }, + { + Type: string(gatewayv1.GatewayConditionProgrammed), + Status: metav1.ConditionTrue, + Message: "Gateway configuration is valid", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonProgrammed), + }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, true), } expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonAccepted) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionTrue @@ -1095,12 +1180,16 @@ func TestMultipleGatewaySameHostname(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, false), } - expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.GatewayReasonAccepted) + expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonAccepted) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionTrue expectedStatus.Listeners[0].Conditions[0].Message = "Listener is valid" + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerReasonResolvedRefs) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionTrue + expectedStatus.Listeners[0].Conditions[1].Message = "All the references are valid" + gateway, err := tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName1, metav1.GetOptions{}) if err != nil || gateway == nil { t.Fatalf("Couldn't get the gateway, err: %+v", err) @@ -1125,15 +1214,27 @@ func TestMultipleGatewaySameHostname(t *testing.T) { { Type: string(gatewayv1.GatewayConditionAccepted), Status: metav1.ConditionFalse, - Message: "Gateway contains 1 invalid listener(s)", + Message: "Gateway does not contain any valid listener", ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonListenersNotValid), }, + { + Type: string(gatewayv1.GatewayConditionProgrammed), + Status: metav1.ConditionFalse, + Message: "Gateway not programmed", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonInvalid), + }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, false, true), } - expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.GatewayReasonListenersNotValid) + expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.ListenerReasonInvalid) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[0].Message = "Hostname overlaps or is same as an existing gateway hostname" + + expectedStatus.Listeners[0].Conditions[1].Reason = string(gatewayv1.ListenerReasonInvalid) + expectedStatus.Listeners[0].Conditions[1].Status = metav1.ConditionFalse + expectedStatus.Listeners[0].Conditions[1].Message = "Virtual service not configured/updated for this listener" expectedStatus.Listeners[0].Conditions[0].Message = "Hostname is same as an existing gateway hostname" gateway, err = tests.GatewayClient.GatewayV1().Gateways(DEFAULT_NAMESPACE).Get(context.TODO(), gatewayName2, metav1.GetOptions{}) @@ -1178,7 +1279,7 @@ func TestMultipleGatewayOverlappingHostname(t *testing.T) { Reason: string(gatewayv1.GatewayReasonAccepted), }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, true, true), } expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.GatewayReasonAccepted) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionTrue @@ -1214,8 +1315,15 @@ func TestMultipleGatewayOverlappingHostname(t *testing.T) { ObservedGeneration: 1, Reason: string(gatewayv1.GatewayReasonAccepted), }, + { + Type: string(gatewayv1.GatewayConditionProgrammed), + Status: metav1.ConditionFalse, + Message: "Gateway not programmed", + ObservedGeneration: 1, + Reason: string(gatewayv1.GatewayReasonInvalid), + }, }, - Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}), + Listeners: tests.GetListenerStatusV1(ports, []int32{0, 0}, false, true), } expectedStatus.Listeners[0].Conditions[0].Reason = string(gatewayv1.GatewayReasonAccepted) expectedStatus.Listeners[0].Conditions[0].Status = metav1.ConditionTrue diff --git a/tests/gatewayapitests/status/httproute_test.go b/tests/gatewayapitests/status/httproute_test.go index 64afb8e84..d9bb02e61 100644 --- a/tests/gatewayapitests/status/httproute_test.go +++ b/tests/gatewayapitests/status/httproute_test.go @@ -70,8 +70,8 @@ func TestHTTPRouteWithValidConfig(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil && - apimeta.FindStatusCondition(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil && + apimeta.FindStatusCondition(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := make(map[string][]metav1.Condition) @@ -79,8 +79,8 @@ func TestHTTPRouteWithValidConfig(t *testing.T) { for _, port := range ports { conditions := make([]metav1.Condition, 0, 1) condition := metav1.Condition{ - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonAccepted), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), Status: metav1.ConditionTrue, Message: "Parent reference is valid", } @@ -138,23 +138,23 @@ func TestHTTPRouteWithAtleastOneParentReferenceValid(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.IsStatusConditionTrue(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) && - apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.GatewayConditionAccepted)) + return apimeta.IsStatusConditionTrue(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) && + apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.RouteConditionAccepted)) }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := make(map[string][]metav1.Condition) conditionMap[fmt.Sprintf("%s-%d", gatewayName, 8080)] = []metav1.Condition{ { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonAccepted), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), Status: metav1.ConditionTrue, Message: "Parent reference is valid", }, } conditionMap[fmt.Sprintf("%s-%d", gatewayName, 8081)] = []metav1.Condition{ { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonNoMatchingParent), Status: metav1.ConditionFalse, Message: "Invalid listener name provided", }, @@ -215,14 +215,14 @@ func TestHTTPRouteTransitionFromInvalidToValid(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) + return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := make(map[string][]metav1.Condition) conditionMap[fmt.Sprintf("%s-%d", gatewayName, 8081)] = []metav1.Condition{ { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonNoMatchingParent), Status: metav1.ConditionFalse, Message: "Invalid listener name provided", }, @@ -250,13 +250,13 @@ func TestHTTPRouteTransitionFromInvalidToValid(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.IsStatusConditionTrue(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) + return apimeta.IsStatusConditionTrue(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) }, 30*time.Second).Should(gomega.Equal(true)) conditionMap[fmt.Sprintf("%s-%d", gatewayName, 8080)] = []metav1.Condition{ { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonAccepted), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), Status: metav1.ConditionTrue, Message: "Parent reference is valid", }, @@ -311,14 +311,14 @@ func TestHTTPRouteTransitionFromValidToInvalid(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.IsStatusConditionTrue(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) + return apimeta.IsStatusConditionTrue(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := make(map[string][]metav1.Condition) - conditionMap[fmt.Sprintf("%s-%d", gatewayName, 8081)] = []metav1.Condition{ + conditionMap[fmt.Sprintf("%s-%d", gatewayName, 8080)] = []metav1.Condition{ { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonAccepted), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), Status: metav1.ConditionTrue, Message: "Parent reference is valid", }, @@ -345,13 +345,13 @@ func TestHTTPRouteTransitionFromValidToInvalid(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) + return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) }, 30*time.Second).Should(gomega.Equal(true)) conditionMap[fmt.Sprintf("%s-%d", gatewayName, 8081)] = []metav1.Condition{ { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonNoMatchingParent), Status: metav1.ConditionFalse, Message: "Invalid listener name provided", }, @@ -458,23 +458,23 @@ func TestHTTPRouteWithAllParentReferenceInvalid(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) && - apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.GatewayConditionAccepted)) + return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) && + apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.RouteConditionAccepted)) }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := map[string][]metav1.Condition{ fmt.Sprintf("%s-%d", gatewayName, 8080): { { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonNoMatchingParent), Status: metav1.ConditionFalse, Message: "Invalid listener name provided", }, }, fmt.Sprintf("%s-%d", gatewayName, 8081): { { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonNoMatchingParent), Status: metav1.ConditionFalse, Message: "Invalid listener name provided", }, @@ -559,23 +559,23 @@ func TestHTTPRouteWithNonExistingListenerReference(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) && - apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.GatewayConditionAccepted)) + return apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) && + apimeta.IsStatusConditionFalse(httpRoute.Status.Parents[1].Conditions, string(gatewayv1.RouteConditionAccepted)) }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := map[string][]metav1.Condition{ fmt.Sprintf("%s-%d", gatewayName, 8080): { { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonNoMatchingParent), Status: metav1.ConditionFalse, Message: "Invalid listener name provided", }, }, fmt.Sprintf("%s-%d", gatewayName, 8081): { { - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonNoMatchingParent), Status: metav1.ConditionFalse, Message: "Invalid listener name provided", }, @@ -694,7 +694,7 @@ func TestHTTPRouteUnprocessedGateway(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := make(map[string][]metav1.Condition) @@ -702,8 +702,8 @@ func TestHTTPRouteUnprocessedGateway(t *testing.T) { for _, port := range ports { conditions := make([]metav1.Condition, 0, 1) condition := metav1.Condition{ - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonInvalid), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonPending), Status: metav1.ConditionFalse, Message: "AKO is yet to process Gateway gateway-hr-11 for parent reference gateway-hr-11", } @@ -759,7 +759,7 @@ func TestHTTPRouteWithInvalidGatewayListener(t *testing.T) { if len(httpRoute.Status.Parents) != len(ports) { return false } - return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := make(map[string][]metav1.Condition) @@ -823,7 +823,7 @@ func TestHTTPRouteWithOneExistingAndOneNonExistingGateway(t *testing.T) { if len(httpRoute.Status.Parents) != 1 { return false } - return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil }, 30*time.Second).Should(gomega.Equal(true)) conditionMap := make(map[string][]metav1.Condition) @@ -831,8 +831,8 @@ func TestHTTPRouteWithOneExistingAndOneNonExistingGateway(t *testing.T) { for _, port := range ports { conditions := make([]metav1.Condition, 0, 1) condition := metav1.Condition{ - Type: string(gatewayv1.GatewayConditionAccepted), - Reason: string(gatewayv1.GatewayReasonAccepted), + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), Status: metav1.ConditionTrue, Message: "Parent reference is valid", } @@ -851,3 +851,177 @@ func TestHTTPRouteWithOneExistingAndOneNonExistingGateway(t *testing.T) { akogatewayapitests.TeardownGateway(t, gatewayName2, namespace) akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) } + +func TestMultipleHttpRoutesWithValidAndInvalidGatewayListeners(t *testing.T) { + gatewayClassName := "gateway-class-hr-14" + gatewayName := "gateway-hr-14" + httpRouteName1 := "httproute-14a" + httpRouteName2 := "httproute-14b" + namespace := "default" + ports := []int32{8080, 8081} + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + + g := gomega.NewGomegaWithT(t) + akogatewayapitests.SetupGateway(t, gatewayName, namespace, gatewayClassName, nil, listeners) + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(namespace).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + return apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, namespace, []int32{ports[0]}) + hostnames := []gatewayv1.Hostname{"foo-8080.com"} + + akogatewayapitests.SetupHTTPRoute(t, httpRouteName1, namespace, parentRefs, hostnames, nil) + g.Eventually(func() bool { + httpRoute, err := akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName1, metav1.GetOptions{}) + if err != nil || httpRoute == nil { + t.Logf("Couldn't get the HTTPRoute, err: %+v", err) + return false + } + if len(httpRoute.Status.Parents) != 1 { + return false + } + return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + httpRoute, err := akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName1, metav1.GetOptions{}) + if err != nil || httpRoute == nil { + t.Fatalf("Couldn't get the HTTPRoute, err: %+v", err) + } + + conditionMap := make(map[string][]metav1.Condition) + + conditions := make([]metav1.Condition, 0) + condition := metav1.Condition{ + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), + Status: metav1.ConditionTrue, + Message: "Parent reference is valid", + } + conditions = append(conditions, condition) + conditionMap[fmt.Sprintf("%s-%d", gatewayName, ports[0])] = conditions + + expectedRouteStatus := akogatewayapitests.GetRouteStatusV1([]string{gatewayName}, namespace, []int32{ports[0]}, conditionMap) + akogatewayapitests.ValidateHTTPRouteStatus(t, &httpRoute.Status, &gatewayv1.HTTPRouteStatus{RouteStatus: *expectedRouteStatus}) + + parentRefs = akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, namespace, []int32{ports[1]}) + hostnames = []gatewayv1.Hostname{"foo-8081.com"} + + akogatewayapitests.SetupHTTPRoute(t, httpRouteName2, namespace, parentRefs, hostnames, nil) + g.Eventually(func() bool { + httpRoute, err := akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName2, metav1.GetOptions{}) + if err != nil || httpRoute == nil { + t.Logf("Couldn't get the HTTPRoute, err: %+v", err) + return false + } + if len(httpRoute.Status.Parents) != 1 { + return false + } + return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + httpRoute, err = akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName2, metav1.GetOptions{}) + if err != nil || httpRoute == nil { + t.Fatalf("Couldn't get the HTTPRoute, err: %+v", err) + } + + conditionMap = make(map[string][]metav1.Condition) + conditions = make([]metav1.Condition, 0, 1) + condition = metav1.Condition{ + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), + Status: metav1.ConditionTrue, + Message: "Parent reference is valid", + } + + conditions = append(conditions, condition) + conditionMap[fmt.Sprintf("%s-%d", gatewayName, ports[1])] = conditions + + conditionMap["gateway-hr-14-8081"][0].Message = "Matching gateway listener is in Invalid state" + conditionMap["gateway-hr-14-8081"][0].Status = metav1.ConditionFalse + conditionMap["gateway-hr-14-8081"][0].Reason = string(gatewayv1.RouteReasonPending) + + expectedRouteStatus = akogatewayapitests.GetRouteStatusV1([]string{gatewayName}, namespace, []int32{ports[1]}, conditionMap) + akogatewayapitests.ValidateHTTPRouteStatus(t, &httpRoute.Status, &gatewayv1.HTTPRouteStatus{RouteStatus: *expectedRouteStatus}) + + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName2, namespace) + akogatewayapitests.TeardownGateway(t, gatewayName, namespace) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} + +func TestHttpRouteWithValidAndInvalidGatewayListeners(t *testing.T) { + gatewayClassName := "gateway-class-hr-15" + gatewayName := "gateway-hr-15" + httpRouteName := "httproute-15" + namespace := "default" + ports := []int32{8080, 8081} + + akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController) + + listeners := akogatewayapitests.GetListenersV1(ports, false, false) + listeners[1].Protocol = "TCP" + + g := gomega.NewGomegaWithT(t) + akogatewayapitests.SetupGateway(t, gatewayName, namespace, gatewayClassName, nil, listeners) + g.Eventually(func() bool { + gateway, err := akogatewayapitests.GatewayClient.GatewayV1().Gateways(namespace).Get(context.TODO(), gatewayName, metav1.GetOptions{}) + if err != nil || gateway == nil { + t.Logf("Couldn't get the gateway, err: %+v", err) + return false + } + return apimeta.FindStatusCondition(gateway.Status.Conditions, string(gatewayv1.GatewayConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, namespace, ports) + hostnames := []gatewayv1.Hostname{"foo-8080.com", "foo-8081.com"} + + akogatewayapitests.SetupHTTPRoute(t, httpRouteName, namespace, parentRefs, hostnames, nil) + g.Eventually(func() bool { + httpRoute, err := akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName, metav1.GetOptions{}) + if err != nil || httpRoute == nil { + t.Logf("Couldn't get the HTTPRoute, err: %+v", err) + return false + } + if len(httpRoute.Status.Parents) != 2 { + return false + } + return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil + }, 30*time.Second).Should(gomega.Equal(true)) + + conditionMap := make(map[string][]metav1.Condition) + + for _, port := range ports { + conditions := make([]metav1.Condition, 0, 1) + condition := metav1.Condition{ + Type: string(gatewayv1.RouteConditionAccepted), + Reason: string(gatewayv1.RouteReasonAccepted), + Status: metav1.ConditionTrue, + Message: "Parent reference is valid", + } + conditions = append(conditions, condition) + conditionMap[fmt.Sprintf("%s-%d", gatewayName, port)] = conditions + } + conditionMap["gateway-hr-15-8081"][0].Message = "Matching gateway listener is in Invalid state" + conditionMap["gateway-hr-15-8081"][0].Status = metav1.ConditionFalse + conditionMap["gateway-hr-15-8081"][0].Reason = string(gatewayv1.RouteReasonPending) + + expectedRouteStatus := akogatewayapitests.GetRouteStatusV1([]string{gatewayName}, namespace, ports, conditionMap) + + httpRoute, err := akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName, metav1.GetOptions{}) + if err != nil || httpRoute == nil { + t.Fatalf("Couldn't get the HTTPRoute, err: %+v", err) + } + akogatewayapitests.ValidateHTTPRouteStatus(t, &httpRoute.Status, &gatewayv1.HTTPRouteStatus{RouteStatus: *expectedRouteStatus}) + + akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, namespace) + akogatewayapitests.TeardownGateway(t, gatewayName, namespace) + akogatewayapitests.TeardownGatewayClass(t, gatewayClassName) +} diff --git a/tests/gatewayapitests/utils.go b/tests/gatewayapitests/utils.go index 50bd27c1c..85f76eb2f 100644 --- a/tests/gatewayapitests/utils.go +++ b/tests/gatewayapitests/utils.go @@ -177,7 +177,7 @@ func GetListenersOnHostname(hostnames []string) []gatewayv1.Listener { return listeners } -func GetListenerStatusV1(ports []int32, attachedRoutes []int32) []gatewayv1.ListenerStatus { +func GetListenerStatusV1(ports []int32, attachedRoutes []int32, getResolvedRefCondition bool, getProgrammedCondition bool) []gatewayv1.ListenerStatus { listeners := make([]gatewayv1.ListenerStatus, 0, len(ports)) for i, port := range ports { listener := gatewayv1.ListenerStatus{ @@ -186,14 +186,34 @@ func GetListenerStatusV1(ports []int32, attachedRoutes []int32) []gatewayv1.List AttachedRoutes: attachedRoutes[i], Conditions: []metav1.Condition{ { - Type: string(gatewayv1.GatewayConditionAccepted), + Type: string(gatewayv1.ListenerConditionAccepted), Status: metav1.ConditionTrue, Message: "Listener is valid", ObservedGeneration: 1, - Reason: string(gatewayv1.GatewayReasonAccepted), + Reason: string(gatewayv1.ListenerReasonAccepted), }, }, } + if getResolvedRefCondition { + resolvedRefCondition := &metav1.Condition{ + Type: string(gatewayv1.ListenerConditionResolvedRefs), + Status: metav1.ConditionTrue, + Message: "All the references are valid", + ObservedGeneration: 1, + Reason: string(gatewayv1.ListenerReasonResolvedRefs), + } + listener.Conditions = append(listener.Conditions, *resolvedRefCondition) + } + if getProgrammedCondition { + programmedCondition := &metav1.Condition{ + Type: string(gatewayv1.ListenerConditionProgrammed), + Status: metav1.ConditionTrue, + Message: "Virtual service configured/updated", + ObservedGeneration: 1, + Reason: string(gatewayv1.ListenerReasonProgrammed), + } + listener.Conditions = append(listener.Conditions, *programmedCondition) + } listeners = append(listeners, listener) } return listeners @@ -603,9 +623,9 @@ func ValidateGatewayStatus(t *testing.T, actualStatus, expectedStatus *gatewayv1 g.Expect(actualStatus.Addresses[0]).Should(gomega.Equal(expectedStatus.Addresses[0])) } + g.Expect(actualStatus.Listeners).To(gomega.HaveLen(len(expectedStatus.Listeners))) ValidateConditions(t, actualStatus.Conditions, expectedStatus.Conditions) - g.Expect(actualStatus.Listeners).To(gomega.HaveLen(len(expectedStatus.Listeners))) for _, actualListenerStatus := range actualStatus.Listeners { for _, expectedListenerStatus := range expectedStatus.Listeners { if actualListenerStatus.Name == expectedListenerStatus.Name {