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

Show information about forwarded debug ports in odo describe component #6537

Merged
1 change: 1 addition & 0 deletions docs/website/docs/command-reference/describe-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ This command returns information extracted from the Devfile:
- supported odo features, indicating if the Devfile defines necessary information to run `odo dev`, `odo dev --debug` and `odo deploy`
- the list of container components,
- the list of Kubernetes components.
- the list of forwarded ports if the component is running in Dev mode.

The command also displays if the component is currently running in the cluster on Dev and/or Deploy mode.

Expand Down
13 changes: 12 additions & 1 deletion docs/website/docs/command-reference/json-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,20 @@ odo describe component -o json
"devForwardedPorts": [
{
"containerName": "runtime",
"portName": "http",
"localAddress": "127.0.0.1",
"localPort": 40001,
"containerPort": 3000
"containerPort": 3000,
"isDebug": false
},
{
"containerName": "runtime",
"portName": "debug",
"localAddress": "127.0.0.1",
"localPort": 40002,
"containerPort": 5858,
"isDebug": true,
"exposure": "none"
}
],
"runningIn": {
Expand Down
3 changes: 3 additions & 0 deletions pkg/api/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ type Component struct {
type ForwardedPort struct {
Platform string `json:"platform,omitempty"`
ContainerName string `json:"containerName"`
PortName string `json:"portName"`
IsDebug bool `json:"isDebug"`
LocalAddress string `json:"localAddress"`
LocalPort int `json:"localPort"`
ContainerPort int `json:"containerPort"`
Exposure string `json:"exposure,omitempty"`
}

type ConnectionData struct {
Expand Down
39 changes: 31 additions & 8 deletions pkg/dev/podmandev/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"math/rand" //#nosec
"time"

"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/v2/pkg/devfile/generator"
"github.com/devfile/library/v2/pkg/devfile/parser"
"github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
Expand Down Expand Up @@ -48,7 +49,15 @@ func createPodFromComponent(
utils.AddOdoProjectVolume(&containers)
utils.AddOdoMandatoryVolume(&containers)

fwPorts := addHostPorts(containers, debug, randomPorts, usedPorts)
// get the endpoint/port information for containers in devfile
containerComponents, err := devfileObj.Data.GetComponents(common.DevfileOptions{
ComponentOptions: common.ComponentOptions{ComponentType: v1alpha2.ContainerComponentType},
})
if err != nil {
return nil, nil, err
}
ceMapping := libdevfile.GetContainerEndpointMapping(containerComponents, debug)
fwPorts := addHostPorts(containers, ceMapping, debug, randomPorts, usedPorts)

volumes := []corev1.Volume{
{
Expand Down Expand Up @@ -114,7 +123,7 @@ func getVolumeName(volume string, componentName string, appName string) string {
return volume + "-" + componentName + "-" + appName
}

func addHostPorts(containers []corev1.Container, debug bool, randomPorts bool, usedPorts []int) []api.ForwardedPort {
func addHostPorts(containers []corev1.Container, ceMapping map[string][]v1alpha2.Endpoint, debug bool, randomPorts bool, usedPorts []int) []api.ForwardedPort {
var result []api.ForwardedPort
startPort := 20001
endPort := startPort + 10000
Expand All @@ -123,10 +132,12 @@ func addHostPorts(containers []corev1.Container, debug bool, randomPorts bool, u
for i := range containers {
var ports []corev1.ContainerPort
for _, port := range containers[i].Ports {
containerName := containers[i].Name
portName := port.Name
if !debug && libdevfile.IsDebugPort(portName) {
isDebugPort := libdevfile.IsDebugPort(portName)
if !debug && isDebugPort {
klog.V(4).Infof("not running in Debug mode, so skipping container Debug port: %v:%v:%v",
containers[i].Name, portName, port.ContainerPort)
containerName, portName, port.ContainerPort)
continue
}
var freePort int
Expand All @@ -153,13 +164,25 @@ func addHostPorts(containers []corev1.Container, debug bool, randomPorts bool, u
}
startPort = freePort + 1
}
result = append(result, api.ForwardedPort{
// Find the endpoint in the container-endpoint mapping
containerPort := int(port.ContainerPort)
fp := api.ForwardedPort{
Platform: commonflags.PlatformPodman,
ContainerName: containers[i].Name,
PortName: portName,
IsDebug: isDebugPort,
ContainerName: containerName,
LocalAddress: "127.0.0.1",
LocalPort: freePort,
ContainerPort: int(port.ContainerPort),
})
ContainerPort: containerPort,
}

for _, ep := range ceMapping[containerName] {
if ep.TargetPort == containerPort {
fp.Exposure = string(ep.Exposure)
break
}
}
result = append(result, fp)
port.HostPort = int32(freePort)
ports = append(ports, port)
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/dev/podmandev/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,11 @@ func Test_createPodFromComponent(t *testing.T) {
{
Platform: "podman",
ContainerName: "mycomponent",
PortName: "http",
LocalAddress: "127.0.0.1",
LocalPort: 20001,
ContainerPort: 8080,
IsDebug: false,
},
},
},
Expand Down Expand Up @@ -274,9 +276,11 @@ func Test_createPodFromComponent(t *testing.T) {
{
Platform: "podman",
ContainerName: "mycomponent",
PortName: "http",
LocalAddress: "127.0.0.1",
LocalPort: 20001,
ContainerPort: 8080,
IsDebug: false,
},
},
},
Expand Down Expand Up @@ -324,16 +328,20 @@ func Test_createPodFromComponent(t *testing.T) {
{
Platform: "podman",
ContainerName: "mycomponent",
PortName: "http",
LocalAddress: "127.0.0.1",
LocalPort: 20001,
ContainerPort: 8080,
IsDebug: false,
},
{
Platform: "podman",
ContainerName: "mycomponent",
PortName: "debug",
LocalAddress: "127.0.0.1",
LocalPort: 20002,
ContainerPort: 5858,
IsDebug: true,
},
},
},
Expand Down
12 changes: 6 additions & 6 deletions pkg/libdevfile/libdevfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,24 +276,24 @@ func execDevfileEvent(devfileObj parser.DevfileObj, events []string, handler Han
return nil
}

// GetContainerEndpointMapping returns a map of container names and slice of its endpoints (in int)
// Debug ports will be included only if includeDebug is true.
func GetContainerEndpointMapping(containers []v1alpha2.Component, includeDebug bool) map[string][]int {
ceMapping := make(map[string][]int)
// GetContainerEndpointMapping returns a map of container names and slice of its endpoints.
// Debug endpoints will be included only if includeDebug is true.
func GetContainerEndpointMapping(containers []v1alpha2.Component, includeDebug bool) map[string][]v1alpha2.Endpoint {
ceMapping := make(map[string][]v1alpha2.Endpoint)
for _, container := range containers {
if container.ComponentUnion.Container == nil {
// this is not a container component; continue prevents panic when accessing Endpoints field
continue
}

var ports []int
var ports []v1alpha2.Endpoint
for _, e := range container.Container.Endpoints {
if !includeDebug && IsDebugEndpoint(e) {
klog.V(4).Infof("not running in Debug mode, so ignored Debug port for container %v:%v:%v",
container.Name, e.Name, e.TargetPort)
continue
}
ports = append(ports, e.TargetPort)
ports = append(ports, e)
}
if len(ports) != 0 {
ceMapping[container.Name] = ports
Expand Down
79 changes: 58 additions & 21 deletions pkg/libdevfile/libdevfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,21 +699,21 @@ func TestGetContainerEndpointMapping(t *testing.T) {
tests := []struct {
name string
args args
want map[string][]int
want map[string][]v1alpha2.Endpoint
}{
{
name: "invalid input - image components instead of container components",
args: args{
containers: []v1alpha2.Component{imageComponent},
},
want: map[string][]int{},
want: map[string][]v1alpha2.Endpoint{},
},
{
name: "one container with no endpoints exposed",
args: args{
containers: []v1alpha2.Component{containerWithNoEndpoints},
},
want: map[string][]int{},
want: map[string][]v1alpha2.Endpoint{},
},
{
name: "multiple containers with varying types of endpoints - without debug",
Expand All @@ -727,11 +727,21 @@ func TestGetContainerEndpointMapping(t *testing.T) {
multiportContainer2,
},
},
want: map[string][]int{
containerWithOnePublicEndpoint.Name: {8080},
containerWithOneInternalEndpoint.Name: {9090},
multiportContainer1.Name: {3000, 8888},
multiportContainer2.Name: {8080, 9100},
want: map[string][]v1alpha2.Endpoint{
containerWithOnePublicEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep1", TargetPort: 8080, Exposure: "public"},
},
containerWithOneInternalEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep2", TargetPort: 9090, Exposure: "internal"},
},
multiportContainer1.Name: {
v1alpha2.Endpoint{Name: "http-3000", TargetPort: 3000, Exposure: "public"},
v1alpha2.Endpoint{Name: "http-8888", TargetPort: 8888, Exposure: "internal"},
},
multiportContainer2.Name: {
v1alpha2.Endpoint{Name: "http-8080", TargetPort: 8080, Exposure: "public"},
v1alpha2.Endpoint{Name: "http-9100", TargetPort: 9100, Exposure: "internal"},
},
},
},
{
Expand All @@ -747,12 +757,29 @@ func TestGetContainerEndpointMapping(t *testing.T) {
},
includeDebug: true,
},
want: map[string][]int{
containerWithOnePublicEndpoint.Name: {8080},
containerWithOneInternalEndpoint.Name: {9090},
containerWithOneNoneDebugEndpoint.Name: {9099},
multiportContainer1.Name: {3000, 8888, 5005, 15005, 25005},
multiportContainer2.Name: {8080, 9100, 18080, 19100},
want: map[string][]v1alpha2.Endpoint{
containerWithOnePublicEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep1", TargetPort: 8080, Exposure: "public"},
},
containerWithOneInternalEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep2", TargetPort: 9090, Exposure: "internal"},
},
containerWithOneNoneDebugEndpoint.Name: {
v1alpha2.Endpoint{Name: "debug", TargetPort: 9099, Exposure: "none"},
},
multiportContainer1.Name: {
v1alpha2.Endpoint{Name: "http-3000", TargetPort: 3000, Exposure: "public"},
v1alpha2.Endpoint{Name: "http-8888", TargetPort: 8888, Exposure: "internal"},
v1alpha2.Endpoint{Name: "debug", TargetPort: 5005, Exposure: "none"},
v1alpha2.Endpoint{Name: "debug-udp", TargetPort: 15005, Exposure: "none", Protocol: "udp"},
v1alpha2.Endpoint{Name: "debug-ws", TargetPort: 25005, Exposure: "none", Protocol: "ws"},
},
multiportContainer2.Name: {
v1alpha2.Endpoint{Name: "http-8080", TargetPort: 8080, Exposure: "public"},
v1alpha2.Endpoint{Name: "http-9100", TargetPort: 9100, Exposure: "internal"},
v1alpha2.Endpoint{Name: "debug", TargetPort: 18080, Exposure: "none"},
v1alpha2.Endpoint{Name: "debug-udp", TargetPort: 19100, Exposure: "none", Protocol: "udp"},
},
},
},
{
Expand All @@ -766,9 +793,13 @@ func TestGetContainerEndpointMapping(t *testing.T) {
imageComponent,
},
},
want: map[string][]int{
containerWithOnePublicEndpoint.Name: {8080},
containerWithOneInternalEndpoint.Name: {9090},
want: map[string][]v1alpha2.Endpoint{
containerWithOnePublicEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep1", TargetPort: 8080, Exposure: "public"},
},
containerWithOneInternalEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep2", TargetPort: 9090, Exposure: "internal"},
},
},
},
{
Expand All @@ -783,10 +814,16 @@ func TestGetContainerEndpointMapping(t *testing.T) {
},
includeDebug: true,
},
want: map[string][]int{
containerWithOnePublicEndpoint.Name: {8080},
containerWithOneInternalEndpoint.Name: {9090},
containerWithOneNoneDebugEndpoint.Name: {9099},
want: map[string][]v1alpha2.Endpoint{
containerWithOnePublicEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep1", TargetPort: 8080, Exposure: "public"},
},
containerWithOneInternalEndpoint.Name: {
v1alpha2.Endpoint{Name: "ep2", TargetPort: 9090, Exposure: "internal"},
},
containerWithOneNoneDebugEndpoint.Name: {
v1alpha2.Endpoint{Name: "debug", TargetPort: 9099, Exposure: "none"},
},
},
},
}
Expand Down
15 changes: 12 additions & 3 deletions pkg/odo/cli/describe/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,15 +383,24 @@ func printHumanReadableOutput(ctx context.Context, cmp api.Component, devfileObj
if len(cmp.DevForwardedPorts) > 0 {
log.Info("Forwarded ports:")
for _, port := range cmp.DevForwardedPorts {
details := fmt.Sprintf("%s:%d -> %s:%d", port.LocalAddress, port.LocalPort, port.ContainerName, port.ContainerPort)
if withPlatformFeature {
p := port.Platform
if p == "" {
p = commonflags.PlatformCluster
}
log.Printf("[%s] %s:%d -> %s:%d", p, port.LocalAddress, port.LocalPort, port.ContainerName, port.ContainerPort)
} else {
log.Printf("%s:%d -> %s:%d", port.LocalAddress, port.LocalPort, port.ContainerName, port.ContainerPort)
details = fmt.Sprintf("[%s] ", p) + details
}
if port.PortName != "" {
details += "\n Name: " + port.PortName
}
if port.Exposure != "" {
details += "\n Exposure: " + port.Exposure
}
if port.IsDebug {
details += "\n Debug: true"
}
log.Printf(details)
}
fmt.Println()
}
Expand Down
11 changes: 6 additions & 5 deletions pkg/portForward/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package portForward
import (
"io"

"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
"github.com/devfile/library/v2/pkg/devfile/parser"
)

Expand All @@ -13,7 +14,7 @@ type Client interface {
// output will be written to errOut writer
StartPortForwarding(
devFileObj parser.DevfileObj,
componenentName string,
componentName string,
debug bool,
randomPorts bool,
errOut io.Writer,
Expand All @@ -22,10 +23,10 @@ type Client interface {
// StopPortForwarding stops the port forwarding
StopPortForwarding()

// GetForwardedPorts returns the list of ports for each containers currently forwarded
GetForwardedPorts() map[string][]int
// GetForwardedPorts returns the list of ports for each container currently forwarded.
GetForwardedPorts() map[string][]v1alpha2.Endpoint

// GetPortsToForward returns the endpoints to forward from the Devfile.
// GetPortsToForward returns the endpoints to forward from the Devfile, by container name.
// Debug ports will be included only if includeDebug is true.
GetPortsToForward(devFileObj parser.DevfileObj, includeDebug bool) (map[string][]int, error)
GetPortsToForward(devFileObj parser.DevfileObj, includeDebug bool) (map[string][]v1alpha2.Endpoint, error)
}
Loading