Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List Routes/Ingresses created by odo deploy in odo describe component #6244

Merged
merged 22 commits into from
Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d39e605
List routes/ingresses deployed by odo in the describe output
valaparthvi Oct 20, 2022
d0e4dff
Remove ListDyanmicResourcesFromSelector and use ListDyanmicResources …
valaparthvi Oct 20, 2022
7c82599
Update pkg/api/component.go
valaparthvi Nov 15, 2022
343af02
Replace DyanmicClient for ingress with a kubeclient
valaparthvi Nov 15, 2022
e26e580
Show ing/route name if *.hosts is empty
valaparthvi Nov 15, 2022
3c4f042
Change API format
valaparthvi Nov 15, 2022
a1a2b09
Ignore owned ing/routes
valaparthvi Nov 15, 2022
88c1c14
Add devfile with default backend ingress
valaparthvi Nov 15, 2022
3f27fa3
Add tests for named describe command
valaparthvi Nov 15, 2022
1b1e247
mock kclient
valaparthvi Nov 15, 2022
a563acd
Fix integration test failure
valaparthvi Nov 15, 2022
35e3b6d
Fix integration test failure with registry
valaparthvi Nov 16, 2022
4d0bbaf
Add test for ingress with default backend
valaparthvi Nov 17, 2022
4325acc
Add unit test for ListRoutesAndIngresses
valaparthvi Nov 17, 2022
65cf1f6
Add documentation
valaparthvi Nov 17, 2022
30efed0
Fix circular dependency and test failures
valaparthvi Nov 17, 2022
6fe76b6
Update upstream docs
valaparthvi Nov 17, 2022
554ba13
Fix integration test and add unit test for owner reference
valaparthvi Nov 17, 2022
ef64aae
DRY the unit test code
valaparthvi Nov 17, 2022
8fb5dbe
Update pkg/component/component.go
valaparthvi Nov 17, 2022
c083f20
Use context to obtain app
valaparthvi Nov 18, 2022
f3c8f3b
rm3l's review
valaparthvi Nov 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions docs/website/docs/command-reference/describe-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,17 @@ Container components:
• runtime

Kubernetes components:
• outerloop-deploy
• outerloop-deployment
• outerloop-service
• outerloop-url-ingress
• outerloop-url-route

Kubernetes Ingresses:
• my-nodejs-app: nodejs.example.com/
• my-nodejs-app: nodejs.example.com/foo

Kubernetes Routes:
• my-nodejs-app: my-nodejs-app-phmartin-crt-dev.apps.sandbox-m2.ll9k.p1.openshiftapps.com/testpath

```
</details>
Expand Down Expand Up @@ -74,7 +84,14 @@ Supported odo features:
• Dev: Unknown
• Deploy: Unknown
• Debug: Unknown


Kubernetes Ingresses:
• my-nodejs-app: nodejs.example.com/
• my-nodejs-app: nodejs.example.com/foo

Kubernetes Routes:
• my-nodejs-app: my-nodejs-app-phmartin-crt-dev.apps.sandbox-m2.ll9k.p1.openshiftapps.com/testpath

```
</details>

Expand Down
84 changes: 76 additions & 8 deletions docs/website/docs/command-reference/json-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ When the `describe component` command is executed without parameter from a direc
- the path of the Devfile,
- the content of the Devfile,
- supported `odo` features, indicating if the Devfile defines necessary information to run `odo dev`, `odo dev --debug` and `odo deploy`
- ingress or routes created in Deploy mode
- the status of the component
- the forwarded ports if odo is currently running in Dev mode,
- the modes in which the component is deployed (either none, Dev, Deploy or both)
Expand All @@ -150,7 +151,7 @@ odo describe component -o json
"dev": true,
"deploy": false,
"debug": true
}
},
},
"devForwardedPorts": [
{
Expand All @@ -164,12 +165,39 @@ odo describe component -o json
"dev": true,
"deploy": false
},
"managedBy": "odo"
"ingresses": [
{
"name": "my-nodejs-app",
"rules": [
{
"host": "nodejs.example.com",
"paths": [
"/",
"/foo"
]
}
]
}
]
"routes": [
{
"name": "my-nodejs-app",
"rules": [
{
"host": "my-nodejs-app-phmartin-crt-dev.apps.sandbox-m2.ll9k.p1.openshiftapps.com",
"paths": [
"/testpath"
]
}
]
}
]
"managedBy": "odo",
}
```

When the `describe component` commmand is executed with a name and namespace, it will return:
- the modes in which the component is deployed (either Dev, Deploy or both)
- ingress and route resources created by the component in Deploy mode

The command with name and namespace is not able to return information about a component that has not been deployed.

Expand All @@ -182,11 +210,51 @@ odo describe component --name aname -o json
```
```json
{
"runningIn": {
"dev": true,
"deploy": false
},
"managedBy": "odo"
"devfileData": {
"devfile": {
"schemaVersion": "",
"metadata": {
"name": "my-nodejs-app",
"version": "Unknown",
"displayName": "Unknown",
"description": "Unknown",
"projectType": "nodejs",
"language": "Unknown"
}
}
},
"runningIn": {
"deploy": true,
"dev": false
},
"ingresses": [
{
"name": "my-nodejs-app",
"rules": [
{
"host": "nodejs.example.com",
"paths": [
"/",
"/foo"
]
}
]
}
],
"routes": [
{
"name": "my-nodejs-app",
"rules": [
{
"host": "my-nodejs-app-phmartin-crt-dev.apps.sandbox-m2.ll9k.p1.openshiftapps.com",
"paths": [
"/testpath"
]
}
]
}
],
"managedBy": "odo",
}
```

Expand Down
3 changes: 2 additions & 1 deletion pkg/alizer/alizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"github.com/golang/mock/gomock"

"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/registry"
)
Expand Down Expand Up @@ -48,7 +49,7 @@ var types = []api.DevfileStack{
},
{
Name: "nodejs",
Language: "javascript",
Language: "JavaScript",
ProjectType: "nodejs",
Tags: []string{"NodeJS", "Express", "ubi8"},
Registry: api.Registry{
Expand Down
22 changes: 17 additions & 5 deletions pkg/api/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,13 @@ func (o RunningModes) String() string {

// Component describes the state of a devfile component
type Component struct {
DevfilePath string `json:"devfilePath,omitempty"`
DevfileData *DevfileData `json:"devfileData,omitempty"`
DevForwardedPorts []ForwardedPort `json:"devForwardedPorts,omitempty"`
RunningIn RunningModes `json:"runningIn"`
ManagedBy string `json:"managedBy"`
DevfilePath string `json:"devfilePath,omitempty"`
DevfileData *DevfileData `json:"devfileData,omitempty"`
DevForwardedPorts []ForwardedPort `json:"devForwardedPorts,omitempty"`
RunningIn RunningModes `json:"runningIn"`
Ingresses []ConnectionData `json:"ingresses,omitempty"`
Routes []ConnectionData `json:"routes,omitempty"`
ManagedBy string `json:"managedBy"`
}

type ForwardedPort struct {
Expand All @@ -58,3 +60,13 @@ type ForwardedPort struct {
LocalPort int `json:"localPort"`
ContainerPort int `json:"containerPort"`
}

type ConnectionData struct {
Name string `json:"name"`
Rules []Rules `json:"rules,omitempty"`
}

type Rules struct {
Host string `json:"host"`
Paths []string `json:"paths"`
}
6 changes: 3 additions & 3 deletions pkg/binding/backend/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ loop:
if err != nil {
return "", schema.GroupVersionKind{}, err
}
resourceList, err := o.kubernetesClient.ListDynamicResources("", gvr)
resourceList, err := o.kubernetesClient.ListDynamicResources("", gvr, "")
if err != nil {
return "", schema.GroupVersionKind{}, err
}
Expand Down Expand Up @@ -130,10 +130,10 @@ func (o *InteractiveBackend) SelectNamespace(_ map[string]string) (string, error
sort.Strings(nsList)
klog.V(4).Infof("all accessible namespaces: %v", nsList)
if len(nsList) == 0 {
//User needs to provide a namespace
// User needs to provide a namespace
return o.askerClient.AskNamespace()
}
//Let users select a namespace from the list
// Let users select a namespace from the list
return o.askerClient.SelectNamespace(nsList)
default:
return "", fmt.Errorf("unknown namespace list option: %d", option)
Expand Down
5 changes: 3 additions & 2 deletions pkg/binding/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package binding

import (
"fmt"
"k8s.io/klog"
"path/filepath"

"k8s.io/klog"

bindingApis "github.com/redhat-developer/service-binding-operator/apis"
bindingApi "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1"
specApi "github.com/redhat-developer/service-binding-operator/apis/spec/v1alpha3"
Expand Down Expand Up @@ -90,7 +91,7 @@ func (o *BindingClient) GetServiceInstances(namespace string) (map[string]unstru
for _, restMapping := range bindableKindRestMappings {
// TODO: Debug into why List returns all the versions instead of the GVR version
// List all the instances of the restMapping object
resources, err := o.kubernetesClient.ListDynamicResources(namespace, restMapping.Resource)
resources, err := o.kubernetesClient.ListDynamicResources(namespace, restMapping.Resource, "")
if err != nil {
if kerrors.IsNotFound(err) || kerrors.IsForbidden(err) {
// Assume the namespace is deleted or being terminated, hence user can't list its resources
Expand Down
6 changes: 3 additions & 3 deletions pkg/binding/binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func TestBindingClient_GetServiceInstances(t *testing.T) {
{Resource: clusterGVR, GroupVersionKind: clusterGVK},
}, nil)

client.EXPECT().ListDynamicResources("", clusterGVR).Return(&unstructured.UnstructuredList{Items: []unstructured.Unstructured{clusterUnstructured}}, nil)
client.EXPECT().ListDynamicResources("", clusterGVR, "").Return(&unstructured.UnstructuredList{Items: []unstructured.Unstructured{clusterUnstructured}}, nil)
return client
},
},
Expand All @@ -145,7 +145,7 @@ func TestBindingClient_GetServiceInstances(t *testing.T) {
{Resource: clusterGVR, GroupVersionKind: clusterGVK},
}, nil)

client.EXPECT().ListDynamicResources(ns, clusterGVR).Return(&unstructured.UnstructuredList{Items: []unstructured.Unstructured{clusterUnstructured}}, nil)
client.EXPECT().ListDynamicResources(ns, clusterGVR, "").Return(&unstructured.UnstructuredList{Items: []unstructured.Unstructured{clusterUnstructured}}, nil)
return client
},
},
Expand Down Expand Up @@ -181,7 +181,7 @@ func TestBindingClient_GetServiceInstances(t *testing.T) {
{Resource: clusterGVR, GroupVersionKind: clusterGVK},
}, nil)

client.EXPECT().ListDynamicResources("", clusterGVR).Return(&unstructured.UnstructuredList{Items: nil}, nil)
client.EXPECT().ListDynamicResources("", clusterGVR, "").Return(&unstructured.UnstructuredList{Items: nil}, nil)
return client
}},
want: map[string]unstructured.Unstructured{},
Expand Down
78 changes: 77 additions & 1 deletion pkg/component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/devfile/api/v2/pkg/devfile"
"github.com/devfile/library/pkg/devfile/parser"
"github.com/devfile/library/pkg/devfile/parser/data"
routev1 "github.com/openshift/api/route/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog"

"github.com/redhat-developer/odo/pkg/alizer"
Expand Down Expand Up @@ -79,7 +81,7 @@ func GatherName(contextDir string, devfileObj *parser.DevfileObj) (string, error
name = filepath.Base(baseDir)
}

//sanitize the name
// sanitize the name
s := util.GetDNS1123Name(name)
klog.V(3).Infof("name of component is %q, and sanitized name is %q", name, s)

Expand Down Expand Up @@ -326,3 +328,77 @@ func GetDevfileInfoFromCluster(ctx context.Context, client kclient.ClientInterfa
Data: devfileData,
}, nil
}

// ListRoutesAndIngresses lists routes and ingresses created by a component;
// it only returns the resources created with Deploy mode;
// it fetches resources from the cluster that match label and return.
func ListRoutesAndIngresses(client kclient.ClientInterface, componentName, appName string) (ings []api.ConnectionData, routes []api.ConnectionData, err error) {
selector := odolabels.GetSelector(componentName, appName, odolabels.ComponentDeployMode, false)

k8sIngresses, err := client.ListIngresses(client.GetCurrentNamespace(), selector)
if err != nil {
return nil, nil, err
}
for _, ing := range k8sIngresses.Items {
if ownerReferences := ing.GetOwnerReferences(); ownerReferences != nil {
klog.V(4).Infof("Skipping Ingress %q created/owned by another resource: %v", ing.GetName(), ownerReferences)
feloy marked this conversation as resolved.
Show resolved Hide resolved
continue
}
ings = append(ings, api.ConnectionData{
Name: ing.GetName(),
Rules: func() (rules []api.Rules) {
for _, rule := range ing.Spec.Rules {
var paths []string
for _, path := range rule.HTTP.Paths {
paths = append(paths, path.Path)
}
host := rule.Host
if host == "" {
host = "*"
}
rules = append(rules, api.Rules{Host: host, Paths: paths})
}
if len(ing.Spec.Rules) == 0 {
rules = append(rules, api.Rules{Host: "*", Paths: []string{"/*"}})
}
return rules
}(),
})
}
// Return early if it is not an OpenShift cluster
if isOC, e := client.IsProjectSupported(); !isOC {
if e != nil {
klog.V(4).Infof("unable to detect project support: %s", e.Error())
}
return ings, nil, nil
}

routeGVR, err := client.GetGVRFromGVK(kclient.RouteGVK)
if err != nil {
return nil, nil, fmt.Errorf("unable to determine GVR for %s: %w", kclient.RouteGVK.String(), err)
}

ocRoutes, err := client.ListDynamicResources(client.GetCurrentNamespace(), routeGVR, selector)
if err != nil {
return nil, nil, err
}
for _, u := range ocRoutes.Items {
if ownerReferences := u.GetOwnerReferences(); ownerReferences != nil {
klog.V(4).Infof("Skipping Route %q created/owned by another resource: %v", u.GetName(), ownerReferences)
continue
}
route := routev1.Route{}
err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.UnstructuredContent(), &route)
if err != nil {
return nil, nil, err
}
routes = append(routes, api.ConnectionData{
Name: route.GetName(),
Rules: []api.Rules{
{Host: route.Spec.Host, Paths: []string{route.Spec.Path}},
},
})
}

return ings, routes, nil
}
Loading