github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/stage1/init/common/pod_test.go (about)

     1  // Copyright 2014 The rkt 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 common
    16  
    17  import (
    18  	"io/ioutil"
    19  	"os"
    20  	"path/filepath"
    21  	"regexp"
    22  	"testing"
    23  
    24  	stage1commontypes "github.com/rkt/rkt/stage1/common/types"
    25  
    26  	"github.com/appc/spec/schema"
    27  	"github.com/appc/spec/schema/types"
    28  )
    29  
    30  const tstprefix = "pod-test"
    31  
    32  func TestQuoteExec(t *testing.T) {
    33  	tests := []struct {
    34  		input  []string
    35  		output string
    36  	}{
    37  		{
    38  			input:  []string{`path`, `"arg1"`, `"'arg2'"`, `'arg3'`},
    39  			output: `"path" "\"arg1\"" "\"\'arg2\'\"" "\'arg3\'"`,
    40  		}, {
    41  			input:  []string{`path`},
    42  			output: `"path"`,
    43  		}, {
    44  			input:  []string{`path`, ``, `arg2`},
    45  			output: `"path" "" "arg2"`,
    46  		}, {
    47  			input:  []string{`path`, `"foo\bar"`, `\`},
    48  			output: `"path" "\"foo\\bar\"" "\\"`,
    49  		}, {
    50  			input:  []string{`path with spaces`, `"foo\bar"`, `\`},
    51  			output: `"path with spaces" "\"foo\\bar\"" "\\"`,
    52  		}, {
    53  			input:  []string{`path with "quo't'es" and \slashes`, `"arg"`, `\`},
    54  			output: `"path with \"quo\'t\'es\" and \\slashes" "\"arg\"" "\\"`,
    55  		}, {
    56  			input:  []string{`$path$`, `$argument`},
    57  			output: `"$path$" "$$argument"`,
    58  		}, {
    59  			input:  []string{`%path%`, `%argument`},
    60  			output: `"%path%" "%%argument"`,
    61  		}, {
    62  			input:  []string{`path`, `Args\nwith\nnewlines`},
    63  			output: `"path" "Args\\nwith\\nnewlines"`,
    64  		}, {
    65  			input:  []string{`path`, "Args\nwith\nnewlines"},
    66  			output: `"path" "Args\nwith\nnewlines"`,
    67  		},
    68  	}
    69  
    70  	for i, tt := range tests {
    71  		o := quoteExec(tt.input)
    72  		if o != tt.output {
    73  			t.Errorf("#%d: expected `%v` got `%v`", i, tt.output, o)
    74  		}
    75  	}
    76  }
    77  
    78  var (
    79  	falseVar = false
    80  	trueVar  = true
    81  )
    82  
    83  // TestAppToNspawnArgsOverridesImageManifestReadOnly tests
    84  // that the ImageManifest's `readOnly` volume setting will be
    85  // overrided by PodManifest.
    86  func Disabled_TestAppToNspawnArgsOverridesImageManifestReadOnly(t *testing.T) {
    87  	tests := []struct {
    88  		imageManifestVolumeReadOnly bool
    89  		podManifestVolumeReadOnly   *bool
    90  		expectReadOnly              bool
    91  	}{
    92  		{
    93  			false,
    94  			nil,
    95  			false,
    96  		},
    97  		{
    98  			false,
    99  			&falseVar,
   100  			false,
   101  		},
   102  		{
   103  			false,
   104  			&trueVar,
   105  			true,
   106  		},
   107  		{
   108  			true,
   109  			nil,
   110  			true,
   111  		},
   112  		{
   113  			true,
   114  			&falseVar,
   115  			false,
   116  		},
   117  		{
   118  			true,
   119  			&trueVar,
   120  			true,
   121  		},
   122  	}
   123  
   124  	for i, tt := range tests {
   125  		podManifest := &schema.PodManifest{
   126  			Volumes: []types.Volume{
   127  				{
   128  					Name:     *types.MustACName("foo-mount"),
   129  					Kind:     "host",
   130  					Source:   "/host/foo",
   131  					ReadOnly: tt.podManifestVolumeReadOnly,
   132  				},
   133  			},
   134  		}
   135  		appManifest := &schema.RuntimeApp{
   136  			Mounts: []schema.Mount{
   137  				{
   138  					Volume: *types.MustACName("foo-mount"),
   139  					Path:   "/app/foo",
   140  				},
   141  			},
   142  			App: &types.App{
   143  				Exec:  []string{"/bin/foo"},
   144  				User:  "0",
   145  				Group: "0",
   146  				MountPoints: []types.MountPoint{
   147  					{
   148  						Name:     *types.MustACName("foo-mount"),
   149  						Path:     "/app/foo",
   150  						ReadOnly: tt.imageManifestVolumeReadOnly,
   151  					},
   152  				},
   153  			},
   154  		}
   155  
   156  		tmpDir, err := ioutil.TempDir("", tstprefix)
   157  		if err != nil {
   158  			t.Errorf("error creating tempdir: %v", err)
   159  			continue
   160  		}
   161  		defer os.RemoveAll(tmpDir)
   162  
   163  		if err := os.MkdirAll(filepath.Join(tmpDir, "/stage1/rootfs/opt/stage2/rootfs"), 0755); err != nil {
   164  			t.Errorf("error stage2 rootfs in tmpdir: %v", err)
   165  			continue
   166  		}
   167  
   168  		p := &stage1commontypes.Pod{Manifest: podManifest, Root: tmpDir}
   169  		output, err := appToNspawnArgs(p, appManifest)
   170  		if err != nil {
   171  			t.Errorf("#%d: unexpected error: `%v`", i, err)
   172  		}
   173  
   174  		if ro := hasBindROArg(output); ro != tt.expectReadOnly {
   175  			t.Errorf("#%d: expected: readOnly: %v, saw: %v \nOutput:\n%v", i, tt.expectReadOnly, ro, output)
   176  		}
   177  	}
   178  }
   179  
   180  func hasBindROArg(output []string) bool {
   181  	roRegexp := regexp.MustCompile("^--bind-ro=/host/foo:.*/app/foo(:rbind)?$")
   182  	for i := len(output) - 1; i >= 0; i-- {
   183  		if roRegexp.MatchString(output[i]) {
   184  			return true
   185  		}
   186  	}
   187  	return false
   188  }
   189  
   190  func Disabled_TestAppToNspawnArgsRecursive(t *testing.T) {
   191  	tests := []struct {
   192  		podManifestVolumeRecursive *bool
   193  		expectRecursive            bool
   194  	}{
   195  		{
   196  			nil,
   197  			true,
   198  		},
   199  		{
   200  			&trueVar,
   201  			true,
   202  		},
   203  		{
   204  			&falseVar,
   205  			false,
   206  		},
   207  	}
   208  
   209  	for i, tt := range tests {
   210  		podManifest := &schema.PodManifest{
   211  			Volumes: []types.Volume{
   212  				{
   213  					Name:      *types.MustACName("foo-mount"),
   214  					Kind:      "host",
   215  					Source:    "/host/foo",
   216  					Recursive: tt.podManifestVolumeRecursive,
   217  				},
   218  			},
   219  		}
   220  		appManifest := &schema.RuntimeApp{
   221  			Mounts: []schema.Mount{
   222  				{
   223  					Volume: *types.MustACName("foo-mount"),
   224  					Path:   "/app/foo",
   225  				},
   226  			},
   227  			App: &types.App{
   228  				Exec:  []string{"/bin/foo"},
   229  				User:  "0",
   230  				Group: "0",
   231  				MountPoints: []types.MountPoint{
   232  					{
   233  						Name: *types.MustACName("foo-mount"),
   234  						Path: "/app/foo",
   235  					},
   236  				},
   237  			},
   238  		}
   239  
   240  		tmpDir, err := ioutil.TempDir("", tstprefix)
   241  		if err != nil {
   242  			t.Errorf("error creating tempdir: %v", err)
   243  			continue
   244  		}
   245  		defer os.RemoveAll(tmpDir)
   246  
   247  		if err := os.MkdirAll(filepath.Join(tmpDir, "/stage1/rootfs/opt/stage2/rootfs"), 0755); err != nil {
   248  			t.Errorf("error stage2 rootfs in tmpdir: %v", err)
   249  			continue
   250  		}
   251  
   252  		p := &stage1commontypes.Pod{Manifest: podManifest, Root: tmpDir}
   253  		output, err := appToNspawnArgs(p, appManifest)
   254  		if err != nil {
   255  			t.Errorf("#%d: unexpected error: `%v`", i, err)
   256  		}
   257  		if rbind := hasRbindArg(output); rbind != tt.expectRecursive {
   258  			t.Errorf("#%d: expected: recursive: %v, saw: %v \nOutput:\n%v", i, tt.expectRecursive, rbind, output)
   259  		}
   260  	}
   261  }
   262  
   263  func hasRbindArg(output []string) bool {
   264  	rbindRegexp := regexp.MustCompile("^--bind(-ro)?=/host/foo:.*/app/foo:rbind$")
   265  	for i := len(output) - 1; i >= 0; i-- {
   266  		if rbindRegexp.MatchString(output[i]) {
   267  			return true
   268  		}
   269  	}
   270  	return false
   271  }