lxd/storage_ceph.go
func (s *storageCeph) doCrossPoolContainerCopy(target container, source container, containerOnly bool, refresh bool, refreshSnapshots []container) error {
	sourcePool, err := source.StoragePool()
	if err != nil {
		return err
	}

	// setup storage for the source volume
	srcStorage, err := storagePoolVolumeInit(s.s, source.Project(), sourcePool, source.Name(), storagePoolVolumeTypeContainer)
	if err != nil {
		return err
	}

	ourMount, err := srcStorage.StoragePoolMount()
	if err != nil {
		return err
	}
	if ourMount {
		defer srcStorage.StoragePoolUmount()
	}

	targetPool, err := target.StoragePool()
	if err != nil {
		return err
	}

	var snapshots []container

	if refresh {
		snapshots = refreshSnapshots
	} else {
		snapshots, err = source.Snapshots()
		if err != nil {
			return err
		}

		// create the main container
		err = s.doContainerCreate(target.Project(), target.Name(), target.IsPrivileged())
		if err != nil {
			return err
		}
	}

	// mount container
	_, err = s.doContainerMount(target.Project(), target.Name())
	if err != nil {
		return err
	}

	destContainerMntPoint := getContainerMountPoint(target.Project(), targetPool, target.Name())
	bwlimit := s.pool.Config["rsync.bwlimit"]
	// Extract container
	if !containerOnly {
		for _, snap := range snapshots {
			srcSnapshotMntPoint := getSnapshotMountPoint(snap.Project(), sourcePool, snap.Name())
			_, err = rsyncLocalCopy(srcSnapshotMntPoint, destContainerMntPoint, bwlimit)
			if err != nil {
				return err
			}

			// This is costly but we need to ensure that all cached data has
			// been committed to disk. If we don't then the rbd snapshot of
			// the underlying filesystem can be inconsistent or - worst case
			// - empty.
			syscall.Sync()

			msg, fsFreezeErr := shared.TryRunCommand("fsfreeze", "--freeze", destContainerMntPoint)
			logger.Debugf("Trying to freeze the filesystem: %s: %s", msg, fsFreezeErr)

			// create snapshot
			_, snapOnlyName, _ := containerGetParentAndSnapshotName(snap.Name())
			err = s.doContainerSnapshotCreate(target.Project(), fmt.Sprintf("%s/%s", target.Name(), snapOnlyName), target.Name())
			if fsFreezeErr == nil {
				msg, fsFreezeErr := shared.TryRunCommand("fsfreeze", "--unfreeze", destContainerMntPoint)
				logger.Debugf("Trying to unfreeze the filesystem: %s: %s", msg, fsFreezeErr)
			}
			if err != nil {
				return err
			}
		}
	}

	srcContainerMntPoint := getContainerMountPoint(source.Project(), sourcePool, source.Name())
	_, err = rsyncLocalCopy(srcContainerMntPoint, destContainerMntPoint, bwlimit)
	if err != nil {
		if !refresh {
			s.StoragePoolVolumeDelete()
		}

		logger.Errorf("Failed to rsync into BTRFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
		return err
	}

	return nil
}
func (s *storageCeph) doCrossPoolContainerCopy(target container, source container, containerOnly bool, refresh bool, refreshSnapshots []container) error {
	sourcePool, err := source.StoragePool()
	if err != nil {
		return err
	}

	// setup storage for the source volume
	srcStorage, err := storagePoolVolumeInit(s.s, source.Project(), sourcePool, source.Name(), storagePoolVolumeTypeContainer)
	if err != nil {
		return err
	}

	ourMount, err := srcStorage.StoragePoolMount()
	if err != nil {
		return err
	}
	if ourMount {
		defer srcStorage.StoragePoolUmount()
	}

	targetPool, err := target.StoragePool()
	if err != nil {
		return err
	}

	var snapshots []container

	if refresh {
		snapshots = refreshSnapshots
	} else {
		snapshots, err = source.Snapshots()
		if err != nil {
			return err
		}

		// create the main container
		err = s.doContainerCreate(target.Project(), target.Name(), target.IsPrivileged())
		if err != nil {
			return err
		}
	}

	// mount container
	_, err = s.doContainerMount(target.Project(), target.Name())
	if err != nil {
		return err
	}

	destContainerMntPoint := getContainerMountPoint(target.Project(), targetPool, target.Name())
	bwlimit := s.pool.Config["rsync.bwlimit"]
	// Extract container
	if !containerOnly {
		for _, snap := range snapshots {
			srcSnapshotMntPoint := getSnapshotMountPoint(snap.Project(), sourcePool, snap.Name())
			_, err = rsyncLocalCopy(srcSnapshotMntPoint, destContainerMntPoint, bwlimit)
			if err != nil {
				return err
			}

			// This is costly but we need to ensure that all cached data has
			// been committed to disk. If we don't then the rbd snapshot of
			// the underlying filesystem can be inconsistent or - worst case
			// - empty.
			syscall.Sync()

			msg, fsFreezeErr := shared.TryRunCommand("fsfreeze", "--freeze", destContainerMntPoint)
			logger.Debugf("Trying to freeze the filesystem: %s: %s", msg, fsFreezeErr)

			// create snapshot
			_, snapOnlyName, _ := containerGetParentAndSnapshotName(snap.Name())
			err = s.doContainerSnapshotCreate(target.Project(), fmt.Sprintf("%s/%s", target.Name(), snapOnlyName), target.Name())
			if fsFreezeErr == nil {
				msg, fsFreezeErr := shared.TryRunCommand("fsfreeze", "--unfreeze", destContainerMntPoint)
				logger.Debugf("Trying to unfreeze the filesystem: %s: %s", msg, fsFreezeErr)
			}
			if err != nil {
				return err
			}
		}
	}

	srcContainerMntPoint := getContainerMountPoint(source.Project(), sourcePool, source.Name())
	_, err = rsyncLocalCopy(srcContainerMntPoint, destContainerMntPoint, bwlimit)
	if err != nil {
		if !refresh {
			s.StoragePoolVolumeDelete()
		}

		logger.Errorf("Failed to rsync into BTRFS storage volume \"%s\" on storage pool \"%s\": %s", s.volume.Name, s.pool.Name, err)
		return err
	}

	return nil
}
func ( s * storageCeph ) doCrossPoolContainerCopy ( target container , source container , containerOnly bool , refresh bool , refreshSnapshots [ ] container ) error { sourcePool , err := source . StoragePool ( ) if err != nil { return err } // setup storage for the source volume srcStorage , err := storagePoolVolumeInit ( s . s , source . Project ( ) , sourcePool , source . Name ( ) , storagePoolVolumeTypeContainer ) if err != nil { return err } ourMount , err := srcStorage . StoragePoolMount ( ) if err != nil { return err } if ourMount { defer srcStorage . StoragePoolUmount ( ) } targetPool , err := target . StoragePool ( ) if err != nil { return err } var snapshots [ ] container if refresh { snapshots = refreshSnapshots } else { snapshots , err = source . Snapshots ( ) if err != nil { return err } // create the main container err = s . doContainerCreate ( target . Project ( ) , target . Name ( ) , target . IsPrivileged ( ) ) if err != nil { return err } } // mount container _ , err = s . doContainerMount ( target . Project ( ) , target . Name ( ) ) if err != nil { return err } destContainerMntPoint := getContainerMountPoint ( target . Project ( ) , targetPool , target . Name ( ) ) bwlimit := s . pool . Config [ " " ] // Extract container if ! containerOnly { for _ , snap := range snapshots { srcSnapshotMntPoint := getSnapshotMountPoint ( snap . Project ( ) , sourcePool , snap . Name ( ) ) _ , err = rsyncLocalCopy ( srcSnapshotMntPoint , destContainerMntPoint , bwlimit ) if err != nil { return err } // This is costly but we need to ensure that all cached data has // been committed to disk. If we don't then the rbd snapshot of // the underlying filesystem can be inconsistent or - worst case // - empty. syscall . Sync ( ) msg , fsFreezeErr := shared . TryRunCommand ( " " , " " , destContainerMntPoint ) logger . Debugf ( " " , msg , fsFreezeErr ) // create snapshot _ , snapOnlyName , _ := containerGetParentAndSnapshotName ( snap . Name ( ) ) err = s . doContainerSnapshotCreate ( target . Project ( ) , fmt . Sprintf ( " " , target . Name ( ) , snapOnlyName ) , target . Name ( ) ) if fsFreezeErr == nil { msg , fsFreezeErr := shared . TryRunCommand ( " " , " " , destContainerMntPoint ) logger . Debugf ( " " , msg , fsFreezeErr ) } if err != nil { return err } } } srcContainerMntPoint := getContainerMountPoint ( source . Project ( ) , sourcePool , source . Name ( ) ) _ , err = rsyncLocalCopy ( srcContainerMntPoint , destContainerMntPoint , bwlimit ) if err != nil { if ! refresh { s . StoragePoolVolumeDelete ( ) } logger . Errorf ( " \" \" \" \" " , s . volume . Name , s . pool . Name , err ) return err } return nil }
// This function recreates an rbd container including its snapshots. It
// recreates the dependencies between the container and the snapshots:
// - create an empty rbd storage volume
// - for each snapshot dump the contents into the empty storage volume and
//   after each dump take a snapshot of the rbd storage volume
// - dump the container contents into the rbd storage volume.
This function recreates an rbd container including its snapshots . It recreates the dependencies between the container and the snapshots : - create an empty rbd storage volume - for each snapshot dump the contents into the empty storage volume and after each dump take a snapshot of the rbd storage volume - dump the container contents into the rbd storage volume .