0d2924408b
Remove docker link Do not add container id as default name Create an auto generated container name if not specified at runtime.
141 lines
3.3 KiB
Go
141 lines
3.3 KiB
Go
package docker
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/dotcloud/docker/iptables"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
type Link struct {
|
|
ParentIP string
|
|
ChildIP string
|
|
Name string
|
|
BridgeInterface string
|
|
ChildEnvironment []string
|
|
Ports []Port
|
|
IsEnabled bool
|
|
}
|
|
|
|
func NewLink(parent, child *Container, name, bridgeInterface string) (*Link, error) {
|
|
if parent.ID == child.ID {
|
|
return nil, fmt.Errorf("Cannot link to self: %s == %s", parent.ID, child.ID)
|
|
}
|
|
if !child.State.Running {
|
|
return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.ID, name)
|
|
}
|
|
|
|
ports := make([]Port, len(child.Config.ExposedPorts))
|
|
var i int
|
|
for p := range child.Config.ExposedPorts {
|
|
ports[i] = p
|
|
i++
|
|
}
|
|
|
|
l := &Link{
|
|
BridgeInterface: bridgeInterface,
|
|
Name: name,
|
|
ChildIP: child.NetworkSettings.IPAddress,
|
|
ParentIP: parent.NetworkSettings.IPAddress,
|
|
ChildEnvironment: child.Config.Env,
|
|
Ports: ports,
|
|
}
|
|
return l, nil
|
|
|
|
}
|
|
|
|
func (l *Link) Alias() string {
|
|
_, alias := path.Split(l.Name)
|
|
return alias
|
|
}
|
|
|
|
func (l *Link) ToEnv() []string {
|
|
env := []string{}
|
|
alias := strings.ToUpper(l.Alias())
|
|
|
|
if p := l.getDefaultPort(); p != nil {
|
|
env = append(env, fmt.Sprintf("%s_PORT=%s://%s:%s", alias, p.Proto(), l.ChildIP, p.Port()))
|
|
}
|
|
|
|
// Load exposed ports into the environment
|
|
for _, p := range l.Ports {
|
|
env = append(env, fmt.Sprintf("%s_PORT_%s_%s=%s://%s:%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto(), l.ChildIP, p.Port()))
|
|
}
|
|
|
|
// Load the linked container's name into the environment
|
|
env = append(env, fmt.Sprintf("%s_NAME=%s", alias, l.Name))
|
|
|
|
if l.ChildEnvironment != nil {
|
|
for _, v := range l.ChildEnvironment {
|
|
parts := strings.Split(v, "=")
|
|
if len(parts) != 2 {
|
|
continue
|
|
}
|
|
// Ignore a few variables that are added during docker build
|
|
if parts[0] == "HOME" || parts[0] == "PATH" {
|
|
continue
|
|
}
|
|
env = append(env, fmt.Sprintf("%s_ENV_%s=%s", alias, parts[0], parts[1]))
|
|
}
|
|
}
|
|
return env
|
|
}
|
|
|
|
// Default port rules
|
|
func (l *Link) getDefaultPort() *Port {
|
|
var p Port
|
|
i := len(l.Ports)
|
|
|
|
if i == 0 {
|
|
return nil
|
|
} else if i > 1 {
|
|
sortPorts(l.Ports, func(ip, jp Port) bool {
|
|
// If the two ports have the same number, tcp takes priority
|
|
// Sort in desc order
|
|
return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp")
|
|
})
|
|
}
|
|
p = l.Ports[0]
|
|
return &p
|
|
}
|
|
|
|
func (l *Link) Enable() error {
|
|
if err := l.toggle("-I", false); err != nil {
|
|
return err
|
|
}
|
|
l.IsEnabled = true
|
|
return nil
|
|
}
|
|
|
|
func (l *Link) Disable() {
|
|
// We do not care about errors here because the link may not
|
|
// exist in iptables
|
|
l.toggle("-D", true)
|
|
|
|
l.IsEnabled = false
|
|
}
|
|
|
|
func (l *Link) toggle(action string, ignoreErrors bool) error {
|
|
for _, p := range l.Ports {
|
|
if err := iptables.Raw(action, "FORWARD",
|
|
"-i", l.BridgeInterface, "-o", l.BridgeInterface,
|
|
"-p", p.Proto(),
|
|
"-s", l.ParentIP,
|
|
"--dport", p.Port(),
|
|
"-d", l.ChildIP,
|
|
"-j", "ACCEPT"); !ignoreErrors && err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := iptables.Raw(action, "FORWARD",
|
|
"-i", l.BridgeInterface, "-o", l.BridgeInterface,
|
|
"-p", p.Proto(),
|
|
"-s", l.ChildIP,
|
|
"--sport", p.Port(),
|
|
"-d", l.ParentIP,
|
|
"-j", "ACCEPT"); !ignoreErrors && err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|