Skip to content

Commit

Permalink
Podman custom port mapping (#6729)
Browse files Browse the repository at this point in the history
* Temp Change

* Custom port mapping works with podman

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Add unit tests

* Move custom port forward formation to the general getPortMapping function

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Integration test

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Fix unit tests

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Refactor integration test

Signed-off-by: Parthvi Vala <pvala@redhat.com>

Add dev --debug integration test for podman

Signed-off-by: Parthvi Vala <pvala@redhat.com>

Add dev --debug integration test for podman

Signed-off-by: Parthvi Vala <pvala@redhat.com>

Fix ci failures

Signed-off-by: Parthvi Vala <pvala@redhat.com>

* Use order to iterate over ceMapping and fix a check with debug integration test

Signed-off-by: Parthvi Vala <pvala@redhat.com>

---------

Signed-off-by: Parthvi Vala <pvala@redhat.com>
  • Loading branch information
valaparthvi authored Apr 18, 2023
1 parent 7a72134 commit 28ba3df
Show file tree
Hide file tree
Showing 7 changed files with 721 additions and 470 deletions.
67 changes: 60 additions & 7 deletions pkg/dev/podmandev/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package podmandev

import (
"fmt"
"math/rand" //#nosec
"math/rand" // #nosec
"sort"
"time"

"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
Expand Down Expand Up @@ -39,6 +40,7 @@ func createPodFromComponent(
debugCommand string,
withHelperContainer bool,
randomPorts bool,
customForwardedPorts []api.ForwardedPort,
usedPorts []int,
) (*corev1.Pod, []api.ForwardedPort, error) {
podTemplate, err := generator.GetPodTemplateSpec(devfileObj, generator.PodTemplateParams{})
Expand All @@ -50,7 +52,8 @@ func createPodFromComponent(
return nil, nil, fmt.Errorf("no valid components found in the devfile")
}

fwPorts, err := getPortMapping(devfileObj, debug, randomPorts, usedPorts)
var fwPorts []api.ForwardedPort
fwPorts, err = getPortMapping(devfileObj, debug, randomPorts, usedPorts, customForwardedPorts)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -174,7 +177,7 @@ func getVolumeName(volume string, componentName string, appName string) string {
return volume + "-" + componentName + "-" + appName
}

func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool, usedPorts []int) ([]api.ForwardedPort, error) {
func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool, usedPorts []int, definedPorts []api.ForwardedPort) ([]api.ForwardedPort, error) {
containerComponents, err := devfileObj.Data.GetComponents(common.DevfileOptions{
ComponentOptions: common.ComponentOptions{ComponentType: v1alpha2.ContainerComponentType},
})
Expand All @@ -190,6 +193,12 @@ func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool,
}
}

// this list makes sure that we ranged ports[20001-30001] do not coincide with a custom local port
customLocalPorts := make(map[int]struct{})
for _, dPort := range definedPorts {
customLocalPorts[dPort.LocalPort] = struct{}{}
}

isPortUsedInContainer := func(p int) bool {
for _, port := range existingContainerPorts {
if p == port {
Expand All @@ -199,12 +208,38 @@ func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool,
return false
}

// getCustomLocalPort analyzes the definedPorts i.e. custom port forwarding to see if a containerPort has a custom localPort, if a container name is provided, it also takes that into account.
getCustomLocalPort := func(containerPort int, container string) int {
for _, dp := range definedPorts {
if dp.ContainerPort == containerPort {
if dp.ContainerName != "" {
if dp.ContainerName == container {
return dp.LocalPort
}
} else {
return dp.LocalPort
}
}
}
return 0
}

var result []api.ForwardedPort
startPort := 20001
endPort := startPort + 10000
usedPortsCopy := make([]int, len(usedPorts))
copy(usedPortsCopy, usedPorts)
for containerName, endpoints := range ceMapping {

// Prepare to iterate over the ceMapping in an orderly fashion
// This ensures we iterate over the ceMapping in the same way every time, obtain the same result every time and avoid any flakes with tests
var containers []string
for container := range ceMapping {
containers = append(containers, container)
}
sort.Strings(containers)

for _, containerName := range containers {
endpoints := ceMapping[containerName]
epLoop:
for _, ep := range endpoints {
portName := ep.Name
Expand All @@ -215,14 +250,32 @@ func getPortMapping(devfileObj parser.DevfileObj, debug bool, randomPorts bool,
continue
}
var freePort int
if randomPorts {
if len(definedPorts) != 0 {
freePort = getCustomLocalPort(ep.TargetPort, containerName)
if freePort == 0 {
for {
freePort, err = util.NextFreePort(startPort, endPort, usedPorts)
if err != nil {
klog.Infof("%s", err)
continue
}
// ensure that freePort is not a custom local port
if _, isPortUsed := customLocalPorts[freePort]; isPortUsed {
startPort = freePort + 1
continue
}
break
}
startPort = freePort + 1
}
} else if randomPorts {
if len(usedPortsCopy) != 0 {
freePort = usedPortsCopy[0]
usedPortsCopy = usedPortsCopy[1:]
} else {
rand.Seed(time.Now().UnixNano()) //#nosec
rand.Seed(time.Now().UnixNano()) // #nosec
for {
freePort = rand.Intn(endPort-startPort+1) + startPort //#nosec
freePort = rand.Intn(endPort-startPort+1) + startPort // #nosec
if !isPortUsedInContainer(freePort) && util.IsPortFree(freePort) {
break
}
Expand Down
Loading

0 comments on commit 28ba3df

Please sign in to comment.