-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdocker_environment_port_binding.go
123 lines (108 loc) · 3.19 KB
/
docker_environment_port_binding.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package dockerit
import (
"fmt"
"net"
)
type dockerEnvironmentPortBinding struct {
bindIP string
context *dockerEnvironmentContext
}
func newDockerEnvironmentPortBinding(bindIP string, context *dockerEnvironmentContext) *dockerEnvironmentPortBinding {
return &dockerEnvironmentPortBinding{
bindIP: bindIP,
context: context,
}
}
func (r *dockerEnvironmentPortBinding) configurePortBindings() error {
componentPorts, err := r.getNormalizedExposedPorts()
if err != nil {
return err
}
portBindings, err := getPortBindings(r.bindIP, componentPorts)
if err != nil {
return err
}
for containerName, ports := range portBindings {
container, err := r.context.getContainer(containerName)
if err != nil {
return err
}
// container port bindings
container.portBindings = ports
}
return nil
}
func (r *dockerEnvironmentPortBinding) getNormalizedExposedPorts() (map[string][]Port, error) {
componentPorts := make(map[string][]Port)
for containerName, container := range r.context.containers {
if _, exists := componentPorts[containerName]; exists {
return nil, fmt.Errorf("DockerComponent '%s' is configured twice", containerName)
}
ports := make([]Port, 0)
if container.DockerComponent.ExposedPorts != nil {
namedPorts := make(map[string]struct{})
for _, exposedPort := range container.DockerComponent.ExposedPorts {
if exposedPort.ContainerPort <= 0 {
return nil, fmt.Errorf("DockerComponent '%s' ContainerPort '%d' is invalid",
containerName, exposedPort.ContainerPort)
}
portName := normalizeName(exposedPort.Name)
if portName == "" {
portName = containerName
}
if _, exists := namedPorts[portName]; exists {
return nil, fmt.Errorf("DockerComponent '%s' port name '%s' is configured twice",
containerName, portName)
}
namedPorts[portName] = struct{}{}
ports = append(ports,
Port{
Name: portName,
ContainerPort: exposedPort.ContainerPort,
HostPort: exposedPort.HostPort},
)
}
}
componentPorts[containerName] = ports
}
return componentPorts, nil
}
func getPortBindings(host string, componentPorts map[string][]Port) (map[string][]Port, error) {
listeners := make([]*net.TCPListener, 0)
result := make(map[string][]Port)
for componentName, ports := range componentPorts {
bindings := make([]Port, 0)
for _, port := range ports {
listener, hostPort, err := listenTCP(host, port.HostPort)
if err != nil {
closeTCPListeners(listeners)
return nil, err
}
listeners = append(listeners, listener)
binding := Port{
Name: port.Name,
ContainerPort: port.ContainerPort,
HostPort: hostPort}
bindings = append(bindings, binding)
}
result[componentName] = bindings
}
closeTCPListeners(listeners)
return result, nil
}
func closeTCPListeners(listeners []*net.TCPListener) {
for _, listener := range listeners {
listener.Close()
}
}
func listenTCP(host string, port int) (*net.TCPListener, int, error) {
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return nil, 0, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return nil, 0, err
}
return l, l.Addr().(*net.TCPAddr).Port, nil
}