detached 220ba47

Fix the Ports mappings in edit view and refactor container editing and creation flow

- Display ports with the protocol in the edit view.
- Rearrange container creation steps for better flow: stopping the old container is now the first step.
- Remove unused code related to ExposedPorts.
- Rename ExposedPort to ContainerPort for better clarity in the PortMapping struct.
- Integrate port parsing directly into the YAML-to-CmdParams conversion.
commit
220ba47f6e3ab74b403ec4bf8bbf2e8943d5b480
author
bnema · · 2023-10-09 18:17 UTC
parent
188621f
signature
unsigned
3 files · +38 -44
M internal/httpserve/handler/editcontainer.go +9 -20
@@ -51,25 +51,14 @@ func ContainerManagerEditGET(c echo.Context, a *app.App) error {
5151 networkNames = append(networkNames, networkName)
5252 }
5353
54- // Prepare Ports (PortBindings and ExposedPorts)
54+ // Prepare Ports
5555 portMappings := make([]string, 0)
5656 for port, bindings := range containerInfo.HostConfig.PortBindings {
5757 for _, binding := range bindings {
58- portMappings = append(portMappings, fmt.Sprintf("%s:%s", binding.HostPort, port.Port()))
58+ portMappings = append(portMappings, fmt.Sprintf("%s:%s/%s", binding.HostPort, port.Port(), port.Proto()))
5959 }
6060 }
6161
62- exposedPorts := make([]string, 0)
63- for port := range containerInfo.Config.ExposedPorts {
64- exposedPorts = append(exposedPorts, port.Port())
65- }
66-
67- // Prepare Ports while using the containerInfo.Config.ExposedPorts
68-
69- for port := range containerInfo.Config.ExposedPorts {
70- fmt.Println(port)
71- }
72-
7362 // Prepare Volumes (Mounts)
7463 volumeMappings := make([]string, 0)
7564 for _, mount := range containerInfo.Mounts {
@@ -187,21 +176,21 @@ func ContainerManagerEditPOST(c echo.Context, a *app.App) error {
187176 tq.NewContainerName = cmdParams.ContainerName
188177 tq.TempContainerName = fmt.Sprintf("%s-temp", tq.NewContainerName)
189178
190- // 1. Create a new container with the new configuration with a temporary name if old container name and new container name are different
191179 cmdParams.ContainerName = tq.TempContainerName
192180
181+ // 1. Stop the old container
182+ tq.Add(StopOldContainerStep(tq), StartOldContainerRollback(tq))
183+
184+ // 2. Create the new container
193185 tq.Add(CreateNewContainerStep(tq, cmdParams), RemoveNewContainerRollback(tq))
194186
195- // 2. Start the new container
187+ // 3. Start the new container
196188 tq.Add(StartNewContainerStep(tq), StopNewContainerRollback(tq))
197189
198- // 3. Stop the old container
199- tq.Add(StopOldContainerStep(tq), StartOldContainerRollback(tq))
200-
201- // 4. Remove the old container
190+ // 4. Rename the new container to the original name
202191 tq.Add(RemoveOldContainerStep(tq), nil)
203192
204- // 5. Rename the new container to the original name
193+ // 5. Remove the old container
205194 tq.Add(RenameNewContainerStep(tq), RenameNewContainerRollback(tq))
206195
207196 err = tq.Execute()
@@ -51,25 +51,14 @@ func ContainerManagerEditGET(c echo.Context, a *app.App) error {
51 networkNames = append(networkNames, networkName)51 networkNames = append(networkNames, networkName)
52 }52 }
53 53
54- // Prepare Ports (PortBindings and ExposedPorts)54+ // Prepare Ports
55 portMappings := make([]string, 0)55 portMappings := make([]string, 0)
56 for port, bindings := range containerInfo.HostConfig.PortBindings {56 for port, bindings := range containerInfo.HostConfig.PortBindings {
57 for _, binding := range bindings {57 for _, binding := range bindings {
58- portMappings = append(portMappings, fmt.Sprintf("%s:%s", binding.HostPort, port.Port()))58+ portMappings = append(portMappings, fmt.Sprintf("%s:%s/%s", binding.HostPort, port.Port(), port.Proto()))
59 }59 }
60 }60 }
61 61
62- exposedPorts := make([]string, 0)
63- for port := range containerInfo.Config.ExposedPorts {
64- exposedPorts = append(exposedPorts, port.Port())
65- }
66-
67- // Prepare Ports while using the containerInfo.Config.ExposedPorts
68-
69- for port := range containerInfo.Config.ExposedPorts {
70- fmt.Println(port)
71- }
72-
73 // Prepare Volumes (Mounts)62 // Prepare Volumes (Mounts)
74 volumeMappings := make([]string, 0)63 volumeMappings := make([]string, 0)
75 for _, mount := range containerInfo.Mounts {64 for _, mount := range containerInfo.Mounts {
@@ -187,21 +176,21 @@ func ContainerManagerEditPOST(c echo.Context, a *app.App) error {
187 tq.NewContainerName = cmdParams.ContainerName176 tq.NewContainerName = cmdParams.ContainerName
188 tq.TempContainerName = fmt.Sprintf("%s-temp", tq.NewContainerName)177 tq.TempContainerName = fmt.Sprintf("%s-temp", tq.NewContainerName)
189 178
190- // 1. Create a new container with the new configuration with a temporary name if old container name and new container name are different
191 cmdParams.ContainerName = tq.TempContainerName179 cmdParams.ContainerName = tq.TempContainerName
192 180
181+ // 1. Stop the old container
182+ tq.Add(StopOldContainerStep(tq), StartOldContainerRollback(tq))
183+
184+ // 2. Create the new container
193 tq.Add(CreateNewContainerStep(tq, cmdParams), RemoveNewContainerRollback(tq))185 tq.Add(CreateNewContainerStep(tq, cmdParams), RemoveNewContainerRollback(tq))
194 186
195- // 2. Start the new container187+ // 3. Start the new container
196 tq.Add(StartNewContainerStep(tq), StopNewContainerRollback(tq))188 tq.Add(StartNewContainerStep(tq), StopNewContainerRollback(tq))
197 189
198- // 3. Stop the old container190+ // 4. Rename the new container to the original name
199- tq.Add(StopOldContainerStep(tq), StartOldContainerRollback(tq))
200-
201- // 4. Remove the old container
202 tq.Add(RemoveOldContainerStep(tq), nil)191 tq.Add(RemoveOldContainerStep(tq), nil)
203 192
204- // 5. Rename the new container to the original name193+ // 5. Remove the old container
205 tq.Add(RenameNewContainerStep(tq), RenameNewContainerRollback(tq))194 tq.Add(RenameNewContainerStep(tq), RenameNewContainerRollback(tq))
206 195
207 err = tq.Execute()196 err = tq.Execute()
M internal/templates/render/cmdparams.go +10 -4
@@ -34,7 +34,7 @@ func FromInputsToCmdParams(inputs map[string]string, a *app.App) (docker.Contain
3434 }
3535
3636 // Get the exposed port for traefik labels
37- exposedPort := portMappings[0].ExposedPort
37+ exposedPort := portMappings[0].ContainerPort
3838
3939 params := docker.ContainerCommandParams{
4040 IsSSL: inputs["container_protocol"] == "https",
@@ -80,9 +80,8 @@ type YAMLContainerParams struct {
8080 Volumes []string `yaml:"Volumes"`
8181 Environment []string `yaml:"Environment"`
8282 Labels map[string]string `yaml:"Labels"`
83- // Network is a slice of strings in the textarea
84- Network []string `yaml:"Network"`
85- Restart string `yaml:"Restart"`
83+ Network []string `yaml:"Network"`
84+ Restart string `yaml:"Restart"`
8685 }
8786
8887 // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct
@@ -100,6 +99,12 @@ func FromYAMLStructToCmdParams(yamlParams YAMLContainerParams) (docker.Container
10099 labels = append(labels, fmt.Sprintf("%s=%s", k, v))
101100 }
102101
102+ // Ports input parsing
103+ portMappings, err := docker.ParsePortsSpecs(yamlParams.Ports)
104+ if err != nil {
105+ return docker.ContainerCommandParams{}, err
106+ }
107+
103108 // Convert the slice of strings to a comma separated string
104109 network := strings.Join(yamlParams.Network, ",")
105110
@@ -112,6 +117,7 @@ func FromYAMLStructToCmdParams(yamlParams YAMLContainerParams) (docker.Container
112117 Labels: labels,
113118 Network: network,
114119 Restart: yamlParams.Restart,
120+ PortMappings: portMappings,
115121 }
116122
117123 return params, nil
@@ -34,7 +34,7 @@ func FromInputsToCmdParams(inputs map[string]string, a *app.App) (docker.Contain
34 }34 }
35 35
36 // Get the exposed port for traefik labels36 // Get the exposed port for traefik labels
37- exposedPort := portMappings[0].ExposedPort37+ exposedPort := portMappings[0].ContainerPort
38 38
39 params := docker.ContainerCommandParams{39 params := docker.ContainerCommandParams{
40 IsSSL: inputs["container_protocol"] == "https",40 IsSSL: inputs["container_protocol"] == "https",
@@ -80,9 +80,8 @@ type YAMLContainerParams struct {
80 Volumes []string `yaml:"Volumes"`80 Volumes []string `yaml:"Volumes"`
81 Environment []string `yaml:"Environment"`81 Environment []string `yaml:"Environment"`
82 Labels map[string]string `yaml:"Labels"`82 Labels map[string]string `yaml:"Labels"`
83- // Network is a slice of strings in the textarea83+ Network []string `yaml:"Network"`
84- Network []string `yaml:"Network"`84+ Restart string `yaml:"Restart"`
85- Restart string `yaml:"Restart"`
86 }85 }
87 86
88 // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct87 // FromYAMLStructToCmdParams converts a YAMLContainerParams struct to a ContainerCommandParams struct
@@ -100,6 +99,12 @@ func FromYAMLStructToCmdParams(yamlParams YAMLContainerParams) (docker.Container
100 labels = append(labels, fmt.Sprintf("%s=%s", k, v))99 labels = append(labels, fmt.Sprintf("%s=%s", k, v))
101 }100 }
102 101
102+ // Ports input parsing
103+ portMappings, err := docker.ParsePortsSpecs(yamlParams.Ports)
104+ if err != nil {
105+ return docker.ContainerCommandParams{}, err
106+ }
107+
103 // Convert the slice of strings to a comma separated string108 // Convert the slice of strings to a comma separated string
104 network := strings.Join(yamlParams.Network, ",")109 network := strings.Join(yamlParams.Network, ",")
105 110
@@ -112,6 +117,7 @@ func FromYAMLStructToCmdParams(yamlParams YAMLContainerParams) (docker.Container
112 Labels: labels,117 Labels: labels,
113 Network: network,118 Network: network,
114 Restart: yamlParams.Restart,119 Restart: yamlParams.Restart,
120+ PortMappings: portMappings,
115 }121 }
116 122
117 return params, nil123 return params, nil
M pkg/docker/containers.go +19 -20
@@ -32,9 +32,9 @@ type ContainerCommandParams struct {
3232 }
3333
3434 type PortMapping struct {
35- HostPort string
36- ExposedPort string
37- Protocol string
35+ HostPort string
36+ ContainerPort string
37+ Protocol string
3838 }
3939
4040 // ParsePortsSpecs receives a slice of strings in the format "hostPort:containerPort/Protocol" and returns a slice of PortMapping structs
@@ -47,28 +47,28 @@ func ParsePortsSpecs(portsSpecs []string) ([]PortMapping, error) {
4747 return nil, fmt.Errorf("invalid port specification: %s. Format should be hostPort:containerPort[/Protocol]", portSpec)
4848 }
4949
50- // Validate hostPort and exposedPort are numbers
50+ // Validate hostPort and containerPort
5151 hostPort := parts[0]
5252 if _, err := strconv.Atoi(hostPort); err != nil {
5353 return nil, fmt.Errorf("invalid host port: %s. Must be a number", hostPort)
5454 }
5555
56- exposedParts := strings.Split(parts[1], "/")
57- exposedPort := exposedParts[0]
58- if _, err := strconv.Atoi(exposedPort); err != nil {
59- return nil, fmt.Errorf("invalid exposed port: %s. Must be a number", exposedPort)
56+ containerParts := strings.Split(parts[1], "/")
57+ containerPort := containerParts[0]
58+ if _, err := strconv.Atoi(containerPort); err != nil {
59+ return nil, fmt.Errorf("invalid exposed port: %s. Must be a number", containerPort)
6060 }
6161
6262 // Default protocol is tcp
6363 protocol := "tcp"
64- if len(exposedParts) > 1 {
65- protocol = exposedParts[1]
64+ if len(containerParts) > 1 {
65+ protocol = containerParts[1]
6666 }
6767
6868 portMappings = append(portMappings, PortMapping{
69- HostPort: hostPort,
70- ExposedPort: exposedPort,
71- Protocol: protocol,
69+ HostPort: hostPort,
70+ ContainerPort: containerPort,
71+ Protocol: protocol,
7272 })
7373 }
7474
@@ -77,12 +77,11 @@ func ParsePortsSpecs(portsSpecs []string) ([]PortMapping, error) {
7777
7878 func ContainerCommandParamsToConfig(cmdParams ContainerCommandParams) (*container.Config, error) {
7979 return &container.Config{
80- Image: cmdParams.ImageName,
81- Hostname: cmdParams.ContainerHost,
82- ExposedPorts: map[nat.Port]struct{}{},
83- Env: cmdParams.Environment,
84- Labels: map[string]string{},
85- Volumes: map[string]struct{}{},
80+ Image: cmdParams.ImageName,
81+ Hostname: cmdParams.ContainerHost,
82+ Env: cmdParams.Environment,
83+ Labels: map[string]string{},
84+ Volumes: map[string]struct{}{},
8685 }, nil
8786 }
8887
@@ -201,7 +200,7 @@ func CreateContainer(cmdParams ContainerCommandParams) (string, error) {
201200 portBindings := nat.PortMap{}
202201 for _, portMapping := range cmdParams.PortMappings {
203202 // Prepare exposed port
204- exposedPort := nat.Port(portMapping.ExposedPort + "/" + portMapping.Protocol)
203+ exposedPort := nat.Port(portMapping.ContainerPort + "/" + portMapping.Protocol)
205204 portBindings[exposedPort] = []nat.PortBinding{
206205 {
207206 HostIP: "0.0.0.0",
@@ -32,9 +32,9 @@ type ContainerCommandParams struct {
32 }32 }
33 33
34 type PortMapping struct {34 type PortMapping struct {
35- HostPort string35+ HostPort string
36- ExposedPort string36+ ContainerPort string
37- Protocol string37+ Protocol string
38 }38 }
39 39
40 // ParsePortsSpecs receives a slice of strings in the format "hostPort:containerPort/Protocol" and returns a slice of PortMapping structs40 // ParsePortsSpecs receives a slice of strings in the format "hostPort:containerPort/Protocol" and returns a slice of PortMapping structs
@@ -47,28 +47,28 @@ func ParsePortsSpecs(portsSpecs []string) ([]PortMapping, error) {
47 return nil, fmt.Errorf("invalid port specification: %s. Format should be hostPort:containerPort[/Protocol]", portSpec)47 return nil, fmt.Errorf("invalid port specification: %s. Format should be hostPort:containerPort[/Protocol]", portSpec)
48 }48 }
49 49
50- // Validate hostPort and exposedPort are numbers50+ // Validate hostPort and containerPort
51 hostPort := parts[0]51 hostPort := parts[0]
52 if _, err := strconv.Atoi(hostPort); err != nil {52 if _, err := strconv.Atoi(hostPort); err != nil {
53 return nil, fmt.Errorf("invalid host port: %s. Must be a number", hostPort)53 return nil, fmt.Errorf("invalid host port: %s. Must be a number", hostPort)
54 }54 }
55 55
56- exposedParts := strings.Split(parts[1], "/")56+ containerParts := strings.Split(parts[1], "/")
57- exposedPort := exposedParts[0]57+ containerPort := containerParts[0]
58- if _, err := strconv.Atoi(exposedPort); err != nil {58+ if _, err := strconv.Atoi(containerPort); err != nil {
59- return nil, fmt.Errorf("invalid exposed port: %s. Must be a number", exposedPort)59+ return nil, fmt.Errorf("invalid exposed port: %s. Must be a number", containerPort)
60 }60 }
61 61
62 // Default protocol is tcp62 // Default protocol is tcp
63 protocol := "tcp"63 protocol := "tcp"
64- if len(exposedParts) > 1 {64+ if len(containerParts) > 1 {
65- protocol = exposedParts[1]65+ protocol = containerParts[1]
66 }66 }
67 67
68 portMappings = append(portMappings, PortMapping{68 portMappings = append(portMappings, PortMapping{
69- HostPort: hostPort,69+ HostPort: hostPort,
70- ExposedPort: exposedPort,70+ ContainerPort: containerPort,
71- Protocol: protocol,71+ Protocol: protocol,
72 })72 })
73 }73 }
74 74
@@ -77,12 +77,11 @@ func ParsePortsSpecs(portsSpecs []string) ([]PortMapping, error) {
77 77
78 func ContainerCommandParamsToConfig(cmdParams ContainerCommandParams) (*container.Config, error) {78 func ContainerCommandParamsToConfig(cmdParams ContainerCommandParams) (*container.Config, error) {
79 return &container.Config{79 return &container.Config{
80- Image: cmdParams.ImageName,80+ Image: cmdParams.ImageName,
81- Hostname: cmdParams.ContainerHost,81+ Hostname: cmdParams.ContainerHost,
82- ExposedPorts: map[nat.Port]struct{}{},82+ Env: cmdParams.Environment,
83- Env: cmdParams.Environment,83+ Labels: map[string]string{},
84- Labels: map[string]string{},84+ Volumes: map[string]struct{}{},
85- Volumes: map[string]struct{}{},
86 }, nil85 }, nil
87 }86 }
88 87
@@ -201,7 +200,7 @@ func CreateContainer(cmdParams ContainerCommandParams) (string, error) {
201 portBindings := nat.PortMap{}200 portBindings := nat.PortMap{}
202 for _, portMapping := range cmdParams.PortMappings {201 for _, portMapping := range cmdParams.PortMappings {
203 // Prepare exposed port202 // Prepare exposed port
204- exposedPort := nat.Port(portMapping.ExposedPort + "/" + portMapping.Protocol)203+ exposedPort := nat.Port(portMapping.ContainerPort + "/" + portMapping.Protocol)
205 portBindings[exposedPort] = []nat.PortBinding{204 portBindings[exposedPort] = []nat.PortBinding{
206 {205 {
207 HostIP: "0.0.0.0",206 HostIP: "0.0.0.0",

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close