Skip to content

Commit

Permalink
Fix Port Conflict Error (#1033)
Browse files Browse the repository at this point in the history
(closes #831 )

* Added ports pre checking

To find out whether they are being used by other applications.

* Check which process is using target port, if any

* Moved excludeWhitespace() function to util package
  • Loading branch information
arknable committed May 14, 2021
1 parent f874275 commit d960f42
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 13 deletions.
1 change: 0 additions & 1 deletion cmd/cmd_pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ func loadCommandHandler(cmd *cobra.Command, args []string) {
buildImageFlags := NewBuildImageCommandFlags(flags)
runLocalInstanceFlags := NewRunLocalInstanceCommandFlags(flags)
pkgFlags := NewPkgCommandFlags(flags)

pkgFlags.Package = args[0]

c := lepton.NewConfig()
Expand Down
11 changes: 5 additions & 6 deletions cmd/cmd_root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,20 @@ func GetRootCommand() *cobra.Command {
var rootCmd = &cobra.Command{
Use: "ops",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var config *types.Config
config := &types.Config{}

configFlag, _ := cmd.Flags().GetString("config")
configFlag = strings.TrimSpace(configFlag)

if configFlag != "" {
config := &types.Config{}
if err := unWarpConfig(configFlag, config); err != nil {
return err
}
}

globalFlags := NewGlobalCommandFlags(cmd.Flags())
if err := globalFlags.MergeToConfig(config); err != nil {
return err
}
globalFlags := NewGlobalCommandFlags(cmd.Flags())
if err := globalFlags.MergeToConfig(config); err != nil {
return err
}

log.InitDefault(os.Stdout, config)
Expand Down
33 changes: 27 additions & 6 deletions cmd/flags_run_local_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net"
"strconv"
"time"

"github.com/nanovms/ops/types"

Expand Down Expand Up @@ -32,7 +33,7 @@ type RunLocalInstanceCommandFlags struct {
}

// MergeToConfig overrides configuration passed by argument with command flags values
func (flags *RunLocalInstanceCommandFlags) MergeToConfig(c *types.Config) (err error) {
func (flags *RunLocalInstanceCommandFlags) MergeToConfig(c *types.Config) error {
c.Debugflags = []string{}

if flags.Trace {
Expand All @@ -46,9 +47,9 @@ func (flags *RunLocalInstanceCommandFlags) MergeToConfig(c *types.Config) (err e

var elfFile *elf.File

elfFile, err = api.GetElfFileInfo(c.ProgramPath)
elfFile, err := api.GetElfFileInfo(c.ProgramPath)
if err != nil {
return
return err
}

if api.IsDynamicLinked(elfFile) {
Expand Down Expand Up @@ -91,8 +92,7 @@ func (flags *RunLocalInstanceCommandFlags) MergeToConfig(c *types.Config) (err e

ports, err := PrepareNetworkPorts(flags.Ports)
if err != nil {
exitWithError(err.Error())
return
return err
}

for _, p := range ports {
Expand All @@ -116,7 +116,28 @@ func (flags *RunLocalInstanceCommandFlags) MergeToConfig(c *types.Config) (err e

}

return
for _, port := range flags.Ports {
conn, err := net.DialTimeout("tcp", ":"+port, time.Second)
if err != nil {
continue // assume port is not being used
}

if conn != nil {
conn.Close()

message := fmt.Sprintf("Port %v is being used by other application", port)
pid, err := checkPortUserPID(port)
if err != nil {
return err
}
if pid != "" {
message += fmt.Sprintf(" (PID %s)", pid)
}
return errors.New(message)
}
}

return nil
}

// NewRunLocalInstanceCommandFlags returns an instance of RunLocalInstanceCommandFlags initialized with command flags values
Expand Down
41 changes: 41 additions & 0 deletions cmd/flags_run_local_instance_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cmd

import (
"bufio"
"os/exec"
"strings"

"github.com/nanovms/ops/util/slice"
)

// Checks which process is using given port number
func checkPortUserPID(portNumber string) (string, error) {
var (
pid string
cmd = exec.Command("lsof", "-i", ":"+portNumber)
)
out, err := cmd.Output()
if err != nil {
return pid, err
}

scanner := bufio.NewScanner(strings.NewReader(string(out)))
scanner.Scan() // check header first
cols := slice.ExcludeWhitespaces(strings.Split(scanner.Text(), " "))
headerIdx := -1
for i, v := range cols {
if strings.ToLower(v) == "pid" {
headerIdx = i
break
}
}

scanner.Scan()
line := strings.Trim(scanner.Text(), " ")
if line != "" {
cols = slice.ExcludeWhitespaces(strings.Split(line, " "))
pid = cols[headerIdx]
}

return pid, err
}
15 changes: 15 additions & 0 deletions util/slice/string.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package slice

import "strings"

// ExcludeWhitespaces removes whitespaces from given slice
func ExcludeWhitespaces(arr []string) []string {
result := make([]string, 0)
for _, h := range arr {
if strings.Trim(h, " ") == "" {
continue
}
result = append(result, h)
}
return result
}
24 changes: 24 additions & 0 deletions util/slice/string_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package slice

import (
"strings"
"testing"
)

func TestExcludeWhitespaces(t *testing.T) {
arr := []string{
"lorem", "ipsum", " ", "dolor", "", "sit", "amet",
}
trimmed := ExcludeWhitespaces(arr)
for _, v := range trimmed {
if v == "" {
t.Error("found unstripped whice space")
}
}

expected := "lorem,ipsum,dolor,sit,amet"
str := strings.Join(trimmed, ",")
if str != expected {
t.Errorf("expected '%s', got '%s'", expected, str)
}
}

0 comments on commit d960f42

Please sign in to comment.