diff --git a/pkg/odo/cli/url/describe.go b/pkg/odo/cli/url/describe.go index 1db6888172b..7f6251ad931 100644 --- a/pkg/odo/cli/url/describe.go +++ b/pkg/odo/cli/url/describe.go @@ -7,6 +7,7 @@ import ( "text/tabwriter" "github.com/openshift/odo/pkg/envinfo" + "github.com/openshift/odo/pkg/occlient" "github.com/openshift/odo/pkg/odo/util/pushtarget" routev1 "github.com/openshift/api/route/v1" @@ -104,7 +105,16 @@ func (o *URLDescribeOptions) Run() (err error) { } } else { componentName := o.EnvSpecificInfo.GetName() - u, err := url.GetIngress(o.KClient, o.EnvSpecificInfo, o.url, componentName) + oclient, err := occlient.New() + if err != nil { + return err + } + oclient.Namespace = o.KClient.Namespace + routeSupported, err := oclient.IsRouteSupported() + if err != nil { + return err + } + u, err := url.GetIngressOrRoute(oclient, o.KClient, o.EnvSpecificInfo, o.url, componentName, routeSupported) if err != nil { return err } @@ -112,11 +122,15 @@ func (o *URLDescribeOptions) Run() (err error) { machineoutput.OutputSuccess(u) } else { tabWriterURL := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent) - fmt.Fprintln(tabWriterURL, "NAME", "\t", "STATE", "\t", "URL", "\t", "PORT", "\t", "SECURE") + fmt.Fprintln(tabWriterURL, "NAME", "\t", "STATE", "\t", "URL", "\t", "PORT", "\t", "SECURE", "\t", "KIND") // are there changes between local and cluster states? outOfSync := false - fmt.Fprintln(tabWriterURL, u.Name, "\t", u.Status.State, "\t", url.GetURLString(url.GetProtocol(routev1.Route{}, url.ConvertIngressURLToIngress(u, componentName), experimental.IsExperimentalModeEnabled()), "", u.Spec.Host, experimental.IsExperimentalModeEnabled()), "\t", u.Spec.Port, "\t", u.Spec.Secure) + if u.Spec.Kind == envinfo.ROUTE { + fmt.Fprintln(tabWriterURL, u.Name, "\t", u.Status.State, "\t", url.GetURLString(u.Spec.Protocol, u.Spec.Host, "", experimental.IsExperimentalModeEnabled()), "\t", u.Spec.Port, "\t", u.Spec.Secure, "\t", u.Spec.Kind) + } else { + fmt.Fprintln(tabWriterURL, u.Name, "\t", u.Status.State, "\t", url.GetURLString(url.GetProtocol(routev1.Route{}, url.ConvertIngressURLToIngress(u, componentName)), "", u.Spec.Host, experimental.IsExperimentalModeEnabled()), "\t", u.Spec.Port, "\t", u.Spec.Secure, "\t", u.Spec.Kind) + } if u.Status.State != url.StateTypePushed { outOfSync = true } diff --git a/pkg/odo/cli/url/list.go b/pkg/odo/cli/url/list.go index 14ced12f0f2..cb9079c39c0 100644 --- a/pkg/odo/cli/url/list.go +++ b/pkg/odo/cli/url/list.go @@ -6,13 +6,14 @@ import ( "strconv" "text/tabwriter" + routev1 "github.com/openshift/api/route/v1" "github.com/openshift/odo/pkg/envinfo" + "github.com/openshift/odo/pkg/occlient" "github.com/openshift/odo/pkg/odo/util/pushtarget" "github.com/openshift/odo/pkg/odo/util/experimental" - routev1 "github.com/openshift/api/route/v1" "github.com/openshift/odo/pkg/config" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/log" @@ -114,7 +115,16 @@ func (o *URLListOptions) Run() (err error) { } } else { componentName := o.EnvSpecificInfo.GetName() - urls, err := url.ListIngressURL(o.KClient, o.EnvSpecificInfo, componentName) + oclient, err := occlient.New() + if err != nil { + return err + } + oclient.Namespace = o.KClient.Namespace + routeSupported, err := oclient.IsRouteSupported() + if err != nil { + return err + } + urls, err := url.ListIngressAndRoute(oclient, o.KClient, o.EnvSpecificInfo, componentName, routeSupported) if err != nil { return err } @@ -124,19 +134,23 @@ func (o *URLListOptions) Run() (err error) { if len(urls.Items) == 0 { return fmt.Errorf("no URLs found for component %v", componentName) } + log.Infof("Found the following URLs for component %v", componentName) tabWriterURL := tabwriter.NewWriter(os.Stdout, 5, 2, 3, ' ', tabwriter.TabIndent) - fmt.Fprintln(tabWriterURL, "NAME", "\t", "STATE", "\t", "URL", "\t", "PORT", "\t", "SECURE") + fmt.Fprintln(tabWriterURL, "NAME", "\t", "STATE", "\t", "URL", "\t", "PORT", "\t", "SECURE", "\t", "KIND") // are there changes between local and cluster states? outOfSync := false for _, u := range urls.Items { - fmt.Fprintln(tabWriterURL, u.Name, "\t", u.Status.State, "\t", url.GetURLString(url.GetProtocol(routev1.Route{}, url.ConvertIngressURLToIngress(u, componentName), experimental.IsExperimentalModeEnabled()), "", u.Spec.Host, experimental.IsExperimentalModeEnabled()), "\t", u.Spec.Port, "\t", u.Spec.Secure) + if u.Spec.Kind == envinfo.ROUTE { + fmt.Fprintln(tabWriterURL, u.Name, "\t", u.Status.State, "\t", url.GetURLString(u.Spec.Protocol, u.Spec.Host, "", experimental.IsExperimentalModeEnabled()), "\t", u.Spec.Port, "\t", u.Spec.Secure, "\t", u.Spec.Kind) + } else { + fmt.Fprintln(tabWriterURL, u.Name, "\t", u.Status.State, "\t", url.GetURLString(url.GetProtocol(routev1.Route{}, url.ConvertIngressURLToIngress(u, o.EnvSpecificInfo.GetName())), "", u.Spec.Host, experimental.IsExperimentalModeEnabled()), "\t", u.Spec.Port, "\t", u.Spec.Secure, "\t", u.Spec.Kind) + } if u.Status.State != url.StateTypePushed { outOfSync = true } } - tabWriterURL.Flush() if outOfSync { log.Info("There are local changes. Please run 'odo push'.") diff --git a/pkg/url/types.go b/pkg/url/types.go index 750ea7a77fa..c8c19a25954 100644 --- a/pkg/url/types.go +++ b/pkg/url/types.go @@ -15,13 +15,13 @@ type URL struct { // URLSpec is type URLSpec struct { - Host string `json:"host,omitempty"` - Protocol string `json:"protocol,omitempty"` - Port int `json:"port,omitempty"` - Secure bool `json:"secure"` - urlKind envinfo.URLKind - TLSSecret string `json:"tlssecret,omitempty"` - ExternalPort int `json:"externalport,omitempty"` + Host string `json:"host,omitempty"` + Protocol string `json:"protocol,omitempty"` + Port int `json:"port,omitempty"` + Secure bool `json:"secure"` + Kind envinfo.URLKind `json:"kind,omitempty"` + TLSSecret string `json:"tlssecret,omitempty"` + ExternalPort int `json:"externalport,omitempty"` } // AppList is a list of applications diff --git a/pkg/url/url.go b/pkg/url/url.go index 0f7b6e44d4d..1b03cfb2a7d 100644 --- a/pkg/url/url.go +++ b/pkg/url/url.go @@ -20,7 +20,6 @@ import ( "github.com/openshift/odo/pkg/kclient" "github.com/openshift/odo/pkg/lclient" "github.com/openshift/odo/pkg/occlient" - "github.com/openshift/odo/pkg/odo/util/experimental" urlLabels "github.com/openshift/odo/pkg/url/labels" "github.com/openshift/odo/pkg/util" "github.com/pkg/errors" @@ -66,11 +65,13 @@ func Get(client *occlient.Client, localConfig *config.LocalConfigInfo, urlName s // search local URL, if it exist in local, update state with remote status if localURL.Name == urlName { if remoteExist { - localURL.Status.State = StateTypePushed + clusterURL := getMachineReadableFormat(*route) + clusterURL.Status.State = StateTypePushed + return clusterURL, nil } else { localURL.Status.State = StateTypeNotPushed + return localURL, nil } - return localURL, nil } } @@ -85,27 +86,50 @@ func Get(client *occlient.Client, localConfig *config.LocalConfigInfo, urlName s return URL{}, errors.New(fmt.Sprintf("the url %v does not exist", urlName)) } -// GetIngress returns ingress spec for given URL name -func GetIngress(kClient *kclient.Client, envSpecificInfo *envinfo.EnvSpecificInfo, urlName string, componentName string) (URL, error) { +// GetIngressOrRoute returns ingress/route spec for given URL name +func GetIngressOrRoute(client *occlient.Client, kClient *kclient.Client, envSpecificInfo *envinfo.EnvSpecificInfo, urlName string, componentName string, routeSupported bool) (URL, error) { remoteExist := true + var ingress *iextensionsv1.Ingress + var route *routev1.Route + var getRouteErr error // Check whether remote already created the ingress - ingress, err := kClient.GetIngress(urlName) - if kerrors.IsNotFound(err) { + ingress, getIngressErr := kClient.GetIngress(urlName) + if kerrors.IsNotFound(getIngressErr) && routeSupported { + // Check whether remote already created the route + route, getRouteErr = client.GetRoute(urlName) + } + if kerrors.IsNotFound(getIngressErr) && (!routeSupported || kerrors.IsNotFound(getRouteErr)) { remoteExist = false - } else if err != nil { - return URL{}, errors.Wrap(err, "unable to get ingress on cluster") + } else if (getIngressErr != nil && !kerrors.IsNotFound(getIngressErr)) || (getRouteErr != nil && !kerrors.IsNotFound(getRouteErr)) { + if getIngressErr != nil { + return URL{}, errors.Wrap(getIngressErr, "unable to get ingress") + } + return URL{}, errors.Wrap(getRouteErr, "unable to get route") } + envinfoURLs := envSpecificInfo.GetURL() for _, url := range envinfoURLs { - // only checks for Ingress URLs - if url.Kind != envinfo.INGRESS { + // ignore Docker URLs + if url.Kind == envinfo.DOCKER { + continue + } + if !routeSupported && url.Kind == envinfo.ROUTE { continue } localURL := ConvertEnvinfoURL(url, componentName) // search local URL, if it exist in local, update state with remote status if localURL.Name == urlName { if remoteExist { - localURL.Status.State = StateTypePushed + if ingress != nil && ingress.Spec.Rules != nil { + // Remote exist, but not in local, so it's deleted status + clusterURL := getMachineReadableFormatIngress(*ingress) + clusterURL.Status.State = StateTypePushed + return clusterURL, nil + } else if route != nil { + clusterURL := getMachineReadableFormat(*route) + clusterURL.Status.State = StateTypePushed + return clusterURL, nil + } } else { localURL.Status.State = StateTypeNotPushed } @@ -113,11 +137,17 @@ func GetIngress(kClient *kclient.Client, envSpecificInfo *envinfo.EnvSpecificInf } } - if err == nil && remoteExist { - // Remote exist, but not in local, so it's deleted status - clusterURL := getMachineReadableFormatIngress(*ingress) - clusterURL.Status.State = StateTypeLocallyDeleted - return clusterURL, nil + if remoteExist { + if ingress != nil && ingress.Spec.Rules != nil { + // Remote exist, but not in local, so it's deleted status + clusterURL := getMachineReadableFormatIngress(*ingress) + clusterURL.Status.State = StateTypeLocallyDeleted + return clusterURL, nil + } else if route != nil { + clusterURL := getMachineReadableFormat(*route) + clusterURL.Status.State = StateTypeLocallyDeleted + return clusterURL, nil + } } // can't find the URL in local and remote @@ -288,7 +318,7 @@ func Create(client *occlient.Client, kClient *kclient.Client, parameters CreateP if err != nil { return "", errors.Wrap(err, "unable to create ingress") } - return GetURLString(GetProtocol(routev1.Route{}, *ingress, isExperimental), "", ingressDomain, isExperimental), nil + return GetURLString(GetProtocol(routev1.Route{}, *ingress), "", ingressDomain, isExperimental), nil } else { if !isRouteSupported { return "", errors.Errorf("routes are not available on non OpenShift clusters") @@ -330,7 +360,7 @@ func Create(client *occlient.Client, kClient *kclient.Client, parameters CreateP if err != nil { return "", errors.Wrap(err, "unable to create route") } - return GetURLString(GetProtocol(*route, iextensionsv1.Ingress{}, isExperimental), route.Spec.Host, "", isExperimental), nil + return GetURLString(GetProtocol(*route, iextensionsv1.Ingress{}), route.Spec.Host, "", isExperimental), nil } } @@ -444,50 +474,67 @@ func List(client *occlient.Client, localConfig *config.LocalConfigInfo, componen return urlList, nil } -// ListIngressURL returns all Ingress URLs for given component. -func ListIngressURL(client *kclient.Client, envSpecificInfo *envinfo.EnvSpecificInfo, componentName string) (URLList, error) { +// ListIngressAndRoute returns all Ingress and Route for given component. +func ListIngressAndRoute(oclient *occlient.Client, client *kclient.Client, envSpecificInfo *envinfo.EnvSpecificInfo, componentName string, routeSupported bool) (URLList, error) { labelSelector := fmt.Sprintf("%v=%v", componentlabels.ComponentLabel, componentName) klog.V(4).Infof("Listing ingresses with label selector: %v", labelSelector) ingresses, err := client.ListIngresses(labelSelector) if err != nil { - return URLList{}, errors.Wrap(err, "unable to list ingress names") + return URLList{}, errors.Wrap(err, "unable to list ingress") + } + routes := []routev1.Route{} + if routeSupported { + routes, err = oclient.ListRoutes(labelSelector) + if err != nil { + return URLList{}, errors.Wrap(err, "unable to list routes") + } } - localEnvinfoURLs := envSpecificInfo.GetURL() var urls []URL - ingressMap := make(map[string]URL) + + clusterURLMap := make(map[string]URL) localMap := make(map[string]URL) for _, i := range ingresses { clusterURL := getMachineReadableFormatIngress(i) - ingressMap[clusterURL.Name] = clusterURL + clusterURLMap[clusterURL.Name] = clusterURL + } + for _, r := range routes { + if r.OwnerReferences != nil && r.OwnerReferences[0].Kind == "Ingress" { + continue + } + clusterURL := getMachineReadableFormat(r) + clusterURLMap[clusterURL.Name] = clusterURL } for _, envinfoURL := range localEnvinfoURLs { - // only checks for Ingress URLs - if envinfoURL.Kind != envinfo.INGRESS { + // only checks for Ingress and Route URLs + if envinfoURL.Kind == envinfo.DOCKER { + continue + } + if !routeSupported && envinfoURL.Kind == envinfo.ROUTE { continue } localURL := ConvertEnvinfoURL(envinfoURL, componentName) localMap[localURL.Name] = localURL } - for ingressName, ingressURL := range ingressMap { - _, found := localMap[ingressName] + for URLName, clusterURL := range clusterURLMap { + _, found := localMap[URLName] if found { // URL is in both local env file and cluster - ingressURL.Status.State = StateTypePushed - urls = append(urls, ingressURL) + clusterURL.Status.State = StateTypePushed + urls = append(urls, clusterURL) } else { // URL is on the cluster but not in local env file - ingressURL.Status.State = StateTypeLocallyDeleted - urls = append(urls, ingressURL) + clusterURL.Status.State = StateTypeLocallyDeleted + urls = append(urls, clusterURL) } } for localName, localURL := range localMap { - _, found := ingressMap[localName] - if !found { - // URL is in the local env file but not pushed to Docker container + _, remoteURLFound := clusterURLMap[localName] + if !remoteURLFound { + // URL is in the local env file but not pushed to cluster localURL.Status.State = StateTypeNotPushed urls = append(urls, localURL) } @@ -581,15 +628,11 @@ func ListDockerURL(client *lclient.Client, componentName string, envSpecificInfo } // GetProtocol returns the protocol string -func GetProtocol(route routev1.Route, ingress iextensionsv1.Ingress, isExperimental bool) string { - if isExperimental { - if ingress.Spec.TLS != nil { - return "https" - } - } else { - if route.Spec.TLS != nil { - return "https" - } +func GetProtocol(route routev1.Route, ingress iextensionsv1.Ingress) string { + if !reflect.DeepEqual(ingress, iextensionsv1.Ingress{}) && ingress.Spec.TLS != nil { + return "https" + } else if !reflect.DeepEqual(route, routev1.Route{}) && route.Spec.TLS != nil { + return "https" } return "http" } @@ -607,6 +650,7 @@ func ConvertConfigURL(configURL config.ConfigURL) URL { Spec: URLSpec{ Port: configURL.Port, Secure: configURL.Secure, + Kind: envinfo.ROUTE, }, } } @@ -624,14 +668,17 @@ func ConvertEnvinfoURL(envinfoURL envinfo.EnvInfoURL, serviceName string) URL { }, Spec: URLSpec{ Port: envinfoURL.Port, - Host: hostString, Secure: envinfoURL.Secure, + Kind: envinfoURL.Kind, }, } - if envinfoURL.Secure && len(envinfoURL.TLSSecret) > 0 { - url.Spec.TLSSecret = envinfoURL.TLSSecret - } else if envinfoURL.Secure && envinfoURL.Kind == envinfo.INGRESS { - url.Spec.TLSSecret = fmt.Sprintf("%s-tlssecret", serviceName) + if envinfoURL.Kind == envinfo.INGRESS { + url.Spec.Host = hostString + if envinfoURL.Secure && len(envinfoURL.TLSSecret) > 0 { + url.Spec.TLSSecret = envinfoURL.TLSSecret + } else if envinfoURL.Secure && envinfoURL.Kind == envinfo.INGRESS { + url.Spec.TLSSecret = fmt.Sprintf("%s-tlssecret", serviceName) + } } return url } @@ -729,7 +776,7 @@ func getMachineReadableFormat(r routev1.Route) URL { return URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: apiVersion}, ObjectMeta: metav1.ObjectMeta{Name: r.Labels[urlLabels.URLLabel]}, - Spec: URLSpec{Host: r.Spec.Host, Port: r.Spec.Port.TargetPort.IntValue(), Protocol: GetProtocol(r, iextensionsv1.Ingress{}, experimental.IsExperimentalModeEnabled()), Secure: r.Spec.TLS != nil}, + Spec: URLSpec{Host: r.Spec.Host, Port: r.Spec.Port.TargetPort.IntValue(), Protocol: GetProtocol(r, iextensionsv1.Ingress{}), Secure: r.Spec.TLS != nil, Kind: envinfo.ROUTE}, } } @@ -749,7 +796,7 @@ func getMachineReadableFormatIngress(i iextensionsv1.Ingress) URL { url := URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: apiVersion}, ObjectMeta: metav1.ObjectMeta{Name: i.Labels[urlLabels.URLLabel]}, - Spec: URLSpec{Host: i.Spec.Rules[0].Host, Port: int(i.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort.IntVal), Secure: i.Spec.TLS != nil}, + Spec: URLSpec{Host: i.Spec.Rules[0].Host, Port: int(i.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort.IntVal), Secure: i.Spec.TLS != nil, Kind: envinfo.INGRESS}, } if i.Spec.TLS != nil { url.Spec.TLSSecret = i.Spec.TLS[0].SecretName @@ -839,7 +886,7 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam Port: url.Port, Secure: url.Secure, TLSSecret: url.TLSSecret, - urlKind: url.Kind, + Kind: url.Kind, }, } } @@ -849,9 +896,9 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam for _, url := range urls { urlLOCAL[url.Name] = URL{ Spec: URLSpec{ - Port: url.Port, - Secure: url.Secure, - urlKind: envinfo.ROUTE, + Port: url.Port, + Secure: url.Secure, + Kind: envinfo.ROUTE, }, } } @@ -866,9 +913,10 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam for _, url := range urlList.Items { urlCLUSTER[url.Name] = URL{ Spec: URLSpec{ - Host: url.Spec.Host, - Port: url.Spec.Port, - urlKind: envinfo.INGRESS, + Host: url.Spec.Host, + Port: url.Spec.Port, + Kind: envinfo.INGRESS, + Secure: url.Spec.Secure, }, } } @@ -882,8 +930,9 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam for _, urlRoute := range urlPushedRoutes.Items { urlCLUSTER[urlRoute.Name] = URL{ Spec: URLSpec{ - Port: urlRoute.Spec.Port, - urlKind: envinfo.ROUTE, + Port: urlRoute.Spec.Port, + Kind: envinfo.ROUTE, + Secure: urlRoute.Spec.Secure, }, } } @@ -900,7 +949,7 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam if ok { // since the host stored in an ingress // is the combination of name and host of the url - if val.Spec.urlKind == envinfo.INGRESS { + if val.Spec.Kind == envinfo.INGRESS { val.Spec.Host = fmt.Sprintf("%v.%v", urlName, val.Spec.Host) } if !reflect.DeepEqual(val.Spec, urlSpec.Spec) { @@ -910,11 +959,11 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam } if !ok || configMismatch { - if urlSpec.Spec.urlKind == envinfo.INGRESS && kClient == nil { + if urlSpec.Spec.Kind == envinfo.INGRESS && kClient == nil { continue } // delete the url - err := Delete(client, kClient, urlName, parameters.ApplicationName, urlSpec.Spec.urlKind) + err := Delete(client, kClient, urlName, parameters.ApplicationName, urlSpec.Spec.Kind) if err != nil { return err } @@ -929,7 +978,7 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam for urlName, urlInfo := range urlLOCAL { _, ok := urlCLUSTER[urlName] if !ok { - if urlInfo.Spec.urlKind == envinfo.INGRESS && kClient == nil { + if urlInfo.Spec.Kind == envinfo.INGRESS && kClient == nil { continue } @@ -941,7 +990,7 @@ func Push(client *occlient.Client, kClient *kclient.Client, parameters PushParam applicationName: parameters.ApplicationName, host: urlInfo.Spec.Host, secretName: urlInfo.Spec.TLSSecret, - urlKind: urlInfo.Spec.urlKind, + urlKind: urlInfo.Spec.Kind, } host, err := Create(client, kClient, createParameters, parameters.IsRouteSupported, parameters.IsExperimentalModeEnabled) if err != nil { diff --git a/pkg/url/url_test.go b/pkg/url/url_test.go index fdb47d8461b..59cfc2f7b47 100644 --- a/pkg/url/url_test.go +++ b/pkg/url/url_test.go @@ -790,9 +790,9 @@ func TestPush(t *testing.T) { Name: "example-app", }, Spec: URLSpec{ - Port: 8080, - Secure: false, - urlKind: envinfo.ROUTE, + Port: 8080, + Secure: false, + Kind: envinfo.ROUTE, }, }, { @@ -800,9 +800,9 @@ func TestPush(t *testing.T) { Name: "example-1-app", }, Spec: URLSpec{ - Port: 9090, - Secure: false, - urlKind: envinfo.ROUTE, + Port: 9090, + Secure: false, + Kind: envinfo.ROUTE, }, }, }, @@ -846,9 +846,9 @@ func TestPush(t *testing.T) { Name: "example-local-0-app", }, Spec: URLSpec{ - Port: 8080, - Secure: false, - urlKind: envinfo.ROUTE, + Port: 8080, + Secure: false, + Kind: envinfo.ROUTE, }, }, { @@ -856,9 +856,9 @@ func TestPush(t *testing.T) { Name: "example-local-1-app", }, Spec: URLSpec{ - Port: 9090, - Secure: false, - urlKind: envinfo.ROUTE, + Port: 9090, + Secure: false, + Kind: envinfo.ROUTE, }, }, }, @@ -921,10 +921,10 @@ func TestPush(t *testing.T) { Name: "example", }, Spec: URLSpec{ - Port: 8080, - Secure: false, - Host: "com", - urlKind: envinfo.INGRESS, + Port: 8080, + Secure: false, + Host: "com", + Kind: envinfo.INGRESS, }, }, { @@ -932,10 +932,10 @@ func TestPush(t *testing.T) { Name: "example-1", }, Spec: URLSpec{ - Port: 9090, - Secure: false, - Host: "com", - urlKind: envinfo.INGRESS, + Port: 9090, + Secure: false, + Host: "com", + Kind: envinfo.INGRESS, }, }, }, @@ -988,10 +988,10 @@ func TestPush(t *testing.T) { Name: "example-local-0", }, Spec: URLSpec{ - Port: 8080, - Secure: false, - Host: "com", - urlKind: envinfo.INGRESS, + Port: 8080, + Secure: false, + Host: "com", + Kind: envinfo.INGRESS, }, }, { @@ -999,10 +999,10 @@ func TestPush(t *testing.T) { Name: "example-local-1", }, Spec: URLSpec{ - Port: 9090, - Secure: false, - Host: "com", - urlKind: envinfo.INGRESS, + Port: 9090, + Secure: false, + Host: "com", + Kind: envinfo.INGRESS, }, }, }, @@ -1071,9 +1071,9 @@ func TestPush(t *testing.T) { Name: "example-local-0", }, Spec: URLSpec{ - Port: 8080, - Secure: false, - urlKind: envinfo.ROUTE, + Port: 8080, + Secure: false, + Kind: envinfo.ROUTE, }, }, { @@ -1081,10 +1081,10 @@ func TestPush(t *testing.T) { Name: "example-local-1", }, Spec: URLSpec{ - Port: 9090, - Secure: false, - Host: "com", - urlKind: envinfo.INGRESS, + Port: 9090, + Secure: false, + Host: "com", + Kind: envinfo.INGRESS, }, }, }, @@ -1127,7 +1127,7 @@ func TestPush(t *testing.T) { Secure: true, Host: "com", TLSSecret: "secret", - urlKind: envinfo.INGRESS, + Kind: envinfo.INGRESS, }, }, }, @@ -1157,9 +1157,9 @@ func TestPush(t *testing.T) { Name: "example-local-0", }, Spec: URLSpec{ - Port: 8080, - Secure: false, - urlKind: envinfo.ROUTE, + Port: 8080, + Secure: false, + Kind: envinfo.ROUTE, }, }, }, @@ -1196,9 +1196,9 @@ func TestPush(t *testing.T) { Name: "example-local-0-app", }, Spec: URLSpec{ - Port: 8080, - Secure: false, - urlKind: envinfo.ROUTE, + Port: 8080, + Secure: false, + Kind: envinfo.ROUTE, }, }, }, @@ -1232,9 +1232,9 @@ func TestPush(t *testing.T) { Name: "example", }, Spec: URLSpec{ - Port: 8080, - Secure: true, - urlKind: envinfo.ROUTE, + Port: 8080, + Secure: true, + Kind: envinfo.ROUTE, }, }, }, @@ -1260,10 +1260,10 @@ func TestPush(t *testing.T) { Name: "example", }, Spec: URLSpec{ - Port: 8080, - Secure: true, - Host: "com", - urlKind: envinfo.INGRESS, + Port: 8080, + Secure: true, + Host: "com", + Kind: envinfo.INGRESS, }, }, }, @@ -1294,7 +1294,7 @@ func TestPush(t *testing.T) { Secure: true, Host: "com", TLSSecret: "secret", - urlKind: envinfo.INGRESS, + Kind: envinfo.INGRESS, }, }, }, @@ -1392,7 +1392,7 @@ func TestPush(t *testing.T) { if createdObject.Name == url.Name && (createdObject.Spec.TLS != nil) == url.Spec.Secure && int(createdObject.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort.IntVal) == url.Spec.Port && - envinfo.INGRESS == url.Spec.urlKind && + envinfo.INGRESS == url.Spec.Kind && fmt.Sprintf("%v.%v", url.Name, url.Spec.Host) == createdObject.Spec.Rules[0].Host { if url.Spec.Secure { @@ -1422,7 +1422,7 @@ func TestPush(t *testing.T) { if createdObject.Name == url.Name && (createdObject.Spec.TLS != nil) == url.Spec.Secure && int(createdObject.Spec.Port.TargetPort.IntVal) == url.Spec.Port && - envinfo.ROUTE == url.Spec.urlKind { + envinfo.ROUTE == url.Spec.Kind { found = true break } @@ -1638,45 +1638,134 @@ func TestGetContainerURL(t *testing.T) { } } -func TestListIngressURL(t *testing.T) { - // initialising the fakeclient +func TestListIngressAndRoute(t *testing.T) { componentName := "testcomponent" testURL1 := envinfo.EnvInfoURL{Name: "example-0", Port: 8080, Host: "com", Kind: "ingress"} testURL2 := envinfo.EnvInfoURL{Name: "example-1", Port: 9090, Host: "com", Kind: "ingress"} testURL3 := envinfo.EnvInfoURL{Name: "ingressurl3", Port: 8080, Host: "com", Secure: true, Kind: "ingress"} - esi := &envinfo.EnvSpecificInfo{} - err := esi.SetConfiguration("url", testURL2) - if err != nil { - // discard the error, since no physical file to write - t.Log("Expected error since no physical env file to write") - } - err = esi.SetConfiguration("url", testURL3) - if err != nil { - // discard the error, since no physical file to write - t.Log("Expected error since no physical env file to write") - } - fkclient, fkclientset := kclient.FakeNew() - fkclient.Namespace = "default" - fkclientset.Kubernetes.PrependReactor("list", "ingresses", func(action ktesting.Action) (bool, runtime.Object, error) { - return true, fake.GetIngressListWithMultiple(componentName), nil - }) + testURL4 := envinfo.EnvInfoURL{Name: "example", Port: 8080, Kind: "route"} + testURL5 := envinfo.EnvInfoURL{Name: "routeurl2", Port: 8080, Kind: "route"} + testURL6 := envinfo.EnvInfoURL{Name: "routeurl3", Port: 8080, Kind: "route"} tests := []struct { - name string - component string - client *kclient.Client - wantURLs []URL + name string + component string + envURLs []envinfo.EnvInfoURL + routeSupported bool + routeList *routev1.RouteList + ingressList *extensionsv1.IngressList + wantURLs []URL }{ { - name: "Should retrieve the URL list", - component: componentName, - client: fkclient, + name: "Should retrieve the URL list with both ingress and routes", + component: componentName, + envURLs: []envinfo.EnvInfoURL{testURL2, testURL3, testURL4, testURL5}, + routeSupported: true, + ingressList: fake.GetIngressListWithMultiple(componentName), + routeList: &routev1.RouteList{ + Items: []routev1.Route{ + testingutil.GetSingleRoute(testURL4.Name, testURL4.Port, componentName, ""), + testingutil.GetSingleRoute(testURL6.Name, testURL6.Port, componentName, ""), + }, + }, + wantURLs: []URL{ + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL1.Name}, + Spec: URLSpec{Host: "example-0.com", Port: testURL1.Port, Secure: testURL1.Secure, Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypeLocallyDeleted, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL2.Name}, + Spec: URLSpec{Host: "example-1.com", Port: testURL2.Port, Secure: testURL2.Secure, Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypePushed, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL3.Name}, + Spec: URLSpec{Host: "ingressurl3.com", Port: testURL3.Port, Secure: testURL3.Secure, TLSSecret: componentName + "-tlssecret", Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypeNotPushed, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL4.Name}, + Spec: URLSpec{Protocol: "http", Port: testURL4.Port, Secure: testURL4.Secure, Kind: envinfo.ROUTE}, + Status: URLStatus{ + State: StateTypePushed, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL5.Name}, + Spec: URLSpec{Port: testURL5.Port, Secure: testURL5.Secure, Kind: envinfo.ROUTE}, + Status: URLStatus{ + State: StateTypeNotPushed, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL6.Name}, + Spec: URLSpec{Protocol: "http", Port: testURL6.Port, Secure: testURL6.Secure, Kind: envinfo.ROUTE}, + Status: URLStatus{ + State: StateTypeLocallyDeleted, + }, + }, + }, + }, + { + name: "Should retrieve only ingress URLs with routeSupported equals to false", + component: componentName, + envURLs: []envinfo.EnvInfoURL{testURL2, testURL3, testURL4, testURL5}, + routeList: &routev1.RouteList{}, + ingressList: fake.GetIngressListWithMultiple(componentName), + routeSupported: false, + wantURLs: []URL{ + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL1.Name}, + Spec: URLSpec{Host: "example-0.com", Port: testURL1.Port, Secure: testURL1.Secure, Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypeLocallyDeleted, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL2.Name}, + Spec: URLSpec{Host: "example-1.com", Port: testURL2.Port, Secure: testURL2.Secure, Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypePushed, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL3.Name}, + Spec: URLSpec{Host: "ingressurl3.com", Port: testURL3.Port, Secure: testURL3.Secure, TLSSecret: componentName + "-tlssecret", Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypeNotPushed, + }, + }, + }, + }, + { + name: "Should retrieve only ingress URLs", + component: componentName, + envURLs: []envinfo.EnvInfoURL{testURL2, testURL3}, + routeSupported: true, + routeList: &routev1.RouteList{}, + ingressList: fake.GetIngressListWithMultiple(componentName), wantURLs: []URL{ URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: testURL1.Name}, - Spec: URLSpec{Host: "example-0.com", Port: testURL1.Port, Secure: testURL1.Secure}, + Spec: URLSpec{Host: "example-0.com", Port: testURL1.Port, Secure: testURL1.Secure, Kind: envinfo.INGRESS}, Status: URLStatus{ State: StateTypeLocallyDeleted, }, @@ -1684,7 +1773,7 @@ func TestListIngressURL(t *testing.T) { URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: testURL2.Name}, - Spec: URLSpec{Host: "example-1.com", Port: testURL2.Port, Secure: testURL2.Secure}, + Spec: URLSpec{Host: "example-1.com", Port: testURL2.Port, Secure: testURL2.Secure, Kind: envinfo.INGRESS}, Status: URLStatus{ State: StateTypePushed, }, @@ -1692,17 +1781,76 @@ func TestListIngressURL(t *testing.T) { URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: testURL3.Name}, - Spec: URLSpec{Host: "ingressurl3.com", Port: testURL3.Port, Secure: testURL3.Secure, TLSSecret: componentName + "-tlssecret"}, + Spec: URLSpec{Host: "ingressurl3.com", Port: testURL3.Port, Secure: testURL3.Secure, TLSSecret: componentName + "-tlssecret", Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypeNotPushed, + }, + }, + }, + }, + { + name: "Should retrieve only route URLs", + component: componentName, + envURLs: []envinfo.EnvInfoURL{testURL4, testURL5}, + routeSupported: true, + routeList: &routev1.RouteList{ + Items: []routev1.Route{ + testingutil.GetSingleRoute(testURL4.Name, testURL4.Port, componentName, ""), + testingutil.GetSingleRoute(testURL6.Name, testURL6.Port, componentName, ""), + }, + }, + ingressList: &extensionsv1.IngressList{}, + wantURLs: []URL{ + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL4.Name}, + Spec: URLSpec{Protocol: "http", Port: testURL4.Port, Secure: testURL4.Secure, Kind: envinfo.ROUTE}, + Status: URLStatus{ + State: StateTypePushed, + }, + }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL5.Name}, + Spec: URLSpec{Port: testURL5.Port, Secure: testURL5.Secure, Kind: envinfo.ROUTE}, Status: URLStatus{ State: StateTypeNotPushed, }, }, + URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL6.Name}, + Spec: URLSpec{Protocol: "http", Port: testURL6.Port, Secure: testURL6.Secure, Kind: envinfo.ROUTE}, + Status: URLStatus{ + State: StateTypeLocallyDeleted, + }, + }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - urls, err := ListIngressURL(tt.client, esi, componentName) + // initialising virtual envinfo + esi := &envinfo.EnvSpecificInfo{} + for _, url := range tt.envURLs { + err := esi.SetConfiguration("url", url) + if err != nil { + // discard the error, since no physical file to write + t.Log("Expected error since no physical env file to write") + } + } + // initialising the fakeclient + fkclient, fkclientset := kclient.FakeNew() + fkclient.Namespace = "default" + fkclientset.Kubernetes.PrependReactor("list", "ingresses", func(action ktesting.Action) (bool, runtime.Object, error) { + return true, tt.ingressList, nil + }) + fakeoclient, fakeoclientSet := occlient.FakeNew() + fakeoclientSet.RouteClientset.PrependReactor("list", "routes", func(action ktesting.Action) (bool, runtime.Object, error) { + return true, tt.routeList, nil + }) + + urls, err := ListIngressAndRoute(fakeoclient, fkclient, esi, componentName, tt.routeSupported) if err != nil { t.Errorf("unexpected error %v", err) } @@ -1724,12 +1872,15 @@ func TestListIngressURL(t *testing.T) { } -func TestGetIngress(t *testing.T) { +func TestGetIngressOrRoute(t *testing.T) { componentName := "testcomponent" testURL1 := envinfo.EnvInfoURL{Name: "ingressurl1", Port: 8080, Host: "com", Kind: "ingress"} testURL2 := envinfo.EnvInfoURL{Name: "ingressurl2", Port: 8080, Host: "com", Kind: "ingress"} testURL3 := envinfo.EnvInfoURL{Name: "ingressurl3", Port: 8080, Host: "com", Secure: true, Kind: "ingress"} + testURL4 := envinfo.EnvInfoURL{Name: "example", Port: 8080, Kind: "route"} + testURL5 := envinfo.EnvInfoURL{Name: "routeurl2", Port: 8080, Kind: "route"} + testURL6 := envinfo.EnvInfoURL{Name: "routeurl3", Port: 8080, Kind: "route"} esi := &envinfo.EnvSpecificInfo{} err := esi.SetConfiguration("url", testURL2) if err != nil { @@ -1741,24 +1892,38 @@ func TestGetIngress(t *testing.T) { // discard the error, since no physical file to write t.Log("Expected error since no physical env file to write") } + err = esi.SetConfiguration("url", testURL4) + if err != nil { + // discard the error, since no physical file to write + t.Log("Expected error since no physical env file to write") + } + err = esi.SetConfiguration("url", testURL5) + if err != nil { + // discard the error, since no physical file to write + t.Log("Expected error since no physical env file to write") + } tests := []struct { - name string - component string - urlName string - pushedIngress *extensionsv1.Ingress - wantURL URL - wantErr bool + name string + component string + urlName string + routeSupported bool + pushedIngress *extensionsv1.Ingress + pushedRoute routev1.Route + wantURL URL + wantErr bool }{ { - name: "Case 1: Successfully retrieve the locally deleted URL object", - component: componentName, - urlName: testURL1.Name, - pushedIngress: fake.GetSingleIngress(testURL1.Name, componentName), + name: "Case 1: Successfully retrieve the locally deleted Ingress URL object", + component: componentName, + urlName: testURL1.Name, + routeSupported: true, + pushedIngress: fake.GetSingleIngress(testURL1.Name, componentName), + pushedRoute: routev1.Route{}, wantURL: URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: testURL1.Name}, - Spec: URLSpec{Host: "ingressurl1.com", Port: testURL1.Port, Secure: testURL1.Secure}, + Spec: URLSpec{Host: "ingressurl1.com", Port: testURL1.Port, Secure: testURL1.Secure, Kind: envinfo.INGRESS}, Status: URLStatus{ State: StateTypeLocallyDeleted, }, @@ -1766,14 +1931,59 @@ func TestGetIngress(t *testing.T) { wantErr: false, }, { - name: "Case 2: Successfully retrieve the pushed URL object", - component: componentName, - urlName: testURL2.Name, - pushedIngress: fake.GetSingleIngress(testURL2.Name, componentName), + name: "Case 2: Successfully retrieve the pushed Ingress URL object", + component: componentName, + urlName: testURL2.Name, + routeSupported: true, + pushedIngress: fake.GetSingleIngress(testURL2.Name, componentName), + pushedRoute: routev1.Route{}, wantURL: URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: testURL2.Name}, - Spec: URLSpec{Host: "ingressurl2.com", Port: testURL2.Port, Secure: testURL2.Secure}, + Spec: URLSpec{Host: "ingressurl2.com", Port: testURL2.Port, Secure: testURL2.Secure, Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypePushed, + }, + }, + wantErr: false, + }, + { + name: "Case 3: Successfully retrieve the not pushed Ingress URL object", + component: componentName, + urlName: testURL3.Name, + routeSupported: true, + pushedIngress: nil, + pushedRoute: routev1.Route{}, + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL3.Name}, + Spec: URLSpec{Host: "ingressurl3.com", Port: testURL3.Port, Secure: testURL3.Secure, TLSSecret: componentName + "-tlssecret", Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypeNotPushed, + }, + }, + wantErr: false, + }, + { + name: "Case 4: Should show error if the url does not exist", + component: componentName, + urlName: "notExistURL", + routeSupported: true, + pushedIngress: nil, + pushedRoute: routev1.Route{}, + wantErr: true, + }, + { + name: "Case 4: Successfully retrieve the pushed Route URL object", + component: componentName, + urlName: testURL4.Name, + routeSupported: true, + pushedIngress: nil, + pushedRoute: testingutil.GetSingleRoute(testURL4.Name, testURL4.Port, componentName, ""), + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL4.Name}, + Spec: URLSpec{Protocol: "http", Port: testURL4.Port, Secure: testURL4.Secure, Kind: envinfo.ROUTE}, Status: URLStatus{ State: StateTypePushed, }, @@ -1781,14 +1991,60 @@ func TestGetIngress(t *testing.T) { wantErr: false, }, { - name: "Case 3: Successfully retrieve the not pushed object", - component: componentName, - urlName: testURL3.Name, - pushedIngress: nil, + name: "Case 5: Successfully retrieve the not pushed Route URL object", + component: componentName, + urlName: testURL5.Name, + routeSupported: true, + pushedIngress: nil, + pushedRoute: routev1.Route{}, + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL5.Name}, + Spec: URLSpec{Port: testURL5.Port, Secure: testURL5.Secure, Kind: envinfo.ROUTE}, + Status: URLStatus{ + State: StateTypeNotPushed, + }, + }, + wantErr: false, + }, + { + name: "Case 6: Successfully retrieve the locally deleted Route URL object", + component: componentName, + urlName: testURL6.Name, + routeSupported: true, + pushedIngress: nil, + pushedRoute: testingutil.GetSingleRoute(testURL6.Name, testURL6.Port, componentName, ""), + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL6.Name}, + Spec: URLSpec{Protocol: "http", Port: testURL6.Port, Secure: testURL6.Secure, Kind: envinfo.ROUTE}, + Status: URLStatus{ + State: StateTypeLocallyDeleted, + }, + }, + wantErr: false, + }, + { + name: "Case 7: If route is not supported, should show error and empty URL when describing a route", + component: componentName, + urlName: testURL5.Name, + routeSupported: false, + pushedIngress: nil, + pushedRoute: routev1.Route{}, + wantURL: URL{}, + wantErr: true, + }, + { + name: "Case 8: If route is not supported, should retrieve not pushed ingress", + component: componentName, + urlName: testURL3.Name, + routeSupported: false, + pushedIngress: nil, + pushedRoute: routev1.Route{}, wantURL: URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: testURL3.Name}, - Spec: URLSpec{Host: "ingressurl3.com", Port: testURL3.Port, Secure: testURL3.Secure, TLSSecret: componentName + "-tlssecret"}, + Spec: URLSpec{Host: "ingressurl3.com", Port: testURL3.Port, Secure: testURL3.Secure, TLSSecret: componentName + "-tlssecret", Kind: envinfo.INGRESS}, Status: URLStatus{ State: StateTypeNotPushed, }, @@ -1796,11 +2052,38 @@ func TestGetIngress(t *testing.T) { wantErr: false, }, { - name: "Case 4: Should show error if the url does not exist", - component: componentName, - urlName: "notExistURL", - pushedIngress: nil, - wantErr: true, + name: "Case 9: If route is not supported, should retrieve pushed ingress", + component: componentName, + urlName: testURL2.Name, + routeSupported: false, + pushedIngress: fake.GetSingleIngress(testURL2.Name, componentName), + pushedRoute: routev1.Route{}, + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL2.Name}, + Spec: URLSpec{Host: "ingressurl2.com", Port: testURL2.Port, Secure: testURL2.Secure, Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypePushed, + }, + }, + wantErr: false, + }, + { + name: "Case 10: If route is not supported, should retrieve locally deleted ingress", + component: componentName, + urlName: testURL1.Name, + routeSupported: false, + pushedIngress: fake.GetSingleIngress(testURL1.Name, componentName), + pushedRoute: routev1.Route{}, + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: testURL1.Name}, + Spec: URLSpec{Host: "ingressurl1.com", Port: testURL1.Port, Secure: testURL1.Secure, Kind: envinfo.INGRESS}, + Status: URLStatus{ + State: StateTypeLocallyDeleted, + }, + }, + wantErr: false, }, } for _, tt := range tests { @@ -1812,7 +2095,13 @@ func TestGetIngress(t *testing.T) { return true, tt.pushedIngress, nil }) } - url, err := GetIngress(fkclient, esi, tt.urlName, tt.component) + client, fakeClientSet := occlient.FakeNew() + if !reflect.DeepEqual(tt.pushedRoute, routev1.Route{}) { + fakeClientSet.RouteClientset.PrependReactor("get", "routes", func(action ktesting.Action) (bool, runtime.Object, error) { + return true, &tt.pushedRoute, nil + }) + } + url, err := GetIngressOrRoute(client, fkclient, esi, tt.urlName, tt.component, tt.routeSupported) if !tt.wantErr == (err != nil) { t.Errorf("unexpected error %v", err) } @@ -1840,11 +2129,12 @@ func TestConvertEnvinfoURL(t *testing.T) { Host: host, Port: 8080, Secure: false, + Kind: envinfo.INGRESS, }, wantURL: URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: urlName}, - Spec: URLSpec{Host: fmt.Sprintf("%s.%s", urlName, host), Port: 8080, Secure: false}, + Spec: URLSpec{Host: fmt.Sprintf("%s.%s", urlName, host), Port: 8080, Secure: false, Kind: envinfo.INGRESS}, }, }, { @@ -1859,7 +2149,7 @@ func TestConvertEnvinfoURL(t *testing.T) { wantURL: URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: urlName}, - Spec: URLSpec{Host: fmt.Sprintf("%s.%s", urlName, host), Port: 8080, Secure: true, TLSSecret: fmt.Sprintf("%s-tlssecret", serviceName)}, + Spec: URLSpec{Host: fmt.Sprintf("%s.%s", urlName, host), Port: 8080, Secure: true, TLSSecret: fmt.Sprintf("%s-tlssecret", serviceName), Kind: envinfo.INGRESS}, }, }, { @@ -1875,7 +2165,34 @@ func TestConvertEnvinfoURL(t *testing.T) { wantURL: URL{ TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, ObjectMeta: metav1.ObjectMeta{Name: urlName}, - Spec: URLSpec{Host: fmt.Sprintf("%s.%s", urlName, host), Port: 8080, Secure: true, TLSSecret: secretName}, + Spec: URLSpec{Host: fmt.Sprintf("%s.%s", urlName, host), Port: 8080, Secure: true, TLSSecret: secretName, Kind: envinfo.INGRESS}, + }, + }, + { + name: "Case 4: Insecure route URL", + envInfoURL: envinfo.EnvInfoURL{ + Name: urlName, + Port: 8080, + Kind: envinfo.ROUTE, + }, + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: urlName}, + Spec: URLSpec{Port: 8080, Secure: false, Kind: envinfo.ROUTE}, + }, + }, + { + name: "Case 4: Secure route URL", + envInfoURL: envinfo.EnvInfoURL{ + Name: urlName, + Port: 8080, + Secure: true, + Kind: envinfo.ROUTE, + }, + wantURL: URL{ + TypeMeta: metav1.TypeMeta{Kind: "url", APIVersion: "odo.dev/v1alpha1"}, + ObjectMeta: metav1.ObjectMeta{Name: urlName}, + Spec: URLSpec{Port: 8080, Secure: true, Kind: envinfo.ROUTE}, }, }, } diff --git a/tests/integration/cmd_url_test.go b/tests/integration/cmd_url_test.go index 6d0b743c99d..905414e39c2 100644 --- a/tests/integration/cmd_url_test.go +++ b/tests/integration/cmd_url_test.go @@ -121,14 +121,17 @@ var _ = Describe("odo url command tests", func() { helper.CmdShouldPass("odo", "url", "create", "myurl", "--secure", "--context", context) actualURLDescribeJSON := helper.CmdShouldPass("odo", "url", "describe", "myurl", "-o", "json", "--context", context) - desiredURLDescribeJSON := fmt.Sprintf(`{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{ "name": "myurl","creationTimestamp": null},"spec":{ "port": 8080,"secure": true},"status": {"state": "Not Pushed"}}`) + desiredURLDescribeJSON := fmt.Sprintf(`{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{ "name": "myurl","creationTimestamp": null},"spec":{"port": 8080,"secure": true,"kind": "route"},"status": {"state": "Not Pushed"}}`) Expect(desiredURLDescribeJSON).Should(MatchJSON(actualURLDescribeJSON)) helper.CmdShouldPass("odo", "push", "--context", context) // odo url describe -o json actualURLDescribeJSON = helper.CmdShouldPass("odo", "url", "describe", "myurl", "-o", "json", "--context", context) - desiredURLDescribeJSON = fmt.Sprintf(`{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{ "name": "myurl","creationTimestamp": null},"spec":{ "port": 8080,"secure": true},"status": {"state": "Pushed"}}`) + // get the route URL + fullURLPath := helper.DetermineRouteURL(context) + pathNoHTTP := strings.Split(fullURLPath, "//")[1] + desiredURLDescribeJSON = fmt.Sprintf(`{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{ "name": "myurl","creationTimestamp": null},"spec":{"host":"%s","protocol": "https","port": 8080,"secure": true,"kind": "route"},"status": {"state": "Pushed"}}`, pathNoHTTP) Expect(desiredURLDescribeJSON).Should(MatchJSON(actualURLDescribeJSON)) }) }) @@ -151,7 +154,7 @@ var _ = Describe("odo url command tests", func() { actualURLListJSON := helper.CmdShouldPass("odo", "url", "list", "-o", "json") fullURLPath := helper.DetermineRouteURL("") pathNoHTTP := strings.Split(fullURLPath, "//")[1] - desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"http","port":8080,"secure":false},"status":{"state": "Pushed"}}]}`, pathNoHTTP) + desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"http","port":8080,"secure":false,"kind": "route"},"status":{"state": "Pushed"}}]}`, pathNoHTTP) Expect(desiredURLListJSON).Should(MatchJSON(actualURLListJSON)) }) @@ -159,7 +162,7 @@ var _ = Describe("odo url command tests", func() { helper.CmdShouldPass("odo", "create", "nodejs", "nodejs", "--app", "myapp", "--project", project, "--git", "https://github.com/openshift/nodejs-ex") helper.CmdShouldPass("odo", "url", "create", "myurl", "--secure") actualURLListJSON := helper.CmdShouldPass("odo", "url", "list", "-o", "json") - desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"port":8080,"secure":true},"status":{"state": "Not Pushed"}}]}`) + desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"port":8080,"secure":true,"kind": "route"},"status":{"state": "Not Pushed"}}]}`) Expect(desiredURLListJSON).Should(MatchJSON(actualURLListJSON)) helper.CmdShouldPass("odo", "push") @@ -168,7 +171,7 @@ var _ = Describe("odo url command tests", func() { actualURLListJSON = helper.CmdShouldPass("odo", "url", "list", "-o", "json") fullURLPath := helper.DetermineRouteURL("") pathNoHTTP := strings.Split(fullURLPath, "//")[1] - desiredURLListJSON = fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"https","port":8080,"secure":true},"status":{"state": "Pushed"}}]}`, pathNoHTTP) + desiredURLListJSON = fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"myurl","creationTimestamp":null},"spec":{"host":"%s","protocol":"https","port":8080,"secure":true,"kind": "route"},"status":{"state": "Pushed"}}]}`, pathNoHTTP) Expect(desiredURLListJSON).Should(MatchJSON(actualURLListJSON)) }) }) diff --git a/tests/integration/component.go b/tests/integration/component.go index 888848b62b4..acac04eda63 100644 --- a/tests/integration/component.go +++ b/tests/integration/component.go @@ -248,7 +248,7 @@ func componentTests(args ...string) { cmpDescribeJSON, err := helper.Unindented(helper.CmdShouldPass("odo", append(args, "describe", "-o", "json", "--context", context)...)) Expect(err).Should(BeNil()) - expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.dev/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","source": "https://github.com/openshift/nodejs-ex","sourceType": "git","urls": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": [{"kind": "url", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "url-1", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false}, "status": {"state": "Not Pushed"}}, {"kind": "url", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "url-2", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false}, "status": {"state": "Not Pushed"}}]},"storages": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": [{"kind": "storage", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "storage-1", "creationTimestamp": null}, "spec": {"size": "1Gi", "path": "/data1"}}]},"ports": ["8080/TCP"]},"status": {"state": "Not Pushed"}}`) + expected, err := helper.Unindented(`{"kind": "Component","apiVersion": "odo.dev/v1alpha1","metadata": {"name": "cmp-git","namespace": "` + project + `","creationTimestamp": null},"spec":{"app": "testing","type":"nodejs","source": "https://github.com/openshift/nodejs-ex","sourceType": "git","urls": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": [{"kind": "url", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "url-1", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false, "kind": "route"}, "status": {"state": "Not Pushed"}}, {"kind": "url", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "url-2", "creationTimestamp": null}, "spec": {"port": 8080, "secure": false,"kind": "route"}, "status": {"state": "Not Pushed"}}]},"storages": {"kind": "List", "apiVersion": "odo.dev/v1alpha1", "metadata": {}, "items": [{"kind": "storage", "apiVersion": "odo.dev/v1alpha1", "metadata": {"name": "storage-1", "creationTimestamp": null}, "spec": {"size": "1Gi", "path": "/data1"}}]},"ports": ["8080/TCP"]},"status": {"state": "Not Pushed"}}`) Expect(err).Should(BeNil()) Expect(cmpDescribeJSON).To(Equal(expected)) diff --git a/tests/integration/devfile/cmd_devfile_url_test.go b/tests/integration/devfile/cmd_devfile_url_test.go index f5dd0f7aa59..c9e24ebc841 100644 --- a/tests/integration/devfile/cmd_devfile_url_test.go +++ b/tests/integration/devfile/cmd_devfile_url_test.go @@ -77,7 +77,7 @@ var _ = Describe("odo devfile url command tests", func() { Expect(stdout).To(ContainSubstring("no URLs found")) }) - It("should be able to list url in machine readable json format", func() { + It("should be able to list ingress url in machine readable json format", func() { url1 := helper.RandString(5) host := helper.RandString(5) + ".com" @@ -91,7 +91,7 @@ var _ = Describe("odo devfile url command tests", func() { // odo url list -o json helper.WaitForCmdOut("odo", []string{"url", "list", "-o", "json"}, 1, true, func(output string) bool { - desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"%s","creationTimestamp":null},"spec":{"host":"%s","port":3000,"secure": false},"status":{"state":"Pushed"}}]}`, url1, url1+"."+host) + desiredURLListJSON := fmt.Sprintf(`{"kind":"List","apiVersion":"odo.dev/v1alpha1","metadata":{},"items":[{"kind":"url","apiVersion":"odo.dev/v1alpha1","metadata":{"name":"%s","creationTimestamp":null},"spec":{"host":"%s","port":3000,"secure": false,"kind":"ingress"},"status":{"state":"Pushed"}}]}`, url1, url1+"."+host) if strings.Contains(output, url1) { Expect(desiredURLListJSON).Should(MatchJSON(output)) return true @@ -100,7 +100,7 @@ var _ = Describe("odo devfile url command tests", func() { }) }) - It("should list url with appropriate state", func() { + It("should list ingress url with appropriate state", func() { url1 := helper.RandString(5) url2 := helper.RandString(5) host := helper.RandString(5) + ".com" @@ -110,17 +110,47 @@ var _ = Describe("odo devfile url command tests", func() { helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context) helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml")) - helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress") + helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--secure", "--ingress") helper.CmdShouldPass("odo", "push") helper.CmdShouldPass("odo", "url", "create", url2, "--port", "3000", "--host", host, "--ingress") stdout := helper.CmdShouldPass("odo", "url", "list") - helper.MatchAllInOutput(stdout, []string{url1, "Pushed"}) - helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed"}) + helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "ingress"}) + helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "ingress"}) helper.CmdShouldPass("odo", "url", "delete", url1, "-f") stdout = helper.CmdShouldPass("odo", "url", "list") - helper.MatchAllInOutput(stdout, []string{url1, "Locally Deleted"}) - helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed"}) + helper.MatchAllInOutput(stdout, []string{url1, "Locally Deleted", "true", "ingress"}) + helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "ingress"}) + }) + + It("should list route and ingress urls with appropriate state", func() { + if os.Getenv("KUBERNETES") == "true" { + Skip("This is a OpenShift specific scenario, skipping") + } + url1 := helper.RandString(5) + url2 := helper.RandString(5) + ingressurl := helper.RandString(5) + host := helper.RandString(5) + ".com" + + helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName) + + helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context) + helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml")) + + helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--secure") + helper.CmdShouldPass("odo", "url", "create", ingressurl, "--port", "3000", "--host", host, "--ingress") + helper.CmdShouldPass("odo", "push", "--project", namespace) + helper.CmdShouldPass("odo", "url", "create", url2, "--port", "3000") + stdout := helper.CmdShouldPass("odo", "url", "list", "--context", context) + helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "route"}) + helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "route"}) + helper.MatchAllInOutput(stdout, []string{ingressurl, "Pushed", "false", "ingress"}) + + helper.CmdShouldPass("odo", "url", "delete", url1, "-f") + stdout = helper.CmdShouldPass("odo", "url", "list", "--context", context) + helper.MatchAllInOutput(stdout, []string{url1, "Locally Deleted", "true", "route"}) + helper.MatchAllInOutput(stdout, []string{url2, "Not Pushed", "false", "route"}) + helper.MatchAllInOutput(stdout, []string{ingressurl, "Pushed", "false", "ingress"}) }) }) @@ -239,7 +269,7 @@ var _ = Describe("odo devfile url command tests", func() { }) Context("Describing urls", func() { - It("should describe appropriate URL and error messages", func() { + It("should describe appropriate Ingress URLs", func() { url1 := helper.RandString(5) host := helper.RandString(5) + ".com" @@ -251,14 +281,48 @@ var _ = Describe("odo devfile url command tests", func() { helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--ingress") stdout := helper.CmdShouldPass("odo", "url", "describe", url1) - helper.MatchAllInOutput(stdout, []string{url1 + "." + host, "Not Pushed", "odo push"}) + helper.MatchAllInOutput(stdout, []string{url1 + "." + host, "Not Pushed", "false", "ingress", "odo push"}) helper.CmdShouldPass("odo", "push", "--project", namespace) stdout = helper.CmdShouldPass("odo", "url", "describe", url1) - helper.MatchAllInOutput(stdout, []string{url1 + "." + host, "Pushed"}) + helper.MatchAllInOutput(stdout, []string{url1 + "." + host, "Pushed", "false", "ingress"}) helper.CmdShouldPass("odo", "url", "delete", url1, "-f") stdout = helper.CmdShouldPass("odo", "url", "describe", url1) - helper.MatchAllInOutput(stdout, []string{url1 + "." + host, "Locally Deleted"}) + helper.MatchAllInOutput(stdout, []string{url1 + "." + host, "Locally Deleted", "false", "ingress"}) + + helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--host", host, "--secure", "--ingress") + helper.CmdShouldPass("odo", "push", "--project", namespace) + stdout = helper.CmdShouldPass("odo", "url", "describe", url1) + helper.MatchAllInOutput(stdout, []string{url1 + "." + host, "Pushed", "true", "ingress"}) + }) + + It("should describe appropriate Route URLs", func() { + if os.Getenv("KUBERNETES") == "true" { + Skip("This is a OpenShift specific scenario, skipping") + } + url1 := helper.RandString(5) + + helper.CmdShouldPass("odo", "create", "nodejs", "--project", namespace, componentName) + + helper.CopyExample(filepath.Join("source", "devfiles", "nodejs", "project"), context) + helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(context, "devfile.yaml")) + + helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000") + + stdout := helper.CmdShouldPass("odo", "url", "describe", url1) + helper.MatchAllInOutput(stdout, []string{url1, "Not Pushed", "false", "route", "odo push"}) + + helper.CmdShouldPass("odo", "push", "--project", namespace) + stdout = helper.CmdShouldPass("odo", "url", "describe", url1) + helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "false", "route"}) + helper.CmdShouldPass("odo", "url", "delete", url1, "-f") + stdout = helper.CmdShouldPass("odo", "url", "describe", url1) + helper.MatchAllInOutput(stdout, []string{url1, "Locally Deleted", "false", "route"}) + + helper.CmdShouldPass("odo", "url", "create", url1, "--port", "3000", "--secure") + helper.CmdShouldPass("odo", "push", "--project", namespace) + stdout = helper.CmdShouldPass("odo", "url", "describe", url1) + helper.MatchAllInOutput(stdout, []string{url1, "Pushed", "true", "route"}) }) })