github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/shim/utils/volumes_test.go (about)

     1  // Copyright 2019 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  //     https://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 utils
    16  
    17  import (
    18  	"fmt"
    19  	"io/ioutil"
    20  	"os"
    21  	"reflect"
    22  	"testing"
    23  
    24  	specs "github.com/opencontainers/runtime-spec/specs-go"
    25  )
    26  
    27  func TestUpdateVolumeAnnotations(t *testing.T) {
    28  	dir, err := ioutil.TempDir("", "test-update-volume-annotations")
    29  	if err != nil {
    30  		t.Fatalf("create tempdir: %v", err)
    31  	}
    32  	defer os.RemoveAll(dir)
    33  	kubeletPodsDir = dir
    34  
    35  	const (
    36  		testPodUID           = "testuid"
    37  		testVolumeName       = "testvolume"
    38  		testLogDirPath       = "/var/log/pods/testns_testname_" + testPodUID
    39  		testLegacyLogDirPath = "/var/log/pods/" + testPodUID
    40  	)
    41  	testVolumePath := fmt.Sprintf("%s/%s/volumes/kubernetes.io~empty-dir/%s", dir, testPodUID, testVolumeName)
    42  
    43  	if err := os.MkdirAll(testVolumePath, 0755); err != nil {
    44  		t.Fatalf("Create test volume: %v", err)
    45  	}
    46  
    47  	for _, test := range []struct {
    48  		name         string
    49  		spec         *specs.Spec
    50  		expected     *specs.Spec
    51  		expectErr    bool
    52  		expectUpdate bool
    53  	}{
    54  		{
    55  			name: "volume annotations for sandbox",
    56  			spec: &specs.Spec{
    57  				Annotations: map[string]string{
    58  					sandboxLogDirAnnotation:                       testLogDirPath,
    59  					ContainerTypeAnnotation:                       containerTypeSandbox,
    60  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
    61  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
    62  					volumeKeyPrefix + testVolumeName + ".options": "ro",
    63  				},
    64  			},
    65  			expected: &specs.Spec{
    66  				Annotations: map[string]string{
    67  					sandboxLogDirAnnotation:                       testLogDirPath,
    68  					ContainerTypeAnnotation:                       containerTypeSandbox,
    69  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
    70  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
    71  					volumeKeyPrefix + testVolumeName + ".options": "ro",
    72  					volumeKeyPrefix + testVolumeName + ".source":  testVolumePath,
    73  				},
    74  			},
    75  			expectUpdate: true,
    76  		},
    77  		{
    78  			name: "volume annotations for sandbox with legacy log path",
    79  			spec: &specs.Spec{
    80  				Annotations: map[string]string{
    81  					sandboxLogDirAnnotation:                       testLegacyLogDirPath,
    82  					ContainerTypeAnnotation:                       containerTypeSandbox,
    83  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
    84  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
    85  					volumeKeyPrefix + testVolumeName + ".options": "ro",
    86  				},
    87  			},
    88  			expected: &specs.Spec{
    89  				Annotations: map[string]string{
    90  					sandboxLogDirAnnotation:                       testLegacyLogDirPath,
    91  					ContainerTypeAnnotation:                       containerTypeSandbox,
    92  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
    93  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
    94  					volumeKeyPrefix + testVolumeName + ".options": "ro",
    95  					volumeKeyPrefix + testVolumeName + ".source":  testVolumePath,
    96  				},
    97  			},
    98  			expectUpdate: true,
    99  		},
   100  		{
   101  			name: "tmpfs: volume annotations for container",
   102  			spec: &specs.Spec{
   103  				Mounts: []specs.Mount{
   104  					{
   105  						Destination: "/test",
   106  						Type:        "bind",
   107  						Source:      testVolumePath,
   108  						Options:     []string{"ro"},
   109  					},
   110  					{
   111  						Destination: "/random",
   112  						Type:        "bind",
   113  						Source:      "/random",
   114  						Options:     []string{"ro"},
   115  					},
   116  				},
   117  				Annotations: map[string]string{
   118  					ContainerTypeAnnotation:                       ContainerTypeContainer,
   119  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
   120  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
   121  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   122  				},
   123  			},
   124  			expected: &specs.Spec{
   125  				Mounts: []specs.Mount{
   126  					{
   127  						Destination: "/test",
   128  						Type:        "tmpfs",
   129  						Source:      testVolumePath,
   130  						Options:     []string{"ro"},
   131  					},
   132  					{
   133  						Destination: "/random",
   134  						Type:        "bind",
   135  						Source:      "/random",
   136  						Options:     []string{"ro"},
   137  					},
   138  				},
   139  				Annotations: map[string]string{
   140  					ContainerTypeAnnotation:                       ContainerTypeContainer,
   141  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
   142  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
   143  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   144  				},
   145  			},
   146  			expectUpdate: true,
   147  		},
   148  		{
   149  			name: "bind: volume annotations for container",
   150  			spec: &specs.Spec{
   151  				Mounts: []specs.Mount{
   152  					{
   153  						Destination: "/test",
   154  						Type:        "bind",
   155  						Source:      testVolumePath,
   156  						Options:     []string{"ro"},
   157  					},
   158  				},
   159  				Annotations: map[string]string{
   160  					ContainerTypeAnnotation:                       ContainerTypeContainer,
   161  					volumeKeyPrefix + testVolumeName + ".share":   "container",
   162  					volumeKeyPrefix + testVolumeName + ".type":    "bind",
   163  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   164  				},
   165  			},
   166  			expected: &specs.Spec{
   167  				Mounts: []specs.Mount{
   168  					{
   169  						Destination: "/test",
   170  						Type:        "bind",
   171  						Source:      testVolumePath,
   172  						Options:     []string{"ro"},
   173  					},
   174  				},
   175  				Annotations: map[string]string{
   176  					ContainerTypeAnnotation:                       ContainerTypeContainer,
   177  					volumeKeyPrefix + testVolumeName + ".share":   "container",
   178  					volumeKeyPrefix + testVolumeName + ".type":    "bind",
   179  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   180  				},
   181  			},
   182  			expectUpdate: true,
   183  		},
   184  		{
   185  			name: "should not return error without pod log directory",
   186  			spec: &specs.Spec{
   187  				Annotations: map[string]string{
   188  					ContainerTypeAnnotation:                       containerTypeSandbox,
   189  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
   190  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
   191  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   192  				},
   193  			},
   194  			expected: &specs.Spec{
   195  				Annotations: map[string]string{
   196  					ContainerTypeAnnotation:                       containerTypeSandbox,
   197  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
   198  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
   199  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   200  				},
   201  			},
   202  		},
   203  		{
   204  			name: "should return error if volume path does not exist",
   205  			spec: &specs.Spec{
   206  				Annotations: map[string]string{
   207  					sandboxLogDirAnnotation:              testLogDirPath,
   208  					ContainerTypeAnnotation:              containerTypeSandbox,
   209  					volumeKeyPrefix + "notexist.share":   "pod",
   210  					volumeKeyPrefix + "notexist.type":    "tmpfs",
   211  					volumeKeyPrefix + "notexist.options": "ro",
   212  				},
   213  			},
   214  			expectErr: true,
   215  		},
   216  		{
   217  			name: "no volume annotations for sandbox",
   218  			spec: &specs.Spec{
   219  				Annotations: map[string]string{
   220  					sandboxLogDirAnnotation: testLogDirPath,
   221  					ContainerTypeAnnotation: containerTypeSandbox,
   222  				},
   223  			},
   224  			expected: &specs.Spec{
   225  				Annotations: map[string]string{
   226  					sandboxLogDirAnnotation: testLogDirPath,
   227  					ContainerTypeAnnotation: containerTypeSandbox,
   228  				},
   229  			},
   230  		},
   231  		{
   232  			name: "no volume annotations for container",
   233  			spec: &specs.Spec{
   234  				Mounts: []specs.Mount{
   235  					{
   236  						Destination: "/test",
   237  						Type:        "bind",
   238  						Source:      "/test",
   239  						Options:     []string{"ro"},
   240  					},
   241  					{
   242  						Destination: "/random",
   243  						Type:        "bind",
   244  						Source:      "/random",
   245  						Options:     []string{"ro"},
   246  					},
   247  				},
   248  				Annotations: map[string]string{
   249  					ContainerTypeAnnotation: ContainerTypeContainer,
   250  				},
   251  			},
   252  			expected: &specs.Spec{
   253  				Mounts: []specs.Mount{
   254  					{
   255  						Destination: "/test",
   256  						Type:        "bind",
   257  						Source:      "/test",
   258  						Options:     []string{"ro"},
   259  					},
   260  					{
   261  						Destination: "/random",
   262  						Type:        "bind",
   263  						Source:      "/random",
   264  						Options:     []string{"ro"},
   265  					},
   266  				},
   267  				Annotations: map[string]string{
   268  					ContainerTypeAnnotation: ContainerTypeContainer,
   269  				},
   270  			},
   271  		},
   272  		{
   273  			name: "bind options removed",
   274  			spec: &specs.Spec{
   275  				Annotations: map[string]string{
   276  					ContainerTypeAnnotation:                       ContainerTypeContainer,
   277  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
   278  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
   279  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   280  					volumeKeyPrefix + testVolumeName + ".source":  testVolumePath,
   281  				},
   282  				Mounts: []specs.Mount{
   283  					{
   284  						Destination: "/dst",
   285  						Type:        "bind",
   286  						Source:      testVolumePath,
   287  						Options:     []string{"ro", "bind", "rbind"},
   288  					},
   289  				},
   290  			},
   291  			expected: &specs.Spec{
   292  				Annotations: map[string]string{
   293  					ContainerTypeAnnotation:                       ContainerTypeContainer,
   294  					volumeKeyPrefix + testVolumeName + ".share":   "pod",
   295  					volumeKeyPrefix + testVolumeName + ".type":    "tmpfs",
   296  					volumeKeyPrefix + testVolumeName + ".options": "ro",
   297  					volumeKeyPrefix + testVolumeName + ".source":  testVolumePath,
   298  				},
   299  				Mounts: []specs.Mount{
   300  					{
   301  						Destination: "/dst",
   302  						Type:        "tmpfs",
   303  						Source:      testVolumePath,
   304  						Options:     []string{"ro"},
   305  					},
   306  				},
   307  			},
   308  			expectUpdate: true,
   309  		},
   310  	} {
   311  		t.Run(test.name, func(t *testing.T) {
   312  			updated, err := UpdateVolumeAnnotations(test.spec)
   313  			if test.expectErr {
   314  				if err == nil {
   315  					t.Fatal("Expected error, but got nil")
   316  				}
   317  				return
   318  			}
   319  			if err != nil {
   320  				t.Fatalf("Unexpected error: %v", err)
   321  			}
   322  			if !reflect.DeepEqual(test.expected, test.spec) {
   323  				t.Fatalf("Expected %+v, got %+v", test.expected, test.spec)
   324  			}
   325  			if test.expectUpdate != updated {
   326  				t.Errorf("Expected %v, got %v", test.expected, updated)
   327  			}
   328  		})
   329  	}
   330  }