github.com/ali-iotechsys/cli@v20.10.0+incompatible/cli/compose/convert/volume.go (about)

     1  package convert
     2  
     3  import (
     4  	composetypes "github.com/docker/cli/cli/compose/types"
     5  	"github.com/docker/docker/api/types/mount"
     6  	"github.com/pkg/errors"
     7  )
     8  
     9  type volumes map[string]composetypes.VolumeConfig
    10  
    11  // Volumes from compose-file types to engine api types
    12  func Volumes(serviceVolumes []composetypes.ServiceVolumeConfig, stackVolumes volumes, namespace Namespace) ([]mount.Mount, error) {
    13  	var mounts []mount.Mount
    14  
    15  	for _, volumeConfig := range serviceVolumes {
    16  		mount, err := convertVolumeToMount(volumeConfig, stackVolumes, namespace)
    17  		if err != nil {
    18  			return nil, err
    19  		}
    20  		mounts = append(mounts, mount)
    21  	}
    22  	return mounts, nil
    23  }
    24  
    25  func createMountFromVolume(volume composetypes.ServiceVolumeConfig) mount.Mount {
    26  	return mount.Mount{
    27  		Type:        mount.Type(volume.Type),
    28  		Target:      volume.Target,
    29  		ReadOnly:    volume.ReadOnly,
    30  		Source:      volume.Source,
    31  		Consistency: mount.Consistency(volume.Consistency),
    32  	}
    33  }
    34  
    35  func handleVolumeToMount(
    36  	volume composetypes.ServiceVolumeConfig,
    37  	stackVolumes volumes,
    38  	namespace Namespace,
    39  ) (mount.Mount, error) {
    40  	result := createMountFromVolume(volume)
    41  
    42  	if volume.Tmpfs != nil {
    43  		return mount.Mount{}, errors.New("tmpfs options are incompatible with type volume")
    44  	}
    45  	if volume.Bind != nil {
    46  		return mount.Mount{}, errors.New("bind options are incompatible with type volume")
    47  	}
    48  	// Anonymous volumes
    49  	if volume.Source == "" {
    50  		return result, nil
    51  	}
    52  
    53  	stackVolume, exists := stackVolumes[volume.Source]
    54  	if !exists {
    55  		return mount.Mount{}, errors.Errorf("undefined volume %q", volume.Source)
    56  	}
    57  
    58  	result.Source = namespace.Scope(volume.Source)
    59  	result.VolumeOptions = &mount.VolumeOptions{}
    60  
    61  	if volume.Volume != nil {
    62  		result.VolumeOptions.NoCopy = volume.Volume.NoCopy
    63  	}
    64  
    65  	if stackVolume.Name != "" {
    66  		result.Source = stackVolume.Name
    67  	}
    68  
    69  	// External named volumes
    70  	if stackVolume.External.External {
    71  		return result, nil
    72  	}
    73  
    74  	result.VolumeOptions.Labels = AddStackLabel(namespace, stackVolume.Labels)
    75  	if stackVolume.Driver != "" || stackVolume.DriverOpts != nil {
    76  		result.VolumeOptions.DriverConfig = &mount.Driver{
    77  			Name:    stackVolume.Driver,
    78  			Options: stackVolume.DriverOpts,
    79  		}
    80  	}
    81  
    82  	return result, nil
    83  }
    84  
    85  func handleBindToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
    86  	result := createMountFromVolume(volume)
    87  
    88  	if volume.Source == "" {
    89  		return mount.Mount{}, errors.New("invalid bind source, source cannot be empty")
    90  	}
    91  	if volume.Volume != nil {
    92  		return mount.Mount{}, errors.New("volume options are incompatible with type bind")
    93  	}
    94  	if volume.Tmpfs != nil {
    95  		return mount.Mount{}, errors.New("tmpfs options are incompatible with type bind")
    96  	}
    97  	if volume.Bind != nil {
    98  		result.BindOptions = &mount.BindOptions{
    99  			Propagation: mount.Propagation(volume.Bind.Propagation),
   100  		}
   101  	}
   102  	return result, nil
   103  }
   104  
   105  func handleTmpfsToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
   106  	result := createMountFromVolume(volume)
   107  
   108  	if volume.Source != "" {
   109  		return mount.Mount{}, errors.New("invalid tmpfs source, source must be empty")
   110  	}
   111  	if volume.Bind != nil {
   112  		return mount.Mount{}, errors.New("bind options are incompatible with type tmpfs")
   113  	}
   114  	if volume.Volume != nil {
   115  		return mount.Mount{}, errors.New("volume options are incompatible with type tmpfs")
   116  	}
   117  	if volume.Tmpfs != nil {
   118  		result.TmpfsOptions = &mount.TmpfsOptions{
   119  			SizeBytes: volume.Tmpfs.Size,
   120  		}
   121  	}
   122  	return result, nil
   123  }
   124  
   125  func handleNpipeToMount(volume composetypes.ServiceVolumeConfig) (mount.Mount, error) {
   126  	result := createMountFromVolume(volume)
   127  
   128  	if volume.Source == "" {
   129  		return mount.Mount{}, errors.New("invalid npipe source, source cannot be empty")
   130  	}
   131  	if volume.Volume != nil {
   132  		return mount.Mount{}, errors.New("volume options are incompatible with type npipe")
   133  	}
   134  	if volume.Tmpfs != nil {
   135  		return mount.Mount{}, errors.New("tmpfs options are incompatible with type npipe")
   136  	}
   137  	if volume.Bind != nil {
   138  		result.BindOptions = &mount.BindOptions{
   139  			Propagation: mount.Propagation(volume.Bind.Propagation),
   140  		}
   141  	}
   142  	return result, nil
   143  }
   144  
   145  func convertVolumeToMount(
   146  	volume composetypes.ServiceVolumeConfig,
   147  	stackVolumes volumes,
   148  	namespace Namespace,
   149  ) (mount.Mount, error) {
   150  
   151  	switch volume.Type {
   152  	case "volume", "":
   153  		return handleVolumeToMount(volume, stackVolumes, namespace)
   154  	case "bind":
   155  		return handleBindToMount(volume)
   156  	case "tmpfs":
   157  		return handleTmpfsToMount(volume)
   158  	case "npipe":
   159  		return handleNpipeToMount(volume)
   160  	}
   161  	return mount.Mount{}, errors.New("volume type must be volume, bind, tmpfs or npipe")
   162  }