func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) error { v1img := &image.V1Image{} if err := json.Unmarshal([]byte(m.History[len(m.History)-1].V1Compatibility), v1img); err != nil { return err } if v1img.Parent == "" { return fmt.Errorf("Last layer %q does not have a base layer reference", v1img.ID) } // There must be an image that already references the baselayer. for _, img := range is.Map() { if img.RootFS.BaseLayerID() == v1img.Parent { rootFS.BaseLayer = img.RootFS.BaseLayer return nil } } return fmt.Errorf("Invalid base layer %q", v1img.Parent) }
func migrateImage(id, root string, ls graphIDRegistrar, is image.Store, ms metadata.Store, mappings map[string]image.ID) (err error) { defer func() { if err != nil { logrus.Errorf("migration failed for %v, err: %v", id, err) } }() parent, err := getParent(filepath.Join(root, graphDirName, id)) if err != nil { return err } var parentID image.ID if parent != "" { var exists bool if parentID, exists = mappings[parent]; !exists { if err := migrateImage(parent, root, ls, is, ms, mappings); err != nil { // todo: fail or allow broken chains? return err } parentID = mappings[parent] } } rootFS := image.NewRootFS() var history []image.History if parentID != "" { parentImg, err := is.Get(parentID) if err != nil { return err } rootFS = parentImg.RootFS history = parentImg.History } diffIDData, err := ioutil.ReadFile(filepath.Join(root, graphDirName, id, migrationDiffIDFileName)) if err != nil { return err } diffID, err := digest.ParseDigest(string(diffIDData)) if err != nil { return err } sizeStr, err := ioutil.ReadFile(filepath.Join(root, graphDirName, id, migrationSizeFileName)) if err != nil { return err } size, err := strconv.ParseInt(string(sizeStr), 10, 64) if err != nil { return err } layer, err := ls.RegisterByGraphID(id, rootFS.ChainID(), layer.DiffID(diffID), filepath.Join(root, graphDirName, id, migrationTarDataFileName), size) if err != nil { return err } logrus.Infof("migrated layer %s to %s", id, layer.DiffID()) jsonFile := filepath.Join(root, graphDirName, id, "json") imageJSON, err := ioutil.ReadFile(jsonFile) if err != nil { return err } h, err := imagev1.HistoryFromConfig(imageJSON, false) if err != nil { return err } history = append(history, h) rootFS.Append(layer.DiffID()) config, err := imagev1.MakeConfigFromV1Config(imageJSON, rootFS, history) if err != nil { return err } strongID, err := is.Create(config) if err != nil { return err } logrus.Infof("migrated image %s to %s", id, strongID) if parentID != "" { if err := is.SetParent(strongID, parentID); err != nil { return err } } checksum, err := ioutil.ReadFile(filepath.Join(root, graphDirName, id, "checksum")) if err == nil { // best effort dgst, err := digest.ParseDigest(string(checksum)) if err == nil { V2MetadataService := metadata.NewV2MetadataService(ms) V2MetadataService.Add(layer.DiffID(), metadata.V2Metadata{Digest: dgst}) } } _, err = ls.Release(layer) if err != nil { return err } mappings[id] = strongID return }
func migrateContainers(root string, ls graphIDMounter, is image.Store, imageMappings map[string]image.ID) error { containersDir := filepath.Join(root, containersDirName) dir, err := ioutil.ReadDir(containersDir) if err != nil { return err } for _, v := range dir { id := v.Name() if _, err := os.Stat(filepath.Join(containersDir, id, configFileName)); err == nil { continue } containerJSON, err := ioutil.ReadFile(filepath.Join(containersDir, id, configFileNameLegacy)) if err != nil { logrus.Errorf("migrate container error: %v", err) continue } var c map[string]*json.RawMessage if err := json.Unmarshal(containerJSON, &c); err != nil { logrus.Errorf("migrate container error: %v", err) continue } imageStrJSON, ok := c["Image"] if !ok { return fmt.Errorf("invalid container configuration for %v", id) } var image string if err := json.Unmarshal([]byte(*imageStrJSON), &image); err != nil { logrus.Errorf("migrate container error: %v", err) continue } imageID, ok := imageMappings[image] if !ok { logrus.Errorf("image not migrated %v", imageID) // non-fatal error continue } c["Image"] = rawJSON(imageID) containerJSON, err = json.Marshal(c) if err != nil { return err } if err := ioutil.WriteFile(filepath.Join(containersDir, id, configFileName), containerJSON, 0600); err != nil { return err } img, err := is.Get(imageID) if err != nil { return err } if err := ls.CreateRWLayerByGraphID(id, id, img.RootFS.ChainID()); err != nil { logrus.Errorf("migrate container error: %v", err) continue } logrus.Infof("migrated container %s to point to %s", id, imageID) } return nil }
func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error { type graphDriverStore interface { GraphDriver() graphdriver.Driver } gds, ok := ls.(graphDriverStore) if !ok { return nil } driver := gds.GraphDriver() wd, ok := driver.(*windows.Driver) if !ok { return nil } imageInfos, err := wd.GetCustomImageInfos() if err != nil { return err } // Convert imageData to valid image configuration for _, info := range imageInfos { name := strings.ToLower(info.Name) type registrar interface { RegisterDiffID(graphID string, size int64) (layer.Layer, error) } r, ok := ls.(registrar) if !ok { return errors.New("Layerstore doesn't support RegisterDiffID") } if _, err := r.RegisterDiffID(info.ID, info.Size); err != nil { return err } // layer is intentionally not released rootFS := image.NewRootFSWithBaseLayer(filepath.Base(info.Path)) // Create history for base layer config, err := json.Marshal(&image.Image{ V1Image: image.V1Image{ DockerVersion: dockerversion.Version, Architecture: runtime.GOARCH, OS: runtime.GOOS, Created: info.CreatedTime, }, RootFS: rootFS, History: []image.History{}, OSVersion: info.OSVersion, OSFeatures: info.OSFeatures, }) named, err := reference.ParseNamed(name) if err != nil { return err } ref, err := reference.WithTag(named, info.Version) if err != nil { return err } id, err := is.Create(config) if err != nil { logrus.Warnf("Failed to restore custom image %s with error: %s.", name, err) logrus.Warnf("Skipping image %s...", name) continue } if err := rs.AddTag(ref, id, true); err != nil { return err } logrus.Debugf("Registered base layer %s as %s", ref, id) } return nil }
func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, rs reference.Store) error { if wd, ok := driver.(*windows.Driver); ok { imageInfos, err := wd.GetCustomImageInfos() if err != nil { return err } // Convert imageData to valid image configuration for i := range imageInfos { name := strings.ToLower(imageInfos[i].Name) type registrar interface { RegisterDiffID(graphID string, size int64) (layer.Layer, error) } r, ok := ls.(registrar) if !ok { return errors.New("Layerstore doesn't support RegisterDiffID") } if _, err := r.RegisterDiffID(imageInfos[i].ID, imageInfos[i].Size); err != nil { return err } // layer is intentionally not released rootFS := image.NewRootFS() rootFS.BaseLayer = filepath.Base(imageInfos[i].Path) // Create history for base layer config, err := json.Marshal(&image.Image{ V1Image: image.V1Image{ DockerVersion: dockerversion.Version, Architecture: runtime.GOARCH, OS: runtime.GOOS, Created: imageInfos[i].CreatedTime, }, RootFS: rootFS, History: []image.History{}, }) named, err := reference.ParseNamed(name) if err != nil { return err } ref, err := reference.WithTag(named, imageInfos[i].Version) if err != nil { return err } id, err := is.Create(config) if err != nil { return err } if err := rs.AddTag(ref, id, true); err != nil { return err } logrus.Debugf("Registered base layer %s as %s", ref, id) } } return nil }
func migrateImage(id, root string, ls graphIDRegistrar, is image.Store, ms metadata.Store, mappings map[string]image.ID) (err error) { defer func() { if err != nil { logrus.Errorf("migration failed for %v, err: %v", id, err) } }() jsonFile := filepath.Join(root, graphDirName, id, "json") imageJSON, err := ioutil.ReadFile(jsonFile) if err != nil { return err } var parent struct { Parent string ParentID digest.Digest `json:"parent_id"` } if err := json.Unmarshal(imageJSON, &parent); err != nil { return err } if parent.Parent == "" && parent.ParentID != "" { // v1.9 parent.Parent = parent.ParentID.Hex() } // compatibilityID for parent parentCompatibilityID, err := ioutil.ReadFile(filepath.Join(root, graphDirName, id, "parent")) if err == nil && len(parentCompatibilityID) > 0 { parent.Parent = string(parentCompatibilityID) } var parentID image.ID if parent.Parent != "" { var exists bool if parentID, exists = mappings[parent.Parent]; !exists { if err := migrateImage(parent.Parent, root, ls, is, ms, mappings); err != nil { // todo: fail or allow broken chains? return err } parentID = mappings[parent.Parent] } } rootFS := image.NewRootFS() var history []image.History if parentID != "" { parentImg, err := is.Get(parentID) if err != nil { return err } rootFS = parentImg.RootFS history = parentImg.History } layer, err := ls.RegisterByGraphID(id, rootFS.ChainID(), filepath.Join(filepath.Join(root, graphDirName, id, tarDataFileName))) if err != nil { return err } logrus.Infof("migrated layer %s to %s", id, layer.DiffID()) h, err := imagev1.HistoryFromConfig(imageJSON, false) if err != nil { return err } history = append(history, h) rootFS.Append(layer.DiffID()) config, err := imagev1.MakeConfigFromV1Config(imageJSON, rootFS, history) if err != nil { return err } strongID, err := is.Create(config) if err != nil { return err } logrus.Infof("migrated image %s to %s", id, strongID) if parentID != "" { if err := is.SetParent(strongID, parentID); err != nil { return err } } checksum, err := ioutil.ReadFile(filepath.Join(root, graphDirName, id, "checksum")) if err == nil { // best effort dgst, err := digest.ParseDigest(string(checksum)) if err == nil { blobSumService := metadata.NewBlobSumService(ms) blobSumService.Add(layer.DiffID(), dgst) } } _, err = ls.Release(layer) if err != nil { return err } mappings[id] = strongID return }