github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/cmd/swarmctl/service/flagparser/tmpfs.go (about)

     1  package flagparser
     2  
     3  import (
     4  	"os"
     5  	"path"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/docker/swarmkit/api"
    10  	"github.com/pkg/errors"
    11  	"github.com/spf13/pflag"
    12  )
    13  
    14  // parseTmpfs supports a simple tmpfs decl, similar to docker run.
    15  //
    16  // This should go away.
    17  func parseTmpfs(flags *pflag.FlagSet, spec *api.ServiceSpec) error {
    18  	if flags.Changed("tmpfs") {
    19  		tmpfss, err := flags.GetStringSlice("tmpfs")
    20  		if err != nil {
    21  			return err
    22  		}
    23  
    24  		container := spec.Task.GetContainer()
    25  		// TODO(stevvooe): Nasty inline parsing code, replace with mount syntax.
    26  		for _, tmpfs := range tmpfss {
    27  			parts := strings.SplitN(tmpfs, ":", 2)
    28  
    29  			if len(parts) < 1 {
    30  				return errors.Errorf("invalid mount spec: %v", tmpfs)
    31  			}
    32  
    33  			if len(parts[0]) == 0 || !path.IsAbs(parts[0]) {
    34  				return errors.Errorf("invalid mount spec: %v", tmpfs)
    35  			}
    36  
    37  			m := api.Mount{
    38  				Type:   api.MountTypeTmpfs,
    39  				Target: parts[0],
    40  			}
    41  
    42  			if len(parts) == 2 {
    43  				if strings.Contains(parts[1], ":") {
    44  					// repeated colon is illegal
    45  					return errors.Errorf("invalid mount spec: %v", tmpfs)
    46  				}
    47  
    48  				// BUG(stevvooe): Cobra stringslice actually doesn't correctly
    49  				// handle comma separated values, so multiple flags aren't
    50  				// really supported. We'll have to replace StringSlice with a
    51  				// type that doesn't use the csv parser. This is good enough
    52  				// for now.
    53  
    54  				flags := strings.Split(parts[1], ",")
    55  				var opts api.Mount_TmpfsOptions
    56  				for _, flag := range flags {
    57  					switch {
    58  					case strings.HasPrefix(flag, "size="):
    59  						meat := strings.TrimPrefix(flag, "size=")
    60  
    61  						// try to parse this into bytes
    62  						i, err := strconv.ParseInt(meat, 10, 64)
    63  						if err != nil {
    64  							// remove suffix and try again
    65  							suffix := meat[len(meat)-1]
    66  							meat = meat[:len(meat)-1]
    67  							var multiplier int64
    68  							switch suffix {
    69  							case 'g':
    70  								multiplier = 1 << 30
    71  							case 'm':
    72  								multiplier = 1 << 20
    73  							case 'k':
    74  								multiplier = 1 << 10
    75  							default:
    76  								return errors.Errorf("invalid size format: %v", flag)
    77  							}
    78  
    79  							// reparse the meat
    80  							var err error
    81  							i, err = strconv.ParseInt(meat, 10, 64)
    82  							if err != nil {
    83  								return err
    84  							}
    85  
    86  							i *= multiplier
    87  						}
    88  						opts.SizeBytes = i
    89  					case strings.HasPrefix(flag, "mode="):
    90  						meat := strings.TrimPrefix(flag, "mode=")
    91  						i, err := strconv.ParseInt(meat, 8, 32)
    92  						if err != nil {
    93  							return err
    94  						}
    95  						opts.Mode = os.FileMode(i)
    96  					case flag == "ro":
    97  						m.ReadOnly = true
    98  					case flag == "rw":
    99  						m.ReadOnly = false
   100  					case flag == "exec":
   101  						opts.Options = "exec"
   102  					case flag == "noexec":
   103  						opts.Options = "noexec"
   104  					default:
   105  						return errors.New("unsupported flag")
   106  					}
   107  				}
   108  				m.TmpfsOptions = &opts
   109  			}
   110  
   111  			container.Mounts = append(container.Mounts, m)
   112  		}
   113  	}
   114  
   115  	return nil
   116  }