lxd/storage_ceph.go
func (s *storageCeph) ContainerBackupLoad(info backupInfo, data io.ReadSeeker, tarArgs []string) error {
	// create the main container
	err := s.doContainerCreate(info.Project, info.Name, info.Privileged)
	if err != nil {
		return err
	}

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

	containerMntPoint := getContainerMountPoint(info.Project, s.pool.Name, info.Name)
	// Extract container
	for _, snap := range info.Snapshots {
		cur := fmt.Sprintf("backup/snapshots/%s", snap)

		// Prepare tar arguments
		args := append(tarArgs, []string{
			"-",
			"--recursive-unlink",
			"--strip-components=3",
			"--xattrs-include=*",
			"-C", containerMntPoint, cur,
		}...)

		// Extract snapshots
		data.Seek(0, 0)
		err = shared.RunCommandWithFds(data, nil, "tar", args...)
		if err != nil {
			logger.Errorf("Failed to untar \"%s\" into \"%s\": %s", cur, containerMntPoint, err)
			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", containerMntPoint)
		logger.Debugf("Trying to freeze the filesystem: %s: %s", msg, fsFreezeErr)

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

	// Prepare tar arguments
	args := append(tarArgs, []string{
		"-",
		"--strip-components=2",
		"--xattrs-include=*",
		"-C", containerMntPoint, "backup/container",
	}...)

	// Extract container
	data.Seek(0, 0)
	err = shared.RunCommandWithFds(data, nil, "tar", args...)
	if err != nil {
		logger.Errorf("Failed to untar \"backup/container\" into \"%s\": %s", containerMntPoint, err)
		return err
	}

	return nil
}
func (s *storageCeph) ContainerBackupLoad(info backupInfo, data io.ReadSeeker, tarArgs []string) error {
	// create the main container
	err := s.doContainerCreate(info.Project, info.Name, info.Privileged)
	if err != nil {
		return err
	}

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

	containerMntPoint := getContainerMountPoint(info.Project, s.pool.Name, info.Name)
	// Extract container
	for _, snap := range info.Snapshots {
		cur := fmt.Sprintf("backup/snapshots/%s", snap)

		// Prepare tar arguments
		args := append(tarArgs, []string{
			"-",
			"--recursive-unlink",
			"--strip-components=3",
			"--xattrs-include=*",
			"-C", containerMntPoint, cur,
		}...)

		// Extract snapshots
		data.Seek(0, 0)
		err = shared.RunCommandWithFds(data, nil, "tar", args...)
		if err != nil {
			logger.Errorf("Failed to untar \"%s\" into \"%s\": %s", cur, containerMntPoint, err)
			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", containerMntPoint)
		logger.Debugf("Trying to freeze the filesystem: %s: %s", msg, fsFreezeErr)

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

	// Prepare tar arguments
	args := append(tarArgs, []string{
		"-",
		"--strip-components=2",
		"--xattrs-include=*",
		"-C", containerMntPoint, "backup/container",
	}...)

	// Extract container
	data.Seek(0, 0)
	err = shared.RunCommandWithFds(data, nil, "tar", args...)
	if err != nil {
		logger.Errorf("Failed to untar \"backup/container\" into \"%s\": %s", containerMntPoint, err)
		return err
	}

	return nil
}
func ( s * storageCeph ) ContainerBackupLoad ( info backupInfo , data io . ReadSeeker , tarArgs [ ] string ) error { // create the main container err := s . doContainerCreate ( info . Project , info . Name , info . Privileged ) if err != nil { return err } // mount container _ , err = s . doContainerMount ( info . Project , info . Name ) if err != nil { return err } containerMntPoint := getContainerMountPoint ( info . Project , s . pool . Name , info . Name ) // Extract container for _ , snap := range info . Snapshots { cur := fmt . Sprintf ( " " , snap ) // Prepare tar arguments args := append ( tarArgs , [ ] string { " " , " " , " " , " " , " " , containerMntPoint , cur , } ... ) // Extract snapshots data . Seek ( 0 , 0 ) err = shared . RunCommandWithFds ( data , nil , " " , args ... ) if err != nil { logger . Errorf ( " \" \" \" \" " , cur , containerMntPoint , err ) 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 ( " " , " " , containerMntPoint ) logger . Debugf ( " " , msg , fsFreezeErr ) // create snapshot err = s . doContainerSnapshotCreate ( info . Project , fmt . Sprintf ( " " , info . Name , snap ) , info . Name ) if fsFreezeErr == nil { msg , fsFreezeErr := shared . TryRunCommand ( " " , " " , containerMntPoint ) logger . Debugf ( " " , msg , fsFreezeErr ) } if err != nil { return err } } // Prepare tar arguments args := append ( tarArgs , [ ] string { " " , " " , " " , " " , containerMntPoint , " " , } ... ) // Extract container data . Seek ( 0 , 0 ) err = shared . RunCommandWithFds ( data , nil , " " , args ... ) if err != nil { logger . Errorf ( " \" \" \" \" " , containerMntPoint , 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 .