github.com/portworx/docker@v1.12.1/daemon/links.go (about)

     1  package daemon
     2  
     3  import (
     4  	"strings"
     5  	"sync"
     6  
     7  	"github.com/Sirupsen/logrus"
     8  	"github.com/docker/docker/container"
     9  	"github.com/docker/docker/pkg/graphdb"
    10  )
    11  
    12  // linkIndex stores link relationships between containers, including their specified alias
    13  // The alias is the name the parent uses to reference the child
    14  type linkIndex struct {
    15  	// idx maps a parent->alias->child relationship
    16  	idx map[*container.Container]map[string]*container.Container
    17  	// childIdx maps  child->parent->aliases
    18  	childIdx map[*container.Container]map[*container.Container]map[string]struct{}
    19  	mu       sync.Mutex
    20  }
    21  
    22  func newLinkIndex() *linkIndex {
    23  	return &linkIndex{
    24  		idx:      make(map[*container.Container]map[string]*container.Container),
    25  		childIdx: make(map[*container.Container]map[*container.Container]map[string]struct{}),
    26  	}
    27  }
    28  
    29  // link adds indexes for the passed in parent/child/alias relationships
    30  func (l *linkIndex) link(parent, child *container.Container, alias string) {
    31  	l.mu.Lock()
    32  
    33  	if l.idx[parent] == nil {
    34  		l.idx[parent] = make(map[string]*container.Container)
    35  	}
    36  	l.idx[parent][alias] = child
    37  	if l.childIdx[child] == nil {
    38  		l.childIdx[child] = make(map[*container.Container]map[string]struct{})
    39  	}
    40  	if l.childIdx[child][parent] == nil {
    41  		l.childIdx[child][parent] = make(map[string]struct{})
    42  	}
    43  	l.childIdx[child][parent][alias] = struct{}{}
    44  
    45  	l.mu.Unlock()
    46  }
    47  
    48  // unlink removes the requested alias for the given parent/child
    49  func (l *linkIndex) unlink(alias string, child, parent *container.Container) {
    50  	l.mu.Lock()
    51  	delete(l.idx[parent], alias)
    52  	delete(l.childIdx[child], parent)
    53  	l.mu.Unlock()
    54  }
    55  
    56  // children maps all the aliases-> children for the passed in parent
    57  // aliases here are the aliases the parent uses to refer to the child
    58  func (l *linkIndex) children(parent *container.Container) map[string]*container.Container {
    59  	l.mu.Lock()
    60  	children := l.idx[parent]
    61  	l.mu.Unlock()
    62  	return children
    63  }
    64  
    65  // parents maps all the aliases->parent for the passed in child
    66  // aliases here are the aliases the parents use to refer to the child
    67  func (l *linkIndex) parents(child *container.Container) map[string]*container.Container {
    68  	l.mu.Lock()
    69  
    70  	parents := make(map[string]*container.Container)
    71  	for parent, aliases := range l.childIdx[child] {
    72  		for alias := range aliases {
    73  			parents[alias] = parent
    74  		}
    75  	}
    76  
    77  	l.mu.Unlock()
    78  	return parents
    79  }
    80  
    81  // delete deletes all link relationships referencing this container
    82  func (l *linkIndex) delete(container *container.Container) {
    83  	l.mu.Lock()
    84  	for _, child := range l.idx[container] {
    85  		delete(l.childIdx[child], container)
    86  	}
    87  	delete(l.idx, container)
    88  	delete(l.childIdx, container)
    89  	l.mu.Unlock()
    90  }
    91  
    92  // migrateLegacySqliteLinks migrates sqlite links to use links from HostConfig
    93  // when sqlite links were used, hostConfig.Links was set to nil
    94  func (daemon *Daemon) migrateLegacySqliteLinks(db *graphdb.Database, container *container.Container) error {
    95  	// if links is populated (or an empty slice), then this isn't using sqlite links and can be skipped
    96  	if container.HostConfig == nil || container.HostConfig.Links != nil {
    97  		return nil
    98  	}
    99  
   100  	logrus.Debugf("migrating legacy sqlite link info for container: %s", container.ID)
   101  
   102  	fullName := container.Name
   103  	if fullName[0] != '/' {
   104  		fullName = "/" + fullName
   105  	}
   106  
   107  	// don't use a nil slice, this ensures that the check above will skip once the migration has completed
   108  	links := []string{}
   109  	children, err := db.Children(fullName, 0)
   110  	if err != nil {
   111  		if !strings.Contains(err.Error(), "Cannot find child for") {
   112  			return err
   113  		}
   114  		// else continue... it's ok if we didn't find any children, it'll just be nil and we can continue the migration
   115  	}
   116  
   117  	for _, child := range children {
   118  		c, err := daemon.GetContainer(child.Entity.ID())
   119  		if err != nil {
   120  			return err
   121  		}
   122  
   123  		links = append(links, c.Name+":"+child.Edge.Name)
   124  	}
   125  
   126  	container.HostConfig.Links = links
   127  	return container.WriteHostConfig()
   128  }