gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/runsc/boot/gofer_conf.go (about)

     1  // Copyright 2023 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package boot
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"gvisor.dev/gvisor/pkg/sentry/fsimpl/erofs"
    22  )
    23  
    24  // GoferMountConfUpperType describes how upper layer is configured for the gofer mount.
    25  type GoferMountConfUpperType byte
    26  
    27  const (
    28  	// NoOverlay indicates that this gofer mount has no upper layer. In this case,
    29  	// this gofer mount must have a lower layer (i.e. lower != NoneLower).
    30  	NoOverlay GoferMountConfUpperType = iota
    31  
    32  	// MemoryOverlay indicates that this gofer mount should be overlaid with a
    33  	// tmpfs backed by application memory.
    34  	MemoryOverlay
    35  
    36  	// SelfOverlay indicates that this gofer mount should be overlaid with a
    37  	// tmpfs backed by a host file in the mount's source directory.
    38  	SelfOverlay
    39  
    40  	// AnonOverlay indicates that this gofer mount should be overlaid with a
    41  	// tmpfs backed by a host file in an anonymous directory.
    42  	AnonOverlay
    43  
    44  	// UpperMax indicates the number of the valid upper layer types.
    45  	UpperMax
    46  )
    47  
    48  // String returns a human-readable string representing the upper layer type.
    49  func (u GoferMountConfUpperType) String() string {
    50  	switch u {
    51  	case NoOverlay:
    52  		return "none"
    53  	case MemoryOverlay:
    54  		return "memory"
    55  	case SelfOverlay:
    56  		return "self"
    57  	case AnonOverlay:
    58  		return "anon"
    59  	}
    60  	panic(fmt.Sprintf("Invalid gofer mount config upper layer type: %d", u))
    61  }
    62  
    63  // Set sets the value. Set(String()) should be idempotent.
    64  func (u *GoferMountConfUpperType) Set(v string) error {
    65  	switch v {
    66  	case "none":
    67  		*u = NoOverlay
    68  	case "memory":
    69  		*u = MemoryOverlay
    70  	case "self":
    71  		*u = SelfOverlay
    72  	case "anon":
    73  		*u = AnonOverlay
    74  	default:
    75  		return fmt.Errorf("invalid gofer mount config upper layer type: %s", v)
    76  	}
    77  	return nil
    78  }
    79  
    80  // GoferMountConfLowerType describes how lower layer is configured for the gofer mount.
    81  type GoferMountConfLowerType byte
    82  
    83  const (
    84  	// NoneLower indicates that this gofer mount has no lower layer.
    85  	NoneLower GoferMountConfLowerType = iota
    86  
    87  	// Lisafs indicates that this gofer mount has a LISAFS lower layer.
    88  	Lisafs
    89  
    90  	// Erofs indicates that this gofer mount has an EROFS lower layer.
    91  	Erofs
    92  
    93  	// LowerMax indicates the number of the valid lower layer types.
    94  	LowerMax
    95  )
    96  
    97  // String returns a human-readable string representing the lower layer type.
    98  func (l GoferMountConfLowerType) String() string {
    99  	switch l {
   100  	case NoneLower:
   101  		return "none"
   102  	case Lisafs:
   103  		return "lisafs"
   104  	case Erofs:
   105  		return erofs.Name
   106  	}
   107  	panic(fmt.Sprintf("Invalid gofer mount config lower layer type: %d", l))
   108  }
   109  
   110  // Set sets the value. Set(String()) should be idempotent.
   111  func (l *GoferMountConfLowerType) Set(v string) error {
   112  	switch v {
   113  	case "none":
   114  		*l = NoneLower
   115  	case "lisafs":
   116  		*l = Lisafs
   117  	case erofs.Name:
   118  		*l = Erofs
   119  	default:
   120  		return fmt.Errorf("invalid gofer mount config lower layer type: %s", v)
   121  	}
   122  	return nil
   123  }
   124  
   125  // GoferMountConf describes how a gofer mount is configured in the sandbox.
   126  type GoferMountConf struct {
   127  	Upper GoferMountConfUpperType `json:"upper"`
   128  	Lower GoferMountConfLowerType `json:"lower"`
   129  }
   130  
   131  // String returns a human-readable string representing the gofer mount config.
   132  func (g GoferMountConf) String() string {
   133  	return fmt.Sprintf("%s:%s", g.Lower, g.Upper)
   134  }
   135  
   136  // Set sets the value. Set(String()) should be idempotent.
   137  func (g *GoferMountConf) Set(v string) error {
   138  	parts := strings.Split(v, ":")
   139  	if len(parts) != 2 {
   140  		return fmt.Errorf("invalid gofer mount config format: %q", v)
   141  	}
   142  	if err := g.Lower.Set(parts[0]); err != nil {
   143  		return err
   144  	}
   145  	if err := g.Upper.Set(parts[1]); err != nil {
   146  		return err
   147  	}
   148  	if !g.valid() {
   149  		return fmt.Errorf("invalid gofer mount config: %+v", g)
   150  	}
   151  	return nil
   152  }
   153  
   154  // IsFilestorePresent returns true if a filestore file was associated with this.
   155  func (g GoferMountConf) IsFilestorePresent() bool {
   156  	return g.Upper == SelfOverlay || g.Upper == AnonOverlay
   157  }
   158  
   159  // IsSelfBacked returns true if this mount is backed by a filestore in itself.
   160  func (g GoferMountConf) IsSelfBacked() bool {
   161  	return g.Upper == SelfOverlay
   162  }
   163  
   164  // ShouldUseOverlayfs returns true if an overlayfs should be applied.
   165  func (g GoferMountConf) ShouldUseOverlayfs() bool {
   166  	return g.Lower != NoneLower && g.Upper != NoOverlay
   167  }
   168  
   169  // ShouldUseTmpfs returns true if a tmpfs should be applied.
   170  func (g GoferMountConf) ShouldUseTmpfs() bool {
   171  	// g.valid() implies that g.Upper != NoOverlay.
   172  	return g.Lower == NoneLower
   173  }
   174  
   175  // ShouldUseLisafs returns true if a lisafs client/server should be set up.
   176  func (g GoferMountConf) ShouldUseLisafs() bool {
   177  	return g.Lower == Lisafs
   178  }
   179  
   180  // ShouldUseErofs returns true if an EROFS should be applied.
   181  func (g GoferMountConf) ShouldUseErofs() bool {
   182  	return g.Lower == Erofs
   183  }
   184  
   185  // valid returns true if this is a valid gofer mount config.
   186  func (g GoferMountConf) valid() bool {
   187  	return g.Lower < LowerMax && g.Upper < UpperMax && (g.Lower != NoneLower || g.Upper != NoOverlay)
   188  }
   189  
   190  // GoferMountConfFlags can be used with GoferMountConf flags that appear
   191  // multiple times.
   192  type GoferMountConfFlags []GoferMountConf
   193  
   194  // String implements flag.Value.
   195  func (g *GoferMountConfFlags) String() string {
   196  	confs := make([]string, 0, len(*g))
   197  	for _, confVal := range *g {
   198  		confs = append(confs, confVal.String())
   199  	}
   200  	return strings.Join(confs, ",")
   201  }
   202  
   203  // Get implements flag.Value.
   204  func (g *GoferMountConfFlags) Get() any {
   205  	return g
   206  }
   207  
   208  // GetArray returns an array of mappings.
   209  func (g *GoferMountConfFlags) GetArray() []GoferMountConf {
   210  	return *g
   211  }
   212  
   213  // Set implements flag.Value and appends a gofer configuration from the command
   214  // line to the configs array. Set(String()) should be idempotent.
   215  func (g *GoferMountConfFlags) Set(s string) error {
   216  	confs := strings.Split(s, ",")
   217  	for _, conf := range confs {
   218  		var confVal GoferMountConf
   219  		if err := confVal.Set(conf); err != nil {
   220  			return fmt.Errorf("invalid GoferMountConf value (%s): %v", conf, err)
   221  		}
   222  		*g = append(*g, confVal)
   223  	}
   224  	return nil
   225  }