lxd/storage_ceph_utils.go
func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath string, backup backup, source container) error {
	sourceIsSnapshot := source.IsSnapshot()
	sourceContainerName := source.Name()
	sourceContainerOnlyName := projectPrefix(source.Project(), sourceContainerName)
	sourceSnapshotOnlyName := ""

	// Prepare for rsync
	rsync := func(oldPath string, newPath string, bwlimit string) error {
		output, err := rsyncLocalCopy(oldPath, newPath, bwlimit)
		if err != nil {
			return fmt.Errorf("Failed to rsync: %s: %s", string(output), err)
		}

		return nil
	}

	bwlimit := s.pool.Config["rsync.bwlimit"]
	// Create a temporary snapshot
	snapshotName := fmt.Sprintf("zombie_snapshot_%s", uuid.NewRandom().String())
	if sourceIsSnapshot {
		sourceContainerOnlyName, sourceSnapshotOnlyName, _ = containerGetParentAndSnapshotName(sourceContainerName)
		sourceContainerOnlyName = projectPrefix(source.Project(), sourceContainerOnlyName)
		snapshotName = fmt.Sprintf("snapshot_%s", projectPrefix(source.Project(), sourceSnapshotOnlyName))
	} else {
		// 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()

		// create snapshot
		err := cephRBDSnapshotCreate(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)
		if err != nil {
			return err
		}
		defer cephRBDSnapshotDelete(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)
	}

	// Protect volume so we can create clones of it
	err := cephRBDSnapshotProtect(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)
	if err != nil {
		return err
	}
	defer cephRBDSnapshotUnprotect(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)

	// Create a new volume from the snapshot
	cloneName := uuid.NewRandom().String()
	err = cephRBDCloneCreate(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.OSDPoolName, cloneName, "backup", s.UserName)
	if err != nil {
		return err
	}
	defer cephRBDVolumeDelete(s.ClusterName, s.OSDPoolName, cloneName, "backup", s.UserName)

	// Map the new volume
	RBDDevPath, err := cephRBDVolumeMap(s.ClusterName, s.OSDPoolName, cloneName, "backup", s.UserName)
	if err != nil {
		return err
	}
	defer cephRBDVolumeUnmap(s.ClusterName, s.OSDPoolName, cloneName, "backup", s.UserName, true)

	// Generate a new UUID if needed
	RBDFilesystem := s.getRBDFilesystem()
	msg, err := fsGenerateNewUUID(RBDFilesystem, RBDDevPath)
	if err != nil {
		logger.Errorf("Failed to create new UUID for filesystem \"%s\": %s: %s", RBDFilesystem, msg, err)
		return err
	}

	// Create a temporary mountpoing
	tmpContainerMntPoint, err := ioutil.TempDir("", "lxd_backup_")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tmpContainerMntPoint)

	err = os.Chmod(tmpContainerMntPoint, 0700)
	if err != nil {
		return err
	}

	// Mount the volume
	mountFlags, mountOptions := lxdResolveMountoptions(s.getRBDMountOptions())
	err = tryMount(RBDDevPath, tmpContainerMntPoint, RBDFilesystem, mountFlags, mountOptions)
	if err != nil {
		logger.Errorf("Failed to mount RBD device %s onto %s: %s", RBDDevPath, tmpContainerMntPoint, err)
		return err
	}
	logger.Debugf("Mounted RBD device %s onto %s", RBDDevPath, tmpContainerMntPoint)
	defer tryUnmount(tmpContainerMntPoint, syscall.MNT_DETACH)

	// Figure out the target name
	targetName := sourceContainerName
	if sourceIsSnapshot {
		_, targetName, _ = containerGetParentAndSnapshotName(sourceContainerName)
	}

	// Create the path for the backup.
	targetBackupMntPoint := fmt.Sprintf("%s/container", tmpPath)
	if sourceIsSnapshot {
		targetBackupMntPoint = fmt.Sprintf("%s/snapshots/%s", tmpPath, targetName)
	}

	err = os.MkdirAll(targetBackupMntPoint, 0711)
	if err != nil {
		return err
	}

	err = rsync(tmpContainerMntPoint, targetBackupMntPoint, bwlimit)
	if err != nil {
		return err
	}

	return nil
}
func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath string, backup backup, source container) error {
	sourceIsSnapshot := source.IsSnapshot()
	sourceContainerName := source.Name()
	sourceContainerOnlyName := projectPrefix(source.Project(), sourceContainerName)
	sourceSnapshotOnlyName := ""

	// Prepare for rsync
	rsync := func(oldPath string, newPath string, bwlimit string) error {
		output, err := rsyncLocalCopy(oldPath, newPath, bwlimit)
		if err != nil {
			return fmt.Errorf("Failed to rsync: %s: %s", string(output), err)
		}

		return nil
	}

	bwlimit := s.pool.Config["rsync.bwlimit"]
	// Create a temporary snapshot
	snapshotName := fmt.Sprintf("zombie_snapshot_%s", uuid.NewRandom().String())
	if sourceIsSnapshot {
		sourceContainerOnlyName, sourceSnapshotOnlyName, _ = containerGetParentAndSnapshotName(sourceContainerName)
		sourceContainerOnlyName = projectPrefix(source.Project(), sourceContainerOnlyName)
		snapshotName = fmt.Sprintf("snapshot_%s", projectPrefix(source.Project(), sourceSnapshotOnlyName))
	} else {
		// 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()

		// create snapshot
		err := cephRBDSnapshotCreate(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)
		if err != nil {
			return err
		}
		defer cephRBDSnapshotDelete(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)
	}

	// Protect volume so we can create clones of it
	err := cephRBDSnapshotProtect(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)
	if err != nil {
		return err
	}
	defer cephRBDSnapshotUnprotect(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.UserName)

	// Create a new volume from the snapshot
	cloneName := uuid.NewRandom().String()
	err = cephRBDCloneCreate(s.ClusterName, s.OSDPoolName, sourceContainerOnlyName, storagePoolVolumeTypeNameContainer, snapshotName, s.OSDPoolName, cloneName, "backup", s.UserName)
	if err != nil {
		return err
	}
	defer cephRBDVolumeDelete(s.ClusterName, s.OSDPoolName, cloneName, "backup", s.UserName)

	// Map the new volume
	RBDDevPath, err := cephRBDVolumeMap(s.ClusterName, s.OSDPoolName, cloneName, "backup", s.UserName)
	if err != nil {
		return err
	}
	defer cephRBDVolumeUnmap(s.ClusterName, s.OSDPoolName, cloneName, "backup", s.UserName, true)

	// Generate a new UUID if needed
	RBDFilesystem := s.getRBDFilesystem()
	msg, err := fsGenerateNewUUID(RBDFilesystem, RBDDevPath)
	if err != nil {
		logger.Errorf("Failed to create new UUID for filesystem \"%s\": %s: %s", RBDFilesystem, msg, err)
		return err
	}

	// Create a temporary mountpoing
	tmpContainerMntPoint, err := ioutil.TempDir("", "lxd_backup_")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tmpContainerMntPoint)

	err = os.Chmod(tmpContainerMntPoint, 0700)
	if err != nil {
		return err
	}

	// Mount the volume
	mountFlags, mountOptions := lxdResolveMountoptions(s.getRBDMountOptions())
	err = tryMount(RBDDevPath, tmpContainerMntPoint, RBDFilesystem, mountFlags, mountOptions)
	if err != nil {
		logger.Errorf("Failed to mount RBD device %s onto %s: %s", RBDDevPath, tmpContainerMntPoint, err)
		return err
	}
	logger.Debugf("Mounted RBD device %s onto %s", RBDDevPath, tmpContainerMntPoint)
	defer tryUnmount(tmpContainerMntPoint, syscall.MNT_DETACH)

	// Figure out the target name
	targetName := sourceContainerName
	if sourceIsSnapshot {
		_, targetName, _ = containerGetParentAndSnapshotName(sourceContainerName)
	}

	// Create the path for the backup.
	targetBackupMntPoint := fmt.Sprintf("%s/container", tmpPath)
	if sourceIsSnapshot {
		targetBackupMntPoint = fmt.Sprintf("%s/snapshots/%s", tmpPath, targetName)
	}

	err = os.MkdirAll(targetBackupMntPoint, 0711)
	if err != nil {
		return err
	}

	err = rsync(tmpContainerMntPoint, targetBackupMntPoint, bwlimit)
	if err != nil {
		return err
	}

	return nil
}
func ( s * storageCeph ) cephRBDVolumeBackupCreate ( tmpPath string , backup backup , source container ) error { sourceIsSnapshot := source . IsSnapshot ( ) sourceContainerName := source . Name ( ) sourceContainerOnlyName := projectPrefix ( source . Project ( ) , sourceContainerName ) sourceSnapshotOnlyName := " " // Prepare for rsync rsync := func ( oldPath string , newPath string , bwlimit string ) error { output , err := rsyncLocalCopy ( oldPath , newPath , bwlimit ) if err != nil { return fmt . Errorf ( " " , string ( output ) , err ) } return nil } bwlimit := s . pool . Config [ " " ] // Create a temporary snapshot snapshotName := fmt . Sprintf ( " " , uuid . NewRandom ( ) . String ( ) ) if sourceIsSnapshot { sourceContainerOnlyName , sourceSnapshotOnlyName , _ = containerGetParentAndSnapshotName ( sourceContainerName ) sourceContainerOnlyName = projectPrefix ( source . Project ( ) , sourceContainerOnlyName ) snapshotName = fmt . Sprintf ( " " , projectPrefix ( source . Project ( ) , sourceSnapshotOnlyName ) ) } else { // 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 ( ) // create snapshot err := cephRBDSnapshotCreate ( s . ClusterName , s . OSDPoolName , sourceContainerOnlyName , storagePoolVolumeTypeNameContainer , snapshotName , s . UserName ) if err != nil { return err } defer cephRBDSnapshotDelete ( s . ClusterName , s . OSDPoolName , sourceContainerOnlyName , storagePoolVolumeTypeNameContainer , snapshotName , s . UserName ) } // Protect volume so we can create clones of it err := cephRBDSnapshotProtect ( s . ClusterName , s . OSDPoolName , sourceContainerOnlyName , storagePoolVolumeTypeNameContainer , snapshotName , s . UserName ) if err != nil { return err } defer cephRBDSnapshotUnprotect ( s . ClusterName , s . OSDPoolName , sourceContainerOnlyName , storagePoolVolumeTypeNameContainer , snapshotName , s . UserName ) // Create a new volume from the snapshot cloneName := uuid . NewRandom ( ) . String ( ) err = cephRBDCloneCreate ( s . ClusterName , s . OSDPoolName , sourceContainerOnlyName , storagePoolVolumeTypeNameContainer , snapshotName , s . OSDPoolName , cloneName , " " , s . UserName ) if err != nil { return err } defer cephRBDVolumeDelete ( s . ClusterName , s . OSDPoolName , cloneName , " " , s . UserName ) // Map the new volume RBDDevPath , err := cephRBDVolumeMap ( s . ClusterName , s . OSDPoolName , cloneName , " " , s . UserName ) if err != nil { return err } defer cephRBDVolumeUnmap ( s . ClusterName , s . OSDPoolName , cloneName , " " , s . UserName , true ) // Generate a new UUID if needed RBDFilesystem := s . getRBDFilesystem ( ) msg , err := fsGenerateNewUUID ( RBDFilesystem , RBDDevPath ) if err != nil { logger . Errorf ( " \" \" " , RBDFilesystem , msg , err ) return err } // Create a temporary mountpoing tmpContainerMntPoint , err := ioutil . TempDir ( " " , " " ) if err != nil { return err } defer os . RemoveAll ( tmpContainerMntPoint ) err = os . Chmod ( tmpContainerMntPoint , 0700 ) if err != nil { return err } // Mount the volume mountFlags , mountOptions := lxdResolveMountoptions ( s . getRBDMountOptions ( ) ) err = tryMount ( RBDDevPath , tmpContainerMntPoint , RBDFilesystem , mountFlags , mountOptions ) if err != nil { logger . Errorf ( " " , RBDDevPath , tmpContainerMntPoint , err ) return err } logger . Debugf ( " " , RBDDevPath , tmpContainerMntPoint ) defer tryUnmount ( tmpContainerMntPoint , syscall . MNT_DETACH ) // Figure out the target name targetName := sourceContainerName if sourceIsSnapshot { _ , targetName , _ = containerGetParentAndSnapshotName ( sourceContainerName ) } // Create the path for the backup. targetBackupMntPoint := fmt . Sprintf ( " " , tmpPath ) if sourceIsSnapshot { targetBackupMntPoint = fmt . Sprintf ( " " , tmpPath , targetName ) } err = os . MkdirAll ( targetBackupMntPoint , 0711 ) if err != nil { return err } err = rsync ( tmpContainerMntPoint , targetBackupMntPoint , bwlimit ) if err != nil { return err } return nil }
// cephRBDVolumeBackupCreate creates a backup of a container or snapshot.
cephRBDVolumeBackupCreate creates a backup of a container or snapshot .