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

🔧 [fix] Fix Port Mapping Issue #62

Merged
merged 6 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 8 additions & 7 deletions commands/deploy_manuscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,20 @@ func DeployManuscript(args []string) {
}
return nil
}},
{"Step 2: Checking manuscript is already deployed", func() error {
{"Step 2: Verifying Port Initialization", func() error { return pkg.InitializePorts(&ms) }},
{"Step 3: Checking manuscript is already deployed", func() error {
err := CheckManuscriptExist(ms)
if err != nil {
return err
}
return nil
}},
{"Step 3: Create Directory", func() error { return createDirectory(manuscriptDir) }},
{"Step 4: Create ManuscriptFile", func() error { return copyManuscriptFile(manuscriptDir, manuscriptPath) }},
{"Step 5: Create DockerComposeFile", func() error { return createDockerComposeFile(manuscriptDir, &ms) }},
{"Step 6: Check Docker Installed", func() error { return checkDockerInstalled() }},
{"Step 7: Start Docker Containers", func() error { return startDockerContainers(manuscriptDir) }},
{"Step 8: Check Container Status", func() error { return checkContainerStatus(&ms) }},
{"Step 4: Create Directory", func() error { return createDirectory(manuscriptDir) }},
{"Step 5: Create ManuscriptFile", func() error { return copyManuscriptFile(manuscriptDir, manuscriptPath) }},
{"Step 6: Create DockerComposeFile", func() error { return createDockerComposeFile(manuscriptDir, &ms) }},
{"Step 7: Check Docker Installed", func() error { return checkDockerInstalled() }},
{"Step 8: Start Docker Containers", func() error { return startDockerContainers(manuscriptDir) }},
{"Step 9: Check Container Status", func() error { return checkContainerStatus(&ms) }},
}

for _, step := range steps {
Expand Down
78 changes: 28 additions & 50 deletions commands/init_manuscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,49 +147,50 @@ func createManuscriptFile(dir string, ms pkg.Manuscript) error {
}

func createDockerComposeFile(dir string, ms *pkg.Manuscript) error {
fmt.Printf("Debug: Creating docker-compose file in directory: %s\n", dir)
composeFilePath := filepath.Join(dir, "docker-compose.yml")
dockComposeTemplate := static.DockerComposeTemplate
switch ms.Sink {
case defaultSink:
m, err := pkg.LoadConfig(manuscriptConfig)
if err != nil {
return fmt.Errorf("failed to load manuscript config: %w", err)
fmt.Printf("Debug: Creating new config as none exists or error loading: %v\n", err)
m = &pkg.Config{
BaseDir: getHomeDir(),
Manuscripts: []pkg.Manuscript{},
}
}

ms.GraphQLImage = graphQLImage
if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
ms.GraphQLImage = graphQLARMImage
}

var excludePorts []int
for _, m := range m.Manuscripts {
if m.Name == ms.Name {
ms.Port = m.Port
ms.DbPort = m.DbPort
ms.DbUser = m.DbUser
ms.DbPassword = m.DbPassword
ms.GraphQLPort = m.GraphQLPort
dockComposeTemplate = static.DockerComposeWithPostgresqlContent
return createTemplateFile(composeFilePath, dockComposeTemplate, ms)
// Check if manuscript already exists in config
var existingMs *pkg.Manuscript
for _, manuscript := range m.Manuscripts {
if manuscript.Name == ms.Name {
existingMs = &manuscript
break
}
excludePorts = append(excludePorts, m.Port, m.GraphQLPort)
}
port, err := FindAvailablePort(8081, 8181, excludePorts)
if err != nil {
return fmt.Errorf("failed to find available port: %w", err)
}
ms.Port = port
excludePorts = append(excludePorts, port)
graphQLPort, err := FindAvailablePort(8081, 8181, excludePorts)
if err != nil {
return fmt.Errorf("failed to find available port: %w", err)
}
dbPort, err := FindAvailablePort(15432, 15532, excludePorts)
if err != nil {
return fmt.Errorf("failed to find available port: %w", err)

if existingMs != nil {
// Use existing ports if manuscript is already configured
ms.Port = existingMs.Port
ms.DbPort = existingMs.DbPort
ms.DbUser = existingMs.DbUser
ms.DbPassword = existingMs.DbPassword
ms.GraphQLPort = existingMs.GraphQLPort
} else {
// Initialize new ports using the common function
if err := pkg.InitializePorts(ms); err != nil {
return fmt.Errorf("failed to initialize ports: %w", err)
}
}
ms.DbPort = dbPort
ms.GraphQLPort = graphQLPort

fmt.Printf("Debug: Using ports - Flink: %d, GraphQL: %d, DB: %d\n",
ms.Port, ms.GraphQLPort, ms.DbPort)
dockComposeTemplate = static.DockerComposeWithPostgresqlContent
default:
}
Expand Down Expand Up @@ -295,29 +296,6 @@ func createTemplateFile(filePath, tmplContent string, data interface{}) error {
return nil
}

func FindAvailablePort(startPort, endPort int, exclude []int) (int, error) {
listeningPorts, err := pkg.GetListeningPorts()
if err != nil {
return 0, err
}

portMap := make(map[int]bool)
for _, port := range listeningPorts {
portMap[port] = true
}
for _, port := range exclude {
portMap[port] = true
}

for port := startPort; port <= endPort; port++ {
if !portMap[port] {
return port, nil
}
}

return 0, fmt.Errorf("no available ports in the range %d-%d", startPort, endPort)
}

func promptInput(prompt, defaultVal string) string {
fmt.Printf("\r\033[33m%s\u001B[0m", prompt)
reader := bufio.NewReader(os.Stdin)
Expand Down
110 changes: 97 additions & 13 deletions pkg/common_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,123 @@ package pkg
import (
"bufio"
"bytes"
"fmt"
"os/exec"
"regexp"
"strconv"
)

func GetListeningPorts() ([]int, error) {
ports := make(map[int]bool)

// Check system ports using lsof
cmd := exec.Command("lsof", "-nP", "-iTCP", "-sTCP:LISTEN")
var out bytes.Buffer
cmd.Stdout = &out

if err := cmd.Run(); err != nil {
return nil, err
// Don't return error here, continue to check Docker ports
fmt.Printf("Warning: Unable to check system ports: %v\n", err)
} else {
re := regexp.MustCompile(`:(\d+)\s+\(LISTEN\)`)
scanner := bufio.NewScanner(&out)
for scanner.Scan() {
line := scanner.Text()
matches := re.FindStringSubmatch(line)
if len(matches) > 1 {
port, err := strconv.Atoi(matches[1])
if err != nil {
continue
}
ports[port] = true
}
}
}

re := regexp.MustCompile(`:(\d+)\s+\(LISTEN\)`)
// Check Docker container ports
dockerCmd := exec.Command("docker", "ps", "--format", "{{.Ports}}")
var dockerOut bytes.Buffer
dockerCmd.Stdout = &dockerOut

var ports []int
scanner := bufio.NewScanner(&out)
if err := dockerCmd.Run(); err != nil {
return nil, fmt.Errorf("failed to check Docker ports: %w", err)
}

// Parse Docker port mappings
scanner := bufio.NewScanner(&dockerOut)
portRegex := regexp.MustCompile(`0\.0\.0\.0:(\d+)`)
for scanner.Scan() {
line := scanner.Text()
matches := re.FindStringSubmatch(line)
if len(matches) > 1 {
port, err := strconv.Atoi(matches[1])
if err != nil {
continue
matches := portRegex.FindAllStringSubmatch(line, -1)
for _, match := range matches {
if len(match) > 1 {
port, err := strconv.Atoi(match[1])
if err != nil {
continue
}
ports[port] = true
}
ports = append(ports, port)
}
}

if err := scanner.Err(); err != nil {
return nil, err
// Convert map to slice
var result []int
for port := range ports {
result = append(result, port)
}
return result, nil
}

func InitializePorts(ms *Manuscript) error {
// Initialize Flink port if not set
if ms.Port == 0 {
port, err := FindAvailablePort(8081, 8181, nil)
if err != nil {
return fmt.Errorf("failed to find available port for Flink: %w", err)
}
ms.Port = port
}

// Initialize GraphQL port if not set
if ms.GraphQLPort == 0 {
graphQLPort, err := FindAvailablePort(8082, 8182, []int{ms.Port})
if err != nil {
return fmt.Errorf("failed to find available port for GraphQL: %w", err)
}
ms.GraphQLPort = graphQLPort
}

// Initialize DB port if not set
if ms.DbPort == 0 {
dbPort, err := FindAvailablePort(15432, 15532, []int{ms.Port, ms.GraphQLPort})
if err != nil {
return fmt.Errorf("failed to find available port for DB: %w", err)
}
ms.DbPort = dbPort
}

return nil
}

func FindAvailablePort(startPort, endPort int, exclude []int) (int, error) {
listeningPorts, err := GetListeningPorts()
if err != nil {
return 0, err
}

portMap := make(map[int]bool)
for _, port := range listeningPorts {
portMap[port] = true
}
for _, port := range exclude {
portMap[port] = true
}

for port := startPort; port <= endPort; port++ {
if !portMap[port] {
return port, nil
}
}

return ports, nil
return 0, fmt.Errorf("no available ports in the range %d-%d", startPort, endPort)
}
Loading