// migrateLegacySqliteLinks migrates sqlite links to use links from HostConfig // when sqlite links were used, hostConfig.Links was set to nil func (daemon *Daemon) migrateLegacySqliteLinks(db *graphdb.Database, container *container.Container) error { // if links is populated (or an empty slice), then this isn't using sqlite links and can be skipped if container.HostConfig == nil || container.HostConfig.Links != nil { return nil } logrus.Debugf("migrating legacy sqlite link info for container: %s", container.ID) fullName := container.Name if fullName[0] != '/' { fullName = "/" + fullName } // don't use a nil slice, this ensures that the check above will skip once the migration has completed links := []string{} children, err := db.Children(fullName, 0) if err != nil { if !strings.Contains(err.Error(), "Cannot find child for") { return err } // else continue... it's ok if we didn't find any children, it'll just be nil and we can continue the migration } for _, child := range children { c, err := daemon.GetContainer(child.Entity.ID()) if err != nil { return err } links = append(links, c.Name+":"+child.Edge.Name) } container.HostConfig.Links = links return container.WriteHostConfig() }
// sqliteMigration performs the link graph DB migration. func (daemon *Daemon) sqliteMigration(containers map[string]*container.Container) error { // migrate any legacy links from sqlite linkdbFile := filepath.Join(daemon.root, "linkgraph.db") var ( legacyLinkDB *graphdb.Database err error ) legacyLinkDB, err = graphdb.NewSqliteConn(linkdbFile) if err != nil { return fmt.Errorf("error connecting to legacy link graph DB %s, container links may be lost: %v", linkdbFile, err) } defer legacyLinkDB.Close() for _, c := range containers { if err := daemon.migrateLegacySqliteLinks(legacyLinkDB, c); err != nil { return err } } return nil }
func (daemon *Daemon) restore() error { var ( debug = utils.IsDebugEnabled() currentDriver = daemon.GraphDriverName() containers = make(map[string]*container.Container) ) if !debug { logrus.Info("Loading containers: start.") } dir, err := ioutil.ReadDir(daemon.repository) if err != nil { return err } containerCount := 0 for _, v := range dir { id := v.Name() container, err := daemon.load(id) if !debug && logrus.GetLevel() == logrus.InfoLevel { fmt.Print(".") containerCount++ } if err != nil { logrus.Errorf("Failed to load container %v: %v", id, err) continue } // Ignore the container if it does not support the current driver being used by the graph if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver { rwlayer, err := daemon.layerStore.GetRWLayer(container.ID) if err != nil { logrus.Errorf("Failed to load container mount %v: %v", id, err) continue } container.RWLayer = rwlayer logrus.Debugf("Loaded container %v", container.ID) containers[container.ID] = container } else { logrus.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID) } } var migrateLegacyLinks bool restartContainers := make(map[*container.Container]chan struct{}) activeSandboxes := make(map[string]interface{}) for _, c := range containers { if err := daemon.registerName(c); err != nil { logrus.Errorf("Failed to register container %s: %s", c.ID, err) continue } if err := daemon.Register(c); err != nil { logrus.Errorf("Failed to register container %s: %s", c.ID, err) continue } // The LogConfig.Type is empty if the container was created before docker 1.12 with default log driver. // We should rewrite it to use the daemon defaults. // Fixes https://github.com/docker/docker/issues/22536 if c.HostConfig.LogConfig.Type == "" { if err := daemon.mergeAndVerifyLogConfig(&c.HostConfig.LogConfig); err != nil { logrus.Errorf("Failed to verify log config for container %s: %q", c.ID, err) continue } } } var wg sync.WaitGroup var mapLock sync.Mutex for _, c := range containers { wg.Add(1) go func(c *container.Container) { defer wg.Done() rm := c.RestartManager(false) if c.IsRunning() || c.IsPaused() { if err := daemon.containerd.Restore(c.ID, libcontainerd.WithRestartManager(rm)); err != nil { logrus.Errorf("Failed to restore %s with containerd: %s", c.ID, err) return } if !c.HostConfig.NetworkMode.IsContainer() && c.IsRunning() { options, err := daemon.buildSandboxOptions(c) if err != nil { logrus.Warnf("Failed build sandbox option to restore container %s: %v", c.ID, err) } mapLock.Lock() activeSandboxes[c.NetworkSettings.SandboxID] = options mapLock.Unlock() } } // fixme: only if not running // get list of containers we need to restart if daemon.configStore.AutoRestart && !c.IsRunning() && !c.IsPaused() && c.ShouldRestart() { mapLock.Lock() restartContainers[c] = make(chan struct{}) mapLock.Unlock() } if c.RemovalInProgress { // We probably crashed in the middle of a removal, reset // the flag. // // We DO NOT remove the container here as we do not // know if the user had requested for either the // associated volumes, network links or both to also // be removed. So we put the container in the "dead" // state and leave further processing up to them. logrus.Debugf("Resetting RemovalInProgress flag from %v", c.ID) c.ResetRemovalInProgress() c.SetDead() c.ToDisk() } // if c.hostConfig.Links is nil (not just empty), then it is using the old sqlite links and needs to be migrated if c.HostConfig != nil && c.HostConfig.Links == nil { migrateLegacyLinks = true } }(c) } wg.Wait() daemon.netController, err = daemon.initNetworkController(daemon.configStore, activeSandboxes) if err != nil { return fmt.Errorf("Error initializing network controller: %v", err) } // migrate any legacy links from sqlite linkdbFile := filepath.Join(daemon.root, "linkgraph.db") var legacyLinkDB *graphdb.Database if migrateLegacyLinks { legacyLinkDB, err = graphdb.NewSqliteConn(linkdbFile) if err != nil { return fmt.Errorf("error connecting to legacy link graph DB %s, container links may be lost: %v", linkdbFile, err) } defer legacyLinkDB.Close() } // Now that all the containers are registered, register the links for _, c := range containers { if migrateLegacyLinks { if err := daemon.migrateLegacySqliteLinks(legacyLinkDB, c); err != nil { return err } } if err := daemon.registerLinks(c, c.HostConfig); err != nil { logrus.Errorf("failed to register link for container %s: %v", c.ID, err) } } group := sync.WaitGroup{} for c, notifier := range restartContainers { group.Add(1) go func(c *container.Container, chNotify chan struct{}) { defer group.Done() logrus.Debugf("Starting container %s", c.ID) // ignore errors here as this is a best effort to wait for children to be // running before we try to start the container children := daemon.children(c) timeout := time.After(5 * time.Second) for _, child := range children { if notifier, exists := restartContainers[child]; exists { select { case <-notifier: case <-timeout: } } } // Make sure networks are available before starting daemon.waitForNetworks(c) if err := daemon.containerStart(c); err != nil { logrus.Errorf("Failed to start container %s: %s", c.ID, err) } close(chNotify) }(c, notifier) } group.Wait() // any containers that were started above would already have had this done, // however we need to now prepare the mountpoints for the rest of the containers as well. // This shouldn't cause any issue running on the containers that already had this run. // This must be run after any containers with a restart policy so that containerized plugins // can have a chance to be running before we try to initialize them. for _, c := range containers { // if the container has restart policy, do not // prepare the mountpoints since it has been done on restarting. // This is to speed up the daemon start when a restart container // has a volume and the volume dirver is not available. if _, ok := restartContainers[c]; ok { continue } group.Add(1) go func(c *container.Container) { defer group.Done() if err := daemon.prepareMountPoints(c); err != nil { logrus.Error(err) } }(c) } group.Wait() if !debug { if logrus.GetLevel() == logrus.InfoLevel && containerCount > 0 { fmt.Println() } logrus.Info("Loading containers: done.") } return nil }
func (daemon *Daemon) restore() error { var ( debug = utils.IsDebugEnabled() currentDriver = daemon.GraphDriverName() containers = make(map[string]*container.Container) ) if !debug { logrus.Info("Loading containers: start.") } dir, err := ioutil.ReadDir(daemon.repository) if err != nil { return err } for _, v := range dir { id := v.Name() container, err := daemon.load(id) if !debug && logrus.GetLevel() == logrus.InfoLevel { fmt.Print(".") } if err != nil { logrus.Errorf("Failed to load container %v: %v", id, err) continue } // Ignore the container if it does not support the current driver being used by the graph if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver { rwlayer, err := daemon.layerStore.GetRWLayer(container.ID) if err != nil { logrus.Errorf("Failed to load container mount %v: %v", id, err) continue } container.RWLayer = rwlayer logrus.Debugf("Loaded container %v", container.ID) containers[container.ID] = container } else { logrus.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID) } } var migrateLegacyLinks bool restartContainers := make(map[*container.Container]chan struct{}) for _, c := range containers { if err := daemon.registerName(c); err != nil { logrus.Errorf("Failed to register container %s: %s", c.ID, err) continue } if err := daemon.Register(c); err != nil { logrus.Errorf("Failed to register container %s: %s", c.ID, err) continue } } var wg sync.WaitGroup var mapLock sync.Mutex for _, c := range containers { wg.Add(1) go func(c *container.Container) { defer wg.Done() rm := c.RestartManager(false) if c.IsRunning() || c.IsPaused() { // Fix activityCount such that graph mounts can be unmounted later if err := daemon.layerStore.ReinitRWLayer(c.RWLayer); err != nil { logrus.Errorf("Failed to ReinitRWLayer for %s due to %s", c.ID, err) return } if err := daemon.containerd.Restore(c.ID, libcontainerd.WithRestartManager(rm)); err != nil { logrus.Errorf("Failed to restore with containerd: %q", err) return } } // fixme: only if not running // get list of containers we need to restart if daemon.configStore.AutoRestart && !c.IsRunning() && !c.IsPaused() && c.ShouldRestart() { mapLock.Lock() restartContainers[c] = make(chan struct{}) mapLock.Unlock() } // if c.hostConfig.Links is nil (not just empty), then it is using the old sqlite links and needs to be migrated if c.HostConfig != nil && c.HostConfig.Links == nil { migrateLegacyLinks = true } }(c) } wg.Wait() // migrate any legacy links from sqlite linkdbFile := filepath.Join(daemon.root, "linkgraph.db") var legacyLinkDB *graphdb.Database if migrateLegacyLinks { legacyLinkDB, err = graphdb.NewSqliteConn(linkdbFile) if err != nil { return fmt.Errorf("error connecting to legacy link graph DB %s, container links may be lost: %v", linkdbFile, err) } defer legacyLinkDB.Close() } // Now that all the containers are registered, register the links for _, c := range containers { if migrateLegacyLinks { if err := daemon.migrateLegacySqliteLinks(legacyLinkDB, c); err != nil { return err } } if err := daemon.registerLinks(c, c.HostConfig); err != nil { logrus.Errorf("failed to register link for container %s: %v", c.ID, err) } } group := sync.WaitGroup{} for c, notifier := range restartContainers { group.Add(1) go func(c *container.Container, chNotify chan struct{}) { defer group.Done() logrus.Debugf("Starting container %s", c.ID) // ignore errors here as this is a best effort to wait for children to be // running before we try to start the container children := daemon.children(c) timeout := time.After(5 * time.Second) for _, child := range children { if notifier, exists := restartContainers[child]; exists { select { case <-notifier: case <-timeout: } } } if err := daemon.containerStart(c); err != nil { logrus.Errorf("Failed to start container %s: %s", c.ID, err) } close(chNotify) }(c, notifier) } group.Wait() // any containers that were started above would already have had this done, // however we need to now prepare the mountpoints for the rest of the containers as well. // This shouldn't cause any issue running on the containers that already had this run. // This must be run after any containers with a restart policy so that containerized plugins // can have a chance to be running before we try to initialize them. for _, c := range containers { // if the container has restart policy, do not // prepare the mountpoints since it has been done on restarting. // This is to speed up the daemon start when a restart container // has a volume and the volume dirver is not available. if _, ok := restartContainers[c]; ok { continue } group.Add(1) go func(c *container.Container) { defer group.Done() if err := daemon.prepareMountPoints(c); err != nil { logrus.Error(err) } }(c) } group.Wait() if !debug { if logrus.GetLevel() == logrus.InfoLevel { fmt.Println() } logrus.Info("Loading containers: done.") } return nil }
func (daemon *Daemon) restore() error { var ( debug = utils.IsDebugEnabled() currentDriver = daemon.GraphDriverName() containers = make(map[string]*container.Container) ) if !debug { logrus.Info("Loading containers: start.") } dir, err := ioutil.ReadDir(daemon.repository) if err != nil { return err } for _, v := range dir { id := v.Name() container, err := daemon.load(id) if !debug && logrus.GetLevel() == logrus.InfoLevel { fmt.Print(".") } if err != nil { logrus.Errorf("Failed to load container %v: %v", id, err) continue } rwlayer, err := daemon.layerStore.GetRWLayer(container.ID) if err != nil { logrus.Errorf("Failed to load container mount %v: %v", id, err) continue } container.RWLayer = rwlayer // Ignore the container if it does not support the current driver being used by the graph if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver { logrus.Debugf("Loaded container %v", container.ID) containers[container.ID] = container } else { logrus.Debugf("Cannot load container %s because it was created with another graph driver.", container.ID) } } var migrateLegacyLinks bool restartContainers := make(map[*container.Container]chan struct{}) for _, c := range containers { if err := daemon.registerName(c); err != nil { logrus.Errorf("Failed to register container %s: %s", c.ID, err) continue } if err := daemon.Register(c); err != nil { logrus.Errorf("Failed to register container %s: %s", c.ID, err) continue } // get list of containers we need to restart if daemon.configStore.AutoRestart && c.ShouldRestart() { restartContainers[c] = make(chan struct{}) } // if c.hostConfig.Links is nil (not just empty), then it is using the old sqlite links and needs to be migrated if c.HostConfig != nil && c.HostConfig.Links == nil { migrateLegacyLinks = true } } // migrate any legacy links from sqlite linkdbFile := filepath.Join(daemon.root, "linkgraph.db") var legacyLinkDB *graphdb.Database if migrateLegacyLinks { legacyLinkDB, err = graphdb.NewSqliteConn(linkdbFile) if err != nil { return fmt.Errorf("error connecting to legacy link graph DB %s, container links may be lost: %v", linkdbFile, err) } defer legacyLinkDB.Close() } // Now that all the containers are registered, register the links for _, c := range containers { if migrateLegacyLinks { if err := daemon.migrateLegacySqliteLinks(legacyLinkDB, c); err != nil { return err } } if err := daemon.registerLinks(c, c.HostConfig); err != nil { logrus.Errorf("failed to register link for container %s: %v", c.ID, err) } } group := sync.WaitGroup{} for c, notifier := range restartContainers { group.Add(1) go func(c *container.Container, chNotify chan struct{}) { defer group.Done() logrus.Debugf("Starting container %s", c.ID) // ignore errors here as this is a best effort to wait for children to be // running before we try to start the container children := daemon.children(c) timeout := time.After(5 * time.Second) for _, child := range children { if notifier, exists := restartContainers[child]; exists { select { case <-notifier: case <-timeout: } } } if err := daemon.containerStart(c); err != nil { logrus.Errorf("Failed to start container %s: %s", c.ID, err) } close(chNotify) }(c, notifier) } group.Wait() if !debug { if logrus.GetLevel() == logrus.InfoLevel { fmt.Println() } logrus.Info("Loading containers: done.") } return nil }