Merge tag 'upstream/0.9.0+git20220423.g0105384'
Reinhard Tartler
2 years ago
0 | name: ci | |
1 | on: | |
2 | push: | |
3 | tags: | |
4 | - v* | |
5 | branches: | |
6 | - master | |
7 | - release-* | |
8 | pull_request: | |
9 | ||
10 | jobs: | |
11 | ||
12 | lint: | |
13 | runs-on: ubuntu-20.04 | |
14 | steps: | |
15 | - uses: actions/checkout@v2 | |
16 | - uses: golangci/golangci-lint-action@v2 | |
17 | with: | |
18 | version: v1.42 | |
19 | ||
20 | commit: | |
21 | runs-on: ubuntu-20.04 | |
22 | # Only check commits on pull requests. | |
23 | if: github.event_name == 'pull_request' | |
24 | steps: | |
25 | - name: get pr commits | |
26 | id: 'get-pr-commits' | |
27 | uses: tim-actions/get-pr-commits@v1.1.0 | |
28 | with: | |
29 | token: ${{ secrets.GITHUB_TOKEN }} | |
30 | ||
31 | - name: check subject line length | |
32 | uses: tim-actions/commit-message-checker-with-regex@v0.3.1 | |
33 | with: | |
34 | commits: ${{ steps.get-pr-commits.outputs.commits }} | |
35 | pattern: '^.{0,72}(\n.*)*$' | |
36 | error: 'Subject too long (max 72)' | |
37 | ||
38 | test: | |
39 | runs-on: ubuntu-20.04 | |
40 | strategy: | |
41 | fail-fast: false | |
42 | matrix: | |
43 | go-version: [1.16.x, 1.17.x] | |
44 | race: ["-race", ""] | |
45 | ||
46 | steps: | |
47 | - name: checkout | |
48 | uses: actions/checkout@v2 | |
49 | - name: install go ${{ matrix.go-version }} | |
50 | uses: actions/setup-go@v2 | |
51 | with: | |
52 | stable: '!contains(${{ matrix.go-version }}, "beta") && !contains(${{ matrix.go-version }}, "rc")' | |
53 | go-version: ${{ matrix.go-version }} | |
54 | - name: build | |
55 | run: make EXTRA_FLAGS="${{ matrix.race }}" | |
56 | - name: test | |
57 | run: make TESTFLAGS="${{ matrix.race }}" test |
0 | # Compiled Object files, Static and Dynamic libs (Shared Objects) | |
1 | *.o | |
2 | *.a | |
3 | *.so | |
4 | ||
5 | # Folders | |
6 | _obj | |
7 | _test | |
8 | rootfs | |
9 | ||
10 | # Architecture specific extensions/prefixes | |
11 | *.[568vq] | |
12 | [568vq].out | |
13 | ||
14 | *.cgo1.go | |
15 | *.cgo2.c | |
16 | _cgo_defun.c | |
17 | _cgo_gotypes.go | |
18 | _cgo_export.* | |
19 | ||
20 | _testmain.go | |
21 | ||
22 | *.exe | |
23 | *.test | |
24 | *.prof | |
25 | ||
26 | # Compiled binaries | |
27 | oci | |
28 | /oci-runtime-tool | |
29 | /runtimetest | |
30 | ||
31 | *.1 | |
32 | *.patch | |
33 | ||
34 | # Temporary symbol links | |
35 | Godeps/_workspace/src/github.com/opencontainers/runtime-tools |
0 | # For documentation, see https://golangci-lint.run/usage/configuration/ | |
1 | ||
2 | linters: | |
3 | disable: | |
4 | - errcheck |
0 | language: go | |
1 | go: | |
2 | - 1.10.x | |
3 | - 1.11.x | |
4 | ||
5 | sudo: false | |
6 | ||
7 | before_install: | |
8 | - mkdir --parents $GOPATH/src/golang.org/x | |
9 | && git clone --depth=1 https://go.googlesource.com/lint $GOPATH/src/golang.org/x/lint | |
10 | && go get golang.org/x/lint/golint | |
11 | - go get github.com/vbatts/git-validation | |
12 | ||
13 | install: true | |
14 | ||
15 | script: | |
16 | - git-validation -run DCO,short-subject -v -range ${TRAVIS_COMMIT_RANGE} | |
17 | - make | |
18 | - make test |
0 | { | |
1 | "ImportPath": "github.com/opencontainers/runtime-tools", | |
2 | "GoVersion": "go1.7", | |
3 | "GodepVersion": "v77", | |
4 | "Packages": [ | |
5 | "./..." | |
6 | ], | |
7 | "Deps": [ | |
8 | { | |
9 | "ImportPath": "github.com/blang/semver", | |
10 | "Comment": "v3.5.0", | |
11 | "Rev": "b38d23b8782a487059e8fc8773e9a5b228a77cb6" | |
12 | }, | |
13 | { | |
14 | "ImportPath": "github.com/davecgh/go-spew/spew", | |
15 | "Comment": "v1.1.0-7-ga476722", | |
16 | "Rev": "a476722483882dd40b8111f0eb64e1d7f43f56e4" | |
17 | }, | |
18 | { | |
19 | "ImportPath": "github.com/hashicorp/errwrap", | |
20 | "Rev": "7554cd9344cec97297fa6649b055a8c98c2a1e55" | |
21 | }, | |
22 | { | |
23 | "ImportPath": "github.com/hashicorp/go-multierror", | |
24 | "Comment": "v1.0.0", | |
25 | "Rev": "886a7fbe3eb1c874d46f623bfa70af45f425b3d1" | |
26 | }, | |
27 | { | |
28 | "ImportPath": "github.com/mndrix/tap-go", | |
29 | "Rev": "629fa407e90bbf3781e448e8e9b8931523ec823c" | |
30 | }, | |
31 | { | |
32 | "ImportPath": "github.com/mrunalp/fileutils", | |
33 | "Rev": "4ee1cc9a80582a0c75febdd5cfa779ee4361cbca" | |
34 | }, | |
35 | { | |
36 | "ImportPath": "github.com/opencontainers/runtime-spec/specs-go", | |
37 | "Comment": "v1.0.1-57-g1722abf", | |
38 | "Rev": "1722abf79c2f8f2675f47367f827c6491472cf27" | |
39 | }, | |
40 | { | |
41 | "ImportPath": "github.com/pmezard/go-difflib/difflib", | |
42 | "Comment": "v1.0.0", | |
43 | "Rev": "792786c7400a136282c1664665ae0a8db921c6c2" | |
44 | }, | |
45 | { | |
46 | "ImportPath": "github.com/opencontainers/selinux/go-selinux", | |
47 | "Comment": "v1.1-1-g2d93b96", | |
48 | "Rev": "2d93b96e1a01b26e3378c49a974d11f6783ec185" | |
49 | }, | |
50 | { | |
51 | "ImportPath": "github.com/opencontainers/selinux/go-selinux/label", | |
52 | "Comment": "v1.1-1-g2d93b96", | |
53 | "Rev": "2d93b96e1a01b26e3378c49a974d11f6783ec185" | |
54 | }, | |
55 | { | |
56 | "ImportPath": "github.com/satori/go.uuid", | |
57 | "Comment": "v1.1.0", | |
58 | "Rev": "879c5887cd475cd7864858769793b2ceb0d44feb" | |
59 | }, | |
60 | { | |
61 | "ImportPath": "github.com/sirupsen/logrus", | |
62 | "Comment": "1.0.2", | |
63 | "Rev": "a3f95b5c423586578a4e099b11a46c2479628cac" | |
64 | }, | |
65 | { | |
66 | "ImportPath": "github.com/stretchr/testify/assert", | |
67 | "Comment": "v1.1.4-71-g890a5c3", | |
68 | "Rev": "890a5c3458b43e6104ff5da8dfa139d013d77544" | |
69 | }, | |
70 | { | |
71 | "ImportPath": "github.com/syndtr/gocapability/capability", | |
72 | "Rev": "db04d3cc01c8b54962a58ec7e491717d06cfcc16" | |
73 | }, | |
74 | { | |
75 | "ImportPath": "github.com/urfave/cli", | |
76 | "Comment": "v1.19.1", | |
77 | "Rev": "0bdeddeeb0f650497d603c4ad7b20cfe685682f6" | |
78 | }, | |
79 | { | |
80 | "ImportPath": "github.com/xeipuuv/gojsonpointer", | |
81 | "Rev": "6fe8760cad3569743d51ddbb243b26f8456742dc" | |
82 | }, | |
83 | { | |
84 | "ImportPath": "github.com/xeipuuv/gojsonreference", | |
85 | "Rev": "e02fc20de94c78484cd5ffb007f8af96be030a45" | |
86 | }, | |
87 | { | |
88 | "ImportPath": "github.com/xeipuuv/gojsonschema", | |
89 | "Rev": "0c8571ac0ce161a5feb57375a9cdf148c98c0f70" | |
90 | }, | |
91 | { | |
92 | "ImportPath": "golang.org/x/sys/unix", | |
93 | "Rev": "f3918c30c5c2cb527c0b071a27c35120a6c0719a" | |
94 | } | |
95 | ] | |
96 | } |
0 | This directory tree is generated automatically by godep. | |
1 | ||
2 | Please do not edit. | |
3 | ||
4 | See https://github.com/tools/godep for more information. |
5 | 5 | Tianon Gravi <admwiggin@gmail.com> (@tianon) |
6 | 6 | Qiang Huang <h.huangqiang@huawei.com> (@hqhq) |
7 | 7 | Liang Chenye <liangchenye@huawei.com> (@liangchenye) |
8 | Ma Shimiao <mashimiao.fnst@cn.fujitsu.com> (@Mashimiao) | |
8 | Ma Shimiao <shimiao.ma@gmail.com> (@Mashimiao) | |
9 | 9 | Zhou Hao <zhouhao@cn.fujitsu.com> (@q384566678) |
10 | Kir Kolyshkin <kolyshkin@gmail.com> (@kolyshkin) |
0 | 0 | PREFIX ?= $(DESTDIR)/usr |
1 | 1 | BINDIR ?= $(DESTDIR)/usr/bin |
2 | TAP ?= tap | |
2 | TAPTOOL ?= tap | |
3 | 3 | |
4 | 4 | BUILDTAGS= |
5 | 5 | RUNTIME ?= runc |
6 | COMMIT=$(shell git rev-parse HEAD 2> /dev/null || true) | |
6 | COMMIT ?= $(shell git describe --dirty --long --always --tags 2> /dev/null) | |
7 | 7 | VERSION := ${shell cat ./VERSION} |
8 | BUILD_FLAGS := -tags "$(BUILDTAGS)" -ldflags "-X main.gitCommit=$(COMMIT) -X main.version=$(VERSION)" $(EXTRA_FLAGS) | |
9 | STATIC_BUILD_FLAGS := -tags "$(BUILDTAGS) netgo osusergo" -ldflags "-extldflags -static -X main.gitCommit=$(COMMIT) -X main.version=$(VERSION)" $(EXTRA_FLAGS) | |
8 | 10 | VALIDATION_TESTS ?= $(patsubst %.go,%.t,$(shell find ./validation/ -name *.go | grep -v util)) |
9 | 11 | |
10 | 12 | all: tool runtimetest validation-executables |
11 | 13 | |
12 | 14 | tool: |
13 | go build -tags "$(BUILDTAGS)" -ldflags "-X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o oci-runtime-tool ./cmd/oci-runtime-tool | |
15 | go build $(BUILD_FLAGS) -o oci-runtime-tool ./cmd/oci-runtime-tool | |
14 | 16 | |
15 | 17 | .PHONY: runtimetest |
16 | 18 | runtimetest: |
17 | CGO_ENABLED=0 go build -installsuffix cgo -tags "$(BUILDTAGS)" -ldflags "-X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o runtimetest ./cmd/runtimetest | |
19 | go build $(STATIC_BUILD_FLAGS) -o runtimetest ./cmd/runtimetest | |
18 | 20 | |
19 | 21 | .PHONY: man |
20 | 22 | man: |
47 | 49 | exit 1; \ |
48 | 50 | fi; \ |
49 | 51 | done |
50 | RUNTIME=$(RUNTIME) $(TAP) $(VALIDATION_TESTS) | |
52 | RUNTIME=$(RUNTIME) $(TAPTOOL) $(VALIDATION_TESTS) | |
51 | 53 | |
52 | 54 | .PHONY: validation-executables |
53 | 55 | validation-executables: $(VALIDATION_TESTS) |
55 | 57 | .PRECIOUS: $(VALIDATION_TESTS) |
56 | 58 | .PHONY: $(VALIDATION_TESTS) |
57 | 59 | $(VALIDATION_TESTS): %.t: %.go |
58 | go build -tags "$(BUILDTAGS)" ${TESTFLAGS} -o $@ $< | |
60 | go build $(BUILD_FLAGS) -o $@ $< | |
59 | 61 | |
60 | 62 | print-validation-tests: |
61 | 63 | @echo $(VALIDATION_TESTS) |
62 | 64 | |
63 | .PHONY: test .gofmt .govet .golint print-validation-tests | |
65 | .PHONY: test .govet print-validation-tests | |
64 | 66 | |
65 | 67 | PACKAGES = $(shell go list ./... | grep -v vendor) |
66 | test: .gofmt .govet .golint .gotest | |
67 | ||
68 | .gofmt: | |
69 | OUT=$$(go fmt $(PACKAGES)); if test -n "$${OUT}"; then echo "$${OUT}" && exit 1; fi | |
68 | test: .govet .gotest | |
70 | 69 | |
71 | 70 | .govet: |
72 | 71 | go vet -x $(PACKAGES) |
73 | 72 | |
74 | .golint: | |
75 | golint -set_exit_status $(PACKAGES) | |
76 | ||
77 | UTDIRS = ./filepath/... ./validate/... ./generate/... | |
78 | 73 | .gotest: |
79 | go test $(UTDIRS) | |
74 | go test $(TESTFLAGS) ./... |
112 | 112 | For example, with [`prove`][prove]: |
113 | 113 | |
114 | 114 | ```console |
115 | $ sudo make TAP='prove -Q -j9' RUNTIME=runc VALIDATION_TESTS=validation/pidfile/pidfile.t localvalidation | |
115 | $ sudo make TAPTOOL='prove -Q -j9' RUNTIME=runc VALIDATION_TESTS=validation/pidfile/pidfile.t localvalidation | |
116 | 116 | RUNTIME=runc prove -Q -j9 validation/pidfile.t |
117 | 117 | All tests successful. |
118 | 118 | Files=1, Tests=1, 0 wallclock secs ( 0.01 usr 0.01 sys + 0.03 cusr 0.03 csys = 0.08 CPU) |
16 | 16 | type CgroupV1 struct { |
17 | 17 | MountPath string |
18 | 18 | } |
19 | ||
20 | // HugePageSizeUnitList is a list of the units used by the linux kernel when | |
21 | // naming the HugePage control files. | |
22 | // https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt | |
23 | var HugePageSizeUnitList = []string{"B", "KB", "MB", "GB", "TB", "PB"} | |
19 | 24 | |
20 | 25 | func getDeviceID(id string) (int64, int64, error) { |
21 | 26 | elem := strings.Split(id, ":") |
392 | 397 | return int64(byteSize), nil |
393 | 398 | } |
394 | 399 | |
395 | func getHugePageSize() ([]string, error) { | |
400 | // GetHugePageSize returns a list of the supported Hugepage sizes on the same format as | |
401 | // opencontainers/runtime-spec (see pageSize): https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#huge-page-limits | |
402 | // eg. ["64KB", "2MB", "1GB"] | |
403 | func GetHugePageSize() ([]string, error) { | |
396 | 404 | var pageSizes []string |
397 | sizeList := []string{"B", "kB", "MB", "GB", "TB", "PB"} | |
398 | 405 | files, err := ioutil.ReadDir("/sys/kernel/mm/hugepages") |
399 | 406 | if err != nil { |
400 | 407 | return pageSizes, err |
408 | 415 | size := float64(pageSize) |
409 | 416 | base := float64(1024.0) |
410 | 417 | i := 0 |
411 | unitsLimit := len(sizeList) - 1 | |
418 | unitsLimit := len(HugePageSizeUnitList) - 1 | |
412 | 419 | for size >= base && i < unitsLimit { |
413 | 420 | size = size / base |
414 | 421 | i++ |
415 | 422 | } |
416 | sizeString := fmt.Sprintf("%g%s", size, sizeList[i]) | |
423 | sizeString := fmt.Sprintf("%g%s", size, HugePageSizeUnitList[i]) | |
417 | 424 | pageSizes = append(pageSizes, sizeString) |
418 | 425 | } |
419 | 426 | |
432 | 439 | } |
433 | 440 | } |
434 | 441 | lh := []rspec.LinuxHugepageLimit{} |
435 | pageSizes, err := getHugePageSize() | |
442 | pageSizes, err := GetHugePageSize() | |
436 | 443 | if err != nil { |
437 | 444 | return lh, err |
438 | 445 | } |
52 | 52 | cli.StringSliceFlag{Name: "linux-gidmappings", Usage: "add GIDMappings e.g HostID:ContainerID:Size"}, |
53 | 53 | cli.StringSliceFlag{Name: "linux-hugepage-limits-add", Usage: "add hugepage resource limits"}, |
54 | 54 | cli.StringSliceFlag{Name: "linux-hugepage-limits-drop", Usage: "drop hugepage resource limits"}, |
55 | cli.StringFlag{Name: "linux-intelRdt-closid", Usage: "RDT Class of Service, i.e. group under the resctrl pseudo-filesystem which to associate the container with"}, | |
55 | 56 | cli.StringFlag{Name: "linux-intelRdt-l3CacheSchema", Usage: "specifies the schema for L3 cache id and capacity bitmask"}, |
56 | 57 | cli.StringSliceFlag{Name: "linux-masked-paths", Usage: "specifies paths can not be read inside container"}, |
57 | 58 | cli.Uint64Flag{Name: "linux-mem-kernel-limit", Usage: "kernel memory limit (in bytes)"}, |
117 | 118 | cli.BoolFlag{Name: "process-rlimits-remove-all", Usage: "remove all resource limits for processes inside the container. "}, |
118 | 119 | cli.BoolFlag{Name: "process-terminal", Usage: "specifies whether a terminal is attached to the process"}, |
119 | 120 | cli.IntFlag{Name: "process-uid", Usage: "uid for the process"}, |
121 | cli.StringFlag{Name: "process-umask", Usage: "umask for the process"}, | |
120 | 122 | cli.StringFlag{Name: "process-username", Usage: "username for the process"}, |
121 | 123 | cli.StringFlag{Name: "rootfs-path", Value: "rootfs", Usage: "path to the root filesystem"}, |
122 | 124 | cli.BoolFlag{Name: "rootfs-readonly", Usage: "make the container's rootfs readonly"}, |
233 | 235 | g.SetProcessUsername(context.String("process-username")) |
234 | 236 | } |
235 | 237 | |
238 | if context.IsSet("process-umask") { | |
239 | g.SetProcessUmask(uint32(context.Int("process-umask"))) | |
240 | } | |
241 | ||
236 | 242 | if context.IsSet("process-gid") { |
237 | 243 | g.SetProcessGID(uint32(context.Int("process-gid"))) |
238 | 244 | } |
523 | 529 | if err := json.Unmarshal([]byte(hook), &tmpHook); err != nil { |
524 | 530 | return err |
525 | 531 | } |
526 | if err := g.AddPostStartHook(tmpHook); err != nil { | |
527 | return err | |
528 | } | |
532 | g.AddPostStartHook(tmpHook) | |
529 | 533 | } |
530 | 534 | } |
531 | 535 | |
540 | 544 | if err := json.Unmarshal([]byte(hook), &tmpHook); err != nil { |
541 | 545 | return err |
542 | 546 | } |
543 | if err := g.AddPostStopHook(tmpHook); err != nil { | |
544 | return err | |
545 | } | |
547 | g.AddPostStopHook(tmpHook) | |
546 | 548 | } |
547 | 549 | } |
548 | 550 | |
557 | 559 | if err := json.Unmarshal([]byte(hook), &tmpHook); err != nil { |
558 | 560 | return err |
559 | 561 | } |
560 | if err := g.AddPreStartHook(tmpHook); err != nil { | |
561 | return err | |
562 | } | |
562 | g.AddPreStartHook(tmpHook) | |
563 | 563 | } |
564 | 564 | } |
565 | 565 | |
738 | 738 | for _, v := range pageList { |
739 | 739 | g.DropLinuxResourcesHugepageLimit(v) |
740 | 740 | } |
741 | } | |
742 | ||
743 | if context.IsSet("linux-intelRdt-closid") { | |
744 | g.SetLinuxIntelRdtClosID(context.String("linux-intelRdt-closid")) | |
741 | 745 | } |
742 | 746 | |
743 | 747 | if context.IsSet("linux-intelRdt-l3CacheSchema") { |
158 | 158 | |
159 | 159 | uid := uint32(os.Getuid()) |
160 | 160 | c.harness.Ok(uid == spec.Process.User.UID, "has expected user ID") |
161 | c.harness.YAML(map[string]uint32{ | |
161 | _ = c.harness.YAML(map[string]uint32{ | |
162 | 162 | "expected": spec.Process.User.UID, |
163 | 163 | "actual": uid, |
164 | 164 | }) |
165 | 165 | |
166 | 166 | gid := uint32(os.Getgid()) |
167 | 167 | c.harness.Ok(gid == spec.Process.User.GID, "has expected group ID") |
168 | c.harness.YAML(map[string]uint32{ | |
168 | _ = c.harness.YAML(map[string]uint32{ | |
169 | 169 | "expected": spec.Process.User.GID, |
170 | 170 | "actual": gid, |
171 | 171 | }) |
201 | 201 | return err |
202 | 202 | } |
203 | 203 | c.harness.Ok(cwd == spec.Process.Cwd, "has expected working directory") |
204 | c.harness.YAML(map[string]string{ | |
204 | _ = c.harness.YAML(map[string]string{ | |
205 | 205 | "expected": spec.Process.Cwd, |
206 | 206 | "actual": cwd, |
207 | 207 | }) |
213 | 213 | expectedValue := parts[1] |
214 | 214 | actualValue := os.Getenv(key) |
215 | 215 | c.harness.Ok(expectedValue == actualValue, fmt.Sprintf("has expected environment variable %v", key)) |
216 | c.harness.YAML(map[string]string{ | |
216 | _ = c.harness.YAML(map[string]string{ | |
217 | 217 | "variable": key, |
218 | 218 | "expected": expectedValue, |
219 | 219 | "actual": actualValue, |
236 | 236 | |
237 | 237 | args := bytes.Split(bytes.Trim(cmdlineBytes, "\x00"), []byte("\x00")) |
238 | 238 | c.harness.Ok(len(args) == len(spec.Process.Args), "has expected number of process arguments") |
239 | c.harness.YAML(map[string]interface{}{ | |
239 | _ = c.harness.YAML(map[string]interface{}{ | |
240 | 240 | "expected": spec.Process.Args, |
241 | 241 | "actual": args, |
242 | 242 | }) |
243 | 243 | for i, a := range args { |
244 | 244 | c.harness.Ok(string(a) == spec.Process.Args[i], fmt.Sprintf("has expected process argument %d", i)) |
245 | c.harness.YAML(map[string]interface{}{ | |
245 | _ = c.harness.YAML(map[string]interface{}{ | |
246 | 246 | "index": i, |
247 | 247 | "expected": spec.Process.Args[i], |
248 | 248 | "actual": string(a), |
271 | 271 | last = capability.CAP_BLOCK_SUSPEND |
272 | 272 | } |
273 | 273 | |
274 | processCaps, err := capability.NewPid(0) | |
275 | if err != nil { | |
274 | processCaps, err := capability.NewPid2(0) | |
275 | if err != nil { | |
276 | return err | |
277 | } | |
278 | if err := processCaps.Load(); err != nil { | |
276 | 279 | return err |
277 | 280 | } |
278 | 281 | |
336 | 339 | return err |
337 | 340 | } |
338 | 341 | c.harness.Ok(spec.Hostname == hostname, "has expected hostname") |
339 | c.harness.YAML(map[string]string{ | |
342 | _ = c.harness.YAML(map[string]string{ | |
340 | 343 | "expected": spec.Hostname, |
341 | 344 | "actual": hostname, |
342 | 345 | }) |
364 | 367 | if err != nil { |
365 | 368 | return err |
366 | 369 | } |
367 | c.harness.YAML(map[string]interface{}{ | |
370 | _ = c.harness.YAML(map[string]interface{}{ | |
368 | 371 | "level": rfcError.Level.String(), |
369 | 372 | "reference": rfcError.Reference, |
370 | 373 | "type": r.Type, |
376 | 379 | if err != nil { |
377 | 380 | return err |
378 | 381 | } |
379 | c.harness.YAML(map[string]interface{}{ | |
382 | _ = c.harness.YAML(map[string]interface{}{ | |
380 | 383 | "level": rfcError.Level.String(), |
381 | 384 | "reference": rfcError.Reference, |
382 | 385 | "type": r.Type, |
401 | 404 | } |
402 | 405 | value := strings.TrimSpace(string(bytes.Trim(vBytes, "\x00"))) |
403 | 406 | c.harness.Ok(value == v, fmt.Sprintf("has expected sysctl %v", k)) |
404 | c.harness.YAML(map[string]string{ | |
407 | _ = c.harness.YAML(map[string]string{ | |
405 | 408 | "sysctl": k, |
406 | 409 | "expected": v, |
407 | 410 | "actual": value, |
521 | 524 | if err != nil { |
522 | 525 | return err |
523 | 526 | } |
524 | c.harness.YAML(map[string]string{ | |
527 | _ = c.harness.YAML(map[string]string{ | |
525 | 528 | "level": rfcError.Level.String(), |
526 | 529 | "reference": rfcError.Reference, |
527 | 530 | }) |
544 | 547 | } |
545 | 548 | defer os.RemoveAll(targetDir) |
546 | 549 | |
550 | mountErr := unix.Mount("/", targetDir, "", unix.MS_BIND|unix.MS_REC, "") | |
551 | if mountErr == unix.EPERM { //nolint:errcheck // unix errors are bare | |
552 | // This test needs CAP_SYS_ADMIN to perform mounts. | |
553 | // EPERM most probably means it was not granted. | |
554 | c.harness.Skip(1, "unable to perform mount (test requires CAP_SYS_ADMIN)") | |
555 | return nil | |
556 | } | |
557 | if err == nil { | |
558 | defer unix.Unmount(targetDir, unix.MNT_DETACH) //nolint:errcheck | |
559 | } | |
560 | ||
547 | 561 | switch spec.Linux.RootfsPropagation { |
548 | 562 | case "shared", "slave", "private": |
563 | if mountErr != nil { | |
564 | return fmt.Errorf("bind-mount / %s: %w", targetDir, err) | |
565 | } | |
549 | 566 | mountDir, err := ioutil.TempDir("/", "mount") |
550 | 567 | if err != nil { |
551 | 568 | return err |
564 | 581 | } |
565 | 582 | defer os.Remove(tmpfile.Name()) |
566 | 583 | |
567 | if err := unix.Mount("/", targetDir, "", unix.MS_BIND|unix.MS_REC, ""); err != nil { | |
568 | return err | |
569 | } | |
570 | defer unix.Unmount(targetDir, unix.MNT_DETACH) | |
571 | 584 | if err := unix.Mount(testDir, mountDir, "", unix.MS_BIND|unix.MS_REC, ""); err != nil { |
572 | return err | |
573 | } | |
574 | defer unix.Unmount(mountDir, unix.MNT_DETACH) | |
585 | return fmt.Errorf("bind-mount %s %s: %w", testDir, mountDir, err) | |
586 | } | |
587 | defer unix.Unmount(mountDir, unix.MNT_DETACH) //nolint:errcheck | |
575 | 588 | targetFile := filepath.Join(targetDir, filepath.Join(mountDir, filepath.Base(tmpfile.Name()))) |
576 | 589 | var exposed bool |
577 | 590 | _, err = os.Stat(targetFile) |
591 | 604 | ) |
592 | 605 | } |
593 | 606 | case "unbindable": |
594 | err = unix.Mount("/", targetDir, "", unix.MS_BIND|unix.MS_REC, "") | |
595 | if err == syscall.EINVAL { | |
607 | if mountErr == syscall.EINVAL { | |
596 | 608 | c.harness.Pass("root propagation is unbindable") |
597 | 609 | return nil |
598 | } else if err != nil { | |
599 | return err | |
600 | } | |
601 | defer unix.Unmount(targetDir, unix.MNT_DETACH) | |
610 | } else if mountErr != nil { | |
611 | return fmt.Errorf("bind-mount / %s: %w", targetDir, err) | |
612 | } | |
602 | 613 | c.harness.Fail("root propagation is unbindable") |
603 | 614 | return nil |
604 | 615 | default: |
624 | 635 | if err != nil { |
625 | 636 | return err |
626 | 637 | } |
627 | c.harness.YAML(map[string]string{ | |
638 | _ = c.harness.YAML(map[string]string{ | |
628 | 639 | "level": rfcError.Level.String(), |
629 | 640 | "reference": rfcError.Reference, |
630 | 641 | "mount": fs, |
670 | 681 | if err != nil { |
671 | 682 | return err |
672 | 683 | } |
673 | c.harness.YAML(map[string]string{ | |
684 | _ = c.harness.YAML(map[string]string{ | |
674 | 685 | "level": rfcError.Level.String(), |
675 | 686 | "reference": rfcError.Reference, |
676 | 687 | "path": device.Path, |
702 | 713 | if err != nil { |
703 | 714 | return err |
704 | 715 | } |
705 | c.harness.YAML(map[string]string{ | |
716 | _ = c.harness.YAML(map[string]string{ | |
706 | 717 | "level": rfcError.Level.String(), |
707 | 718 | "reference": rfcError.Reference, |
708 | 719 | "path": device.Path, |
721 | 732 | if err != nil { |
722 | 733 | return err |
723 | 734 | } |
724 | c.harness.YAML(map[string]interface{}{ | |
735 | _ = c.harness.YAML(map[string]interface{}{ | |
725 | 736 | "level": rfcError.Level.String(), |
726 | 737 | "reference": rfcError.Reference, |
727 | 738 | "path": device.Path, |
732 | 743 | if err != nil { |
733 | 744 | return err |
734 | 745 | } |
735 | c.harness.YAML(map[string]interface{}{ | |
746 | _ = c.harness.YAML(map[string]interface{}{ | |
736 | 747 | "level": rfcError.Level.String(), |
737 | 748 | "reference": rfcError.Reference, |
738 | 749 | "path": device.Path, |
750 | 761 | if err != nil { |
751 | 762 | return err |
752 | 763 | } |
753 | c.harness.YAML(map[string]interface{}{ | |
764 | _ = c.harness.YAML(map[string]interface{}{ | |
754 | 765 | "level": rfcError.Level.String(), |
755 | 766 | "reference": rfcError.Reference, |
756 | 767 | "path": device.Path, |
771 | 782 | if err != nil { |
772 | 783 | return err |
773 | 784 | } |
774 | c.harness.YAML(map[string]interface{}{ | |
785 | _ = c.harness.YAML(map[string]interface{}{ | |
775 | 786 | "level": rfcError.Level.String(), |
776 | 787 | "reference": rfcError.Reference, |
777 | 788 | "path": device.Path, |
787 | 798 | if err != nil { |
788 | 799 | return err |
789 | 800 | } |
790 | c.harness.YAML(map[string]interface{}{ | |
801 | _ = c.harness.YAML(map[string]interface{}{ | |
791 | 802 | "level": rfcError.Level.String(), |
792 | 803 | "reference": rfcError.Reference, |
793 | 804 | "path": device.Path, |
814 | 825 | if err != nil { |
815 | 826 | return err |
816 | 827 | } |
817 | c.harness.YAML(map[string]string{ | |
828 | _ = c.harness.YAML(map[string]string{ | |
818 | 829 | "level": rfcError.Level.String(), |
819 | 830 | "reference": rfcError.Reference, |
820 | 831 | "path": symlink, |
832 | 843 | if err != nil { |
833 | 844 | return err |
834 | 845 | } |
835 | c.harness.YAML(map[string]interface{}{ | |
846 | _ = c.harness.YAML(map[string]interface{}{ | |
836 | 847 | "level": rfcError.Level.String(), |
837 | 848 | "reference": rfcError.Reference, |
838 | 849 | "path": symlink, |
854 | 865 | if err != nil { |
855 | 866 | return err |
856 | 867 | } |
857 | c.harness.YAML(map[string]string{ | |
868 | _ = c.harness.YAML(map[string]string{ | |
858 | 869 | "level": rfcError.Level.String(), |
859 | 870 | "reference": rfcError.Reference, |
860 | 871 | "path": symlink, |
981 | 992 | if err != nil { |
982 | 993 | return err |
983 | 994 | } |
984 | rfcError, err := c.Ok(actual == expected, specerror.LinuxProcOomScoreAdjSet, spec.Version, fmt.Sprintf("has expected OOM score adjustment")) | |
985 | if err != nil { | |
986 | return err | |
987 | } | |
988 | c.harness.YAML(map[string]interface{}{ | |
995 | rfcError, err := c.Ok(actual == expected, specerror.LinuxProcOomScoreAdjSet, spec.Version, "has expected OOM score adjustment") | |
996 | if err != nil { | |
997 | return err | |
998 | } | |
999 | _ = c.harness.YAML(map[string]interface{}{ | |
989 | 1000 | "level": rfcError.Level.String(), |
990 | 1001 | "reference": rfcError.Reference, |
991 | 1002 | "expected": expected, |
1046 | 1057 | return err |
1047 | 1058 | } |
1048 | 1059 | c.harness.Ok(len(idMaps) == len(mappings), fmt.Sprintf("%s has expected number of mappings", path)) |
1049 | c.harness.YAML(map[string]interface{}{ | |
1060 | _ = c.harness.YAML(map[string]interface{}{ | |
1050 | 1061 | "expected": mappings, |
1051 | 1062 | "actual": idMaps, |
1052 | 1063 | }) |
1178 | 1189 | rfcError, err = c.Ok(false, specerror.MountsInOrder, spec.Version, fmt.Sprintf("mounts[%d] (%s) found", i, configMount.Destination)) |
1179 | 1190 | } else { |
1180 | 1191 | rfcError, err = c.Ok(foundInOrder, specerror.MountsInOrder, spec.Version, fmt.Sprintf("mounts[%d] (%s) found in order", i, configMount.Destination)) |
1181 | c.harness.YAML(map[string]interface{}{ | |
1182 | "level": rfcError.Level.String(), | |
1183 | "reference": rfcError.Reference, | |
1184 | "config": configMount, | |
1185 | "indexConfig": i, | |
1186 | "indexSystem": configSys[i], | |
1187 | "earlier": map[string]interface{}{ | |
1188 | "config": spec.Mounts[highestMatchedConfig], | |
1189 | "indexConfig": highestMatchedConfig, | |
1190 | "indexSystem": configSys[highestMatchedConfig], | |
1191 | }, | |
1192 | }) | |
1193 | } | |
1192 | } | |
1193 | _ = c.harness.YAML(map[string]interface{}{ | |
1194 | "level": rfcError.Level.String(), | |
1195 | "reference": rfcError.Reference, | |
1196 | "config": configMount, | |
1197 | "indexConfig": i, | |
1198 | "indexSystem": configSys[i], | |
1199 | "earlier": map[string]interface{}{ | |
1200 | "config": spec.Mounts[highestMatchedConfig], | |
1201 | "indexConfig": highestMatchedConfig, | |
1202 | "indexSystem": configSys[highestMatchedConfig], | |
1203 | }, | |
1204 | }) | |
1194 | 1205 | } |
1195 | 1206 | |
1196 | 1207 | return mountErrs |
1230 | 1241 | return fmt.Errorf("Failed to get mountLabel of %v", mount.Destination) |
1231 | 1242 | } |
1232 | 1243 | c.harness.Ok(spec.Linux.MountLabel == fileLabel, "has expected mountlabel") |
1233 | c.harness.YAML(map[string]string{ | |
1244 | _ = c.harness.YAML(map[string]string{ | |
1234 | 1245 | "expected": spec.Linux.MountLabel, |
1235 | 1246 | "actual": fileLabel, |
1236 | 1247 | }) |
0 | //go:build (!windows && !linux && !freebsd && !solaris) || (freebsd && !cgo) || (solaris && !cgo) | |
0 | 1 | // +build !windows,!linux,!freebsd,!solaris freebsd,!cgo solaris,!cgo |
1 | 2 | |
2 | 3 | package mount |
334 | 334 | --linux-gidmappings |
335 | 335 | --linux-hugepage-limits-add |
336 | 336 | --linux-hugepage-limits-drop |
337 | --linux-intelRdt-closid | |
337 | 338 | --linux-intelRdt-l3CacheSchema |
338 | 339 | --linux-masked-paths |
339 | 340 | --linux-mem-kernel-limit |
122 | 122 | } |
123 | 123 | } |
124 | 124 | |
125 | func (g *Generator) initConfigLinuxResourcesUnified() { | |
126 | g.initConfigLinuxResources() | |
127 | if g.Config.Linux.Resources.Unified == nil { | |
128 | g.Config.Linux.Resources.Unified = map[string]string{} | |
129 | } | |
130 | } | |
131 | ||
125 | 132 | func (g *Generator) initConfigSolaris() { |
126 | 133 | g.initConfig() |
127 | 134 | if g.Config.Solaris == nil { |
184 | 191 | g.Config.VM = &rspec.VM{} |
185 | 192 | } |
186 | 193 | } |
187 | ||
188 | func (g *Generator) initConfigVMHypervisor() { | |
189 | g.initConfigVM() | |
190 | if &g.Config.VM.Hypervisor == nil { | |
191 | g.Config.VM.Hypervisor = rspec.VMHypervisor{} | |
192 | } | |
193 | } | |
194 | ||
195 | func (g *Generator) initConfigVMKernel() { | |
196 | g.initConfigVM() | |
197 | if &g.Config.VM.Kernel == nil { | |
198 | g.Config.VM.Kernel = rspec.VMKernel{} | |
199 | } | |
200 | } | |
201 | ||
202 | func (g *Generator) initConfigVMImage() { | |
203 | g.initConfigVM() | |
204 | if &g.Config.VM.Image == nil { | |
205 | g.Config.VM.Image = rspec.VMImage{} | |
206 | } | |
207 | } |
28 | 28 | type Generator struct { |
29 | 29 | Config *rspec.Spec |
30 | 30 | HostSpecific bool |
31 | // This is used to keep a cache of the ENVs added to improve | |
32 | // performance when adding a huge number of ENV variables | |
33 | envMap map[string]int | |
31 | 34 | } |
32 | 35 | |
33 | 36 | // ExportOptions have toggles for exporting only certain parts of the specification |
178 | 181 | Destination: "/dev", |
179 | 182 | Type: "tmpfs", |
180 | 183 | Source: "tmpfs", |
181 | Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"}, | |
184 | Options: []string{"nosuid", "noexec", "strictatime", "mode=755", "size=65536k"}, | |
182 | 185 | }, |
183 | 186 | { |
184 | 187 | Destination: "/dev/pts", |
235 | 238 | } |
236 | 239 | } |
237 | 240 | |
238 | return Generator{Config: &config}, nil | |
241 | envCache := map[string]int{} | |
242 | if config.Process != nil { | |
243 | envCache = createEnvCacheMap(config.Process.Env) | |
244 | } | |
245 | ||
246 | return Generator{Config: &config, envMap: envCache}, nil | |
239 | 247 | } |
240 | 248 | |
241 | 249 | // NewFromSpec creates a configuration Generator from a given |
245 | 253 | // |
246 | 254 | // generator := Generator{Config: config} |
247 | 255 | func NewFromSpec(config *rspec.Spec) Generator { |
256 | envCache := map[string]int{} | |
257 | if config != nil && config.Process != nil { | |
258 | envCache = createEnvCacheMap(config.Process.Env) | |
259 | } | |
260 | ||
248 | 261 | return Generator{ |
249 | 262 | Config: config, |
263 | envMap: envCache, | |
250 | 264 | } |
251 | 265 | } |
252 | 266 | |
272 | 286 | if err := json.NewDecoder(r).Decode(&config); err != nil { |
273 | 287 | return Generator{}, err |
274 | 288 | } |
289 | ||
290 | envCache := map[string]int{} | |
291 | if config.Process != nil { | |
292 | envCache = createEnvCacheMap(config.Process.Env) | |
293 | } | |
294 | ||
275 | 295 | return Generator{ |
276 | 296 | Config: &config, |
297 | envMap: envCache, | |
277 | 298 | }, nil |
299 | } | |
300 | ||
301 | // createEnvCacheMap creates a hash map with the ENV variables given by the config | |
302 | func createEnvCacheMap(env []string) map[string]int { | |
303 | envMap := make(map[string]int, len(env)) | |
304 | for i, val := range env { | |
305 | envMap[val] = i | |
306 | } | |
307 | return envMap | |
278 | 308 | } |
279 | 309 | |
280 | 310 | // SetSpec sets the configuration in the Generator g. |
413 | 443 | g.Config.Process.User.Username = username |
414 | 444 | } |
415 | 445 | |
446 | // SetProcessUmask sets g.Config.Process.User.Umask. | |
447 | func (g *Generator) SetProcessUmask(umask uint32) { | |
448 | g.initConfigProcess() | |
449 | u := umask | |
450 | g.Config.Process.User.Umask = &u | |
451 | } | |
452 | ||
416 | 453 | // SetProcessGID sets g.Config.Process.User.GID. |
417 | 454 | func (g *Generator) SetProcessGID(gid uint32) { |
418 | 455 | g.initConfigProcess() |
455 | 492 | return |
456 | 493 | } |
457 | 494 | g.Config.Process.Env = []string{} |
495 | // Clear out the env cache map as well | |
496 | g.envMap = map[string]int{} | |
458 | 497 | } |
459 | 498 | |
460 | 499 | // AddProcessEnv adds name=value into g.Config.Process.Env, or replaces an |
461 | 500 | // existing entry with the given name. |
462 | 501 | func (g *Generator) AddProcessEnv(name, value string) { |
502 | if name == "" { | |
503 | return | |
504 | } | |
505 | ||
463 | 506 | g.initConfigProcess() |
464 | ||
465 | env := fmt.Sprintf("%s=%s", name, value) | |
466 | for idx := range g.Config.Process.Env { | |
467 | if strings.HasPrefix(g.Config.Process.Env[idx], name+"=") { | |
468 | g.Config.Process.Env[idx] = env | |
469 | return | |
470 | } | |
471 | } | |
472 | g.Config.Process.Env = append(g.Config.Process.Env, env) | |
507 | g.addEnv(fmt.Sprintf("%s=%s", name, value), name) | |
508 | } | |
509 | ||
510 | // AddMultipleProcessEnv adds multiple name=value into g.Config.Process.Env, or replaces | |
511 | // existing entries with the given name. | |
512 | func (g *Generator) AddMultipleProcessEnv(envs []string) { | |
513 | g.initConfigProcess() | |
514 | ||
515 | for _, val := range envs { | |
516 | split := strings.SplitN(val, "=", 2) | |
517 | g.addEnv(val, split[0]) | |
518 | } | |
519 | } | |
520 | ||
521 | // addEnv looks through adds ENV to the Process and checks envMap for | |
522 | // any duplicates | |
523 | // This is called by both AddMultipleProcessEnv and AddProcessEnv | |
524 | func (g *Generator) addEnv(env, key string) { | |
525 | if idx, ok := g.envMap[key]; ok { | |
526 | // The ENV exists in the cache, so change its value in g.Config.Process.Env | |
527 | g.Config.Process.Env[idx] = env | |
528 | } else { | |
529 | // else the env doesn't exist, so add it and add it's index to g.envMap | |
530 | g.Config.Process.Env = append(g.Config.Process.Env, env) | |
531 | g.envMap[key] = len(g.Config.Process.Env) - 1 | |
532 | } | |
473 | 533 | } |
474 | 534 | |
475 | 535 | // AddProcessRlimits adds rlimit into g.Config.Process.Rlimits. |
541 | 601 | func (g *Generator) SetLinuxCgroupsPath(path string) { |
542 | 602 | g.initConfigLinux() |
543 | 603 | g.Config.Linux.CgroupsPath = path |
604 | } | |
605 | ||
606 | // SetLinuxIntelRdtClosID sets g.Config.Linux.IntelRdt.ClosID | |
607 | func (g *Generator) SetLinuxIntelRdtClosID(clos string) { | |
608 | g.initConfigLinuxIntelRdt() | |
609 | g.Config.Linux.IntelRdt.ClosID = clos | |
544 | 610 | } |
545 | 611 | |
546 | 612 | // SetLinuxIntelRdtL3CacheSchema sets g.Config.Linux.IntelRdt.L3CacheSchema |
788 | 854 | return |
789 | 855 | } |
790 | 856 | } |
857 | } | |
858 | ||
859 | // AddLinuxResourcesUnified sets the g.Config.Linux.Resources.Unified | |
860 | func (g *Generator) SetLinuxResourcesUnified(unified map[string]string) { | |
861 | g.initConfigLinuxResourcesUnified() | |
862 | for k, v := range unified { | |
863 | g.Config.Linux.Resources.Unified[k] = v | |
864 | } | |
865 | } | |
866 | ||
867 | // AddLinuxResourcesUnified adds or updates the key-value pair from g.Config.Linux.Resources.Unified | |
868 | func (g *Generator) AddLinuxResourcesUnified(key, val string) { | |
869 | g.initConfigLinuxResourcesUnified() | |
870 | g.Config.Linux.Resources.Unified[key] = val | |
871 | } | |
872 | ||
873 | // DropLinuxResourcesUnified drops a key-value pair from g.Config.Linux.Resources.Unified | |
874 | func (g *Generator) DropLinuxResourcesUnified(key string) { | |
875 | if g.Config == nil || g.Config.Linux == nil || g.Config.Linux.Resources == nil || g.Config.Linux.Resources.Unified == nil { | |
876 | return | |
877 | } | |
878 | delete(g.Config.Linux.Resources.Unified, key) | |
791 | 879 | } |
792 | 880 | |
793 | 881 | // SetLinuxResourcesMemoryLimit sets g.Config.Linux.Resources.Memory.Limit. |
964 | 1052 | } |
965 | 1053 | |
966 | 1054 | // AddPreStartHook add a prestart hook into g.Config.Hooks.Prestart. |
967 | func (g *Generator) AddPreStartHook(preStartHook rspec.Hook) error { | |
1055 | func (g *Generator) AddPreStartHook(preStartHook rspec.Hook) { | |
968 | 1056 | g.initConfigHooks() |
969 | 1057 | g.Config.Hooks.Prestart = append(g.Config.Hooks.Prestart, preStartHook) |
970 | return nil | |
971 | 1058 | } |
972 | 1059 | |
973 | 1060 | // ClearPostStopHooks clear g.Config.Hooks.Poststop. |
979 | 1066 | } |
980 | 1067 | |
981 | 1068 | // AddPostStopHook adds a poststop hook into g.Config.Hooks.Poststop. |
982 | func (g *Generator) AddPostStopHook(postStopHook rspec.Hook) error { | |
1069 | func (g *Generator) AddPostStopHook(postStopHook rspec.Hook) { | |
983 | 1070 | g.initConfigHooks() |
984 | 1071 | g.Config.Hooks.Poststop = append(g.Config.Hooks.Poststop, postStopHook) |
985 | return nil | |
986 | 1072 | } |
987 | 1073 | |
988 | 1074 | // ClearPostStartHooks clear g.Config.Hooks.Poststart. |
994 | 1080 | } |
995 | 1081 | |
996 | 1082 | // AddPostStartHook adds a poststart hook into g.Config.Hooks.Poststart. |
997 | func (g *Generator) AddPostStartHook(postStartHook rspec.Hook) error { | |
1083 | func (g *Generator) AddPostStartHook(postStartHook rspec.Hook) { | |
998 | 1084 | g.initConfigHooks() |
999 | 1085 | g.Config.Hooks.Poststart = append(g.Config.Hooks.Poststart, postStartHook) |
1000 | return nil | |
1001 | 1086 | } |
1002 | 1087 | |
1003 | 1088 | // AddMount adds a mount into g.Config.Mounts. |
1441 | 1526 | g.Config.Linux.Devices[i] = device |
1442 | 1527 | return |
1443 | 1528 | } |
1444 | if dev.Type == device.Type && dev.Major == device.Major && dev.Minor == device.Minor { | |
1445 | fmt.Fprintln(os.Stderr, "WARNING: The same type, major and minor should not be used for multiple devices.") | |
1446 | } | |
1447 | 1529 | } |
1448 | 1530 | |
1449 | 1531 | g.Config.Linux.Devices = append(g.Config.Linux.Devices, device) |
1502 | 1584 | return |
1503 | 1585 | } |
1504 | 1586 | } |
1505 | return | |
1506 | } | |
1507 | ||
1508 | // strPtr returns the pointer pointing to the string s. | |
1509 | func strPtr(s string) *string { return &s } | |
1587 | } | |
1510 | 1588 | |
1511 | 1589 | // SetSyscallAction adds rules for syscalls with the specified action |
1512 | 1590 | func (g *Generator) SetSyscallAction(arguments seccomp.SyscallOpts) error { |
1633 | 1711 | if !strings.HasPrefix(path, "/") { |
1634 | 1712 | return fmt.Errorf("hypervisorPath %v is not an absolute path", path) |
1635 | 1713 | } |
1636 | g.initConfigVMHypervisor() | |
1714 | g.initConfigVM() | |
1637 | 1715 | g.Config.VM.Hypervisor.Path = path |
1638 | 1716 | return nil |
1639 | 1717 | } |
1640 | 1718 | |
1641 | 1719 | // SetVMHypervisorParameters sets g.Config.VM.Hypervisor.Parameters |
1642 | 1720 | func (g *Generator) SetVMHypervisorParameters(parameters []string) { |
1643 | g.initConfigVMHypervisor() | |
1721 | g.initConfigVM() | |
1644 | 1722 | g.Config.VM.Hypervisor.Parameters = parameters |
1645 | 1723 | } |
1646 | 1724 | |
1649 | 1727 | if !strings.HasPrefix(path, "/") { |
1650 | 1728 | return fmt.Errorf("kernelPath %v is not an absolute path", path) |
1651 | 1729 | } |
1652 | g.initConfigVMKernel() | |
1730 | g.initConfigVM() | |
1653 | 1731 | g.Config.VM.Kernel.Path = path |
1654 | 1732 | return nil |
1655 | 1733 | } |
1656 | 1734 | |
1657 | 1735 | // SetVMKernelParameters sets g.Config.VM.Kernel.Parameters |
1658 | 1736 | func (g *Generator) SetVMKernelParameters(parameters []string) { |
1659 | g.initConfigVMKernel() | |
1737 | g.initConfigVM() | |
1660 | 1738 | g.Config.VM.Kernel.Parameters = parameters |
1661 | 1739 | } |
1662 | 1740 | |
1665 | 1743 | if !strings.HasPrefix(initrd, "/") { |
1666 | 1744 | return fmt.Errorf("kernelInitrd %v is not an absolute path", initrd) |
1667 | 1745 | } |
1668 | g.initConfigVMKernel() | |
1746 | g.initConfigVM() | |
1669 | 1747 | g.Config.VM.Kernel.InitRD = initrd |
1670 | 1748 | return nil |
1671 | 1749 | } |
1675 | 1753 | if !strings.HasPrefix(path, "/") { |
1676 | 1754 | return fmt.Errorf("imagePath %v is not an absolute path", path) |
1677 | 1755 | } |
1678 | g.initConfigVMImage() | |
1756 | g.initConfigVM() | |
1679 | 1757 | g.Config.VM.Image.Path = path |
1680 | 1758 | return nil |
1681 | 1759 | } |
1691 | 1769 | default: |
1692 | 1770 | return fmt.Errorf("Commonly supported formats are: raw, qcow2, vdi, vmdk, vhd") |
1693 | 1771 | } |
1694 | g.initConfigVMImage() | |
1772 | g.initConfigVM() | |
1695 | 1773 | g.Config.VM.Image.Format = format |
1696 | 1774 | return nil |
1697 | 1775 | } |
10 | 10 | "github.com/opencontainers/runtime-tools/generate" |
11 | 11 | "github.com/opencontainers/runtime-tools/specerror" |
12 | 12 | "github.com/opencontainers/runtime-tools/validate" |
13 | "github.com/stretchr/testify/assert" | |
13 | 14 | ) |
14 | 15 | |
15 | 16 | // Smoke test to ensure that _at the very least_ our default configuration |
92 | 93 | t.Errorf("Unable to remove /dev/shm from mounts") |
93 | 94 | } |
94 | 95 | } |
96 | ||
97 | func TestEnvCaching(t *testing.T) { | |
98 | // Start with empty ENV and add a few | |
99 | g, err := generate.New("windows") | |
100 | if err != nil { | |
101 | t.Fatal(err) | |
102 | } | |
103 | expected := []string{"k1=v1", "k2=v2"} | |
104 | g.AddProcessEnv("k1", "v1") | |
105 | g.AddProcessEnv("k2", "v2") | |
106 | assert.Equal(t, expected, g.Config.Process.Env) | |
107 | ||
108 | // Test override and existing ENV | |
109 | g, err = generate.New("linux") | |
110 | if err != nil { | |
111 | t.Fatal(err) | |
112 | } | |
113 | expected = []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm", "k1=v1", "k2=v4", "k3=v3"} | |
114 | g.AddProcessEnv("k1", "v1") | |
115 | g.AddProcessEnv("k2", "v2") | |
116 | g.AddProcessEnv("k3", "v3") | |
117 | g.AddProcessEnv("k2", "v4") | |
118 | assert.Equal(t, expected, g.Config.Process.Env) | |
119 | ||
120 | // Test empty ENV | |
121 | g, err = generate.New("windows") | |
122 | if err != nil { | |
123 | t.Fatal(err) | |
124 | } | |
125 | g.AddProcessEnv("", "") | |
126 | assert.Equal(t, []string(nil), g.Config.Process.Env) | |
127 | } | |
128 | ||
129 | func TestMultipleEnvCaching(t *testing.T) { | |
130 | // Start with empty ENV and add a few | |
131 | g, err := generate.New("windows") | |
132 | if err != nil { | |
133 | t.Fatal(err) | |
134 | } | |
135 | newEnvs := []string{"k1=v1", "k2=v2"} | |
136 | expected := []string{"k1=v1", "k2=v2"} | |
137 | g.AddMultipleProcessEnv(newEnvs) | |
138 | assert.Equal(t, expected, g.Config.Process.Env) | |
139 | ||
140 | // Test override and existing ENV | |
141 | g, err = generate.New("linux") | |
142 | if err != nil { | |
143 | t.Fatal(err) | |
144 | } | |
145 | newEnvs = []string{"k1=v1", "k2=v2", "k3=v3", "k2=v4"} | |
146 | expected = []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm", "k1=v1", "k2=v4", "k3=v3"} | |
147 | g.AddMultipleProcessEnv(newEnvs) | |
148 | assert.Equal(t, expected, g.Config.Process.Env) | |
149 | ||
150 | // Test empty ENV | |
151 | g, err = generate.New("windows") | |
152 | if err != nil { | |
153 | t.Fatal(err) | |
154 | } | |
155 | g.AddMultipleProcessEnv([]string{}) | |
156 | assert.Equal(t, []string(nil), g.Config.Process.Env) | |
157 | } |
3 | 3 | seccompOverwrite = "overwrite" |
4 | 4 | seccompAppend = "append" |
5 | 5 | nothing = "nothing" |
6 | kill = "kill" | |
7 | trap = "trap" | |
8 | trace = "trace" | |
9 | allow = "allow" | |
10 | errno = "errno" | |
11 | 6 | ) |
302 | 302 | "stat64", |
303 | 303 | "statfs", |
304 | 304 | "statfs64", |
305 | "statx", | |
305 | 306 | "symlink", |
306 | 307 | "symlinkat", |
307 | 308 | "sync", |
565 | 566 | }, |
566 | 567 | }...) |
567 | 568 | /* Flags parameter of the clone syscall is the 2nd on s390 */ |
569 | syscalls = append(syscalls, []rspec.LinuxSyscall{ | |
570 | { | |
571 | Names: []string{"clone"}, | |
572 | Action: rspec.ActAllow, | |
573 | Args: []rspec.LinuxSeccompArg{ | |
574 | { | |
575 | Index: 1, | |
576 | Value: 2080505856, | |
577 | ValueTwo: 0, | |
578 | Op: rspec.OpMaskedEqual, | |
579 | }, | |
580 | }, | |
581 | }, | |
582 | }...) | |
568 | 583 | } |
569 | 584 | |
570 | 585 | return &rspec.LinuxSeccomp{ |
91 | 91 | return reflect.DeepEqual(config1, config2) |
92 | 92 | } |
93 | 93 | |
94 | func identicalExceptAction(config1, config2 *rspec.LinuxSyscall) bool { | |
95 | samename := sameName(config1, config2) | |
96 | sameAction := sameAction(config1, config2) | |
97 | sameArgs := sameArgs(config1, config2) | |
98 | ||
99 | return samename && !sameAction && sameArgs | |
100 | } | |
101 | ||
102 | func identicalExceptArgs(config1, config2 *rspec.LinuxSyscall) bool { | |
103 | samename := sameName(config1, config2) | |
104 | sameAction := sameAction(config1, config2) | |
105 | sameArgs := sameArgs(config1, config2) | |
106 | ||
107 | return samename && sameAction && !sameArgs | |
108 | } | |
109 | ||
110 | 94 | func sameName(config1, config2 *rspec.LinuxSyscall) bool { |
111 | 95 | return reflect.DeepEqual(config1.Names, config2.Names) |
112 | 96 | } |
0 | module github.com/opencontainers/runtime-tools | |
1 | ||
2 | go 1.16 | |
3 | ||
4 | require ( | |
5 | github.com/blang/semver v3.5.0+incompatible | |
6 | github.com/google/uuid v1.3.0 | |
7 | github.com/hashicorp/go-multierror v1.1.1 | |
8 | github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b | |
9 | github.com/mrunalp/fileutils v0.5.0 | |
10 | github.com/opencontainers/runtime-spec v1.0.3-0.20201121164853-7413a7f753e1 | |
11 | github.com/opencontainers/selinux v1.9.1 | |
12 | github.com/sirupsen/logrus v1.8.1 | |
13 | github.com/stretchr/testify v1.3.0 | |
14 | github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 | |
15 | github.com/urfave/cli v1.19.1 | |
16 | github.com/xeipuuv/gojsonschema v1.2.0 | |
17 | golang.org/x/sys v0.0.0-20191115151921-52ab43148777 | |
18 | ) | |
19 | ||
20 | require gopkg.in/yaml.v2 v2.4.0 // indirect |
0 | github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= | |
1 | github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= | |
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |
4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
5 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= | |
6 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | |
7 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= | |
8 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | |
9 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= | |
10 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= | |
11 | github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b h1:Ga1nclDSe8gOw37MVLMhfu2QKWtD6gvtQ298zsKVh8g= | |
12 | github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= | |
13 | github.com/mrunalp/fileutils v0.5.0 h1:NKzVxiH7eSk+OQ4M+ZYW1K6h27RUV3MI6NUTsHhU6Z4= | |
14 | github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= | |
15 | github.com/opencontainers/runtime-spec v1.0.3-0.20201121164853-7413a7f753e1 h1:UAfI7SOCo1CNIu3RevW9B4HQyf7SY5aSzcSeoC7OPs0= | |
16 | github.com/opencontainers/runtime-spec v1.0.3-0.20201121164853-7413a7f753e1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= | |
17 | github.com/opencontainers/selinux v1.9.1 h1:b4VPEF3O5JLZgdTDBmGepaaIbAo0GqoF6EBRq5f/g3Y= | |
18 | github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= | |
19 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |
20 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
21 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= | |
22 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= | |
23 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |
24 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | |
25 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | |
26 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |
27 | github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= | |
28 | github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= | |
29 | github.com/urfave/cli v1.19.1 h1:0mKm4ZoB74PxYmZVua162y1dGt1qc10MyymYRBf3lb8= | |
30 | github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= | |
31 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= | |
32 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= | |
33 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= | |
34 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= | |
35 | github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= | |
36 | github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= | |
37 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
38 | golang.org/x/sys v0.0.0-20191115151921-52ab43148777 h1:wejkGHRTr38uaKRqECZlsCsJ1/TGxIyFbH32x5zUdu4= | |
39 | golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
40 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |
41 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
42 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | |
43 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
192 | 192 | Drop hugepage rsource limits. Just need to specify PAGESIZE. e.g. --linux-hugepage-limits-drop=4MB |
193 | 193 | This option can be specified multiple times. |
194 | 194 | |
195 | **--linux-intelRdt-closid**="" | |
196 | RDT Class of Service, i.e. group under the resctrl pseudo-filesystem, which | |
197 | to associate the container with. | |
198 | ||
195 | 199 | **--linux-intelRdt-l3CacheSchema**="" |
196 | 200 | Specifies the schema for L3 cache id and capacity bitmask. |
197 | 201 |
Binary diff not shown
Binary diff not shown
130 | 130 | if err != nil { |
131 | 131 | return "", specerror.NewError(specerror.SpecVersionInSemVer, err, rspec.Version) |
132 | 132 | } |
133 | configRenamedToConfigSchemaVersion, err := semver.Parse("1.0.0-rc2") // config.json became config-schema.json in 1.0.0-rc2 | |
134 | if ver.Compare(configRenamedToConfigSchemaVersion) == -1 { | |
135 | return "", fmt.Errorf("unsupported configuration version (older than %s)", configRenamedToConfigSchemaVersion) | |
133 | if ver.LT(semver.Version{Major: 1, Minor: 0, Patch: 2}) { | |
134 | return "", errors.New("unsupported configuration version (older than 1.0.2)") | |
136 | 135 | } |
137 | 136 | return fmt.Sprintf(configSchemaTemplate, version), nil |
138 | 137 | } |
143 | 142 | func (v *Validator) CheckJSONSchema() (errs error) { |
144 | 143 | logrus.Debugf("check JSON schema") |
145 | 144 | |
146 | url, err := JSONSchemaURL(v.spec.Version) | |
145 | url, err := JSONSchemaURL(strings.TrimSuffix(v.spec.Version, "-dev")) | |
147 | 146 | if err != nil { |
148 | 147 | errs = multierror.Append(errs, err) |
149 | 148 | return errs |
42 | 42 | }{ |
43 | 43 | { |
44 | 44 | config: &rspec.Spec{}, |
45 | error: "1 error occurred:\n\t* Version string empty\nRefer to: https://github.com/opencontainers/runtime-spec/blob/v1.0.1/config.md#specification-version\n\n", | |
46 | }, | |
47 | { | |
48 | config: &rspec.Spec{ | |
49 | Version: "1.0.1-rc1", | |
45 | error: fmt.Sprintf("1 error occurred:\n\t* Version string empty\nRefer to: https://github.com/opencontainers/runtime-spec/blob/v%s/config.md#specification-version\n\n", rspec.Version), | |
46 | }, | |
47 | { | |
48 | config: &rspec.Spec{ | |
49 | Version: "1.0.99-rc1", // non-existent | |
50 | 50 | }, |
51 | 51 | error: "Could not read schema from HTTP, response status is 404 Not Found", |
52 | 52 | }, |
53 | 53 | { |
54 | 54 | config: &rspec.Spec{ |
55 | Version: "1.0.0", | |
56 | }, | |
57 | error: "", | |
58 | }, | |
59 | { | |
60 | config: &rspec.Spec{ | |
61 | Version: "1.0.0", | |
62 | Process: &rspec.Process{}, | |
63 | }, | |
64 | error: "process.args: Invalid type. Expected: array, given: null", | |
65 | }, | |
66 | { | |
67 | config: &rspec.Spec{ | |
68 | Version: "1.0.0", | |
55 | Version: "1.0.0", // too old | |
56 | }, | |
57 | error: "1 error occurred:\n\t* unsupported configuration version (older than 1.0.2)\n\n", | |
58 | }, | |
59 | { | |
60 | config: &rspec.Spec{ | |
61 | Version: "1.0.2", | |
62 | }, | |
63 | error: "", | |
64 | }, | |
65 | { | |
66 | config: &rspec.Spec{ | |
67 | Version: "1.0.2", | |
69 | 68 | Linux: &rspec.Linux{}, |
70 | 69 | }, |
71 | 70 | error: "", |
72 | 71 | }, |
73 | 72 | { |
74 | 73 | config: &rspec.Spec{ |
75 | Version: "1.0.0", | |
74 | Version: "1.0.2", | |
76 | 75 | Linux: &rspec.Linux{ |
77 | 76 | RootfsPropagation: "", |
78 | 77 | }, |
81 | 80 | }, |
82 | 81 | { |
83 | 82 | config: &rspec.Spec{ |
84 | Version: "1.0.0", | |
83 | Version: "1.0.2", | |
85 | 84 | Linux: &rspec.Linux{ |
86 | 85 | RootfsPropagation: "shared", |
87 | 86 | }, |
90 | 89 | }, |
91 | 90 | { |
92 | 91 | config: &rspec.Spec{ |
93 | Version: "1.0.0", | |
92 | Version: "1.0.2", | |
94 | 93 | Linux: &rspec.Linux{ |
95 | 94 | RootfsPropagation: "rshared", |
96 | 95 | }, |
99 | 98 | }, |
100 | 99 | { |
101 | 100 | config: &rspec.Spec{ |
102 | Version: "1.0.0-rc5", | |
103 | }, | |
104 | error: "process: process is required", | |
105 | }, | |
106 | { | |
107 | config: &rspec.Spec{ | |
108 | Version: "1.0.0", | |
101 | Version: "1.0.2", | |
109 | 102 | Linux: &rspec.Linux{ |
110 | 103 | Namespaces: []rspec.LinuxNamespace{ |
111 | 104 | { |
118 | 111 | }, |
119 | 112 | { |
120 | 113 | config: &rspec.Spec{ |
121 | Version: "1.0.0", | |
114 | Version: "1.0.2", | |
122 | 115 | Linux: &rspec.Linux{ |
123 | 116 | Namespaces: []rspec.LinuxNamespace{ |
124 | 117 | { |
131 | 124 | }, |
132 | 125 | { |
133 | 126 | config: &rspec.Spec{ |
134 | Version: "1.0.0", | |
127 | Version: "1.0.2", | |
135 | 128 | Linux: &rspec.Linux{ |
136 | 129 | Seccomp: &rspec.LinuxSeccomp{ |
137 | 130 | DefaultAction: "SCMP_ACT_ALLOW", |
146 | 139 | }, |
147 | 140 | { |
148 | 141 | config: &rspec.Spec{ |
149 | Version: "1.0.0", | |
142 | Version: "1.0.2", | |
150 | 143 | Linux: &rspec.Linux{ |
151 | 144 | Seccomp: &rspec.LinuxSeccomp{ |
152 | 145 | DefaultAction: "SCMP_ACT_ALLOW", |
161 | 154 | }, |
162 | 155 | { |
163 | 156 | config: &rspec.Spec{ |
164 | Version: "1.0.0", | |
157 | Version: "1.0.2", | |
165 | 158 | Linux: &rspec.Linux{ |
166 | 159 | Seccomp: &rspec.LinuxSeccomp{ |
167 | 160 | DefaultAction: "SCMP_ACT_ALLOW", |
178 | 171 | }, |
179 | 172 | { |
180 | 173 | config: &rspec.Spec{ |
181 | Version: "1.0.0", | |
174 | Version: "1.0.2", | |
182 | 175 | Linux: &rspec.Linux{ |
183 | 176 | Seccomp: &rspec.LinuxSeccomp{ |
184 | 177 | DefaultAction: "SCMP_ACT_ALLOW", |
191 | 184 | }, |
192 | 185 | }, |
193 | 186 | }, |
194 | error: "linux.seccomp.syscalls.0.action: linux.seccomp.syscalls.0.action must be one of the following: \"SCMP_ACT_KILL\", \"SCMP_ACT_TRAP\", \"SCMP_ACT_ERRNO\", \"SCMP_ACT_TRACE\", \"SCMP_ACT_ALLOW\"", | |
195 | }, | |
196 | { | |
197 | config: &rspec.Spec{ | |
198 | Version: "1.0.0", | |
187 | error: "linux.seccomp.syscalls.0.action: linux.seccomp.syscalls.0.action must be one of the following: \"SCMP_ACT_KILL\", \"SCMP_ACT_TRAP\", \"SCMP_ACT_ERRNO\", \"SCMP_ACT_TRACE\", \"SCMP_ACT_ALLOW\", \"SCMP_ACT_LOG\"", | |
188 | }, | |
189 | { | |
190 | config: &rspec.Spec{ | |
191 | Version: "1.0.2", | |
199 | 192 | Linux: &rspec.Linux{ |
200 | 193 | Seccomp: &rspec.LinuxSeccomp{ |
201 | 194 | DefaultAction: "SCMP_ACT_ALLOW", |
219 | 212 | }, |
220 | 213 | { |
221 | 214 | config: &rspec.Spec{ |
222 | Version: "1.0.0", | |
215 | Version: "1.0.2", | |
223 | 216 | Linux: &rspec.Linux{ |
224 | 217 | Seccomp: &rspec.LinuxSeccomp{ |
225 | 218 | DefaultAction: "SCMP_ACT_ALLOW", |
321 | 314 | expected specerror.Code |
322 | 315 | }{ |
323 | 316 | {rspec.Version, specerror.NonError}, |
324 | //FIXME: validate currently only handles rpsec.Version | |
317 | // FIXME: validate currently only handles rpsec.Version | |
325 | 318 | {"0.0.1", specerror.NonRFCError}, |
326 | 319 | {"invalid", specerror.SpecVersionInSemVer}, |
327 | 320 | } |
5 | 5 | "path/filepath" |
6 | 6 | "time" |
7 | 7 | |
8 | "github.com/google/uuid" | |
8 | 9 | tap "github.com/mndrix/tap-go" |
9 | 10 | "github.com/mrunalp/fileutils" |
10 | 11 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
11 | 12 | "github.com/opencontainers/runtime-tools/generate" |
12 | 13 | "github.com/opencontainers/runtime-tools/specerror" |
13 | 14 | "github.com/opencontainers/runtime-tools/validation/util" |
14 | uuid "github.com/satori/go.uuid" | |
15 | 15 | ) |
16 | 16 | |
17 | 17 | func main() { |
30 | 30 | } |
31 | 31 | |
32 | 32 | testPath := filepath.Join(bundleDir, "test.json") |
33 | r.SetID(uuid.NewV4().String()) | |
33 | r.SetID(uuid.NewString()) | |
34 | 34 | // generate a config has all the testing properties |
35 | 35 | g, err := util.GetDefaultGenerator() |
36 | 36 | if err != nil { |
64 | 64 | util.Fatal(err) |
65 | 65 | } |
66 | 66 | |
67 | spec := &rspec.Spec{ | |
67 | g.Config = &rspec.Spec{ | |
68 | 68 | Version: "1.0.0", |
69 | 69 | } |
70 | g.SetSpec(spec) | |
71 | 70 | err = r.SetConfig(g) |
72 | 71 | if err != nil { |
73 | 72 | util.Fatal(err) |
4 | 4 | "os/exec" |
5 | 5 | "runtime" |
6 | 6 | |
7 | "github.com/google/uuid" | |
7 | 8 | "github.com/mndrix/tap-go" |
8 | 9 | rspecs "github.com/opencontainers/runtime-spec/specs-go" |
9 | 10 | "github.com/opencontainers/runtime-tools/generate" |
10 | 11 | "github.com/opencontainers/runtime-tools/specerror" |
11 | 12 | "github.com/opencontainers/runtime-tools/validation/util" |
12 | "github.com/satori/go.uuid" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | func main() { |
32 | 32 | if err != nil { |
33 | 33 | util.Fatal(err) |
34 | 34 | } |
35 | defer r.Clean(true, true) | |
35 | defer r.Clean() | |
36 | 36 | |
37 | 37 | err = r.SetConfig(&g) |
38 | 38 | if err != nil { |
39 | 39 | util.Fatal(err) |
40 | 40 | } |
41 | 41 | |
42 | containerID := uuid.NewV4().String() | |
42 | containerID := uuid.NewString() | |
43 | 43 | cases := []struct { |
44 | 44 | id string |
45 | 45 | errExpected bool |
65 | 65 | } |
66 | 66 | } |
67 | 67 | } |
68 | t.YAML(diagnostic) | |
68 | _ = t.YAML(diagnostic) | |
69 | 69 | |
70 | 70 | if err == nil { |
71 | 71 | state, err := r.State() |
72 | 72 | t.Ok(err == nil && state.ID == c.id, "'state' MUST return the state of a container") |
73 | 73 | if err == nil { |
74 | t.YAML(map[string]string{ | |
74 | _ = t.YAML(map[string]string{ | |
75 | 75 | "container ID": c.id, |
76 | 76 | "state ID": state.ID, |
77 | 77 | }) |
84 | 84 | diagnostic["stderr"] = string(e.Stderr) |
85 | 85 | } |
86 | 86 | } |
87 | t.YAML(diagnostic) | |
87 | _ = t.YAML(diagnostic) | |
88 | 88 | } |
89 | 89 | } |
90 | 90 | } |
9 | 9 | "github.com/opencontainers/runtime-tools/generate" |
10 | 10 | "github.com/opencontainers/runtime-tools/specerror" |
11 | 11 | "github.com/opencontainers/runtime-tools/validation/util" |
12 | uuid "github.com/satori/go.uuid" | |
12 | "github.com/google/uuid" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | func main() { |
33 | 33 | util.Fatal(err) |
34 | 34 | } |
35 | 35 | runningConfig.SetProcessArgs([]string{"sleep", "30"}) |
36 | containerID := uuid.NewV4().String() | |
36 | containerID := uuid.NewString() | |
37 | 37 | testRuntime, _ := util.NewRuntime(util.RuntimeCommand, bundleDir) |
38 | 38 | cases := []struct { |
39 | 39 | config *generate.Generator |
12 | 12 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
13 | 13 | "github.com/opencontainers/runtime-tools/specerror" |
14 | 14 | "github.com/opencontainers/runtime-tools/validation/util" |
15 | uuid "github.com/satori/go.uuid" | |
15 | "github.com/google/uuid" | |
16 | 16 | ) |
17 | 17 | |
18 | 18 | func main() { |
36 | 36 | util.Fatal(err) |
37 | 37 | } |
38 | 38 | |
39 | r.SetID(uuid.NewV4().String()) | |
39 | r.SetID(uuid.NewString()) | |
40 | 40 | g, err := util.GetDefaultGenerator() |
41 | 41 | if err != nil { |
42 | 42 | util.Fatal(err) |
11 | 11 | "github.com/opencontainers/runtime-tools/cgroups" |
12 | 12 | "github.com/opencontainers/runtime-tools/specerror" |
13 | 13 | "github.com/opencontainers/runtime-tools/validation/util" |
14 | uuid "github.com/satori/go.uuid" | |
14 | "github.com/google/uuid" | |
15 | 15 | ) |
16 | 16 | |
17 | 17 | func main() { |
29 | 29 | util.Fatal(err) |
30 | 30 | } |
31 | 31 | |
32 | r.SetID(uuid.NewV4().String()) | |
32 | r.SetID(uuid.NewString()) | |
33 | 33 | g, err := util.GetDefaultGenerator() |
34 | 34 | if err != nil { |
35 | 35 | util.Fatal(err) |
58 | 58 | if err != nil { |
59 | 59 | util.Fatal(err) |
60 | 60 | } |
61 | if err := util.ValidateLinuxResourcesPids(g.Spec(), t, &state); err != nil { | |
61 | if err := util.ValidateLinuxResourcesPids(g.Config, t, &state); err != nil { | |
62 | 62 | util.Fatal(err) |
63 | 63 | } |
64 | 64 |
10 | 10 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
11 | 11 | "github.com/opencontainers/runtime-tools/specerror" |
12 | 12 | "github.com/opencontainers/runtime-tools/validation/util" |
13 | uuid "github.com/satori/go.uuid" | |
13 | "github.com/google/uuid" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | func main() { |
21 | 21 | config := util.LifecycleConfig{ |
22 | 22 | Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, |
23 | 23 | PreCreate: func(r *util.Runtime) error { |
24 | r.SetID(uuid.NewV4().String()) | |
24 | r.SetID(uuid.NewString()) | |
25 | 25 | g, err := util.GetDefaultGenerator() |
26 | 26 | if err != nil { |
27 | 27 | util.Fatal(err) |
28 | 28 | } |
29 | output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output") | |
30 | shPath := filepath.Join(r.BundleDir, g.Spec().Root.Path, "/bin/sh") | |
31 | err = g.AddPreStartHook(rspec.Hook{ | |
29 | output = filepath.Join(r.BundleDir, g.Config.Root.Path, "output") | |
30 | shPath := filepath.Join(r.BundleDir, g.Config.Root.Path, "/bin/sh") | |
31 | g.AddPreStartHook(rspec.Hook{ | |
32 | 32 | Path: shPath, |
33 | 33 | Args: []string{ |
34 | 34 | "sh", "-c", fmt.Sprintf("echo 'pre-start1 called' >> %s", output), |
35 | 35 | }, |
36 | 36 | }) |
37 | if err != nil { | |
38 | return err | |
39 | } | |
40 | err = g.AddPreStartHook(rspec.Hook{ | |
37 | g.AddPreStartHook(rspec.Hook{ | |
41 | 38 | Path: shPath, |
42 | 39 | Args: []string{ |
43 | 40 | "sh", "-c", fmt.Sprintf("echo 'pre-start2 called' >> %s", output), |
44 | 41 | }, |
45 | 42 | }) |
46 | if err != nil { | |
47 | return err | |
48 | } | |
49 | err = g.AddPostStartHook(rspec.Hook{ | |
43 | g.AddPostStartHook(rspec.Hook{ | |
50 | 44 | Path: shPath, |
51 | 45 | Args: []string{ |
52 | 46 | "sh", "-c", fmt.Sprintf("echo 'post-start1 called' >> %s", output), |
53 | 47 | }, |
54 | 48 | }) |
55 | if err != nil { | |
56 | return err | |
57 | } | |
58 | err = g.AddPostStartHook(rspec.Hook{ | |
49 | g.AddPostStartHook(rspec.Hook{ | |
59 | 50 | Path: shPath, |
60 | 51 | Args: []string{ |
61 | 52 | "sh", "-c", fmt.Sprintf("echo 'post-start2 called' >> %s", output), |
62 | 53 | }, |
63 | 54 | }) |
64 | if err != nil { | |
65 | return err | |
66 | } | |
67 | err = g.AddPostStopHook(rspec.Hook{ | |
55 | g.AddPostStopHook(rspec.Hook{ | |
68 | 56 | Path: shPath, |
69 | 57 | Args: []string{ |
70 | 58 | "sh", "-c", fmt.Sprintf("echo 'post-stop1 called' >> %s", output), |
71 | 59 | }, |
72 | 60 | }) |
73 | if err != nil { | |
74 | return err | |
75 | } | |
76 | err = g.AddPostStopHook(rspec.Hook{ | |
61 | g.AddPostStopHook(rspec.Hook{ | |
77 | 62 | Path: shPath, |
78 | 63 | Args: []string{ |
79 | 64 | "sh", "-c", fmt.Sprintf("echo 'post-stop2 called' >> %s", output), |
80 | 65 | }, |
81 | 66 | }) |
82 | if err != nil { | |
83 | return err | |
84 | } | |
85 | 67 | g.SetProcessArgs([]string{"true"}) |
86 | 68 | return r.SetConfig(g) |
87 | 69 | }, |
98 | 80 | diagnostic := map[string]string{ |
99 | 81 | "error": err.Error(), |
100 | 82 | } |
101 | t.YAML(diagnostic) | |
83 | _ = t.YAML(diagnostic) | |
102 | 84 | } else { |
103 | 85 | diagnostic := map[string]string{ |
104 | 86 | "error": err.Error(), |
108 | 90 | diagnostic["stderr"] = string(e.Stderr) |
109 | 91 | } |
110 | 92 | } |
111 | t.YAML(diagnostic) | |
93 | _ = t.YAML(diagnostic) | |
112 | 94 | } |
113 | 95 | |
114 | 96 | t.AutoPlan() |
14 | 14 | rspecs "github.com/opencontainers/runtime-spec/specs-go" |
15 | 15 | "github.com/opencontainers/runtime-tools/specerror" |
16 | 16 | "github.com/opencontainers/runtime-tools/validation/util" |
17 | uuid "github.com/satori/go.uuid" | |
17 | "github.com/google/uuid" | |
18 | 18 | ) |
19 | 19 | |
20 | 20 | func stdinStateCheck(outputDir, hookName string, expectedState rspecs.State) (errs *multierror.Error) { |
82 | 82 | if err != nil { |
83 | 83 | util.Fatal(err) |
84 | 84 | } |
85 | containerID := uuid.NewV4().String() | |
85 | containerID := uuid.NewString() | |
86 | 86 | defer os.RemoveAll(bundleDir) |
87 | 87 | |
88 | 88 | var containerPid int |
93 | 93 | if err != nil { |
94 | 94 | util.Fatal(err) |
95 | 95 | } |
96 | outputDir := filepath.Join(bundleDir, g.Spec().Root.Path) | |
96 | outputDir := filepath.Join(bundleDir, g.Config.Root.Path) | |
97 | 97 | timeout := 1 |
98 | 98 | g.AddAnnotation(annotationKey, annotationValue) |
99 | 99 | g.AddPreStartHook(rspecs.Hook{ |
100 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/sh"), | |
100 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/sh"), | |
101 | 101 | Args: []string{ |
102 | 102 | "sh", "-c", fmt.Sprintf("cat > %s", filepath.Join(outputDir, "prestart")), |
103 | 103 | }, |
104 | 104 | Timeout: &timeout, |
105 | 105 | }) |
106 | 106 | g.AddPostStartHook(rspecs.Hook{ |
107 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/sh"), | |
107 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/sh"), | |
108 | 108 | Args: []string{ |
109 | 109 | "sh", "-c", fmt.Sprintf("cat > %s", filepath.Join(outputDir, "poststart")), |
110 | 110 | }, |
111 | 111 | Timeout: &timeout, |
112 | 112 | }) |
113 | 113 | g.AddPostStopHook(rspecs.Hook{ |
114 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/sh"), | |
114 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/sh"), | |
115 | 115 | Args: []string{ |
116 | 116 | "sh", "-c", fmt.Sprintf("cat > %s", filepath.Join(outputDir, "poststop")), |
117 | 117 | }, |
126 | 126 | r.SetID(containerID) |
127 | 127 | return nil |
128 | 128 | }, |
129 | PreDelete: func(r *util.Runtime) error { | |
129 | PostCreate: func(r *util.Runtime) error { | |
130 | 130 | state, err := r.State() |
131 | 131 | if err != nil { |
132 | 132 | return err |
133 | 133 | } |
134 | 134 | containerPid = state.Pid |
135 | return nil | |
136 | }, | |
137 | PreDelete: func(r *util.Runtime) error { | |
135 | 138 | util.WaitingForStatus(*r, util.LifecycleStatusStopped, time.Second*10, time.Second) |
136 | 139 | return nil |
137 | 140 | }, |
30 | 30 | defer t.AutoPlan() |
31 | 31 | |
32 | 32 | if "linux" != runtime.GOOS { |
33 | t.Skip(1, fmt.Sprintf("linux-specific namespace test")) | |
33 | t.Skip(1, "linux-specific namespace test") | |
34 | 34 | } |
35 | 35 | |
36 | 36 | hostnames := []string{ |
9 | 9 | "github.com/opencontainers/runtime-tools/generate" |
10 | 10 | "github.com/opencontainers/runtime-tools/specerror" |
11 | 11 | "github.com/opencontainers/runtime-tools/validation/util" |
12 | uuid "github.com/satori/go.uuid" | |
12 | "github.com/google/uuid" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | func main() { |
31 | 31 | util.Fatal(err) |
32 | 32 | } |
33 | 33 | runningConfig.SetProcessArgs([]string{"sleep", "30"}) |
34 | containerID := uuid.NewV4().String() | |
34 | containerID := uuid.NewString() | |
35 | 35 | |
36 | 36 | cases := []struct { |
37 | 37 | config *generate.Generator |
9 | 9 | rspecs "github.com/opencontainers/runtime-spec/specs-go" |
10 | 10 | "github.com/opencontainers/runtime-tools/specerror" |
11 | 11 | "github.com/opencontainers/runtime-tools/validation/util" |
12 | uuid "github.com/satori/go.uuid" | |
12 | "github.com/google/uuid" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | func main() { |
22 | 22 | defer os.RemoveAll(bundleDir) |
23 | 23 | |
24 | 24 | targetErr := specerror.NewError(specerror.KillNonCreateRunHaveNoEffect, fmt.Errorf("attempting to send a signal to a container that is neither `created` nor `running` MUST have no effect on the container"), rspecs.Version) |
25 | containerID := uuid.NewV4().String() | |
25 | containerID := uuid.NewString() | |
26 | 26 | g, err := util.GetDefaultGenerator() |
27 | 27 | if err != nil { |
28 | 28 | util.Fatal(err) |
9 | 9 | rspecs "github.com/opencontainers/runtime-spec/specs-go" |
10 | 10 | "github.com/opencontainers/runtime-tools/specerror" |
11 | 11 | "github.com/opencontainers/runtime-tools/validation/util" |
12 | uuid "github.com/satori/go.uuid" | |
12 | "github.com/google/uuid" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | var signals = []string{ |
27 | 27 | } |
28 | 28 | defer os.RemoveAll(bundleDir) |
29 | 29 | |
30 | containerID := uuid.NewV4().String() | |
30 | containerID := uuid.NewString() | |
31 | 31 | sigConfig, err := util.GetDefaultGenerator() |
32 | 32 | if err != nil { |
33 | 33 | os.RemoveAll(bundleDir) |
34 | 34 | util.Fatal(err) |
35 | 35 | } |
36 | rootDir := filepath.Join(bundleDir, sigConfig.Spec().Root.Path) | |
36 | rootDir := filepath.Join(bundleDir, sigConfig.Config.Root.Path) | |
37 | 37 | for _, signal := range signals { |
38 | 38 | sigConfig.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("trap 'touch /%s' %s; sleep 10 & wait $!", signal, signal)}) |
39 | 39 | config := util.LifecycleConfig{ |
14 | 14 | t.Header(0) |
15 | 15 | defer t.AutoPlan() |
16 | 16 | |
17 | // limit =~ 100 * page size | |
18 | // NOTE: on some systems, pagesize "1GB" doesn't seem to work. | |
19 | // Ideally we should auto-detect the value. | |
20 | cases := []struct { | |
21 | page string | |
22 | limit uint64 | |
23 | }{ | |
24 | {"2MB", 100 * 2 * 1024 * 1024}, | |
25 | {"1GB", 100 * 1024 * 1024 * 1024}, | |
26 | {"2MB", 100 * 2 * 1024 * 1024}, | |
27 | {"1GB", 100 * 1024 * 1024 * 1024}, | |
17 | pageSizes, err := cgroups.GetHugePageSize() | |
18 | ||
19 | if err != nil { | |
20 | t.Fail(fmt.Sprintf("error when getting hugepage sizes: %+v", err)) | |
28 | 21 | } |
29 | 22 | |
30 | for _, c := range cases { | |
23 | // When setting the limit just for checking if writing works, the amount of memory | |
24 | // requested does not matter, as all insigned integers will be accepted. | |
25 | // Use 2GiB as an example | |
26 | var limit uint64 = 2 * (1 << 30) | |
27 | ||
28 | for _, pageSize := range pageSizes { | |
31 | 29 | g, err := util.GetDefaultGenerator() |
32 | 30 | if err != nil { |
33 | 31 | return err |
34 | 32 | } |
35 | 33 | g.SetLinuxCgroupsPath(cgroups.AbsCgroupPath) |
36 | g.AddLinuxResourcesHugepageLimit(c.page, c.limit) | |
34 | g.AddLinuxResourcesHugepageLimit(pageSize, limit) | |
37 | 35 | err = util.RuntimeOutsideValidate(g, t, func(config *rspec.Spec, t *tap.T, state *rspec.State) error { |
38 | 36 | cg, err := cgroups.FindCgroup() |
39 | 37 | if err != nil { |
44 | 42 | return err |
45 | 43 | } |
46 | 44 | for _, lhl := range lhd { |
47 | if lhl.Pagesize != c.page { | |
45 | if lhl.Pagesize != pageSize { | |
48 | 46 | continue |
49 | 47 | } |
50 | t.Ok(lhl.Limit == c.limit, "hugepage limit is set correctly") | |
51 | t.Diagnosticf("expect: %d, actual: %d", c.limit, lhl.Limit) | |
48 | t.Ok(lhl.Limit == limit, fmt.Sprintf("hugepage limit is set correctly for size: %s", pageSize)) | |
49 | t.Diagnosticf("expect: %d, actual: %d", limit, lhl.Limit) | |
52 | 50 | } |
53 | 51 | return nil |
54 | 52 | }) |
62 | 60 | |
63 | 61 | func testWrongHugetlb() error { |
64 | 62 | // We deliberately set the page size to a wrong value, "3MB", to see |
65 | // if the container really returns an error. | |
63 | // if the container really returns an error. Page sizes will always be a | |
64 | // on the format 2^(integer) | |
66 | 65 | page := "3MB" |
67 | 66 | var limit uint64 = 100 * 3 * 1024 * 1024 |
68 | 67 |
0 | 0 | package main |
1 | 1 | |
2 | 2 | import ( |
3 | "fmt" | |
3 | 4 | "github.com/mndrix/tap-go" |
4 | 5 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
5 | 6 | "github.com/opencontainers/runtime-tools/cgroups" |
7 | 8 | ) |
8 | 9 | |
9 | 10 | func main() { |
10 | page := "1GB" | |
11 | var limit uint64 = 56892210544640 | |
12 | ||
13 | 11 | t := tap.New() |
14 | 12 | t.Header(0) |
15 | 13 | defer t.AutoPlan() |
16 | 14 | |
17 | g, err := util.GetDefaultGenerator() | |
18 | if err != nil { | |
19 | util.Fatal(err) | |
20 | } | |
21 | g.SetLinuxCgroupsPath(cgroups.RelCgroupPath) | |
22 | g.AddLinuxResourcesHugepageLimit(page, limit) | |
23 | err = util.RuntimeOutsideValidate(g, t, func(config *rspec.Spec, t *tap.T, state *rspec.State) error { | |
24 | cg, err := cgroups.FindCgroup() | |
25 | t.Ok((err == nil), "find hugetlb cgroup") | |
26 | if err != nil { | |
27 | t.Diagnostic(err.Error()) | |
28 | return nil | |
29 | } | |
30 | ||
31 | lhd, err := cg.GetHugepageLimitData(state.Pid, config.Linux.CgroupsPath) | |
32 | t.Ok((err == nil), "get hugetlb cgroup data") | |
33 | if err != nil { | |
34 | t.Diagnostic(err.Error()) | |
35 | return nil | |
36 | } | |
37 | ||
38 | found := false | |
39 | for _, lhl := range lhd { | |
40 | if lhl.Pagesize == page { | |
41 | found = true | |
42 | t.Ok(lhl.Limit == limit, "hugepage limit is set correctly") | |
43 | t.Diagnosticf("expect: %d, actual: %d", limit, lhl.Limit) | |
44 | } | |
45 | } | |
46 | t.Ok(found, "hugepage limit found") | |
47 | ||
48 | return nil | |
49 | }) | |
15 | pageSizes, err := cgroups.GetHugePageSize() | |
50 | 16 | |
51 | 17 | if err != nil { |
52 | t.Fail(err.Error()) | |
18 | t.Fail(fmt.Sprintf("error when getting hugepage sizes: %+v", err)) | |
19 | } | |
20 | // When setting the limit just for checking if writing works, the amount of memory | |
21 | // requested does not matter, as all insigned integers will be accepted. | |
22 | // Use 2GiB as an example | |
23 | var limit uint64 = 2 * (1 << 30) | |
24 | ||
25 | for _, pageSize := range pageSizes { | |
26 | g, err := util.GetDefaultGenerator() | |
27 | if err != nil { | |
28 | util.Fatal(err) | |
29 | } | |
30 | g.SetLinuxCgroupsPath(cgroups.RelCgroupPath) | |
31 | g.AddLinuxResourcesHugepageLimit(pageSize, limit) | |
32 | err = util.RuntimeOutsideValidate(g, t, func(config *rspec.Spec, t *tap.T, state *rspec.State) error { | |
33 | cg, err := cgroups.FindCgroup() | |
34 | t.Ok((err == nil), "find hugetlb cgroup") | |
35 | if err != nil { | |
36 | t.Diagnostic(err.Error()) | |
37 | return nil | |
38 | } | |
39 | ||
40 | lhd, err := cg.GetHugepageLimitData(state.Pid, config.Linux.CgroupsPath) | |
41 | t.Ok((err == nil), "get hugetlb cgroup data") | |
42 | if err != nil { | |
43 | t.Diagnostic(err.Error()) | |
44 | return nil | |
45 | } | |
46 | ||
47 | found := false | |
48 | for _, lhl := range lhd { | |
49 | if lhl.Pagesize == pageSize { | |
50 | found = true | |
51 | t.Ok(lhl.Limit == limit, fmt.Sprintf("hugepage limit is set correctly for size: %s", pageSize)) | |
52 | t.Diagnosticf("expect: %d, actual: %d", limit, lhl.Limit) | |
53 | } | |
54 | } | |
55 | t.Ok(found, "hugepage limit found") | |
56 | ||
57 | return nil | |
58 | }) | |
59 | ||
60 | if err != nil { | |
61 | t.Fail(err.Error()) | |
62 | } | |
53 | 63 | } |
54 | 64 | } |
21 | 21 | "level": specErr.(*specerror.Error).Err.Level.String(), |
22 | 22 | "reference": specErr.(*specerror.Error).Err.Reference, |
23 | 23 | } |
24 | t.YAML(diagnostic) | |
24 | _ = t.YAML(diagnostic) | |
25 | 25 | } |
26 | 26 | |
27 | 27 | func testNamespaceInheritType(t *tap.T) error { |
118 | 118 | t.Header(0) |
119 | 119 | |
120 | 120 | if "linux" != runtime.GOOS { |
121 | t.Skip(1, fmt.Sprintf("linux-specific namespace test")) | |
121 | t.Skip(1, "linux-specific namespace test") | |
122 | 122 | } |
123 | 123 | |
124 | 124 | err := testNamespaceInheritType(t) |
21 | 21 | "level": specErr.(*specerror.Error).Err.Level.String(), |
22 | 22 | "reference": specErr.(*specerror.Error).Err.Reference, |
23 | 23 | } |
24 | t.YAML(diagnostic) | |
24 | _ = t.YAML(diagnostic) | |
25 | 25 | } |
26 | 26 | |
27 | 27 | func testNamespaceNoPath(t *tap.T) error { |
119 | 119 | t.Header(0) |
120 | 120 | |
121 | 121 | if "linux" != runtime.GOOS { |
122 | t.Skip(1, fmt.Sprintf("linux-specific namespace test")) | |
122 | t.Skip(1, "linux-specific namespace test") | |
123 | 123 | } |
124 | 124 | |
125 | 125 | err := testNamespaceNoPath(t) |
165 | 165 | "level": rfcError.Level.String(), |
166 | 166 | "reference": rfcError.Reference, |
167 | 167 | } |
168 | t.YAML(diagnostic) | |
168 | _ = t.YAML(diagnostic) | |
169 | 169 | } |
170 | 170 | } |
171 | 171 |
41 | 41 | "level": rfcError.Level.String(), |
42 | 42 | "reference": rfcError.Reference, |
43 | 43 | } |
44 | t.YAML(diagnostic) | |
44 | _ = t.YAML(diagnostic) | |
45 | 45 | |
46 | 46 | return fmt.Errorf("cannot validate path with wrong type") |
47 | 47 | } |
9 | 9 | if err != nil { |
10 | 10 | util.Fatal(err) |
11 | 11 | } |
12 | g.SetupPrivileged(true) | |
12 | // Test case validateRootfsPropagation needs CAP_SYS_ADMIN to perform mounts. | |
13 | g.AddProcessCapability("CAP_SYS_ADMIN") | |
14 | // The generated seccomp profile does not enable mount/umount/umount2 syscalls. | |
15 | g.Config.Linux.Seccomp = nil | |
16 | ||
13 | 17 | g.SetLinuxRootPropagation(propMode) |
14 | g.AddAnnotation("TestName", "check root propagation") | |
18 | g.AddAnnotation("TestName", "check root propagation: "+propMode) | |
15 | 19 | return util.RuntimeInsideValidate(g, t, nil) |
16 | 20 | } |
17 | 21 |
11 | 11 | rspecs "github.com/opencontainers/runtime-spec/specs-go" |
12 | 12 | "github.com/opencontainers/runtime-tools/specerror" |
13 | 13 | "github.com/opencontainers/runtime-tools/validation/util" |
14 | uuid "github.com/satori/go.uuid" | |
14 | "github.com/google/uuid" | |
15 | 15 | ) |
16 | 16 | |
17 | 17 | func saveConfig(path string, v interface{}) error { |
38 | 38 | Unknown string `json:"unknown,omitempty"` |
39 | 39 | } |
40 | 40 | |
41 | containerID := uuid.NewV4().String() | |
41 | containerID := uuid.NewString() | |
42 | 42 | basicConfig, err := util.GetDefaultGenerator() |
43 | 43 | if err != nil { |
44 | 44 | util.Fatal(err) |
61 | 61 | errExpected bool |
62 | 62 | err error |
63 | 63 | }{ |
64 | {extendedSpec{Spec: *annotationConfig.Spec()}, util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, true, specerror.NewError(specerror.AnnotationsKeyIgnoreUnknown, fmt.Errorf("implementations that are reading/processing this configuration file MUST NOT generate an error if they encounter an unknown annotation key"), rspecs.Version)}, | |
65 | {extendedSpec{Spec: *basicConfig.Spec(), Unknown: "unknown"}, util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, true, specerror.NewError(specerror.ExtensibilityIgnoreUnknownProp, fmt.Errorf("runtimes that are reading or processing this configuration file MUST NOT generate an error if they encounter an unknown property"), rspecs.Version)}, | |
66 | {extendedSpec{Spec: *invalidConfig.Spec()}, util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, false, specerror.NewError(specerror.ValidValues, fmt.Errorf("runtimes that are reading or processing this configuration file MUST generate an error when invalid or unsupported values are encountered"), rspecs.Version)}, | |
64 | {extendedSpec{Spec: *annotationConfig.Config}, util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, true, specerror.NewError(specerror.AnnotationsKeyIgnoreUnknown, fmt.Errorf("implementations that are reading/processing this configuration file MUST NOT generate an error if they encounter an unknown annotation key"), rspecs.Version)}, | |
65 | {extendedSpec{Spec: *basicConfig.Config, Unknown: "unknown"}, util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, true, specerror.NewError(specerror.ExtensibilityIgnoreUnknownProp, fmt.Errorf("runtimes that are reading or processing this configuration file MUST NOT generate an error if they encounter an unknown property"), rspecs.Version)}, | |
66 | {extendedSpec{Spec: *invalidConfig.Config}, util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, false, specerror.NewError(specerror.ValidValues, fmt.Errorf("runtimes that are reading or processing this configuration file MUST generate an error when invalid or unsupported values are encountered"), rspecs.Version)}, | |
67 | 67 | } |
68 | 68 | |
69 | 69 | for _, c := range cases { |
10 | 10 | |
11 | 11 | tap "github.com/mndrix/tap-go" |
12 | 12 | "github.com/opencontainers/runtime-tools/validation/util" |
13 | uuid "github.com/satori/go.uuid" | |
13 | "github.com/google/uuid" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | func main() { |
33 | 33 | Config: g, |
34 | 34 | Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, |
35 | 35 | PreCreate: func(r *util.Runtime) error { |
36 | r.SetID(uuid.NewV4().String()) | |
36 | r.SetID(uuid.NewString()) | |
37 | 37 | r.PidFile = tempPidFile |
38 | 38 | return nil |
39 | 39 | }, |
75 | 75 | diagnostic["stderr"] = string(e.Stderr) |
76 | 76 | } |
77 | 77 | } |
78 | t.YAML(diagnostic) | |
78 | _ = t.YAML(diagnostic) | |
79 | 79 | } |
80 | 80 | |
81 | 81 | t.AutoPlan() |
12 | 12 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
13 | 13 | "github.com/opencontainers/runtime-tools/specerror" |
14 | 14 | "github.com/opencontainers/runtime-tools/validation/util" |
15 | uuid "github.com/satori/go.uuid" | |
15 | "github.com/google/uuid" | |
16 | 16 | ) |
17 | 17 | |
18 | 18 | func main() { |
23 | 23 | config := util.LifecycleConfig{ |
24 | 24 | Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, |
25 | 25 | PreCreate: func(r *util.Runtime) error { |
26 | r.SetID(uuid.NewV4().String()) | |
26 | r.SetID(uuid.NewString()) | |
27 | 27 | g, err := util.GetDefaultGenerator() |
28 | 28 | if err != nil { |
29 | 29 | util.Fatal(err) |
30 | 30 | } |
31 | output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output") | |
32 | err = g.AddPostStartHook(rspec.Hook{ | |
33 | Path: filepath.Join(r.BundleDir, g.Spec().Root.Path, "/bin/sh"), | |
31 | output = filepath.Join(r.BundleDir, g.Config.Root.Path, "output") | |
32 | g.AddPostStartHook(rspec.Hook{ | |
33 | Path: filepath.Join(r.BundleDir, g.Config.Root.Path, "/bin/sh"), | |
34 | 34 | Args: []string{ |
35 | 35 | "sh", "-c", fmt.Sprintf("echo 'post-start called' >> %s", output), |
36 | 36 | }, |
37 | 37 | }) |
38 | if err != nil { | |
39 | return err | |
40 | } | |
41 | 38 | g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")}) |
42 | 39 | return r.SetConfig(g) |
43 | 40 | }, |
85 | 82 | diagnostic["stderr"] = string(e.Stderr) |
86 | 83 | } |
87 | 84 | } |
88 | t.YAML(diagnostic) | |
85 | _ = t.YAML(diagnostic) | |
89 | 86 | } |
90 | 87 | |
91 | 88 | t.AutoPlan() |
10 | 10 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
11 | 11 | "github.com/opencontainers/runtime-tools/specerror" |
12 | 12 | "github.com/opencontainers/runtime-tools/validation/util" |
13 | uuid "github.com/satori/go.uuid" | |
13 | "github.com/google/uuid" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | func main() { |
27 | 27 | if err != nil { |
28 | 28 | util.Fatal(err) |
29 | 29 | } |
30 | output := filepath.Join(bundleDir, g.Spec().Root.Path, "output") | |
30 | output := filepath.Join(bundleDir, g.Config.Root.Path, "output") | |
31 | 31 | poststart := rspec.Hook{ |
32 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/false"), | |
32 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/false"), | |
33 | 33 | Args: []string{"false"}, |
34 | 34 | } |
35 | 35 | g.AddPostStartHook(poststart) |
36 | 36 | poststartOK := rspec.Hook{ |
37 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/sh"), | |
37 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/sh"), | |
38 | 38 | Args: []string{ |
39 | 39 | "sh", "-c", fmt.Sprintf("echo 'post-start called' >> %s", output), |
40 | 40 | }, |
46 | 46 | BundleDir: bundleDir, |
47 | 47 | Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, |
48 | 48 | PreCreate: func(r *util.Runtime) error { |
49 | r.SetID(uuid.NewV4().String()) | |
49 | r.SetID(uuid.NewString()) | |
50 | 50 | return nil |
51 | 51 | }, |
52 | 52 | PreDelete: func(r *util.Runtime) error { |
65 | 65 | diagnostic := map[string]string{ |
66 | 66 | "error": err.Error(), |
67 | 67 | } |
68 | t.YAML(diagnostic) | |
68 | _ = t.YAML(diagnostic) | |
69 | 69 | } |
70 | 70 | |
71 | 71 | t.AutoPlan() |
13 | 13 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
14 | 14 | "github.com/opencontainers/runtime-tools/specerror" |
15 | 15 | "github.com/opencontainers/runtime-tools/validation/util" |
16 | uuid "github.com/satori/go.uuid" | |
16 | "github.com/google/uuid" | |
17 | 17 | ) |
18 | 18 | |
19 | 19 | func main() { |
24 | 24 | config := util.LifecycleConfig{ |
25 | 25 | Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, |
26 | 26 | PreCreate: func(r *util.Runtime) error { |
27 | r.SetID(uuid.NewV4().String()) | |
27 | r.SetID(uuid.NewString()) | |
28 | 28 | g, err := util.GetDefaultGenerator() |
29 | 29 | if err != nil { |
30 | 30 | util.Fatal(err) |
31 | 31 | } |
32 | output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output") | |
33 | err = g.AddPostStopHook(rspec.Hook{ | |
34 | Path: filepath.Join(r.BundleDir, g.Spec().Root.Path, "/bin/sh"), | |
32 | output = filepath.Join(r.BundleDir, g.Config.Root.Path, "output") | |
33 | g.AddPostStopHook(rspec.Hook{ | |
34 | Path: filepath.Join(r.BundleDir, g.Config.Root.Path, "/bin/sh"), | |
35 | 35 | Args: []string{ |
36 | 36 | "sh", "-c", fmt.Sprintf("echo 'post-stop called' >> %s", output), |
37 | 37 | }, |
38 | 38 | }) |
39 | if err != nil { | |
40 | return err | |
41 | } | |
42 | 39 | g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")}) |
43 | 40 | return r.SetConfig(g) |
44 | 41 | }, |
102 | 99 | diagnostic["stderr"] = string(e.Stderr) |
103 | 100 | } |
104 | 101 | } |
105 | t.YAML(diagnostic) | |
102 | _ = t.YAML(diagnostic) | |
106 | 103 | } |
107 | 104 | |
108 | 105 | t.AutoPlan() |
10 | 10 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
11 | 11 | "github.com/opencontainers/runtime-tools/specerror" |
12 | 12 | "github.com/opencontainers/runtime-tools/validation/util" |
13 | uuid "github.com/satori/go.uuid" | |
13 | "github.com/google/uuid" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | func main() { |
27 | 27 | if err != nil { |
28 | 28 | util.Fatal(err) |
29 | 29 | } |
30 | output := filepath.Join(bundleDir, g.Spec().Root.Path, "output") | |
30 | output := filepath.Join(bundleDir, g.Config.Root.Path, "output") | |
31 | 31 | poststop := rspec.Hook{ |
32 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/false"), | |
32 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/false"), | |
33 | 33 | Args: []string{"false"}, |
34 | 34 | } |
35 | 35 | g.AddPostStopHook(poststop) |
36 | 36 | poststopOK := rspec.Hook{ |
37 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/sh"), | |
37 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/sh"), | |
38 | 38 | Args: []string{ |
39 | 39 | "sh", "-c", fmt.Sprintf("echo 'post-stop called' >> %s", output), |
40 | 40 | }, |
47 | 47 | BundleDir: bundleDir, |
48 | 48 | Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, |
49 | 49 | PreCreate: func(r *util.Runtime) error { |
50 | r.SetID(uuid.NewV4().String()) | |
50 | r.SetID(uuid.NewString()) | |
51 | 51 | return nil |
52 | 52 | }, |
53 | 53 | PreDelete: func(r *util.Runtime) error { |
65 | 65 | diagnostic := map[string]string{ |
66 | 66 | "error": err.Error(), |
67 | 67 | } |
68 | t.YAML(diagnostic) | |
68 | _ = t.YAML(diagnostic) | |
69 | 69 | } |
70 | 70 | |
71 | 71 | t.AutoPlan() |
11 | 11 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
12 | 12 | "github.com/opencontainers/runtime-tools/specerror" |
13 | 13 | "github.com/opencontainers/runtime-tools/validation/util" |
14 | uuid "github.com/satori/go.uuid" | |
14 | "github.com/google/uuid" | |
15 | 15 | ) |
16 | 16 | |
17 | 17 | func main() { |
22 | 22 | config := util.LifecycleConfig{ |
23 | 23 | Actions: util.LifecycleActionCreate | util.LifecycleActionStart | util.LifecycleActionDelete, |
24 | 24 | PreCreate: func(r *util.Runtime) error { |
25 | r.SetID(uuid.NewV4().String()) | |
25 | r.SetID(uuid.NewString()) | |
26 | 26 | g, err := util.GetDefaultGenerator() |
27 | 27 | if err != nil { |
28 | 28 | util.Fatal(err) |
29 | 29 | } |
30 | output = filepath.Join(r.BundleDir, g.Spec().Root.Path, "output") | |
31 | err = g.AddPreStartHook(rspec.Hook{ | |
32 | Path: filepath.Join(r.BundleDir, g.Spec().Root.Path, "/bin/sh"), | |
30 | output = filepath.Join(r.BundleDir, g.Config.Root.Path, "output") | |
31 | g.AddPreStartHook(rspec.Hook{ | |
32 | Path: filepath.Join(r.BundleDir, g.Config.Root.Path, "/bin/sh"), | |
33 | 33 | Args: []string{ |
34 | 34 | "sh", "-c", fmt.Sprintf("echo 'pre-start called' >> %s", output), |
35 | 35 | }, |
36 | 36 | }) |
37 | if err != nil { | |
38 | return err | |
39 | } | |
40 | 37 | g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("echo 'process called' >> %s", "/output")}) |
41 | 38 | return r.SetConfig(g) |
42 | 39 | }, |
84 | 81 | diagnostic["stderr"] = string(e.Stderr) |
85 | 82 | } |
86 | 83 | } |
87 | t.YAML(diagnostic) | |
84 | _ = t.YAML(diagnostic) | |
88 | 85 | } |
89 | 86 | |
90 | 87 | t.AutoPlan() |
8 | 8 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
9 | 9 | "github.com/opencontainers/runtime-tools/specerror" |
10 | 10 | "github.com/opencontainers/runtime-tools/validation/util" |
11 | uuid "github.com/satori/go.uuid" | |
11 | "github.com/google/uuid" | |
12 | 12 | ) |
13 | 13 | |
14 | 14 | func main() { |
26 | 26 | util.Fatal(err) |
27 | 27 | } |
28 | 28 | prestart := rspec.Hook{ |
29 | Path: filepath.Join(bundleDir, g.Spec().Root.Path, "/bin/false"), | |
29 | Path: filepath.Join(bundleDir, g.Config.Root.Path, "/bin/false"), | |
30 | 30 | Args: []string{"false"}, |
31 | 31 | } |
32 | 32 | g.AddPreStartHook(prestart) |
33 | 33 | g.SetProcessArgs([]string{"sh", "-c", fmt.Sprintf("touch %s", "/output")}) |
34 | containerID := uuid.NewV4().String() | |
34 | containerID := uuid.NewString() | |
35 | 35 | |
36 | 36 | config := util.LifecycleConfig{ |
37 | 37 | Config: g, |
44 | 44 | } |
45 | 45 | |
46 | 46 | runErr := util.RuntimeLifecycleValidate(config) |
47 | _, outputErr := os.Stat(filepath.Join(bundleDir, g.Spec().Root.Path, "output")) | |
47 | _, outputErr := os.Stat(filepath.Join(bundleDir, g.Config.Root.Path, "output")) | |
48 | 48 | |
49 | 49 | // query the state |
50 | 50 | r, _ := util.NewRuntime(util.RuntimeCommand, "") |
63 | 63 | diagnostic := map[string]string{ |
64 | 64 | "error": err.Error(), |
65 | 65 | } |
66 | t.YAML(diagnostic) | |
66 | _ = t.YAML(diagnostic) | |
67 | 67 | } |
68 | 68 | |
69 | 69 | t.AutoPlan() |
16 | 16 | g.SetProcessUID(10) |
17 | 17 | g.SetProcessGID(10) |
18 | 18 | g.AddProcessAdditionalGid(5) |
19 | g.SetProcessUmask(002) | |
19 | 20 | case "windows": |
20 | 21 | g.SetProcessUsername("test") |
21 | 22 | default: |
10 | 10 | rspecs "github.com/opencontainers/runtime-spec/specs-go" |
11 | 11 | "github.com/opencontainers/runtime-tools/specerror" |
12 | 12 | "github.com/opencontainers/runtime-tools/validation/util" |
13 | uuid "github.com/satori/go.uuid" | |
13 | "github.com/google/uuid" | |
14 | 14 | ) |
15 | 15 | |
16 | 16 | func main() { |
24 | 24 | } |
25 | 25 | defer os.RemoveAll(bundleDir) |
26 | 26 | |
27 | containerID := uuid.NewV4().String() | |
27 | containerID := uuid.NewString() | |
28 | 28 | |
29 | 29 | r, err := util.NewRuntime(util.RuntimeCommand, bundleDir) |
30 | 30 | if err != nil { |
39 | 39 | if err != nil { |
40 | 40 | util.Fatal(err) |
41 | 41 | } |
42 | output := filepath.Join(bundleDir, g.Spec().Root.Path, "output") | |
42 | output := filepath.Join(bundleDir, g.Config.Root.Path, "output") | |
43 | 43 | |
44 | 44 | // start without id |
45 | 45 | err = r.Start() |
97 | 97 | return |
98 | 98 | } |
99 | 99 | |
100 | g.Spec().Process = nil | |
100 | g.Config.Process = nil | |
101 | 101 | err = r.SetConfig(g) |
102 | 102 | if err != nil { |
103 | 103 | util.Fatal(err) |
9 | 9 | rfc2119 "github.com/opencontainers/runtime-tools/error" |
10 | 10 | "github.com/opencontainers/runtime-tools/specerror" |
11 | 11 | "github.com/opencontainers/runtime-tools/validation/util" |
12 | uuid "github.com/satori/go.uuid" | |
12 | "github.com/google/uuid" | |
13 | 13 | ) |
14 | 14 | |
15 | 15 | func main() { |
21 | 21 | util.Fatal(err) |
22 | 22 | } |
23 | 23 | g.SetProcessArgs([]string{"true"}) |
24 | containerID := uuid.NewV4().String() | |
24 | containerID := uuid.NewString() | |
25 | 25 | |
26 | 26 | cases := []struct { |
27 | 27 | id string |
56 | 56 | "reference": e.Err.Reference, |
57 | 57 | "error": e.Err.Error(), |
58 | 58 | } |
59 | t.YAML(diagnostic) | |
59 | _ = t.YAML(diagnostic) | |
60 | 60 | continue |
61 | 61 | } |
62 | 62 | |
72 | 72 | } |
73 | 73 | } |
74 | 74 | } |
75 | t.YAML(diagnostic) | |
75 | _ = t.YAML(diagnostic) | |
76 | 76 | } |
77 | 77 | |
78 | 78 | t.AutoPlan() |
3 | 3 | "encoding/json" |
4 | 4 | "errors" |
5 | 5 | "fmt" |
6 | "io" | |
7 | 6 | "io/ioutil" |
8 | 7 | "os" |
9 | 8 | "os/exec" |
10 | 9 | "path/filepath" |
11 | "time" | |
12 | ||
10 | ||
11 | "github.com/google/uuid" | |
13 | 12 | rspecs "github.com/opencontainers/runtime-spec/specs-go" |
14 | 13 | "github.com/opencontainers/runtime-tools/generate" |
15 | 14 | "github.com/opencontainers/runtime-tools/specerror" |
16 | "github.com/satori/go.uuid" | |
17 | 15 | ) |
18 | 16 | |
19 | 17 | // Runtime represents the basic requirement of a container runtime |
79 | 77 | args = append(args, r.ID) |
80 | 78 | } |
81 | 79 | cmd := exec.Command(r.RuntimeCommand, args...) |
82 | id := uuid.NewV4().String() | |
80 | id := uuid.NewString() | |
83 | 81 | r.stdout, err = os.OpenFile(filepath.Join(r.bundleDir(), fmt.Sprintf("stdout-%s", id)), os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) |
84 | 82 | if err != nil { |
85 | 83 | return err |
109 | 107 | |
110 | 108 | // ReadStandardStreams collects content from the stdout and stderr buffers. |
111 | 109 | func (r *Runtime) ReadStandardStreams() (stdout []byte, stderr []byte, err error) { |
112 | _, err = r.stdout.Seek(0, io.SeekStart) | |
113 | stdout, err2 := ioutil.ReadAll(r.stdout) | |
110 | stdout, err = ioutil.ReadFile(r.stdout.Name()) | |
111 | stderr, err2 := ioutil.ReadFile(r.stderr.Name()) | |
114 | 112 | if err == nil && err2 != nil { |
115 | 113 | err = err2 |
116 | 114 | } |
117 | _, err = r.stderr.Seek(0, io.SeekStart) | |
118 | stderr, err2 = ioutil.ReadAll(r.stderr) | |
119 | if err == nil && err2 != nil { | |
120 | err = err2 | |
121 | } | |
122 | return stdout, stderr, err | |
115 | return | |
123 | 116 | } |
124 | 117 | |
125 | 118 | // Start a container |
180 | 173 | return execWithStderrFallbackToStdout(cmd) |
181 | 174 | } |
182 | 175 | |
183 | // Delete a container | |
184 | func (r *Runtime) Delete() (err error) { | |
176 | // Delete removes a (stopped) container. | |
177 | func (r *Runtime) Delete() error { | |
178 | return r.del(false) | |
179 | } | |
180 | ||
181 | // ForceDelete removes a container (killing it if necessary). | |
182 | func (r *Runtime) ForceDelete() error { | |
183 | return r.del(true) | |
184 | } | |
185 | ||
186 | func (r *Runtime) del(force bool) (err error) { | |
185 | 187 | var args []string |
186 | 188 | args = append(args, "delete") |
189 | if force { | |
190 | args = append(args, "--force") | |
191 | } | |
187 | 192 | if r.ID != "" { |
188 | 193 | args = append(args, r.ID) |
189 | 194 | } |
192 | 197 | return execWithStderrFallbackToStdout(cmd) |
193 | 198 | } |
194 | 199 | |
195 | // Clean deletes the container. If removeBundle is set, the bundle | |
196 | // directory is removed after the container is deleted successfully or, if | |
197 | // forceRemoveBundle is true, after the deletion attempt regardless of | |
198 | // whether it was successful or not. | |
199 | func (r *Runtime) Clean(removeBundle bool, forceRemoveBundle bool) error { | |
200 | r.Kill("KILL") | |
201 | WaitingForStatus(*r, LifecycleStatusStopped, time.Second*10, time.Second/10) | |
202 | ||
203 | err := r.Delete() | |
204 | ||
205 | if removeBundle && (err == nil || forceRemoveBundle) { | |
206 | err2 := os.RemoveAll(r.bundleDir()) | |
207 | if err2 != nil && err == nil { | |
208 | err = err2 | |
209 | } | |
210 | } | |
211 | ||
212 | return err | |
200 | // Clean kills and removes the container and its bundle directory. | |
201 | func (r *Runtime) Clean() { | |
202 | err := r.ForceDelete() | |
203 | if err != nil { | |
204 | fmt.Fprintln(os.Stderr, "Clean: Delete: ", err) | |
205 | } | |
206 | ||
207 | err = os.RemoveAll(r.bundleDir()) | |
208 | if err != nil { | |
209 | fmt.Fprintln(os.Stderr, "Clean: ", err) | |
210 | } | |
213 | 211 | } |
214 | 212 | |
215 | 213 | func execWithStderrFallbackToStdout(cmd *exec.Cmd) (err error) { |
25 | 25 | } |
26 | 26 | |
27 | 27 | for i, device := range config.Linux.Resources.Devices { |
28 | if device.Allow == true { | |
28 | if device.Allow { | |
29 | 29 | found := false |
30 | 30 | if lnd[i-1].Type == device.Type && *lnd[i-1].Major == *device.Major && *lnd[i-1].Minor == *device.Minor && lnd[i-1].Access == device.Access { |
31 | 31 | found = true |
10 | 10 | "strings" |
11 | 11 | "time" |
12 | 12 | |
13 | "github.com/google/uuid" | |
13 | 14 | "github.com/mndrix/tap-go" |
14 | 15 | "github.com/mrunalp/fileutils" |
15 | 16 | rspec "github.com/opencontainers/runtime-spec/specs-go" |
16 | 17 | "github.com/opencontainers/runtime-tools/generate" |
17 | 18 | "github.com/opencontainers/runtime-tools/specerror" |
18 | "github.com/satori/go.uuid" | |
19 | 19 | ) |
20 | 20 | |
21 | var ( | |
22 | // RuntimeCommand is the default runtime command. | |
23 | RuntimeCommand = "runc" | |
24 | ) | |
21 | // RuntimeCommand is the default runtime command. | |
22 | var RuntimeCommand = "runc" | |
25 | 23 | |
26 | 24 | // LifecycleAction defines the phases will be called. |
27 | 25 | type LifecycleAction int |
51 | 49 | LifecycleStatusStopped |
52 | 50 | ) |
53 | 51 | |
54 | var lifecycleStatusMap = map[string]LifecycleStatus{ | |
55 | "creating": LifecycleStatusCreating, | |
56 | "created": LifecycleStatusCreated, | |
57 | "running": LifecycleStatusRunning, | |
58 | "stopped": LifecycleStatusStopped, | |
52 | var lifecycleStatusMap = map[rspec.ContainerState]LifecycleStatus{ | |
53 | rspec.StateCreating: LifecycleStatusCreating, | |
54 | rspec.StateCreated: LifecycleStatusCreated, | |
55 | rspec.StateRunning: LifecycleStatusRunning, | |
56 | rspec.StateStopped: LifecycleStatusStopped, | |
59 | 57 | } |
60 | 58 | |
61 | 59 | // LifecycleConfig includes |
99 | 97 | t.Header(1) |
100 | 98 | t.Skip(1, message) |
101 | 99 | if diagnostic != nil { |
102 | t.YAML(diagnostic) | |
100 | _ = t.YAML(diagnostic) | |
103 | 101 | } |
104 | 102 | } |
105 | 103 | |
118 | 116 | } |
119 | 117 | } |
120 | 118 | } |
121 | t.YAML(diagnostic) | |
119 | _ = t.YAML(diagnostic) | |
122 | 120 | } |
123 | 121 | |
124 | 122 | // PrepareBundle creates a test bundle in a temporary directory. |
193 | 191 | os.RemoveAll(bundleDir) |
194 | 192 | return err |
195 | 193 | } |
196 | defer r.Clean(true, true) | |
194 | defer r.Clean() | |
197 | 195 | err = r.SetConfig(g) |
198 | 196 | if err != nil { |
199 | 197 | return err |
203 | 201 | return err |
204 | 202 | } |
205 | 203 | |
206 | r.SetID(uuid.NewV4().String()) | |
204 | r.SetID(uuid.NewString()) | |
207 | 205 | err = r.Create() |
208 | 206 | if err != nil { |
209 | 207 | os.Stderr.WriteString("failed to create the container\n") |
246 | 244 | if err != nil { |
247 | 245 | diagnostic["error"] = fmt.Sprintf("%v", err) |
248 | 246 | } |
249 | t.YAML(diagnostic) | |
247 | _ = t.YAML(diagnostic) | |
250 | 248 | t.Ok(err == nil && !strings.Contains(string(stdout), "not ok"), g.Config.Annotations["TestName"]) |
251 | 249 | } else { |
252 | 250 | if runtimeInsideValidateCalled { |
270 | 268 | os.RemoveAll(bundleDir) |
271 | 269 | return err |
272 | 270 | } |
273 | defer r.Clean(true, true) | |
271 | defer r.Clean() | |
274 | 272 | err = r.SetConfig(g) |
275 | 273 | if err != nil { |
276 | 274 | return err |
280 | 278 | return err |
281 | 279 | } |
282 | 280 | |
283 | r.SetID(uuid.NewV4().String()) | |
281 | r.SetID(uuid.NewString()) | |
284 | 282 | err = r.Create() |
285 | 283 | if err != nil { |
286 | 284 | os.Stderr.WriteString("failed to create the container\n") |
295 | 293 | if err != nil { |
296 | 294 | return err |
297 | 295 | } |
298 | if err := f(g.Spec(), t, &state); err != nil { | |
296 | if err := f(g.Config, t, &state); err != nil { | |
299 | 297 | return err |
300 | 298 | } |
301 | 299 | } |
0 | This is free and unencumbered software released into the public domain. | |
1 | ||
2 | Anyone is free to copy, modify, publish, use, compile, sell, or | |
3 | distribute this software, either in source code form or as a compiled | |
4 | binary, for any purpose, commercial or non-commercial, and by any | |
5 | means. | |
6 | ||
7 | In jurisdictions that recognize copyright laws, the author or authors | |
8 | of this software dedicate any and all copyright interest in the | |
9 | software to the public domain. We make this dedication for the benefit | |
10 | of the public at large and to the detriment of our heirs and | |
11 | successors. We intend this dedication to be an overt act of | |
12 | relinquishment in perpetuity of all present and future rights to this | |
13 | software under copyright law. | |
14 | ||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
18 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
19 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
20 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
21 | OTHER DEALINGS IN THE SOFTWARE. | |
22 | ||
23 | For more information, please refer to <http://unlicense.org> |
0 | TESTS = auto check diagnostic failing known skip todo writer yaml | |
1 | GOPATH ?= $(CURDIR)/gopath | |
2 | ||
3 | .PHONY: $(TESTS) | |
4 | ||
5 | all: $(foreach t,$(TESTS),test/$(t)/test) | |
6 | prove -v -e '' test/*/test | |
7 | ||
8 | clean: | |
9 | rm -f test/*/test | |
10 | ||
11 | test/%/test: test/%/*.go tap.go yaml_json.go yaml_yaml.go | |
12 | go build -o $@ -tags yaml ./test/$* | |
13 | ||
14 | $(TESTS): %: test/%/test | |
15 | prove -v -e '' test/$@/test |
0 | # Test Anything Protocol for Go | |
1 | ||
2 | The [Test Anything Protocol](http://testanything.org/) ("TAP") is a text-based | |
3 | interface between tests and a test harness. This package helps Go to generate | |
4 | TAP output. | |
5 | ||
6 | Read the [full package documentation](https://godoc.org/github.com/mndrix/tap-go) |
0 | // Package tap provides support for automated Test Anything Protocol ("TAP") | |
1 | // tests in Go. For example: | |
2 | // | |
3 | // package main | |
4 | // | |
5 | // import "github.com/mndrix/tap-go" | |
6 | // | |
7 | // func main() { | |
8 | // t := tap.New() | |
9 | // t.Header(2) | |
10 | // t.Ok(true, "first test") | |
11 | // t.Ok(true, "second test") | |
12 | // } | |
13 | // | |
14 | // generates the following output | |
15 | // | |
16 | // TAP version 13 | |
17 | // 1..2 | |
18 | // ok 1 - first test | |
19 | // ok 2 - second test | |
20 | package tap | |
21 | ||
22 | import ( | |
23 | "fmt" | |
24 | "io" | |
25 | "os" | |
26 | "strings" | |
27 | ) | |
28 | import "testing/quick" | |
29 | ||
30 | // T is a type to encapsulate test state. Methods on this type generate TAP | |
31 | // output. | |
32 | type T struct { | |
33 | nextTestNumber *int | |
34 | ||
35 | // TODO toggles the TODO directive for Ok, Fail, Pass, and similar. | |
36 | TODO bool | |
37 | ||
38 | // Writer indicates where TAP output should be sent. The default is os.Stdout. | |
39 | Writer io.Writer | |
40 | } | |
41 | ||
42 | // New creates a new Tap value | |
43 | func New() *T { | |
44 | nextTestNumber := 1 | |
45 | return &T{ | |
46 | nextTestNumber: &nextTestNumber, | |
47 | } | |
48 | } | |
49 | ||
50 | func (t *T) w() io.Writer { | |
51 | if t.Writer == nil { | |
52 | return os.Stdout | |
53 | } | |
54 | return t.Writer | |
55 | } | |
56 | ||
57 | func (t *T) printf(format string, a ...interface{}) { | |
58 | fmt.Fprintf(t.w(), format, a...) | |
59 | } | |
60 | ||
61 | // Header displays a TAP header including version number and expected | |
62 | // number of tests to run. For an unknown number of tests, set | |
63 | // testCount to zero (in which case the plan is not written); this is | |
64 | // useful with AutoPlan. | |
65 | func (t *T) Header(testCount int) { | |
66 | t.printf("TAP version 13\n") | |
67 | if testCount > 0 { | |
68 | t.printf("1..%d\n", testCount) | |
69 | } | |
70 | } | |
71 | ||
72 | // Ok generates TAP output indicating whether a test passed or failed. | |
73 | func (t *T) Ok(test bool, description string) { | |
74 | // did the test pass or not? | |
75 | ok := "ok" | |
76 | if !test { | |
77 | ok = "not ok" | |
78 | } | |
79 | ||
80 | if t.TODO { | |
81 | t.printf("%s %d # TODO %s\n", ok, *t.nextTestNumber, description) | |
82 | } else { | |
83 | t.printf("%s %d - %s\n", ok, *t.nextTestNumber, description) | |
84 | } | |
85 | (*t.nextTestNumber)++ | |
86 | } | |
87 | ||
88 | // Fail indicates that a test has failed. This is typically only used when the | |
89 | // logic is too complex to fit naturally into an Ok() call. | |
90 | func (t *T) Fail(description string) { | |
91 | t.Ok(false, description) | |
92 | } | |
93 | ||
94 | // Pass indicates that a test has passed. This is typically only used when the | |
95 | // logic is too complex to fit naturally into an Ok() call. | |
96 | func (t *T) Pass(description string) { | |
97 | t.Ok(true, description) | |
98 | } | |
99 | ||
100 | // Check runs randomized tests against a function just as "testing/quick.Check" | |
101 | // does. Success or failure generate appropriate TAP output. | |
102 | func (t *T) Check(function interface{}, description string) { | |
103 | err := quick.Check(function, nil) | |
104 | if err == nil { | |
105 | t.Ok(true, description) | |
106 | return | |
107 | } | |
108 | ||
109 | t.Diagnostic(err.Error()) | |
110 | t.Ok(false, description) | |
111 | } | |
112 | ||
113 | // Count returns the number of tests completed so far. | |
114 | func (t *T) Count() int { | |
115 | return *t.nextTestNumber - 1 | |
116 | } | |
117 | ||
118 | // AutoPlan generates a test plan based on the number of tests that were run. | |
119 | func (t *T) AutoPlan() { | |
120 | t.printf("1..%d\n", t.Count()) | |
121 | } | |
122 | ||
123 | func escapeNewlines(s string) string { | |
124 | return strings.Replace(strings.TrimRight(s, "\n"), "\n", "\n# ", -1) | |
125 | } | |
126 | ||
127 | // Todo returns copy of the test-state with TODO set. | |
128 | func (t *T) Todo() *T { | |
129 | newT := *t | |
130 | newT.TODO = true | |
131 | return &newT | |
132 | } | |
133 | ||
134 | // Skip indicates that a test has been skipped. | |
135 | func (t *T) Skip(count int, description string) { | |
136 | for i := 0; i < count; i++ { | |
137 | t.printf("ok %d # SKIP %s\n", *t.nextTestNumber, description) | |
138 | (*t.nextTestNumber)++ | |
139 | } | |
140 | } | |
141 | ||
142 | // Diagnostic generates a diagnostic from the message, | |
143 | // which may span multiple lines. | |
144 | func (t *T) Diagnostic(message string) { | |
145 | t.printf("# %s\n", escapeNewlines(message)) | |
146 | } | |
147 | ||
148 | // Diagnosticf generates a diagnostic from the format string and arguments, | |
149 | // which may span multiple lines. | |
150 | func (t *T) Diagnosticf(format string, a ...interface{}) { | |
151 | t.printf("# "+escapeNewlines(format)+"\n", a...) | |
152 | } | |
153 | ||
154 | // YAML generates a YAML block from the message. | |
155 | func (t *T) YAML(message interface{}) error { | |
156 | bytes, err := yaml(message, " ") | |
157 | if err != nil { | |
158 | return err | |
159 | } | |
160 | t.printf(" ---\n ") | |
161 | t.printf(string(bytes)) | |
162 | t.printf(" ...\n") | |
163 | return nil | |
164 | } |
0 | // +build !yaml | |
1 | ||
2 | package tap | |
3 | ||
4 | import ( | |
5 | "encoding/json" | |
6 | ) | |
7 | ||
8 | // yaml serializes a message to YAML. This implementation uses JSON, | |
9 | // which is a subset of YAML [1] and is implemented by Go's standard | |
10 | // library. | |
11 | // | |
12 | // [1]: http://www.yaml.org/spec/1.2/spec.html#id2759572 | |
13 | func yaml(message interface{}, prefix string) (marshaled []byte, err error) { | |
14 | marshaled, err = json.MarshalIndent(message, prefix, " ") | |
15 | if err != nil { | |
16 | return marshaled, err | |
17 | } | |
18 | ||
19 | marshaled = append(marshaled, []byte("\n")...) | |
20 | return marshaled, err | |
21 | } |
0 | // +build yaml | |
1 | ||
2 | package tap | |
3 | ||
4 | import ( | |
5 | "bytes" | |
6 | ||
7 | goyaml "gopkg.in/yaml.v2" | |
8 | ) | |
9 | ||
10 | // yaml serializes a message to YAML. This implementation uses | |
11 | // non-JSON YAML, which has better prove support [1]. | |
12 | // | |
13 | // [1]: https://rt.cpan.org/Public/Bug/Display.html?id=121606 | |
14 | func yaml(message interface{}, prefix string) (marshaled []byte, err error) { | |
15 | marshaled, err = goyaml.Marshal(message) | |
16 | if err != nil { | |
17 | return marshaled, err | |
18 | } | |
19 | ||
20 | marshaled = bytes.Replace(marshaled, []byte("\n"), []byte("\n"+prefix), -1) | |
21 | return marshaled[:len(marshaled)-len(prefix)], err | |
22 | } |