func (s *storageZfs) ContainerSnapshotDelete(snapshotContainer container) error { fields := strings.SplitN(snapshotContainer.Name(), shared.SnapshotDelimiter, 2) cName := fields[0] snapName := fmt.Sprintf("snapshot-%s", fields[1]) removable, err := s.zfsSnapshotRemovable(fmt.Sprintf("containers/%s", cName), snapName) if removable { err = s.zfsSnapshotDestroy(fmt.Sprintf("containers/%s", cName), snapName) if err != nil { return err } } else { err = s.zfsSnapshotRename(fmt.Sprintf("containers/%s", cName), snapName, fmt.Sprintf("copy-%s", uuid.NewV4().String())) if err != nil { return err } } err = os.Remove(shared.VarPath(fmt.Sprintf("snapshots/%s/%s.zfs", cName, fields[1]))) if err != nil { return err } parent := shared.VarPath(fmt.Sprintf("snapshots/%s", cName)) if ok, _ := shared.PathIsEmpty(parent); ok { err = os.Remove(parent) if err != nil { return err } } return nil }
// ContainerSnapshotRename renames a snapshot of a container. func (s *storageBtrfs) ContainerSnapshotRename( snapshotContainer container, newName string) error { oldPath := snapshotContainer.Path() newPath := containerPath(newName, true) // Create the new parent. if !shared.PathExists(filepath.Dir(newPath)) { os.MkdirAll(filepath.Dir(newPath), 0700) } // Now rename the snapshot. if !s.isSubvolume(oldPath) { if err := os.Rename(oldPath, newPath); err != nil { return err } } else { if err := s.subvolsSnapshot(oldPath, newPath, true); err != nil { return err } if err := s.subvolsDelete(oldPath); err != nil { return err } } // Remove the old parent (on container rename) if its empty. if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok { os.Remove(filepath.Dir(oldPath)) } return nil }
func (s *storageLvm) ContainerDelete(container container) error { // First remove the LVM LV if err := s.removeLV(container.NameGet()); err != nil { return err } // Then remove the symlink lvLinkPath := shared.VarPath("containers", fmt.Sprintf("%s.lv", container.NameGet())) if err := os.Remove(lvLinkPath); err != nil { return err } // Then the container path (e.g. /var/lib/lxd/containers/<name>) cPath := container.PathGet("") if err := os.RemoveAll(cPath + "/*"); err != nil { s.log.Error("ContainerDelete: failed", log.Ctx{"cPath": cPath, "err": err}) return fmt.Errorf("Cleaning up %s: %s", cPath, err) } // If its name contains a "/" also remove the parent, // this should only happen with snapshot containers if strings.Contains(container.NameGet(), "/") { oldPathParent := filepath.Dir(container.PathGet("")) if ok, _ := shared.PathIsEmpty(oldPathParent); ok { os.Remove(oldPathParent) } else { shared.Log.Debug( "Cannot remove the parent of this container its not empty", log.Ctx{"container": container.NameGet(), "parent": oldPathParent}) } } return nil }
func (s *storageLvm) ContainerSnapshotRename( snapshotContainer container, newContainerName string) error { oldName := containerNameToLVName(snapshotContainer.NameGet()) newName := containerNameToLVName(newContainerName) output, err := s.renameLV(oldName, newName) if err != nil { s.log.Error("Failed to rename a snapshot LV", log.Ctx{"oldName": oldName, "newName": newName, "err": err, "output": string(output)}) return fmt.Errorf("Failed to rename a container LV, oldName='%s', newName='%s', err='%s'", oldName, newName, err) } oldPath := snapshotContainer.PathGet("") oldSymPath := fmt.Sprintf("%s.lv", oldPath) newPath := snapshotContainer.PathGet(newName) newSymPath := fmt.Sprintf("%s.lv", newPath) if err := os.Rename(oldSymPath, newSymPath); err != nil { s.log.Error("Failed to rename symlink", log.Ctx{"oldSymPath": oldSymPath, "newSymPath": newSymPath, "err": err}) return fmt.Errorf("Failed to rename symlink err='%s'", err) } if strings.Contains(snapshotContainer.NameGet(), "/") { if !shared.PathExists(filepath.Dir(newPath)) { os.MkdirAll(filepath.Dir(newPath), 0700) } } if strings.Contains(snapshotContainer.NameGet(), "/") { if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok { os.Remove(filepath.Dir(oldPath)) } } return nil }
func (s *storageDir) ContainerSnapshotRename( snapshotContainer container, newName string) error { oldPath := snapshotContainer.PathGet("") newPath := snapshotContainer.PathGet(newName) // Create the new parent. if strings.Contains(snapshotContainer.NameGet(), "/") { if !shared.PathExists(filepath.Dir(newPath)) { os.MkdirAll(filepath.Dir(newPath), 0700) } } // Now rename the snapshot. if err := os.Rename(oldPath, newPath); err != nil { return err } // Remove the old parent (on container rename) if its empty. if strings.Contains(snapshotContainer.NameGet(), "/") { if ok, _ := shared.PathIsEmpty(filepath.Dir(oldPath)); ok { os.Remove(filepath.Dir(oldPath)) } } return nil }
func (s *storageLvm) ContainerSnapshotDelete( snapshotContainer container) error { err := s.ContainerDelete(snapshotContainer) if err != nil { return fmt.Errorf("Error deleting snapshot %s: %s", snapshotContainer.Name(), err) } oldPathParent := filepath.Dir(snapshotContainer.Path()) if ok, _ := shared.PathIsEmpty(oldPathParent); ok { os.Remove(oldPathParent) } return nil }
func (s *storageZfs) ContainerSnapshotRename(snapshotContainer container, newName string) error { oldFields := strings.SplitN(snapshotContainer.Name(), shared.SnapshotDelimiter, 2) oldcName := oldFields[0] oldName := fmt.Sprintf("snapshot-%s", oldFields[1]) newFields := strings.SplitN(newName, shared.SnapshotDelimiter, 2) newcName := newFields[0] newName = fmt.Sprintf("snapshot-%s", newFields[1]) if oldName != newName { err := s.zfsSnapshotRename(fmt.Sprintf("containers/%s", oldcName), oldName, newName) if err != nil { return err } } err := os.Remove(shared.VarPath(fmt.Sprintf("snapshots/%s/%s.zfs", oldcName, oldFields[1]))) if err != nil { return err } if !shared.PathExists(shared.VarPath(fmt.Sprintf("snapshots/%s", newcName))) { err = os.MkdirAll(shared.VarPath(fmt.Sprintf("snapshots/%s", newcName)), 0700) if err != nil { return err } } err = os.Symlink("on-zfs", shared.VarPath(fmt.Sprintf("snapshots/%s/%s.zfs", newcName, newFields[1]))) if err != nil { return err } parent := shared.VarPath(fmt.Sprintf("snapshots/%s", oldcName)) if ok, _ := shared.PathIsEmpty(parent); ok { err = os.Remove(parent) if err != nil { return err } } return nil }
func dbUpdateFromV11(d *Daemon) error { if d.IsMock { // No need to move snapshots no mock runs, // dbUpdateFromV12 will then set the db version to 13 return nil } cNames, err := dbContainersList(d.db, cTypeSnapshot) if err != nil { return err } errors := 0 for _, cName := range cNames { snappieces := strings.SplitN(cName, shared.SnapshotDelimiter, 2) oldPath := shared.VarPath("containers", snappieces[0], "snapshots", snappieces[1]) newPath := shared.VarPath("snapshots", snappieces[0], snappieces[1]) if shared.PathExists(oldPath) && !shared.PathExists(newPath) { shared.Log.Info( "Moving snapshot", log.Ctx{ "snapshot": cName, "oldPath": oldPath, "newPath": newPath}) // Rsync // containers/<container>/snapshots/<snap0> // to // snapshots/<container>/<snap0> output, err := storageRsyncCopy(oldPath, newPath) if err != nil { shared.Log.Error( "Failed rsync snapshot", log.Ctx{ "snapshot": cName, "output": output, "err": err}) errors++ continue } // Remove containers/<container>/snapshots/<snap0> if err := os.RemoveAll(oldPath); err != nil { shared.Log.Error( "Failed to remove the old snapshot path", log.Ctx{ "snapshot": cName, "oldPath": oldPath, "err": err}) // Ignore this error. // errors++ // continue } // Remove /var/lib/lxd/containers/<container>/snapshots // if its empty. cPathParent := filepath.Dir(oldPath) if ok, _ := shared.PathIsEmpty(cPathParent); ok { os.Remove(cPathParent) } } // if shared.PathExists(oldPath) && !shared.PathExists(newPath) { } // for _, cName := range cNames { // Refuse to start lxd if a rsync failed. if errors > 0 { return fmt.Errorf("Got errors while moving snapshots, see the log output.") } stmt := ` INSERT INTO schema (version, updated_at) VALUES (?, strftime("%s"));` _, err = d.db.Exec(stmt, 12) return err }
func (s *storageLvm) ContainerRename( container container, newContainerName string) error { oldName := containerNameToLVName(container.Name()) newName := containerNameToLVName(newContainerName) output, err := s.renameLV(oldName, newName) if err != nil { s.log.Error("Failed to rename a container LV", log.Ctx{"oldName": oldName, "newName": newName, "err": err, "output": string(output)}) return fmt.Errorf("Failed to rename a container LV, oldName='%s', newName='%s', err='%s'", oldName, newName, err) } // Rename the snapshots if !container.IsSnapshot() { snaps, err := container.Snapshots() if err != nil { return err } for _, snap := range snaps { baseSnapName := filepath.Base(snap.Name()) newSnapshotName := newName + shared.SnapshotDelimiter + baseSnapName err := s.ContainerRename(snap, newSnapshotName) if err != nil { return err } oldPathParent := filepath.Dir(snap.Path()) if ok, _ := shared.PathIsEmpty(oldPathParent); ok { os.Remove(oldPathParent) } } } // Create a new symlink newSymPath := fmt.Sprintf("%s.lv", containerPath(newContainerName, container.IsSnapshot())) err = os.MkdirAll(filepath.Dir(containerPath(newContainerName, container.IsSnapshot())), 0700) if err != nil { return err } err = os.Symlink(fmt.Sprintf("/dev/%s/%s", s.vgName, newName), newSymPath) if err != nil { return err } // Remove the old symlink oldSymPath := fmt.Sprintf("%s.lv", container.Path()) err = os.Remove(oldSymPath) if err != nil { return err } // Rename the directory err = os.Rename(container.Path(), containerPath(newContainerName, container.IsSnapshot())) if err != nil { return err } return nil }
func (s *storageBtrfs) MigrationSink(live bool, container container, snapshots []*Snapshot, conn *websocket.Conn, srcIdmap *shared.IdmapSet) error { if runningInUserns { return rsyncMigrationSink(live, container, snapshots, conn, srcIdmap) } cName := container.Name() snapshotsPath := shared.VarPath(fmt.Sprintf("snapshots/%s", cName)) if !shared.PathExists(snapshotsPath) { err := os.MkdirAll(shared.VarPath(fmt.Sprintf("snapshots/%s", cName)), 0700) if err != nil { return err } } btrfsRecv := func(btrfsPath string, targetPath string, isSnapshot bool) error { args := []string{"receive", "-e", btrfsPath} cmd := exec.Command("btrfs", args...) // Remove the existing pre-created subvolume err := s.subvolsDelete(targetPath) if err != nil { return err } stdin, err := cmd.StdinPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } if err := cmd.Start(); err != nil { return err } <-shared.WebsocketRecvStream(stdin, conn) output, err := ioutil.ReadAll(stderr) if err != nil { shared.LogDebugf("problem reading btrfs receive stderr %s", err) } err = cmd.Wait() if err != nil { shared.LogError("problem with btrfs receive", log.Ctx{"output": string(output)}) return err } if !isSnapshot { cPath := containerPath(fmt.Sprintf("%s/.root", cName), true) err := s.subvolSnapshot(cPath, targetPath, false) if err != nil { shared.LogError("problem with btrfs snapshot", log.Ctx{"err": err}) return err } err = s.subvolsDelete(cPath) if err != nil { shared.LogError("problem with btrfs delete", log.Ctx{"err": err}) return err } } return nil } for _, snap := range snapshots { args := snapshotProtobufToContainerArgs(container.Name(), snap) s, err := containerCreateEmptySnapshot(container.Daemon(), args) if err != nil { return err } if err := btrfsRecv(containerPath(cName, true), s.Path(), true); err != nil { return err } } /* finally, do the real container */ if err := btrfsRecv(containerPath(cName, true), container.Path(), false); err != nil { return err } if live { if err := btrfsRecv(containerPath(cName, true), container.Path(), false); err != nil { return err } } // Cleanup if ok, _ := shared.PathIsEmpty(snapshotsPath); ok { err := os.Remove(snapshotsPath) if err != nil { return err } } return nil }