97 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
| package volumes
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/containers/common/pkg/completion"
 | |
| 	"github.com/containers/podman/v3/cmd/podman/common"
 | |
| 	"github.com/containers/podman/v3/cmd/podman/inspect"
 | |
| 	"github.com/containers/podman/v3/cmd/podman/registry"
 | |
| 	"github.com/containers/podman/v3/pkg/domain/entities"
 | |
| 	"github.com/containers/podman/v3/utils"
 | |
| 	"github.com/pkg/errors"
 | |
| 	"github.com/sirupsen/logrus"
 | |
| 	"github.com/spf13/cobra"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	volumeExportDescription = `
 | |
| podman volume export
 | |
| 
 | |
| Allow content of volume to be exported into external tar.`
 | |
| 	exportCommand = &cobra.Command{
 | |
| 		Annotations:       map[string]string{registry.EngineMode: registry.ABIMode},
 | |
| 		Use:               "export [options] VOLUME",
 | |
| 		Short:             "Export volumes",
 | |
| 		Args:              cobra.ExactArgs(1),
 | |
| 		Long:              volumeExportDescription,
 | |
| 		RunE:              export,
 | |
| 		ValidArgsFunction: common.AutocompleteVolumes,
 | |
| 	}
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// Temporary struct to hold cli values.
 | |
| 	cliExportOpts = struct {
 | |
| 		Output string
 | |
| 	}{}
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	registry.Commands = append(registry.Commands, registry.CliCommand{
 | |
| 		Command: exportCommand,
 | |
| 		Parent:  volumeCmd,
 | |
| 	})
 | |
| 	flags := exportCommand.Flags()
 | |
| 
 | |
| 	outputFlagName := "output"
 | |
| 	flags.StringVarP(&cliExportOpts.Output, outputFlagName, "o", "/dev/stdout", "Write to a specified file (default: stdout, which must be redirected)")
 | |
| 	_ = exportCommand.RegisterFlagCompletionFunc(outputFlagName, completion.AutocompleteDefault)
 | |
| }
 | |
| 
 | |
| func export(cmd *cobra.Command, args []string) error {
 | |
| 	var inspectOpts entities.InspectOptions
 | |
| 	containerEngine := registry.ContainerEngine()
 | |
| 	ctx := context.Background()
 | |
| 
 | |
| 	if cliExportOpts.Output == "" {
 | |
| 		return errors.New("expects output path, use --output=[path]")
 | |
| 	}
 | |
| 	inspectOpts.Type = inspect.VolumeType
 | |
| 	volumeData, _, err := containerEngine.VolumeInspect(ctx, args, inspectOpts)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if len(volumeData) < 1 {
 | |
| 		return errors.New("no volume data found")
 | |
| 	}
 | |
| 	mountPoint := volumeData[0].VolumeConfigResponse.Mountpoint
 | |
| 	driver := volumeData[0].VolumeConfigResponse.Driver
 | |
| 	volumeOptions := volumeData[0].VolumeConfigResponse.Options
 | |
| 	volumeMountStatus, err := containerEngine.VolumeMounted(ctx, args[0])
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if mountPoint == "" {
 | |
| 		return errors.New("volume is not mounted anywhere on host")
 | |
| 	}
 | |
| 	// Check if volume is using external plugin and export only if volume is mounted
 | |
| 	if driver != "" && driver != "local" {
 | |
| 		if !volumeMountStatus.Value {
 | |
| 			return fmt.Errorf("volume is using a driver %s and volume is not mounted on %s", driver, mountPoint)
 | |
| 		}
 | |
| 	}
 | |
| 	// Check if volume is using `local` driver and has mount options type other than tmpfs
 | |
| 	if driver == "local" {
 | |
| 		if mountOptionType, ok := volumeOptions["type"]; ok {
 | |
| 			if mountOptionType != "tmpfs" && !volumeMountStatus.Value {
 | |
| 				return fmt.Errorf("volume is using a driver %s and volume is not mounted on %s", driver, mountPoint)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	logrus.Debugf("Exporting volume data from %s to %s", mountPoint, cliExportOpts.Output)
 | |
| 	err = utils.CreateTarFromSrc(mountPoint, cliExportOpts.Output)
 | |
| 	return err
 | |
| }
 |