github.com/torfuzx/docker@v1.8.1/links/links.go (about)

     1  package links
     2  
     3  import (
     4  	"fmt"
     5  	"path"
     6  	"strings"
     7  
     8  	"github.com/docker/docker/pkg/nat"
     9  )
    10  
    11  type Link struct {
    12  	ParentIP         string
    13  	ChildIP          string
    14  	Name             string
    15  	ChildEnvironment []string
    16  	Ports            []nat.Port
    17  	IsEnabled        bool
    18  }
    19  
    20  func NewLink(parentIP, childIP, name string, env []string, exposedPorts map[nat.Port]struct{}) (*Link, error) {
    21  
    22  	var (
    23  		i     int
    24  		ports = make([]nat.Port, len(exposedPorts))
    25  	)
    26  
    27  	for p := range exposedPorts {
    28  		ports[i] = p
    29  		i++
    30  	}
    31  
    32  	l := &Link{
    33  		Name:             name,
    34  		ChildIP:          childIP,
    35  		ParentIP:         parentIP,
    36  		ChildEnvironment: env,
    37  		Ports:            ports,
    38  	}
    39  	return l, nil
    40  
    41  }
    42  
    43  func (l *Link) Alias() string {
    44  	_, alias := path.Split(l.Name)
    45  	return alias
    46  }
    47  
    48  func nextContiguous(ports []nat.Port, value int, index int) int {
    49  	if index+1 == len(ports) {
    50  		return index
    51  	}
    52  	for i := index + 1; i < len(ports); i++ {
    53  		if ports[i].Int() > value+1 {
    54  			return i - 1
    55  		}
    56  
    57  		value++
    58  	}
    59  	return len(ports) - 1
    60  }
    61  
    62  func (l *Link) ToEnv() []string {
    63  	env := []string{}
    64  	alias := strings.Replace(strings.ToUpper(l.Alias()), "-", "_", -1)
    65  
    66  	if p := l.getDefaultPort(); p != nil {
    67  		env = append(env, fmt.Sprintf("%s_PORT=%s://%s:%s", alias, p.Proto(), l.ChildIP, p.Port()))
    68  	}
    69  
    70  	//sort the ports so that we can bulk the continuous ports together
    71  	nat.Sort(l.Ports, func(ip, jp nat.Port) bool {
    72  		// If the two ports have the same number, tcp takes priority
    73  		// Sort in desc order
    74  		return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp")
    75  	})
    76  
    77  	for i := 0; i < len(l.Ports); {
    78  		p := l.Ports[i]
    79  		j := nextContiguous(l.Ports, p.Int(), i)
    80  		if j > i+1 {
    81  			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_START=%s://%s:%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto(), l.ChildIP, p.Port()))
    82  			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_ADDR=%s", alias, p.Port(), strings.ToUpper(p.Proto()), l.ChildIP))
    83  			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PROTO=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto()))
    84  			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT_START=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Port()))
    85  
    86  			q := l.Ports[j]
    87  			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_END=%s://%s:%s", alias, p.Port(), strings.ToUpper(q.Proto()), q.Proto(), l.ChildIP, q.Port()))
    88  			env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT_END=%s", alias, p.Port(), strings.ToUpper(q.Proto()), q.Port()))
    89  
    90  			i = j + 1
    91  			continue
    92  		} else {
    93  			i++
    94  		}
    95  	}
    96  	for _, p := range l.Ports {
    97  		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()))
    98  		env = append(env, fmt.Sprintf("%s_PORT_%s_%s_ADDR=%s", alias, p.Port(), strings.ToUpper(p.Proto()), l.ChildIP))
    99  		env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PORT=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Port()))
   100  		env = append(env, fmt.Sprintf("%s_PORT_%s_%s_PROTO=%s", alias, p.Port(), strings.ToUpper(p.Proto()), p.Proto()))
   101  	}
   102  
   103  	// Load the linked container's name into the environment
   104  	env = append(env, fmt.Sprintf("%s_NAME=%s", alias, l.Name))
   105  
   106  	if l.ChildEnvironment != nil {
   107  		for _, v := range l.ChildEnvironment {
   108  			parts := strings.SplitN(v, "=", 2)
   109  			if len(parts) < 2 {
   110  				continue
   111  			}
   112  			// Ignore a few variables that are added during docker build (and not really relevant to linked containers)
   113  			if parts[0] == "HOME" || parts[0] == "PATH" {
   114  				continue
   115  			}
   116  			env = append(env, fmt.Sprintf("%s_ENV_%s=%s", alias, parts[0], parts[1]))
   117  		}
   118  	}
   119  	return env
   120  }
   121  
   122  // Default port rules
   123  func (l *Link) getDefaultPort() *nat.Port {
   124  	var p nat.Port
   125  	i := len(l.Ports)
   126  
   127  	if i == 0 {
   128  		return nil
   129  	} else if i > 1 {
   130  		nat.Sort(l.Ports, func(ip, jp nat.Port) bool {
   131  			// If the two ports have the same number, tcp takes priority
   132  			// Sort in desc order
   133  			return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp")
   134  		})
   135  	}
   136  	p = l.Ports[0]
   137  	return &p
   138  }
   139  
   140  func (l *Link) Enable() error {
   141  	l.IsEnabled = true
   142  	return nil
   143  }
   144  
   145  func (l *Link) Disable() {
   146  	l.IsEnabled = false
   147  }