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

     1  // Copyright 2021 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  	"path/filepath"
    19  	"regexp"
    20  	"slices"
    21  	"testing"
    22  
    23  	specs "github.com/opencontainers/runtime-spec/specs-go"
    24  	"gvisor.dev/gvisor/runsc/config"
    25  )
    26  
    27  func TestGetMountAccessType(t *testing.T) {
    28  	const source = "foo"
    29  	for _, tst := range []struct {
    30  		name        string
    31  		annotations map[string]string
    32  		want        config.FileAccessType
    33  	}{
    34  		{
    35  			name: "container=exclusive",
    36  			annotations: map[string]string{
    37  				MountPrefix + "mount1.source": source,
    38  				MountPrefix + "mount1.type":   "bind",
    39  				MountPrefix + "mount1.share":  "container",
    40  			},
    41  			want: config.FileAccessExclusive,
    42  		},
    43  		{
    44  			name: "pod=shared",
    45  			annotations: map[string]string{
    46  				MountPrefix + "mount1.source": source,
    47  				MountPrefix + "mount1.type":   "bind",
    48  				MountPrefix + "mount1.share":  "pod",
    49  			},
    50  			want: config.FileAccessShared,
    51  		},
    52  		{
    53  			name: "share=shared",
    54  			annotations: map[string]string{
    55  				MountPrefix + "mount1.source": source,
    56  				MountPrefix + "mount1.type":   "bind",
    57  				MountPrefix + "mount1.share":  "shared",
    58  			},
    59  			want: config.FileAccessShared,
    60  		},
    61  		{
    62  			name: "default=shared",
    63  			annotations: map[string]string{
    64  				MountPrefix + "mount1.source": source + "mismatch",
    65  				MountPrefix + "mount1.type":   "bind",
    66  				MountPrefix + "mount1.share":  "container",
    67  			},
    68  			want: config.FileAccessShared,
    69  		},
    70  		{
    71  			name: "tmpfs+container=exclusive",
    72  			annotations: map[string]string{
    73  				MountPrefix + "mount1.source": source,
    74  				MountPrefix + "mount1.type":   "tmpfs",
    75  				MountPrefix + "mount1.share":  "container",
    76  			},
    77  			want: config.FileAccessExclusive,
    78  		},
    79  		{
    80  			name: "tmpfs+pod=exclusive",
    81  			annotations: map[string]string{
    82  				MountPrefix + "mount1.source": source,
    83  				MountPrefix + "mount1.type":   "tmpfs",
    84  				MountPrefix + "mount1.share":  "pod",
    85  			},
    86  			want: config.FileAccessExclusive,
    87  		},
    88  	} {
    89  		t.Run(tst.name, func(t *testing.T) {
    90  			spec := &specs.Spec{Annotations: tst.annotations}
    91  			podHints, err := NewPodMountHints(spec)
    92  			if err != nil {
    93  				t.Fatalf("newPodMountHints failed: %v", err)
    94  			}
    95  			conf := &config.Config{FileAccessMounts: config.FileAccessShared}
    96  			if got := getMountAccessType(conf, podHints.FindMount(source)); got != tst.want {
    97  				t.Errorf("getMountAccessType(), got: %v, want: %v", got, tst.want)
    98  			}
    99  		})
   100  	}
   101  }
   102  
   103  func TestTPUPath(t *testing.T) {
   104  	for _, tst := range []struct {
   105  		name     string
   106  		pathGlob string
   107  		path     string
   108  		submatch []string
   109  	}{
   110  		{
   111  			name:     "TPUv4PCIPathMatch",
   112  			pathGlob: pciPathGlobTPUv4,
   113  			path:     "/sys/devices/pci0000:00/0000:00:01.0/accel/accel16",
   114  			submatch: []string{"/sys/devices/pci0000:00/0000:00:01.0/accel/accel16", "16"},
   115  		},
   116  		{
   117  			name:     "TPUv4PCIPathNoMatch",
   118  			pathGlob: pciPathGlobTPUv4,
   119  			path:     "/sys/devices/pci0000:00/0000:00:01.0/accel/123",
   120  			submatch: nil,
   121  		},
   122  		{
   123  			name:     "TPUv5PCIPathMatch",
   124  			pathGlob: pciPathGlobTPUv5,
   125  			path:     "/sys/devices/pci0000:00/0000:00:05.0/vfio-dev/vfio20",
   126  			submatch: []string{"/sys/devices/pci0000:00/0000:00:05.0/vfio-dev/vfio20", "20"},
   127  		},
   128  		{
   129  			name:     "TPUv5PCIPathNoMatch",
   130  			pathGlob: pciPathGlobTPUv5,
   131  			path:     "/sys/devices/pci0000:00/0000:00:05.0/vfio/vfio20",
   132  			submatch: nil,
   133  		},
   134  	} {
   135  		t.Run(tst.name, func(t *testing.T) {
   136  			if _, err := filepath.Glob(tst.pathGlob); err != nil {
   137  				t.Errorf("Malformed path glob: %v", err)
   138  			}
   139  			pathRegex := regexp.MustCompile(pathGlobToPathRegex[tst.pathGlob])
   140  			if submatch := pathRegex.FindStringSubmatch(tst.path); !slices.Equal(submatch, tst.submatch) {
   141  				t.Errorf("Match TPU PCI path, got: %v, want: %v", submatch, tst.submatch)
   142  			}
   143  		})
   144  	}
   145  }