Skip to content

Commit

Permalink
Consider running containers to improve port suggestions (#270)
Browse files Browse the repository at this point in the history
* Consider exposed ports of running containers for port suggestions

* Optimize code

* Add more tests
  • Loading branch information
marcauberer committed Jan 13, 2022
1 parent 404f3ba commit 76bc7d5
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 16 deletions.
25 changes: 25 additions & 0 deletions src/util/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,31 @@ func getOuterVolumePathOnDockerizedEnvironment() string {
return ""
}

func getUsedPortsOfRunningServices() []int {
// Obtain Docker client
client, err := newClientWithOpts(client.FromEnv)
if err != nil {
ErrorLogger.Println("Docker client initialization failed: " + err.Error())
logError("Could not intanciate Docker client. Please check your Docker installation", true)
return []int{}
}
// Get runnings containers
containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
WarningLogger.Println("Could not obtain container list: " + err.Error())
logWarning("Could not obtain container list. Please check your Docker installation")
return []int{}
}
// Get ports from running services
ports := []int{}
for _, container := range containers {
for _, port := range container.Ports {
ports = append(ports, int(port.PublicPort))
}
}
return ports
}

// IsLinux checks if the os in Linux
func IsLinux() bool {
return runtime.GOOS == "linux"
Expand Down
5 changes: 4 additions & 1 deletion src/util/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,20 @@ func AskTemplateQuestions(project *model.CGProject, template *model.PredefinedTe
defaultValue := ReplaceVarsInString(question.DefaultValue, project.Vars)

if question.Validator == "port" {
externallyUsedPorts := getUsedPortsOfRunningServices()
// If the port is already in use, find unused one
port, err := strconv.Atoi(defaultValue)
if err != nil {
ErrorLogger.Println("Could not convert port to integer: " + err.Error())
logError("Could not convert port to integer. Please check template", true)
}
for SliceContainsInt(project.Ports, port) {
// Check usages in current stack and in externally running containers
for SliceContainsInt(project.Ports, port) || SliceContainsInt(externallyUsedPorts, port) {
port++
}
defaultValue = strconv.Itoa(port)
}

// Only ask advanced questions when the project was created in advanced mode
if project.AdvancedConfig || !question.Advanced {
// Question can be answered
Expand Down
78 changes: 63 additions & 15 deletions src/util/templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,6 @@ import (

// -------------------------------------------------------- TemplateListToPreselectedLabelList -----------------------------------------------------

// -------------------------------------------------------------- TemplateListToLabelList ----------------------------------------------------------

func TestTemplateListToLabelList(t *testing.T) {
// Test data
templates := []model.PredefinedTemplateConfig{
{Label: "Angular"},
{Label: "Wordpress"},
{Label: "MySQL"},
}
// Execute test
result := TemplateListToLabelList(templates)
// Assert
assert.EqualValues(t, result, []string{"Angular", "Wordpress", "MySQL"})
}

// ---------------------------------------------------------------- EvaluateProxyLabels ------------------------------------------------------------

func TestEvaluateProxyLabels1(t *testing.T) {
Expand Down Expand Up @@ -119,3 +104,66 @@ func TestEvaluateProxyLabels2(t *testing.T) {
// Assert
assert.Equal(t, expectedProject, project)
}

// -------------------------------------------------------------- TemplateListToLabelList ----------------------------------------------------------

func TestTemplateListToLabelList(t *testing.T) {
// Test data
templates := []model.PredefinedTemplateConfig{
{Label: "Angular"},
{Label: "Wordpress"},
{Label: "MySQL"},
}
// Execute test
result := TemplateListToLabelList(templates)
// Assert
assert.EqualValues(t, result, []string{"Angular", "Wordpress", "MySQL"})
}

// --------------------------------------------------------- TemplateListToPreselectedLabelList ----------------------------------------------------

func TestTemplateListToPreselectedLabelList(t *testing.T) {
// Test data
templates := []model.PredefinedTemplateConfig{
{
Label: "Angular",
Preselected: "services.database contains name == \"mysql\" | services.database contains name == \"mariadb\"",
},
{
Label: "Wordpress",
Preselected: "true",
},
{
Label: "MySQL",
Preselected: "false",
},
}
selected := &model.SelectedTemplates{
FrontendServices: []model.PredefinedTemplateConfig{
{
Name: "mariadb",
Label: "MariaDB",
},
},
}
// Mock functions
evaluateConditionCallCount := 0
evaluateCondition = func(condition string, s *model.SelectedTemplates, varMap model.Vars) bool {
evaluateConditionCallCount++
assert.Equal(t, selected, s)
assert.Nil(t, varMap)
if evaluateConditionCallCount == 1 {
assert.Equal(t, "services.database contains name == \"mysql\" | services.database contains name == \"mariadb\"", condition)
} else if evaluateConditionCallCount == 2 {
assert.Equal(t, "true", condition)
} else if evaluateConditionCallCount == 3 {
assert.Equal(t, "false", condition)
return false
}
return true
}
// Execute test
result := TemplateListToPreselectedLabelList(templates, selected)
// Assert
assert.EqualValues(t, result, []string{"Angular", "Wordpress"})
}

0 comments on commit 76bc7d5

Please sign in to comment.