// AttachToContainers attaches to all containers that specified to be running func (client *DockerClient) AttachToContainers(containers []*Container) error { running := []*Container{} for _, c := range containers { if c.State.Running { running = append(running, c) } } // Listen to events of all containers and re-attach if necessary go client.listenReAttach(containers) wg := util.NewErrorWaitGroup(len(running)) for _, container := range running { if container.Io == nil { if err := client.AttachToContainer(container); err != nil { return err } } go func(container *Container) { wg.Done(container.Io.Wait()) }(container) } return wg.Wait() }
// FetchImages fetches the missing images for all containers in the manifest func (client *DockerClient) FetchImages(containers []*Container) error { type message struct { container *Container result chan error } wg := util.NewErrorWaitGroup(len(containers)) chPullImages := make(chan message) done := make(chan struct{}, 1) checkedImages := map[string]struct{}{} // Pull worker // We do not want to pull images in parallel // instead, we use an actor to pull images sequentially // // TODO: WAAAT? we can simplify it by going though a list of images sequentially // and pull those images which are missing. go func() { for { select { case msg := <-chPullImages: msg.result <- client.pullImageForContainer(msg.container) case <-done: return } } }() defer func() { done <- struct{}{} }() for _, container := range containers { if container.Image == nil { return fmt.Errorf("Image is not specified for container %s", container.Name) } if _, ok := checkedImages[container.Image.String()]; ok { wg.Done(nil) continue } checkedImages[container.Image.String()] = struct{}{} go func(container *Container) { image, err := client.Docker.InspectImage(container.Image.String()) if err == docker.ErrNoSuchImage { msg := message{container, make(chan error)} chPullImages <- msg wg.Done(<-msg.result) return } else if err != nil { wg.Done(err) return } container.ImageID = image.ID wg.Done(nil) }(container) } return wg.Wait() }