From b8acd7657af90bc17dc5417386e71898c1b34ef5 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 29 Oct 2021 16:44:31 +0200 Subject: [PATCH 01/13] Import internal/oci package from experimental branch Signed-off-by: Evan Lezar --- internal/oci/args.go | 115 ++++++++++++ internal/oci/args_test.go | 184 +++++++++++++++++++ internal/oci/runtime.go | 2 + internal/oci/runtime_low_level.go | 61 +++++++ internal/oci/runtime_mock.go | 105 ++++++----- internal/oci/runtime_path.go | 70 ++++++++ internal/oci/runtime_path_test.go | 97 +++++++++++ internal/oci/runtime_syscall_exec.go | 38 ++++ internal/oci/spec.go | 73 +------- internal/oci/spec_file.go | 153 ++++++++++++++++ internal/oci/spec_file_test.go | 252 +++++++++++++++++++++++++++ internal/oci/spec_mock.go | 231 ++++++++++++++++++------ 12 files changed, 1222 insertions(+), 159 deletions(-) create mode 100644 internal/oci/args.go create mode 100644 internal/oci/args_test.go create mode 100644 internal/oci/runtime_low_level.go create mode 100644 internal/oci/runtime_path.go create mode 100644 internal/oci/runtime_path_test.go create mode 100644 internal/oci/runtime_syscall_exec.go create mode 100644 internal/oci/spec_file.go create mode 100644 internal/oci/spec_file_test.go diff --git a/internal/oci/args.go b/internal/oci/args.go new file mode 100644 index 00000000..de85d9cc --- /dev/null +++ b/internal/oci/args.go @@ -0,0 +1,115 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + "path/filepath" + "strings" +) + +const ( + specFileName = "config.json" +) + +// GetBundleDir returns the bundle directory or default depending on the +// supplied command line arguments. +func GetBundleDir(args []string) (string, error) { + bundleDir, err := GetBundleDirFromArgs(args) + if err != nil { + return "", fmt.Errorf("error getting bundle dir from args: %v", err) + } + + return bundleDir, nil +} + +// GetBundleDirFromArgs checks the specified slice of strings (argv) for a 'bundle' flag as allowed by runc. +// The following are supported: +// --bundle{{SEP}}BUNDLE_PATH +// -bundle{{SEP}}BUNDLE_PATH +// -b{{SEP}}BUNDLE_PATH +// where {{SEP}} is either ' ' or '=' +func GetBundleDirFromArgs(args []string) (string, error) { + var bundleDir string + + for i := 0; i < len(args); i++ { + param := args[i] + + parts := strings.SplitN(param, "=", 2) + if !IsBundleFlag(parts[0]) { + continue + } + + // The flag has the format --bundle=/path + if len(parts) == 2 { + bundleDir = parts[1] + continue + } + + // The flag has the format --bundle /path + if i+1 < len(args) { + bundleDir = args[i+1] + i++ + continue + } + + // --bundle / -b was the last element of args + return "", fmt.Errorf("bundle option requires an argument") + } + + return bundleDir, nil +} + +// GetSpecFilePath returns the expected path to the OCI specification file for the given +// bundle directory. +func GetSpecFilePath(bundleDir string) string { + specFilePath := filepath.Join(bundleDir, specFileName) + return specFilePath +} + +// IsBundleFlag is a helper function that checks wither the specified argument represents +// a bundle flag (--bundle or -b) +func IsBundleFlag(arg string) bool { + if !strings.HasPrefix(arg, "-") { + return false + } + + trimmed := strings.TrimLeft(arg, "-") + return trimmed == "b" || trimmed == "bundle" +} + +// HasCreateSubcommand checks the supplied arguments for a 'create' subcommand +func HasCreateSubcommand(args []string) bool { + var previousWasBundle bool + for _, a := range args { + // We check for '--bundle create' explicitly to ensure that we + // don't inadvertently trigger a modification if the bundle directory + // is specified as `create` + if !previousWasBundle && IsBundleFlag(a) { + previousWasBundle = true + continue + } + + if !previousWasBundle && a == "create" { + return true + } + + previousWasBundle = false + } + + return false +} diff --git a/internal/oci/args_test.go b/internal/oci/args_test.go new file mode 100644 index 00000000..562dd0a9 --- /dev/null +++ b/internal/oci/args_test.go @@ -0,0 +1,184 @@ +package oci + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGetBundleDir(t *testing.T) { + type expected struct { + bundle string + isError bool + } + testCases := []struct { + argv []string + expected expected + }{ + { + argv: []string{}, + expected: expected{ + bundle: "", + }, + }, + { + argv: []string{"create"}, + expected: expected{ + bundle: "", + }, + }, + { + argv: []string{"--bundle"}, + expected: expected{ + isError: true, + }, + }, + { + argv: []string{"-b"}, + expected: expected{ + isError: true, + }, + }, + { + argv: []string{"--bundle", "/foo/bar"}, + expected: expected{ + bundle: "/foo/bar", + }, + }, + { + argv: []string{"--not-bundle", "/foo/bar"}, + expected: expected{ + bundle: "", + }, + }, + { + argv: []string{"--"}, + expected: expected{ + bundle: "", + }, + }, + { + argv: []string{"-bundle", "/foo/bar"}, + expected: expected{ + bundle: "/foo/bar", + }, + }, + { + argv: []string{"--bundle=/foo/bar"}, + expected: expected{ + bundle: "/foo/bar", + }, + }, + { + argv: []string{"-b=/foo/bar"}, + expected: expected{ + bundle: "/foo/bar", + }, + }, + { + argv: []string{"-b=/foo/=bar"}, + expected: expected{ + bundle: "/foo/=bar", + }, + }, + { + argv: []string{"-b", "/foo/bar"}, + expected: expected{ + bundle: "/foo/bar", + }, + }, + { + argv: []string{"create", "-b", "/foo/bar"}, + expected: expected{ + bundle: "/foo/bar", + }, + }, + { + argv: []string{"-b", "create", "create"}, + expected: expected{ + bundle: "create", + }, + }, + { + argv: []string{"-b=create", "create"}, + expected: expected{ + bundle: "create", + }, + }, + { + argv: []string{"-b", "create"}, + expected: expected{ + bundle: "create", + }, + }, + } + + for i, tc := range testCases { + bundle, err := GetBundleDir(tc.argv) + + if tc.expected.isError { + require.Errorf(t, err, "%d: %v", i, tc) + } else { + require.NoErrorf(t, err, "%d: %v", i, tc) + } + + require.Equalf(t, tc.expected.bundle, bundle, "%d: %v", i, tc) + } +} + +func TestGetSpecFilePathAppendsFilename(t *testing.T) { + testCases := []struct { + bundleDir string + expected string + }{ + { + bundleDir: "", + expected: "config.json", + }, + { + bundleDir: "/not/empty/", + expected: "/not/empty/config.json", + }, + { + bundleDir: "not/absolute", + expected: "not/absolute/config.json", + }, + } + + for i, tc := range testCases { + specPath := GetSpecFilePath(tc.bundleDir) + + require.Equalf(t, tc.expected, specPath, "%d: %v", i, tc) + } +} + +func TestHasCreateSubcommand(t *testing.T) { + testCases := []struct { + args []string + shouldModify bool + }{ + { + shouldModify: false, + }, + { + args: []string{"create"}, + shouldModify: true, + }, + { + args: []string{"--bundle=create"}, + shouldModify: false, + }, + { + args: []string{"--bundle", "create"}, + shouldModify: false, + }, + { + args: []string{"create"}, + shouldModify: true, + }, + } + + for i, tc := range testCases { + require.Equal(t, tc.shouldModify, HasCreateSubcommand(tc.args), "%d: %v", i, tc) + } +} diff --git a/internal/oci/runtime.go b/internal/oci/runtime.go index 89df5aa1..438fc5d2 100644 --- a/internal/oci/runtime.go +++ b/internal/oci/runtime.go @@ -16,6 +16,8 @@ package oci +//go:generate moq -stub -out runtime_mock.go . Runtime + // Runtime is an interface for a runtime shim. The Exec method accepts a list // of command line arguments, and returns an error / nil. type Runtime interface { diff --git a/internal/oci/runtime_low_level.go b/internal/oci/runtime_low_level.go new file mode 100644 index 00000000..56c9e367 --- /dev/null +++ b/internal/oci/runtime_low_level.go @@ -0,0 +1,61 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + "os/exec" + + log "github.com/sirupsen/logrus" +) + +// NewLowLevelRuntime creates a Runtime that wraps a low-level runtime executable. +// The executable specified is taken from the list of supplied candidates, with the first match +// present in the PATH being selected. +func NewLowLevelRuntime(candidates ...string) (Runtime, error) { + return NewLowLevelRuntimeWithLogger(log.StandardLogger(), candidates...) +} + +// NewLowLevelRuntimeWithLogger creates a Runtime as with NewLowLevelRuntime using the specified logger. +func NewLowLevelRuntimeWithLogger(logger *log.Logger, candidates ...string) (Runtime, error) { + runtimePath, err := findRuntime(candidates) + if err != nil { + return nil, fmt.Errorf("error locating runtime: %v", err) + } + + return NewRuntimeForPathWithLogger(logger, runtimePath) +} + +// findRuntime checks elements in a list of supplied candidates for a matching executable in the PATH. +// The absolute path to the first match is returned. +func findRuntime(candidates []string) (string, error) { + if len(candidates) == 0 { + return "", fmt.Errorf("at least one runtime candidate must be specified") + } + + for _, candidate := range candidates { + log.Infof("Looking for runtime binary '%v'", candidate) + runcPath, err := exec.LookPath(candidate) + if err == nil { + log.Infof("Found runtime binary '%v'", runcPath) + return runcPath, nil + } + log.Warnf("Runtime binary '%v' not found: %v", candidate, err) + } + + return "", fmt.Errorf("no runtime binary found from candidate list: %v", candidates) +} diff --git a/internal/oci/runtime_mock.go b/internal/oci/runtime_mock.go index e09cfb79..2887fb22 100644 --- a/internal/oci/runtime_mock.go +++ b/internal/oci/runtime_mock.go @@ -1,49 +1,76 @@ -/* -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -*/ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq package oci -// MockExecRuntime wraps a SyscallExecRuntime, intercepting the exec call for testing -type MockExecRuntime struct { - SyscallExecRuntime - execMock -} +import ( + "sync" +) -// WithMockExec wraps a specified SyscallExecRuntime with a mocked exec function for testing -func WithMockExec(e SyscallExecRuntime, execResult error) *MockExecRuntime { - m := MockExecRuntime{ - SyscallExecRuntime: e, - execMock: execMock{result: execResult}, +// Ensure, that RuntimeMock does implement Runtime. +// If this is not the case, regenerate this file with moq. +var _ Runtime = &RuntimeMock{} + +// RuntimeMock is a mock implementation of Runtime. +// +// func TestSomethingThatUsesRuntime(t *testing.T) { +// +// // make and configure a mocked Runtime +// mockedRuntime := &RuntimeMock{ +// ExecFunc: func(strings []string) error { +// panic("mock out the Exec method") +// }, +// } +// +// // use mockedRuntime in code that requires Runtime +// // and then make assertions. +// +// } +type RuntimeMock struct { + // ExecFunc mocks the Exec method. + ExecFunc func(strings []string) error + + // calls tracks calls to the methods. + calls struct { + // Exec holds details about calls to the Exec method. + Exec []struct { + // Strings is the strings argument value. + Strings []string + } } - // overrdie the exec function to the mocked exec function. - m.SyscallExecRuntime.exec = m.execMock.exec - return &m + lockExec sync.RWMutex } -type execMock struct { - argv0 string - argv []string - envv []string - result error +// Exec calls ExecFunc. +func (mock *RuntimeMock) Exec(strings []string) error { + callInfo := struct { + Strings []string + }{ + Strings: strings, + } + mock.lockExec.Lock() + mock.calls.Exec = append(mock.calls.Exec, callInfo) + mock.lockExec.Unlock() + if mock.ExecFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.ExecFunc(strings) } -func (m *execMock) exec(argv0 string, argv []string, envv []string) error { - m.argv0 = argv0 - m.argv = argv - m.envv = envv - - return m.result +// ExecCalls gets all the calls that were made to Exec. +// Check the length with: +// len(mockedRuntime.ExecCalls()) +func (mock *RuntimeMock) ExecCalls() []struct { + Strings []string +} { + var calls []struct { + Strings []string + } + mock.lockExec.RLock() + calls = mock.calls.Exec + mock.lockExec.RUnlock() + return calls } diff --git a/internal/oci/runtime_path.go b/internal/oci/runtime_path.go new file mode 100644 index 00000000..abf225b2 --- /dev/null +++ b/internal/oci/runtime_path.go @@ -0,0 +1,70 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + "os" + + log "github.com/sirupsen/logrus" +) + +// pathRuntime wraps the path that a binary and defines the semanitcs for how to exec into it. +// This can be used to wrap an OCI-compliant low-level runtime binary, allowing it to be used through the +// Runtime internface. +type pathRuntime struct { + logger *log.Logger + path string + execRuntime Runtime +} + +var _ Runtime = (*pathRuntime)(nil) + +// NewRuntimeForPath creates a Runtime for the specified path with the standard logger +func NewRuntimeForPath(path string) (Runtime, error) { + return NewRuntimeForPathWithLogger(log.StandardLogger(), path) +} + +// NewRuntimeForPathWithLogger creates a Runtime for the specified logger and path +func NewRuntimeForPathWithLogger(logger *log.Logger, path string) (Runtime, error) { + info, err := os.Stat(path) + if err != nil { + return nil, fmt.Errorf("invalid path '%v': %v", path, err) + } + if info.IsDir() || info.Mode()&0111 == 0 { + return nil, fmt.Errorf("specified path '%v' is not an executable file", path) + } + + shim := pathRuntime{ + logger: logger, + path: path, + execRuntime: syscallExec{}, + } + + return &shim, nil +} + +// Exec exces into the binary at the path from the pathRuntime struct, passing it the supplied arguments +// after ensuring that the first argument is the path of the target binary. +func (s pathRuntime) Exec(args []string) error { + runtimeArgs := []string{s.path} + if len(args) > 1 { + runtimeArgs = append(runtimeArgs, args[1:]...) + } + + return s.execRuntime.Exec(runtimeArgs) +} diff --git a/internal/oci/runtime_path_test.go b/internal/oci/runtime_path_test.go new file mode 100644 index 00000000..0d936a3f --- /dev/null +++ b/internal/oci/runtime_path_test.go @@ -0,0 +1,97 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ +package oci + +import ( + "fmt" + "testing" + + testlog "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/require" +) + +func TestPathRuntimeConstructor(t *testing.T) { + r, err := NewRuntimeForPath("////an/invalid/path") + require.Error(t, err) + require.Nil(t, r) + + r, err = NewRuntimeForPath("/tmp") + require.Error(t, err) + require.Nil(t, r) + + r, err = NewRuntimeForPath("/dev/null") + require.Error(t, err) + require.Nil(t, r) + + r, err = NewRuntimeForPath("/bin/sh") + require.NoError(t, err) + + f, ok := r.(*pathRuntime) + require.True(t, ok) + + require.Equal(t, "/bin/sh", f.path) +} + +func TestPathRuntimeForwardsArgs(t *testing.T) { + logger, _ := testlog.NewNullLogger() + + testCases := []struct { + execRuntimeError error + args []string + }{ + {}, + { + args: []string{"shouldBeReplaced"}, + }, + { + args: []string{"shouldBeReplaced", "arg1"}, + }, + { + execRuntimeError: fmt.Errorf("exec error"), + }, + } + + for _, tc := range testCases { + mockedRuntime := &RuntimeMock{ + ExecFunc: func(strings []string) error { + return tc.execRuntimeError + }, + } + r := pathRuntime{ + logger: logger, + path: "runtime", + execRuntime: mockedRuntime, + } + err := r.Exec(tc.args) + + require.ErrorIs(t, err, tc.execRuntimeError) + + calls := mockedRuntime.ExecCalls() + require.Len(t, calls, 1) + + numArgs := len(tc.args) + if numArgs == 0 { + numArgs = 1 + } + + require.Len(t, calls[0].Strings, numArgs) + require.Equal(t, "runtime", calls[0].Strings[0]) + + if numArgs > 1 { + require.EqualValues(t, tc.args[1:], calls[0].Strings[1:]) + } + } +} diff --git a/internal/oci/runtime_syscall_exec.go b/internal/oci/runtime_syscall_exec.go new file mode 100644 index 00000000..d752776a --- /dev/null +++ b/internal/oci/runtime_syscall_exec.go @@ -0,0 +1,38 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "fmt" + "os" + "syscall" +) + +type syscallExec struct{} + +var _ Runtime = (*syscallExec)(nil) + +func (r syscallExec) Exec(args []string) error { + err := syscall.Exec(args[0], args, os.Environ()) + if err != nil { + return fmt.Errorf("could not exec '%v': %v", args[0], err) + } + + // syscall.Exec is not expected to return. This is an error state regardless of whether + // err is nil or not. + return fmt.Errorf("unexpected return from exec '%v'", args[0]) +} diff --git a/internal/oci/spec.go b/internal/oci/spec.go index 0c3aaf4d..259ce054 100644 --- a/internal/oci/spec.go +++ b/internal/oci/spec.go @@ -17,10 +17,6 @@ package oci import ( - "encoding/json" - "fmt" - "os" - oci "github.com/opencontainers/runtime-spec/specs-go" ) @@ -28,75 +24,12 @@ import ( // error. The intention is that the function would modify the spec in-place. type SpecModifier func(*oci.Spec) error +//go:generate moq -stub -out spec_mock.go . Spec + // Spec defines the operations to be performed on an OCI specification type Spec interface { Load() error Flush() error Modify(SpecModifier) error -} - -type fileSpec struct { - *oci.Spec - path string -} - -var _ Spec = (*fileSpec)(nil) - -// NewSpecFromFile creates an object that encapsulates a file-backed OCI spec. -// This can be used to read from the file, modify the spec, and write to the -// same file. -func NewSpecFromFile(filepath string) Spec { - oci := fileSpec{ - path: filepath, - } - - return &oci -} - -// Load reads the contents of an OCI spec from file to be referenced internally. -// The file is opened "read-only" -func (s *fileSpec) Load() error { - specFile, err := os.Open(s.path) - if err != nil { - return fmt.Errorf("error opening OCI specification file: %v", err) - } - defer specFile.Close() - - decoder := json.NewDecoder(specFile) - - var spec oci.Spec - err = decoder.Decode(&spec) - if err != nil { - return fmt.Errorf("error reading OCI specification from file: %v", err) - } - - s.Spec = &spec - return nil -} - -// Modify applies the specified SpecModifier to the stored OCI specification. -func (s *fileSpec) Modify(f SpecModifier) error { - if s.Spec == nil { - return fmt.Errorf("no spec loaded for modification") - } - return f(s.Spec) -} - -// Flush writes the stored OCI specification to the filepath specifed by the path member. -// The file is truncated upon opening, overwriting any existing contents. -func (s fileSpec) Flush() error { - specFile, err := os.Create(s.path) - if err != nil { - return fmt.Errorf("error opening OCI specification file: %v", err) - } - defer specFile.Close() - - encoder := json.NewEncoder(specFile) - - err = encoder.Encode(s.Spec) - if err != nil { - return fmt.Errorf("error writing OCI specification to file: %v", err) - } - - return nil + LookupEnv(string) (string, bool) } diff --git a/internal/oci/spec_file.go b/internal/oci/spec_file.go new file mode 100644 index 00000000..886e2cb3 --- /dev/null +++ b/internal/oci/spec_file.go @@ -0,0 +1,153 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" + + oci "github.com/opencontainers/runtime-spec/specs-go" +) + +type fileSpec struct { + *oci.Spec + path string +} + +var _ Spec = (*fileSpec)(nil) + +// NewSpecFromArgs creates fileSpec based on the command line arguments passed to the +// application +func NewSpecFromArgs(args []string) (Spec, string, error) { + bundleDir, err := GetBundleDir(args) + if err != nil { + return nil, "", fmt.Errorf("error getting bundle directory: %v", err) + } + + ociSpecPath := GetSpecFilePath(bundleDir) + + ociSpec := NewSpecFromFile(ociSpecPath) + + return ociSpec, bundleDir, nil +} + +// NewSpecFromFile creates an object that encapsulates a file-backed OCI spec. +// This can be used to read from the file, modify the spec, and write to the +// same file. +func NewSpecFromFile(filepath string) Spec { + oci := fileSpec{ + path: filepath, + } + + return &oci +} + +// Load reads the contents of an OCI spec from file to be referenced internally. +// The file is opened "read-only" +func (s *fileSpec) Load() error { + specFile, err := os.Open(s.path) + if err != nil { + return fmt.Errorf("error opening OCI specification file: %v", err) + } + defer specFile.Close() + + return s.loadFrom(specFile) +} + +// loadFrom reads the contents of the OCI spec from the specified io.Reader. +func (s *fileSpec) loadFrom(reader io.Reader) error { + decoder := json.NewDecoder(reader) + + var spec oci.Spec + err := decoder.Decode(&spec) + if err != nil { + return fmt.Errorf("error reading OCI specification: %v", err) + } + + s.Spec = &spec + return nil +} + +// Modify applies the specified SpecModifier to the stored OCI specification. +func (s *fileSpec) Modify(f SpecModifier) error { + if s.Spec == nil { + return fmt.Errorf("no spec loaded for modification") + } + return f(s.Spec) +} + +// Flush writes the stored OCI specification to the filepath specifed by the path member. +// The file is truncated upon opening, overwriting any existing contents. +func (s fileSpec) Flush() error { + if s.Spec == nil { + return fmt.Errorf("no OCI specification loaded") + } + + specFile, err := os.Create(s.path) + if err != nil { + return fmt.Errorf("error opening OCI specification file: %v", err) + } + defer specFile.Close() + + return s.flushTo(specFile) +} + +// flushTo writes the stored OCI specification to the specified io.Writer. +func (s fileSpec) flushTo(writer io.Writer) error { + if s.Spec == nil { + return nil + } + encoder := json.NewEncoder(writer) + + err := encoder.Encode(s.Spec) + if err != nil { + return fmt.Errorf("error writing OCI specification: %v", err) + } + + return nil +} + +// LookupEnv mirrors os.LookupEnv for the OCI specification. It +// retrieves the value of the environment variable named +// by the key. If the variable is present in the environment the +// value (which may be empty) is returned and the boolean is true. +// Otherwise the returned value will be empty and the boolean will +// be false. +func (s fileSpec) LookupEnv(key string) (string, bool) { + if s.Spec == nil || s.Spec.Process == nil { + return "", false + } + + for _, env := range s.Spec.Process.Env { + if !strings.HasPrefix(env, key) { + continue + } + + parts := strings.SplitN(env, "=", 2) + if parts[0] == key { + if len(parts) < 2 { + return "", true + } + return parts[1], true + } + } + + return "", false +} diff --git a/internal/oci/spec_file_test.go b/internal/oci/spec_file_test.go new file mode 100644 index 00000000..fe273824 --- /dev/null +++ b/internal/oci/spec_file_test.go @@ -0,0 +1,252 @@ +/* +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +*/ + +package oci + +import ( + "bytes" + "fmt" + "testing" + + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/stretchr/testify/require" +) + +func TestLookupEnv(t *testing.T) { + const envName = "TEST_ENV" + testCases := []struct { + spec *specs.Spec + expectedValue string + expectedExits bool + }{ + { + // nil spec + spec: nil, + expectedValue: "", + expectedExits: false, + }, + { + // nil process + spec: &specs.Spec{}, + expectedValue: "", + expectedExits: false, + }, + { + // nil env + spec: &specs.Spec{ + Process: &specs.Process{}, + }, + expectedValue: "", + expectedExits: false, + }, + { + // empty env + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{}}, + }, + expectedValue: "", + expectedExits: false, + }, + { + // different env set + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{"SOMETHING_ELSE=foo"}}, + }, + expectedValue: "", + expectedExits: false, + }, + { + // same prefix + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{"TEST_ENV_BUT_NOT=foo"}}, + }, + expectedValue: "", + expectedExits: false, + }, + { + // same suffix + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{"NOT_TEST_ENV=foo"}}, + }, + expectedValue: "", + expectedExits: false, + }, + { + // set blank + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{"TEST_ENV="}}, + }, + expectedValue: "", + expectedExits: true, + }, + { + // set no-equals + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{"TEST_ENV"}}, + }, + expectedValue: "", + expectedExits: true, + }, + { + // set value + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{"TEST_ENV=something"}}, + }, + expectedValue: "something", + expectedExits: true, + }, + { + // set with equals + spec: &specs.Spec{ + Process: &specs.Process{Env: []string{"TEST_ENV=something=somethingelse"}}, + }, + expectedValue: "something=somethingelse", + expectedExits: true, + }, + } + + for i, tc := range testCases { + spec := fileSpec{ + Spec: tc.spec, + } + + value, exists := spec.LookupEnv(envName) + + require.Equal(t, tc.expectedValue, value, "%d: %v", i, tc) + require.Equal(t, tc.expectedExits, exists, "%d: %v", i, tc) + } +} + +func TestLoadFrom(t *testing.T) { + testCases := []struct { + contents []byte + isError bool + spec *specs.Spec + }{ + { + contents: []byte{}, + isError: true, + }, + { + contents: []byte("{}"), + isError: false, + spec: &specs.Spec{}, + }, + } + + for i, tc := range testCases { + spec := fileSpec{} + err := spec.loadFrom(bytes.NewReader(tc.contents)) + + if tc.isError { + require.Error(t, err, "%d: %v", i, tc) + } else { + require.NoError(t, err, "%d: %v", i, tc) + } + + if tc.spec == nil { + require.Nil(t, spec.Spec, "%d: %v", i, tc) + } else { + require.EqualValues(t, tc.spec, spec.Spec, "%d: %v", i, tc) + } + } +} + +func TestFlushTo(t *testing.T) { + testCases := []struct { + isError bool + spec *specs.Spec + contents string + }{ + { + spec: nil, + }, + { + spec: &specs.Spec{}, + contents: "{\"ociVersion\":\"\"}\n", + }, + } + + for i, tc := range testCases { + buffer := bytes.Buffer{} + + spec := fileSpec{Spec: tc.spec} + err := spec.flushTo(&buffer) + + if tc.isError { + require.Error(t, err, "%d: %v", i, tc) + } else { + require.NoError(t, err, "%d: %v", i, tc) + } + + require.EqualValues(t, tc.contents, buffer.String(), "%d: %v", i, tc) + } + + // Add a simple test for a writer that returns an error when writing + spec := fileSpec{Spec: &specs.Spec{}} + err := spec.flushTo(errorWriter{}) + require.Error(t, err) +} + +func TestModify(t *testing.T) { + + testCases := []struct { + spec *specs.Spec + modifierError error + }{ + { + spec: nil, + }, + { + spec: &specs.Spec{}, + }, + { + spec: &specs.Spec{}, + modifierError: fmt.Errorf("error in modifier"), + }, + } + + for i, tc := range testCases { + spec := fileSpec{Spec: tc.spec} + + modifier := func(spec *specs.Spec) error { + if tc.modifierError == nil { + spec.Version = "updated" + } + return tc.modifierError + } + + err := spec.Modify(modifier) + + if tc.spec == nil { + require.Error(t, err, "%d: %v", i, tc) + } else if tc.modifierError != nil { + require.EqualError(t, err, tc.modifierError.Error(), "%d: %v", i, tc) + require.EqualValues(t, &specs.Spec{}, spec.Spec, "%d: %v", i, tc) + } else { + require.NoError(t, err, "%d: %v", i, tc) + require.Equal(t, "updated", spec.Spec.Version, "%d: %v", i, tc) + } + } +} + +// errorWriter implements the io.Writer interface, always returning an error when +// writing. +type errorWriter struct{} + +func (e errorWriter) Write([]byte) (int, error) { + return 0, fmt.Errorf("error writing") +} diff --git a/internal/oci/spec_mock.go b/internal/oci/spec_mock.go index 1247adaf..1656552c 100644 --- a/internal/oci/spec_mock.go +++ b/internal/oci/spec_mock.go @@ -1,70 +1,201 @@ -/* -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -*/ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq package oci import ( - oci "github.com/opencontainers/runtime-spec/specs-go" + "sync" ) -// MockSpec provides a simple mock for an OCI spec to be used in testing. -// It also implements the SpecModifier interface. -type MockSpec struct { - *oci.Spec - MockLoad mockFunc - MockFlush mockFunc - MockModify mockFunc -} +// Ensure, that SpecMock does implement Spec. +// If this is not the case, regenerate this file with moq. +var _ Spec = &SpecMock{} -var _ Spec = (*MockSpec)(nil) +// SpecMock is a mock implementation of Spec. +// +// func TestSomethingThatUsesSpec(t *testing.T) { +// +// // make and configure a mocked Spec +// mockedSpec := &SpecMock{ +// FlushFunc: func() error { +// panic("mock out the Flush method") +// }, +// LoadFunc: func() error { +// panic("mock out the Load method") +// }, +// LookupEnvFunc: func(s string) (string, bool) { +// panic("mock out the LookupEnv method") +// }, +// ModifyFunc: func(specModifier SpecModifier) error { +// panic("mock out the Modify method") +// }, +// } +// +// // use mockedSpec in code that requires Spec +// // and then make assertions. +// +// } +type SpecMock struct { + // FlushFunc mocks the Flush method. + FlushFunc func() error -// NewMockSpec constructs a MockSpec to be used in testing as a Spec -func NewMockSpec(spec *oci.Spec, flushResult error, modifyResult error) *MockSpec { - s := MockSpec{ - Spec: spec, - MockFlush: mockFunc{result: flushResult}, - MockModify: mockFunc{result: modifyResult}, + // LoadFunc mocks the Load method. + LoadFunc func() error + + // LookupEnvFunc mocks the LookupEnv method. + LookupEnvFunc func(s string) (string, bool) + + // ModifyFunc mocks the Modify method. + ModifyFunc func(specModifier SpecModifier) error + + // calls tracks calls to the methods. + calls struct { + // Flush holds details about calls to the Flush method. + Flush []struct { + } + // Load holds details about calls to the Load method. + Load []struct { + } + // LookupEnv holds details about calls to the LookupEnv method. + LookupEnv []struct { + // S is the s argument value. + S string + } + // Modify holds details about calls to the Modify method. + Modify []struct { + // SpecModifier is the specModifier argument value. + SpecModifier SpecModifier + } } - - return &s + lockFlush sync.RWMutex + lockLoad sync.RWMutex + lockLookupEnv sync.RWMutex + lockModify sync.RWMutex } -// Load invokes the mocked Load function to return the predefined error / result -func (s *MockSpec) Load() error { - return s.MockLoad.call() +// Flush calls FlushFunc. +func (mock *SpecMock) Flush() error { + callInfo := struct { + }{} + mock.lockFlush.Lock() + mock.calls.Flush = append(mock.calls.Flush, callInfo) + mock.lockFlush.Unlock() + if mock.FlushFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.FlushFunc() } -// Flush invokes the mocked Load function to return the predefined error / result -func (s *MockSpec) Flush() error { - return s.MockFlush.call() +// FlushCalls gets all the calls that were made to Flush. +// Check the length with: +// len(mockedSpec.FlushCalls()) +func (mock *SpecMock) FlushCalls() []struct { +} { + var calls []struct { + } + mock.lockFlush.RLock() + calls = mock.calls.Flush + mock.lockFlush.RUnlock() + return calls } -// Modify applies the specified SpecModifier to the spec and invokes the -// mocked modify function to return the predefined error / result. -func (s *MockSpec) Modify(f SpecModifier) error { - f(s.Spec) - return s.MockModify.call() +// Load calls LoadFunc. +func (mock *SpecMock) Load() error { + callInfo := struct { + }{} + mock.lockLoad.Lock() + mock.calls.Load = append(mock.calls.Load, callInfo) + mock.lockLoad.Unlock() + if mock.LoadFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.LoadFunc() } -type mockFunc struct { - Callcount int - result error +// LoadCalls gets all the calls that were made to Load. +// Check the length with: +// len(mockedSpec.LoadCalls()) +func (mock *SpecMock) LoadCalls() []struct { +} { + var calls []struct { + } + mock.lockLoad.RLock() + calls = mock.calls.Load + mock.lockLoad.RUnlock() + return calls } -func (m *mockFunc) call() error { - m.Callcount++ - return m.result +// LookupEnv calls LookupEnvFunc. +func (mock *SpecMock) LookupEnv(s string) (string, bool) { + callInfo := struct { + S string + }{ + S: s, + } + mock.lockLookupEnv.Lock() + mock.calls.LookupEnv = append(mock.calls.LookupEnv, callInfo) + mock.lockLookupEnv.Unlock() + if mock.LookupEnvFunc == nil { + var ( + sOut string + bOut bool + ) + return sOut, bOut + } + return mock.LookupEnvFunc(s) +} + +// LookupEnvCalls gets all the calls that were made to LookupEnv. +// Check the length with: +// len(mockedSpec.LookupEnvCalls()) +func (mock *SpecMock) LookupEnvCalls() []struct { + S string +} { + var calls []struct { + S string + } + mock.lockLookupEnv.RLock() + calls = mock.calls.LookupEnv + mock.lockLookupEnv.RUnlock() + return calls +} + +// Modify calls ModifyFunc. +func (mock *SpecMock) Modify(specModifier SpecModifier) error { + callInfo := struct { + SpecModifier SpecModifier + }{ + SpecModifier: specModifier, + } + mock.lockModify.Lock() + mock.calls.Modify = append(mock.calls.Modify, callInfo) + mock.lockModify.Unlock() + if mock.ModifyFunc == nil { + var ( + errOut error + ) + return errOut + } + return mock.ModifyFunc(specModifier) +} + +// ModifyCalls gets all the calls that were made to Modify. +// Check the length with: +// len(mockedSpec.ModifyCalls()) +func (mock *SpecMock) ModifyCalls() []struct { + SpecModifier SpecModifier +} { + var calls []struct { + SpecModifier SpecModifier + } + mock.lockModify.RLock() + calls = mock.calls.Modify + mock.lockModify.RUnlock() + return calls } From d234077780e09e1ac1e8c830ea8ed8fb1a952551 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 29 Oct 2021 16:49:02 +0200 Subject: [PATCH 02/13] Remove unneeded files Signed-off-by: Evan Lezar --- internal/oci/runtime_exec.go | 79 ----------------------- internal/oci/runtime_exec_test.go | 100 ------------------------------ 2 files changed, 179 deletions(-) delete mode 100644 internal/oci/runtime_exec.go delete mode 100644 internal/oci/runtime_exec_test.go diff --git a/internal/oci/runtime_exec.go b/internal/oci/runtime_exec.go deleted file mode 100644 index 98415747..00000000 --- a/internal/oci/runtime_exec.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -*/ - -package oci - -import ( - "fmt" - "os" - "syscall" - - log "github.com/sirupsen/logrus" -) - -// SyscallExecRuntime wraps the path that a binary and defines the semanitcs for how to exec into it. -// This can be used to wrap an OCI-compliant low-level runtime binary, allowing it to be used through the -// Runtime internface. -type SyscallExecRuntime struct { - logger *log.Logger - path string - // exec is used for testing. This defaults to syscall.Exec - exec func(argv0 string, argv []string, envv []string) error -} - -var _ Runtime = (*SyscallExecRuntime)(nil) - -// NewSyscallExecRuntime creates a SyscallExecRuntime for the specified path with the standard logger -func NewSyscallExecRuntime(path string) (Runtime, error) { - return NewSyscallExecRuntimeWithLogger(log.StandardLogger(), path) -} - -// NewSyscallExecRuntimeWithLogger creates a SyscallExecRuntime for the specified logger and path -func NewSyscallExecRuntimeWithLogger(logger *log.Logger, path string) (Runtime, error) { - info, err := os.Stat(path) - if err != nil { - return nil, fmt.Errorf("invalid path '%v': %v", path, err) - } - if info.IsDir() || info.Mode()&0111 == 0 { - return nil, fmt.Errorf("specified path '%v' is not an executable file", path) - } - - shim := SyscallExecRuntime{ - logger: logger, - path: path, - exec: syscall.Exec, - } - - return &shim, nil -} - -// Exec exces into the binary at the path from the SyscallExecRuntime struct, passing it the supplied arguments -// after ensuring that the first argument is the path of the target binary. -func (s SyscallExecRuntime) Exec(args []string) error { - runtimeArgs := []string{s.path} - if len(args) > 1 { - runtimeArgs = append(runtimeArgs, args[1:]...) - } - - err := s.exec(s.path, runtimeArgs, os.Environ()) - if err != nil { - return fmt.Errorf("could not exec '%v': %v", s.path, err) - } - - // syscall.Exec is not expected to return. This is an error state regardless of whether - // err is nil or not. - return fmt.Errorf("unexpected return from exec '%v'", s.path) -} diff --git a/internal/oci/runtime_exec_test.go b/internal/oci/runtime_exec_test.go deleted file mode 100644 index 83ac64a2..00000000 --- a/internal/oci/runtime_exec_test.go +++ /dev/null @@ -1,100 +0,0 @@ -/* -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -*/ -package oci - -import ( - "fmt" - "strings" - "testing" - - testlog "github.com/sirupsen/logrus/hooks/test" - "github.com/stretchr/testify/require" -) - -func TestSyscallExecConstructor(t *testing.T) { - r, err := NewSyscallExecRuntime("////an/invalid/path") - require.Error(t, err) - require.Nil(t, r) - - r, err = NewSyscallExecRuntime("/tmp") - require.Error(t, err) - require.Nil(t, r) - - r, err = NewSyscallExecRuntime("/dev/null") - require.Error(t, err) - require.Nil(t, r) - - r, err = NewSyscallExecRuntime("/bin/sh") - require.NoError(t, err) - - f, ok := r.(*SyscallExecRuntime) - require.True(t, ok) - - require.Equal(t, "/bin/sh", f.path) -} - -func TestSyscallExecForwardsArgs(t *testing.T) { - logger, _ := testlog.NewNullLogger() - f := SyscallExecRuntime{ - logger: logger, - path: "runtime", - } - - testCases := []struct { - returnError error - args []string - errorPrefix string - }{ - { - returnError: nil, - errorPrefix: "unexpected return from exec", - }, - { - returnError: fmt.Errorf("error from exec"), - errorPrefix: "could not exec", - }, - { - returnError: nil, - args: []string{"otherargv0"}, - errorPrefix: "unexpected return from exec", - }, - { - returnError: nil, - args: []string{"otherargv0", "arg1", "arg2", "arg3"}, - errorPrefix: "unexpected return from exec", - }, - } - - for i, tc := range testCases { - execMock := WithMockExec(f, tc.returnError) - - err := execMock.Exec(tc.args) - - require.Errorf(t, err, "%d: %v", i, tc) - require.Truef(t, strings.HasPrefix(err.Error(), tc.errorPrefix), "%d: %v", i, tc) - if tc.returnError != nil { - require.Truef(t, strings.HasSuffix(err.Error(), tc.returnError.Error()), "%d: %v", i, tc) - } - - require.Equalf(t, f.path, execMock.argv0, "%d: %v", i, tc) - require.Equalf(t, f.path, execMock.argv[0], "%d: %v", i, tc) - - require.LessOrEqualf(t, len(tc.args), len(execMock.argv), "%d: %v", i, tc) - if len(tc.args) > 1 { - require.Equalf(t, tc.args[1:], execMock.argv[1:], "%d: %v", i, tc) - } - } -} From ec8a6d978d7821a08bdc54b1ebe76600b489f6fe Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 29 Oct 2021 16:45:04 +0200 Subject: [PATCH 03/13] Import cmd/nvidia-container-runtime from experimental branch Signed-off-by: Evan Lezar --- cmd/nvidia-container-runtime/nvcr.go | 19 +- cmd/nvidia-container-runtime/nvcr_test.go | 47 ++--- .../runtime_factory.go | 108 +----------- .../runtime_factory_test.go | 162 ------------------ 4 files changed, 23 insertions(+), 313 deletions(-) diff --git a/cmd/nvidia-container-runtime/nvcr.go b/cmd/nvidia-container-runtime/nvcr.go index 1eb23a26..6c4185b3 100644 --- a/cmd/nvidia-container-runtime/nvcr.go +++ b/cmd/nvidia-container-runtime/nvcr.go @@ -66,22 +66,9 @@ func (r nvidiaContainerRuntime) Exec(args []string) error { // modificationRequired checks the intput arguments to determine whether a modification // to the OCI spec is required. func (r nvidiaContainerRuntime) modificationRequired(args []string) bool { - var previousWasBundle bool - for _, a := range args { - // We check for '--bundle create' explicitly to ensure that we - // don't inadvertently trigger a modification if the bundle directory - // is specified as `create` - if !previousWasBundle && isBundleFlag(a) { - previousWasBundle = true - continue - } - - if !previousWasBundle && a == "create" { - r.logger.Infof("'create' command detected; modification required") - return true - } - - previousWasBundle = false + if oci.HasCreateSubcommand(args) { + r.logger.Infof("'create' command detected; modification required") + return true } r.logger.Infof("No modification required") diff --git a/cmd/nvidia-container-runtime/nvcr_test.go b/cmd/nvidia-container-runtime/nvcr_test.go index 5650e635..16e1b447 100644 --- a/cmd/nvidia-container-runtime/nvcr_test.go +++ b/cmd/nvidia-container-runtime/nvcr_test.go @@ -27,32 +27,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestArgsGetConfigFilePath(t *testing.T) { - testCases := []struct { - bundleDir string - ociSpecPath string - }{ - { - ociSpecPath: "config.json", - }, - { - bundleDir: "/foo/bar", - ociSpecPath: "/foo/bar/config.json", - }, - { - bundleDir: "/foo/bar/", - ociSpecPath: "/foo/bar/config.json", - }, - } - - for i, tc := range testCases { - cp, err := getOCISpecFilePath(tc.bundleDir) - - require.NoErrorf(t, err, "%d: %v", i, tc) - require.Equalf(t, tc.ociSpecPath, cp, "%d: %v", i, tc) - } -} - func TestAddNvidiaHook(t *testing.T) { logger, logHook := testlog.NewNullLogger() shim := nvidiaContainerRuntime{ @@ -181,9 +155,14 @@ func TestNvidiaContainerRuntime(t *testing.T) { tc.shim.logger = logger hook.Reset() - spec := &specs.Spec{} - ociMock := oci.NewMockSpec(spec, tc.writeError, tc.modifyError) - + ociMock := &oci.SpecMock{ + ModifyFunc: func(specModifier oci.SpecModifier) error { + return tc.modifyError + }, + FlushFunc: func() error { + return tc.writeError + }, + } require.Equal(t, tc.shouldModify, tc.shim.modificationRequired(tc.args), "%d: %v", i, tc) tc.shim.ociSpec = ociMock @@ -197,18 +176,16 @@ func TestNvidiaContainerRuntime(t *testing.T) { } if tc.shouldModify { - require.Equal(t, 1, ociMock.MockModify.Callcount, "%d: %v", i, tc) - require.Equal(t, 1, nvidiaHookCount(spec.Hooks), "%d: %v", i, tc) + require.Equal(t, 1, len(ociMock.ModifyCalls()), "%d: %v", i, tc) } else { - require.Equal(t, 0, ociMock.MockModify.Callcount, "%d: %v", i, tc) - require.Nil(t, spec.Hooks, "%d: %v", i, tc) + require.Equal(t, 0, len(ociMock.ModifyCalls()), "%d: %v", i, tc) } writeExpected := tc.shouldModify && tc.modifyError == nil if writeExpected { - require.Equal(t, 1, ociMock.MockFlush.Callcount, "%d: %v", i, tc) + require.Equal(t, 1, len(ociMock.FlushCalls()), "%d: %v", i, tc) } else { - require.Equal(t, 0, ociMock.MockFlush.Callcount, "%d: %v", i, tc) + require.Equal(t, 0, len(ociMock.FlushCalls()), "%d: %v", i, tc) } } } diff --git a/cmd/nvidia-container-runtime/runtime_factory.go b/cmd/nvidia-container-runtime/runtime_factory.go index 151de77a..0af37f6e 100644 --- a/cmd/nvidia-container-runtime/runtime_factory.go +++ b/cmd/nvidia-container-runtime/runtime_factory.go @@ -18,9 +18,6 @@ package main import ( "fmt" - "os/exec" - "path/filepath" - "strings" "github.com/NVIDIA/nvidia-container-toolkit/internal/oci" ) @@ -53,15 +50,15 @@ func newRuntime(argv []string) (oci.Runtime, error) { // newOCISpec constructs an OCI spec for the provided arguments func newOCISpec(argv []string) (oci.Spec, error) { - bundlePath, err := getBundlePath(argv) + bundleDir, err := oci.GetBundleDir(argv) if err != nil { return nil, fmt.Errorf("error parsing command line arguments: %v", err) } + logger.Infof("Using bundle directory: %v", bundleDir) + + ociSpecPath := oci.GetSpecFilePath(bundleDir) + logger.Infof("Using OCI specification file path: %v", ociSpecPath) - ociSpecPath, err := getOCISpecFilePath(bundlePath) - if err != nil { - return nil, fmt.Errorf("error getting OCI specification file path: %v", err) - } ociSpec := oci.NewSpecFromFile(ociSpecPath) return ociSpec, nil @@ -69,98 +66,9 @@ func newOCISpec(argv []string) (oci.Spec, error) { // newRuncRuntime locates the runc binary and wraps it in a SyscallExecRuntime func newRuncRuntime() (oci.Runtime, error) { - runtimePath, err := findRunc() - if err != nil { - return nil, fmt.Errorf("error locating runtime: %v", err) - } - - runc, err := oci.NewSyscallExecRuntimeWithLogger(logger.Logger, runtimePath) - if err != nil { - return nil, fmt.Errorf("error constructing runtime: %v", err) - } - - return runc, nil -} - -// getBundlePath checks the specified slice of strings (argv) for a 'bundle' flag as allowed by runc. -// The following are supported: -// --bundle{{SEP}}BUNDLE_PATH -// -bundle{{SEP}}BUNDLE_PATH -// -b{{SEP}}BUNDLE_PATH -// where {{SEP}} is either ' ' or '=' -func getBundlePath(argv []string) (string, error) { - var bundlePath string - - for i := 0; i < len(argv); i++ { - param := argv[i] - - parts := strings.SplitN(param, "=", 2) - if !isBundleFlag(parts[0]) { - continue - } - - // The flag has the format --bundle=/path - if len(parts) == 2 { - bundlePath = parts[1] - continue - } - - // The flag has the format --bundle /path - if i+1 < len(argv) { - bundlePath = argv[i+1] - i++ - continue - } - - // --bundle / -b was the last element of argv - return "", fmt.Errorf("bundle option requires an argument") - } - - return bundlePath, nil -} - -// findRunc locates runc in the path, returning the full path to the -// binary or an error. -func findRunc() (string, error) { - runtimeCandidates := []string{ + return oci.NewLowLevelRuntimeWithLogger( + logger.Logger, dockerRuncExecutableName, runcExecutableName, - } - - return findRuntime(runtimeCandidates) -} - -func findRuntime(runtimeCandidates []string) (string, error) { - for _, candidate := range runtimeCandidates { - logger.Infof("Looking for runtime binary '%v'", candidate) - runcPath, err := exec.LookPath(candidate) - if err == nil { - logger.Infof("Found runtime binary '%v'", runcPath) - return runcPath, nil - } - logger.Warnf("Runtime binary '%v' not found: %v", candidate, err) - } - - return "", fmt.Errorf("no runtime binary found from candidate list: %v", runtimeCandidates) -} - -func isBundleFlag(arg string) bool { - if !strings.HasPrefix(arg, "-") { - return false - } - - trimmed := strings.TrimLeft(arg, "-") - return trimmed == "b" || trimmed == "bundle" -} - -// getOCISpecFilePath returns the expected path to the OCI specification file for the given -// bundle directory. If the bundle directory is empty, only `config.json` is returned. -func getOCISpecFilePath(bundleDir string) (string, error) { - logger.Infof("Using bundle directory: %v", bundleDir) - - OCISpecFilePath := filepath.Join(bundleDir, ociSpecFileName) - - logger.Infof("Using OCI specification file path: %v", OCISpecFilePath) - - return OCISpecFilePath, nil + ) } diff --git a/cmd/nvidia-container-runtime/runtime_factory_test.go b/cmd/nvidia-container-runtime/runtime_factory_test.go index b5a6d461..07d02232 100644 --- a/cmd/nvidia-container-runtime/runtime_factory_test.go +++ b/cmd/nvidia-container-runtime/runtime_factory_test.go @@ -17,10 +17,8 @@ package main import ( - "path/filepath" "testing" - testlog "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/require" ) @@ -30,163 +28,3 @@ func TestConstructor(t *testing.T) { require.NoError(t, err) require.NotNil(t, shim) } - -func TestGetBundlePath(t *testing.T) { - type expected struct { - bundle string - isError bool - } - testCases := []struct { - argv []string - expected expected - }{ - { - argv: []string{}, - }, - { - argv: []string{"create"}, - }, - { - argv: []string{"--bundle"}, - expected: expected{ - isError: true, - }, - }, - { - argv: []string{"-b"}, - expected: expected{ - isError: true, - }, - }, - { - argv: []string{"--bundle", "/foo/bar"}, - expected: expected{ - bundle: "/foo/bar", - }, - }, - { - argv: []string{"--not-bundle", "/foo/bar"}, - }, - { - argv: []string{"--"}, - }, - { - argv: []string{"-bundle", "/foo/bar"}, - expected: expected{ - bundle: "/foo/bar", - }, - }, - { - argv: []string{"--bundle=/foo/bar"}, - expected: expected{ - bundle: "/foo/bar", - }, - }, - { - argv: []string{"-b=/foo/bar"}, - expected: expected{ - bundle: "/foo/bar", - }, - }, - { - argv: []string{"-b=/foo/=bar"}, - expected: expected{ - bundle: "/foo/=bar", - }, - }, - { - argv: []string{"-b", "/foo/bar"}, - expected: expected{ - bundle: "/foo/bar", - }, - }, - { - argv: []string{"create", "-b", "/foo/bar"}, - expected: expected{ - bundle: "/foo/bar", - }, - }, - { - argv: []string{"-b", "create", "create"}, - expected: expected{ - bundle: "create", - }, - }, - { - argv: []string{"-b=create", "create"}, - expected: expected{ - bundle: "create", - }, - }, - { - argv: []string{"-b", "create"}, - expected: expected{ - bundle: "create", - }, - }, - } - - for i, tc := range testCases { - bundle, err := getBundlePath(tc.argv) - - if tc.expected.isError { - require.Errorf(t, err, "%d: %v", i, tc) - } else { - require.NoErrorf(t, err, "%d: %v", i, tc) - } - - require.Equalf(t, tc.expected.bundle, bundle, "%d: %v", i, tc) - } -} - -func TestFindRunc(t *testing.T) { - testLogger, _ := testlog.NewNullLogger() - logger.Logger = testLogger - - runcPath, err := findRunc() - require.NoError(t, err) - require.Equal(t, filepath.Join(cfg.binPath, runcExecutableName), runcPath) -} - -func TestFindRuntime(t *testing.T) { - testLogger, _ := testlog.NewNullLogger() - logger.Logger = testLogger - - testCases := []struct { - candidates []string - expectedPath string - }{ - { - candidates: []string{}, - }, - { - candidates: []string{"not-runc"}, - }, - { - candidates: []string{"not-runc", "also-not-runc"}, - }, - { - candidates: []string{runcExecutableName}, - expectedPath: filepath.Join(cfg.binPath, runcExecutableName), - }, - { - candidates: []string{runcExecutableName, "not-runc"}, - expectedPath: filepath.Join(cfg.binPath, runcExecutableName), - }, - { - candidates: []string{"not-runc", runcExecutableName}, - expectedPath: filepath.Join(cfg.binPath, runcExecutableName), - }, - } - - for i, tc := range testCases { - runcPath, err := findRuntime(tc.candidates) - if tc.expectedPath == "" { - require.Error(t, err, "%d: %v", i, tc) - } else { - require.NoError(t, err, "%d: %v", i, tc) - } - require.Equal(t, tc.expectedPath, runcPath, "%d: %v", i, tc) - } - -} From 93ecf3aeaf175cc26ae0561b057e3b81d28365c2 Mon Sep 17 00:00:00 2001 From: Christopher Desiniotis Date: Wed, 27 Oct 2021 17:26:46 -0700 Subject: [PATCH 04/13] [ci] use pulse instead of contamer for scans Signed-off-by: Christopher Desiniotis --- .nvidia-ci.yml | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/.nvidia-ci.yml b/.nvidia-ci.yml index 5f52749d..f3fddd0a 100644 --- a/.nvidia-ci.yml +++ b/.nvidia-ci.yml @@ -45,10 +45,10 @@ variables: # images. .scan: stage: scan + image: "${PULSE_IMAGE}" variables: IMAGE: "${CI_REGISTRY_IMAGE}/container-toolkit:${CI_COMMIT_SHORT_SHA}-${DIST}" - # SCAN_IMAGE must be a local image - SCAN_IMAGE: "container-toolkit:${CI_COMMIT_SHORT_SHA}-${DIST}" + IMAGE_ARCHIVE: "container-toolkit.tar" rules: - if: $CI_COMMIT_MESSAGE =~ /\[skip[ _-]scans?\]/i when: never @@ -57,18 +57,25 @@ variables: - if: $CI_COMMIT_TAG == null && $CI_COMMIT_BRANCH != $RELEASE_DEVEL_BRANCH allow_failure: true before_script: - - apk add --no-cache git - - apk add --no-cache python3 python3-dev py3-pip py3-wheel libmagic - docker login -u "${CI_REGISTRY_USER}" -p "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" # TODO: We should specify the architecture here and scan all architectures - docker pull "${IMAGE}" - - docker tag "${IMAGE}" "${SCAN_IMAGE}" - - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab-master.nvidia.com/sectooling/scanning/contamer.git - - pip3 install -r contamer/requirements.txt + - docker save "${IMAGE}" -o "${IMAGE_ARCHIVE}" + - AuthHeader=$(echo -n $SSA_CLIENT_ID:$SSA_CLIENT_SECRET | base64 -w0) + - > + export SSA_TOKEN=$(curl --request POST --header "Authorization: Basic $AuthHeader" --header "Content-Type: application/x-www-form-urlencoded" ${SSA_ISSUER_URL} | jq ".access_token" | tr -d '"') + - if [ -z "$SSA_TOKEN" ]; then exit 1; else echo "SSA_TOKEN set!"; fi script: - - cd contamer - - python3 contamer.py -ls --fail-on-non-os ${CONTAMER_SUPPRESS_VULNS:+--suppress-vulns ${CONTAMER_SUPPRESS_VULNS}} -- "${SCAN_IMAGE}" - + - pulse-cli -n $NSPECT_ID --pss $PSS_URL --ssa $SSA_TOKEN scan -i $IMAGE_ARCHIVE -p $CONTAINER_POLICY -o + artifacts: + when: always + expire_in: 1 week + paths: + - pulse-cli.log + - licenses.json + - sbom.json + - vulns.json + - policy_evaluation.json # Define the scan targets scan-centos7: From 8afd89676fa618de8f79b387cf30b3f76b0653ce Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Thu, 4 Nov 2021 13:42:21 +0100 Subject: [PATCH 05/13] Add basic test for preservation of OCI spec under modification Signed-off-by: Evan Lezar --- internal/oci/spec_test.go | 58 +++ test/input/config.clone3.json | 784 ++++++++++++++++++++++++++++++++++ 2 files changed, 842 insertions(+) create mode 100644 internal/oci/spec_test.go create mode 100644 test/input/config.clone3.json diff --git a/internal/oci/spec_test.go b/internal/oci/spec_test.go new file mode 100644 index 00000000..20fc97b3 --- /dev/null +++ b/internal/oci/spec_test.go @@ -0,0 +1,58 @@ +package oci + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMaintainSpec(t *testing.T) { + moduleRoot, err := getModuleRoot() + require.NoError(t, err) + + files := []string{ + "config.clone3.json", + } + + for _, f := range files { + inputSpecPath := filepath.Join(moduleRoot, "test/input", f) + + spec := NewSpecFromFile(inputSpecPath).(*fileSpec) + + spec.Load() + + outputSpecPath := filepath.Join(moduleRoot, "test/output", f) + spec.path = outputSpecPath + spec.Flush() + + inputContents, err := os.ReadFile(inputSpecPath) + require.NoError(t, err) + + outputContents, err := os.ReadFile(outputSpecPath) + require.NoError(t, err) + + require.JSONEq(t, string(inputContents), string(outputContents)) + } +} + +func getModuleRoot() (string, error) { + _, filename, _, _ := runtime.Caller(0) + + return hasGoMod(filename) +} + +func hasGoMod(dir string) (string, error) { + if dir == "" || dir == "/" { + return "", fmt.Errorf("module root not found") + } + + _, err := os.Stat(filepath.Join(dir, "go.mod")) + if err != nil { + return hasGoMod(filepath.Dir(dir)) + } + return dir, nil +} diff --git a/test/input/config.clone3.json b/test/input/config.clone3.json new file mode 100644 index 00000000..92d8d223 --- /dev/null +++ b/test/input/config.clone3.json @@ -0,0 +1,784 @@ +{ + "ociVersion": "1.0.2-dev", + "process": { + "terminal": true, + "user": { + "uid": 0, + "gid": 0 + }, + "args": [ + "sleep", + "60" + ], + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "HOSTNAME=8de5efc6a95c", + "TERM=xterm" + ], + "cwd": "/", + "capabilities": { + "bounding": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ], + "effective": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ], + "inheritable": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ], + "permitted": [ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" + ] + }, + "apparmorProfile": "docker-default", + "oomScoreAdj": 0 + }, + "root": { + "path": "/var/lib/docker/overlay2/fbf92f54592ddb439159bc7eb25c865b9347a2d71d63b41b7b4e4a471847c84f/merged" + }, + "hostname": "8de5efc6a95c", + "mounts": [ + { + "destination": "/proc", + "type": "proc", + "source": "proc", + "options": [ + "nosuid", + "noexec", + "nodev" + ] + }, + { + "destination": "/dev", + "type": "tmpfs", + "source": "tmpfs", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ] + }, + { + "destination": "/dev/pts", + "type": "devpts", + "source": "devpts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ] + }, + { + "destination": "/sys", + "type": "sysfs", + "source": "sysfs", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ] + }, + { + "destination": "/sys/fs/cgroup", + "type": "cgroup", + "source": "cgroup", + "options": [ + "ro", + "nosuid", + "noexec", + "nodev" + ] + }, + { + "destination": "/dev/mqueue", + "type": "mqueue", + "source": "mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ] + }, + { + "destination": "/dev/shm", + "type": "tmpfs", + "source": "shm", + "options": [ + "nosuid", + "noexec", + "nodev", + "mode=1777", + "size=67108864" + ] + }, + { + "destination": "/etc/resolv.conf", + "type": "bind", + "source": "/var/lib/docker/containers/8de5efc6a95c4ddae36dde7beb656ed5c7de912ecec2f628c42dbd0ef7bbeec6/resolv.conf", + "options": [ + "rbind", + "rprivate" + ] + }, + { + "destination": "/etc/hostname", + "type": "bind", + "source": "/var/lib/docker/containers/8de5efc6a95c4ddae36dde7beb656ed5c7de912ecec2f628c42dbd0ef7bbeec6/hostname", + "options": [ + "rbind", + "rprivate" + ] + }, + { + "destination": "/etc/hosts", + "type": "bind", + "source": "/var/lib/docker/containers/8de5efc6a95c4ddae36dde7beb656ed5c7de912ecec2f628c42dbd0ef7bbeec6/hosts", + "options": [ + "rbind", + "rprivate" + ] + } + ], + "hooks": { + "prestart": [ + { + "path": "/proc/593/exe", + "args": [ + "libnetwork-setkey", + "-exec-root=/var/run/docker", + "8de5efc6a95c4ddae36dde7beb656ed5c7de912ecec2f628c42dbd0ef7bbeec6", + "9967b9f7c4d4" + ] + } + ] + }, + "linux": { + "sysctl": { + "net.ipv4.ip_unprivileged_port_start": "0" + }, + "resources": { + "devices": [ + { + "allow": false, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 5, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 3, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 9, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 1, + "minor": 8, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "minor": 0, + "access": "rwm" + }, + { + "allow": true, + "type": "c", + "major": 5, + "minor": 1, + "access": "rwm" + }, + { + "allow": false, + "type": "c", + "major": 10, + "minor": 229, + "access": "rwm" + } + ], + "memory": { + "disableOOMKiller": false + }, + "cpu": { + "shares": 0 + }, + "blockIO": { + "weight": 0 + } + }, + "cgroupsPath": "/docker/8de5efc6a95c4ddae36dde7beb656ed5c7de912ecec2f628c42dbd0ef7bbeec6", + "namespaces": [ + { + "type": "mount" + }, + { + "type": "network" + }, + { + "type": "uts" + }, + { + "type": "pid" + }, + { + "type": "ipc" + } + ], + "seccomp": { + "defaultAction": "SCMP_ACT_ERRNO", + "architectures": [ + "SCMP_ARCH_X86_64", + "SCMP_ARCH_X86", + "SCMP_ARCH_X32" + ], + "syscalls": [ + { + "names": [ + "accept", + "accept4", + "access", + "adjtimex", + "alarm", + "bind", + "brk", + "capget", + "capset", + "chdir", + "chmod", + "chown", + "chown32", + "clock_adjtime", + "clock_adjtime64", + "clock_getres", + "clock_getres_time64", + "clock_gettime", + "clock_gettime64", + "clock_nanosleep", + "clock_nanosleep_time64", + "close", + "close_range", + "connect", + "copy_file_range", + "creat", + "dup", + "dup2", + "dup3", + "epoll_create", + "epoll_create1", + "epoll_ctl", + "epoll_ctl_old", + "epoll_pwait", + "epoll_pwait2", + "epoll_wait", + "epoll_wait_old", + "eventfd", + "eventfd2", + "execve", + "execveat", + "exit", + "exit_group", + "faccessat", + "faccessat2", + "fadvise64", + "fadvise64_64", + "fallocate", + "fanotify_mark", + "fchdir", + "fchmod", + "fchmodat", + "fchown", + "fchown32", + "fchownat", + "fcntl", + "fcntl64", + "fdatasync", + "fgetxattr", + "flistxattr", + "flock", + "fork", + "fremovexattr", + "fsetxattr", + "fstat", + "fstat64", + "fstatat64", + "fstatfs", + "fstatfs64", + "fsync", + "ftruncate", + "ftruncate64", + "futex", + "futex_time64", + "futimesat", + "getcpu", + "getcwd", + "getdents", + "getdents64", + "getegid", + "getegid32", + "geteuid", + "geteuid32", + "getgid", + "getgid32", + "getgroups", + "getgroups32", + "getitimer", + "getpeername", + "getpgid", + "getpgrp", + "getpid", + "getppid", + "getpriority", + "getrandom", + "getresgid", + "getresgid32", + "getresuid", + "getresuid32", + "getrlimit", + "get_robust_list", + "getrusage", + "getsid", + "getsockname", + "getsockopt", + "get_thread_area", + "gettid", + "gettimeofday", + "getuid", + "getuid32", + "getxattr", + "inotify_add_watch", + "inotify_init", + "inotify_init1", + "inotify_rm_watch", + "io_cancel", + "ioctl", + "io_destroy", + "io_getevents", + "io_pgetevents", + "io_pgetevents_time64", + "ioprio_get", + "ioprio_set", + "io_setup", + "io_submit", + "io_uring_enter", + "io_uring_register", + "io_uring_setup", + "ipc", + "kill", + "lchown", + "lchown32", + "lgetxattr", + "link", + "linkat", + "listen", + "listxattr", + "llistxattr", + "_llseek", + "lremovexattr", + "lseek", + "lsetxattr", + "lstat", + "lstat64", + "madvise", + "membarrier", + "memfd_create", + "mincore", + "mkdir", + "mkdirat", + "mknod", + "mknodat", + "mlock", + "mlock2", + "mlockall", + "mmap", + "mmap2", + "mprotect", + "mq_getsetattr", + "mq_notify", + "mq_open", + "mq_timedreceive", + "mq_timedreceive_time64", + "mq_timedsend", + "mq_timedsend_time64", + "mq_unlink", + "mremap", + "msgctl", + "msgget", + "msgrcv", + "msgsnd", + "msync", + "munlock", + "munlockall", + "munmap", + "nanosleep", + "newfstatat", + "_newselect", + "open", + "openat", + "openat2", + "pause", + "pidfd_open", + "pidfd_send_signal", + "pipe", + "pipe2", + "poll", + "ppoll", + "ppoll_time64", + "prctl", + "pread64", + "preadv", + "preadv2", + "prlimit64", + "pselect6", + "pselect6_time64", + "pwrite64", + "pwritev", + "pwritev2", + "read", + "readahead", + "readlink", + "readlinkat", + "readv", + "recv", + "recvfrom", + "recvmmsg", + "recvmmsg_time64", + "recvmsg", + "remap_file_pages", + "removexattr", + "rename", + "renameat", + "renameat2", + "restart_syscall", + "rmdir", + "rseq", + "rt_sigaction", + "rt_sigpending", + "rt_sigprocmask", + "rt_sigqueueinfo", + "rt_sigreturn", + "rt_sigsuspend", + "rt_sigtimedwait", + "rt_sigtimedwait_time64", + "rt_tgsigqueueinfo", + "sched_getaffinity", + "sched_getattr", + "sched_getparam", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_getscheduler", + "sched_rr_get_interval", + "sched_rr_get_interval_time64", + "sched_setaffinity", + "sched_setattr", + "sched_setparam", + "sched_setscheduler", + "sched_yield", + "seccomp", + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "semtimedop_time64", + "send", + "sendfile", + "sendfile64", + "sendmmsg", + "sendmsg", + "sendto", + "setfsgid", + "setfsgid32", + "setfsuid", + "setfsuid32", + "setgid", + "setgid32", + "setgroups", + "setgroups32", + "setitimer", + "setpgid", + "setpriority", + "setregid", + "setregid32", + "setresgid", + "setresgid32", + "setresuid", + "setresuid32", + "setreuid", + "setreuid32", + "setrlimit", + "set_robust_list", + "setsid", + "setsockopt", + "set_thread_area", + "set_tid_address", + "setuid", + "setuid32", + "setxattr", + "shmat", + "shmctl", + "shmdt", + "shmget", + "shutdown", + "sigaltstack", + "signalfd", + "signalfd4", + "sigprocmask", + "sigreturn", + "socket", + "socketcall", + "socketpair", + "splice", + "stat", + "stat64", + "statfs", + "statfs64", + "statx", + "symlink", + "symlinkat", + "sync", + "sync_file_range", + "syncfs", + "sysinfo", + "tee", + "tgkill", + "time", + "timer_create", + "timer_delete", + "timer_getoverrun", + "timer_gettime", + "timer_gettime64", + "timer_settime", + "timer_settime64", + "timerfd_create", + "timerfd_gettime", + "timerfd_gettime64", + "timerfd_settime", + "timerfd_settime64", + "times", + "tkill", + "truncate", + "truncate64", + "ugetrlimit", + "umask", + "uname", + "unlink", + "unlinkat", + "utime", + "utimensat", + "utimensat_time64", + "utimes", + "vfork", + "vmsplice", + "wait4", + "waitid", + "waitpid", + "write", + "writev" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "ptrace" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 0, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 8, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 131072, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 131080, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "personality" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 4294967295, + "op": "SCMP_CMP_EQ" + } + ] + }, + { + "names": [ + "arch_prctl" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "modify_ldt" + ], + "action": "SCMP_ACT_ALLOW" + }, + { + "names": [ + "clone" + ], + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 2114060288, + "op": "SCMP_CMP_MASKED_EQ" + } + ] + }, + { + "names": [ + "clone3" + ], + "action": "SCMP_ACT_ERRNO", + "errnoRet": 38 + }, + { + "names": [ + "chroot" + ], + "action": "SCMP_ACT_ALLOW" + } + ] + }, + "maskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware" + ], + "readonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + } +} \ No newline at end of file From e8cc95c53b43f5728eca018fb4f0a922dd2037fc Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Thu, 4 Nov 2021 13:24:14 +0100 Subject: [PATCH 06/13] Update imported OCI runtime spec This change updates the imported OCI runtime spec to a3c33d663ebc which includes the ability to override the return code for syscalls. This is used by docker for the clone3 syscall, for example. Signed-off-by: Evan Lezar --- go.mod | 2 +- go.sum | 26 ++++++++- .../runtime-spec/specs-go/config.go | 53 +++++++++++++++---- vendor/modules.txt | 2 +- 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index fca1049e..ec8979b3 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/BurntSushi/toml v0.3.1 github.com/containerd/containerd v1.5.7 github.com/containers/podman/v2 v2.2.1 - github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 + github.com/opencontainers/runtime-spec v1.0.3-0.20211101234015-a3c33d663ebc github.com/pelletier/go-toml v1.9.3 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index 1059eeb6..7e831ebb 100644 --- a/go.sum +++ b/go.sum @@ -186,6 +186,7 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2 h1:2/O3oTZN36q2xRolk0a2WWGgh7/Vf/liElg5hFYLX9U= github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= @@ -217,6 +218,7 @@ github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/ github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g= github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/podman/v2 v2.2.1 h1:ONDOHuzYnPF+ZJ+sV9hjtssAG93gTbyvlKN0LhbFIRY= github.com/containers/podman/v2 v2.2.1/go.mod h1:4CuPT3c5jB1XxIjFRiAkqrvXrW+g5NR5wQb58u4KJE0= github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU= github.com/containers/storage v1.23.6/go.mod h1:haFs0HRowKwyzvWEx9EgI3WsL8XCSnBDb5f8P5CAxJY= @@ -240,8 +242,10 @@ github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -252,6 +256,7 @@ github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -268,6 +273,7 @@ github.com/docker/docker v17.12.0-ce-rc1.0.20201020191947-73dc6a680cdd+incompati github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= @@ -338,6 +344,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -485,6 +492,7 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -547,6 +555,7 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -573,9 +582,11 @@ github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 h1:yN8BPXVwMBAm3Cuvh1L5XE8XpvYRMdsVLd82ILprhUU= github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.0.0-20190425234816-dae70e8efea4/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= @@ -594,8 +605,9 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.m github.com/opencontainers/runtime-spec v1.0.3-0.20200710190001-3e4195d92445/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200817204227-f9c09b4ea1df/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20211101234015-a3c33d663ebc h1:Q4P71bRTYvUK/qLX897YrMBA1oznb1noH0rLB5ji9SE= +github.com/opencontainers/runtime-spec v1.0.3-0.20211101234015-a3c33d663ebc/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= @@ -616,7 +628,9 @@ github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9/go.mod h1:bwawxfHBFNV+L github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= @@ -655,7 +669,9 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rootless-containers/rootlesskit v0.11.1/go.mod h1:pCUqFJBGOIonbjQBaxSVnk3w3KnK2drqjllgpgvNnO8= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= @@ -663,6 +679,7 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/seccomp/libseccomp-golang v0.9.2-0.20200616122406-847368b35ebf/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v0.0.0-20190403091019-9b3cdde74fbe/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= @@ -672,6 +689,7 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -706,6 +724,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -715,6 +734,7 @@ github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tsaikd/KDGoLib v0.0.0-20191001134900-7f3cf518e07d h1:hq9X/cf03C5rCx9yWhY7eMHiNxmhTMJAc5DQBq9BfnI= github.com/tsaikd/KDGoLib v0.0.0-20191001134900-7f3cf518e07d/go.mod h1:oFPCwcQpP90RVZxlBdgPN+iu2tPkboPUa4xaVEI6pO4= github.com/tsaikd/govalidator v0.0.0-20161031084447-986f2244fc69/go.mod h1:yJymgtZhuWi1Ih5t37Ej381BGZFZvlb9YMTwBxB/QjU= github.com/u-root/u-root v6.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= @@ -726,7 +746,9 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b/go.mod h1:YHaw8N660ESgMgLOZfLQqT1htFItynAUxMesFBho52s= github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g= @@ -948,6 +970,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -999,6 +1022,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go index 6a7a91e5..c0e87944 100644 --- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go +++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go @@ -15,7 +15,7 @@ type Spec struct { // Mounts configures additional mounts (on top of Root). Mounts []Mount `json:"mounts,omitempty"` // Hooks configures callbacks for container lifecycle events. - Hooks *Hooks `json:"hooks,omitempty" platform:"linux,solaris"` + Hooks *Hooks `json:"hooks,omitempty" platform:"linux,solaris,zos"` // Annotations contains arbitrary metadata for the container. Annotations map[string]string `json:"annotations,omitempty"` @@ -27,6 +27,8 @@ type Spec struct { Windows *Windows `json:"windows,omitempty" platform:"windows"` // VM specifies configuration for virtual-machine-based containers. VM *VM `json:"vm,omitempty" platform:"vm"` + // ZOS is platform-specific configuration for z/OS based containers. + ZOS *ZOS `json:"zos,omitempty" platform:"zos"` } // Process contains information to start a specific application inside the container. @@ -49,7 +51,7 @@ type Process struct { // Capabilities are Linux capabilities that are kept for the process. Capabilities *LinuxCapabilities `json:"capabilities,omitempty" platform:"linux"` // Rlimits specifies rlimit options to apply to the process. - Rlimits []POSIXRlimit `json:"rlimits,omitempty" platform:"linux,solaris"` + Rlimits []POSIXRlimit `json:"rlimits,omitempty" platform:"linux,solaris,zos"` // NoNewPrivileges controls whether additional privileges could be gained by processes in the container. NoNewPrivileges bool `json:"noNewPrivileges,omitempty" platform:"linux"` // ApparmorProfile specifies the apparmor profile for the container. @@ -86,11 +88,11 @@ type Box struct { // User specifies specific user (and group) information for the container process. type User struct { // UID is the user id. - UID uint32 `json:"uid" platform:"linux,solaris"` + UID uint32 `json:"uid" platform:"linux,solaris,zos"` // GID is the group id. - GID uint32 `json:"gid" platform:"linux,solaris"` + GID uint32 `json:"gid" platform:"linux,solaris,zos"` // Umask is the umask for the init process. - Umask *uint32 `json:"umask,omitempty" platform:"linux,solaris"` + Umask *uint32 `json:"umask,omitempty" platform:"linux,solaris,zos"` // AdditionalGids are additional group ids set for the container's process. AdditionalGids []uint32 `json:"additionalGids,omitempty" platform:"linux,solaris"` // Username is the user name. @@ -110,7 +112,7 @@ type Mount struct { // Destination is the absolute path where the mount will be placed in the container. Destination string `json:"destination"` // Type specifies the mount kind. - Type string `json:"type,omitempty" platform:"linux,solaris"` + Type string `json:"type,omitempty" platform:"linux,solaris,zos"` // Source specifies the source path of the mount. Source string `json:"source,omitempty"` // Options are fstab style mount options. @@ -178,7 +180,7 @@ type Linux struct { // MountLabel specifies the selinux context for the mounts in the container. MountLabel string `json:"mountLabel,omitempty"` // IntelRdt contains Intel Resource Director Technology (RDT) information for - // handling resource constraints (e.g., L3 cache, memory bandwidth) for the container + // handling resource constraints and monitoring metrics (e.g., L3 cache, memory bandwidth) for the container IntelRdt *LinuxIntelRdt `json:"intelRdt,omitempty"` // Personality contains configuration for the Linux personality syscall Personality *LinuxPersonality `json:"personality,omitempty"` @@ -683,8 +685,9 @@ type LinuxSyscall struct { Args []LinuxSeccompArg `json:"args,omitempty"` } -// LinuxIntelRdt has container runtime resource constraints for Intel RDT -// CAT and MBA features which introduced in Linux 4.10 and 4.12 kernel +// LinuxIntelRdt has container runtime resource constraints for Intel RDT CAT and MBA +// features and flags enabling Intel RDT CMT and MBM features. +// Intel RDT features are available in Linux 4.14 and newer kernel versions. type LinuxIntelRdt struct { // The identity for RDT Class of Service ClosID string `json:"closID,omitempty"` @@ -697,4 +700,36 @@ type LinuxIntelRdt struct { // The unit of memory bandwidth is specified in "percentages" by // default, and in "MBps" if MBA Software Controller is enabled. MemBwSchema string `json:"memBwSchema,omitempty"` + + // EnableCMT is the flag to indicate if the Intel RDT CMT is enabled. CMT (Cache Monitoring Technology) supports monitoring of + // the last-level cache (LLC) occupancy for the container. + EnableCMT bool `json:"enableCMT,omitempty"` + + // EnableMBM is the flag to indicate if the Intel RDT MBM is enabled. MBM (Memory Bandwidth Monitoring) supports monitoring of + // total and local memory bandwidth for the container. + EnableMBM bool `json:"enableMBM,omitempty"` +} + +// ZOS contains platform-specific configuration for z/OS based containers. +type ZOS struct { + // Devices are a list of device nodes that are created for the container + Devices []ZOSDevice `json:"devices,omitempty"` +} + +// ZOSDevice represents the mknod information for a z/OS special device file +type ZOSDevice struct { + // Path to the device. + Path string `json:"path"` + // Device type, block, char, etc. + Type string `json:"type"` + // Major is the device's major number. + Major int64 `json:"major"` + // Minor is the device's minor number. + Minor int64 `json:"minor"` + // FileMode permission bits for the device. + FileMode *os.FileMode `json:"fileMode,omitempty"` + // UID of the device. + UID *uint32 `json:"uid,omitempty"` + // Gid of the device. + GID *uint32 `json:"gid,omitempty"` } diff --git a/vendor/modules.txt b/vendor/modules.txt index 0703e5f0..5f9b1101 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -39,7 +39,7 @@ github.com/opencontainers/go-digest # github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 +# github.com/opencontainers/runtime-spec v1.0.3-0.20211101234015-a3c33d663ebc ## explicit github.com/opencontainers/runtime-spec/specs-go # github.com/pelletier/go-toml v1.9.3 From d6a2733557eb76d907e41bfe42669245d09f776c Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Thu, 4 Nov 2021 16:39:40 +0100 Subject: [PATCH 07/13] Update nvidia-container-runtime submodule Signed-off-by: Evan Lezar --- third_party/nvidia-container-runtime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/nvidia-container-runtime b/third_party/nvidia-container-runtime index cd6aef41..1a27fc49 160000 --- a/third_party/nvidia-container-runtime +++ b/third_party/nvidia-container-runtime @@ -1 +1 @@ -Subproject commit cd6aef41126b5409c2329b66803b278a697aaaf3 +Subproject commit 1a27fc49850b75d146fca3064aa5bd1b1ff85a1e From 98168ea16c72b0af18a4acaf6edf77560c55bb96 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Thu, 4 Nov 2021 16:40:09 +0100 Subject: [PATCH 08/13] Update libnvidia-container submodule Signed-off-by: Evan Lezar --- third_party/libnvidia-container | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/libnvidia-container b/third_party/libnvidia-container index fc1b6c41..badec1fa 160000 --- a/third_party/libnvidia-container +++ b/third_party/libnvidia-container @@ -1 +1 @@ -Subproject commit fc1b6c4102fd0ccac155e2e26fec33c64bd06da2 +Subproject commit badec1fa4a2c085aa9396f95b6bb1d69f1c7996b From 988e067091f1692d17c717091b741711ae215aa8 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Thu, 4 Nov 2021 16:47:37 +0100 Subject: [PATCH 09/13] Forward nvidia-container-toolkit versions to dependants Signed-off-by: Evan Lezar --- scripts/build-all-components.sh | 18 ++++++++++++------ scripts/get-component-versions.sh | 13 +++++++------ scripts/release.sh | 4 ++++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/scripts/build-all-components.sh b/scripts/build-all-components.sh index 528c2f3d..a3de5fe4 100755 --- a/scripts/build-all-components.sh +++ b/scripts/build-all-components.sh @@ -55,13 +55,19 @@ make -C ${LIBNVIDIA_CONTAINER_ROOT} -f mk/docker.mk ${TARGET} # Build nvidia-container-toolkit make -C ${NVIDIA_CONTAINER_TOOLKIT_ROOT} ${TARGET} -# We set the TOOLKIT_VERSION for the nvidia-container-runtime and nvidia-docker targets -# TODO: This is not yet enabled in the makefiles below -: ${PREVIOUS_TOOLKIT_VERSION:=1.5.1} -echo "Using TOOLKIT_VERSION=${PREVIOUS_TOOLKIT_VERSION} as previous nvidia-container-toolkit version" +if [[ -z ${NVIDIA_CONTAINER_TOOLKIT_VERSION} ]]; then +eval $(${SCRIPTS_DIR}/get-component-versions.sh) +fi +# We set the TOOLKIT_VERSION for the nvidia-container-runtime and nvidia-docker targets # Build nvidia-container-runtime -make -C ${NVIDIA_CONTAINER_RUNTIME_ROOT} TOOLKIT_VERSION=${PREVIOUS_TOOLKIT_VERSION} ${TARGET} +make -C ${NVIDIA_CONTAINER_RUNTIME_ROOT} \ + TOOLKIT_VERSION="${NVIDIA_CONTAINER_TOOLKIT_VERSION}" \ + TOOLKIT_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \ + ${TARGET} # Build nvidia-docker2 -make -C ${NVIDIA_DOCKER_ROOT} TOOLKIT_VERSION=${PREVIOUS_TOOLKIT_VERSION} ${TARGET} +make -C ${NVIDIA_DOCKER_ROOT} \ + TOOLKIT_VERSION="${NVIDIA_CONTAINER_TOOLKIT_VERSION}" \ + TOOLKIT_TAG="${NVIDIA_CONTAINER_TOOLKIT_TAG}" \ + ${TARGET} diff --git a/scripts/get-component-versions.sh b/scripts/get-component-versions.sh index 2c51a700..758078be 100755 --- a/scripts/get-component-versions.sh +++ b/scripts/get-component-versions.sh @@ -34,28 +34,29 @@ PROJECT_ROOT="$( cd ${SCRIPTS_DIR}/.. && pwd )" : ${NVIDIA_DOCKER_ROOT:=${PROJECT_ROOT}/third_party/nvidia-docker} # Get version for libnvidia-container -libnvidia_container_version=$(grep "#define NVC_VERSION" ${LIBNVIDIA_CONTAINER_ROOT}/src/nvc.h \ +libnvidia_container_version_tag=$(grep "#define NVC_VERSION" ${LIBNVIDIA_CONTAINER_ROOT}/src/nvc.h \ | sed -e 's/#define NVC_VERSION[[:space:]]"\(.*\)"/\1/') # Get version for nvidia-container-toolit nvidia_container_toolkit_version=$(grep -m 1 "^LIB_VERSION := " ${NVIDIA_CONTAINER_TOOLKIT_ROOT}/Makefile | sed -e 's/LIB_VERSION :=[[:space:]]\(.*\)[[:space:]]*/\1/') nvidia_container_toolkit_tag=$(grep -m 1 "^LIB_TAG .= " ${NVIDIA_CONTAINER_TOOLKIT_ROOT}/Makefile | sed -e 's/LIB_TAG .=[[:space:]]\(.*\)[[:space:]]*/\1/') -nvidia_container_toolkit_version="${nvidia_container_toolkit_version}${nvidia_container_toolkit_tag:+~${nvidia_container_toolkit_tag}}" +nvidia_container_toolkit_version_tag="${nvidia_container_toolkit_version}${nvidia_container_toolkit_tag:+~${nvidia_container_toolkit_tag}}" # Get version for nvidia-container-runtime nvidia_container_runtime_version=$(grep -m 1 "^LIB_VERSION := " ${NVIDIA_CONTAINER_RUNTIME_ROOT}/Makefile | sed -e 's/LIB_VERSION :=[[:space:]]\(.*\)[[:space:]]*/\1/') nvidia_container_runtime_tag=$(grep -m 1 "^LIB_TAG .= " ${NVIDIA_CONTAINER_RUNTIME_ROOT}/Makefile | sed -e 's/LIB_TAG .=[[:space:]]\(.*\)[[:space:]]*/\1/') -nvidia_container_runtime_version="${nvidia_container_runtime_version}${nvidia_container_runtime_tag:+~${nvidia_container_runtime_tag}}" +nvidia_container_runtime_version_tag="${nvidia_container_runtime_version}${nvidia_container_runtime_tag:+~${nvidia_container_runtime_tag}}" # Get version for nvidia-docker nvidia_docker_version=$(grep -m 1 "^LIB_VERSION := " ${NVIDIA_DOCKER_ROOT}/Makefile | sed -e 's/LIB_VERSION :=[[:space:]]\(.*\)[[:space:]]*/\1/') nvidia_docker_tag=$(grep -m 1 "^LIB_TAG .= " ${NVIDIA_DOCKER_ROOT}/Makefile | sed -e 's/LIB_TAG .=[[:space:]]\(.*\)[[:space:]]*/\1/') -nvidia_docker_version="${nvidia_docker_version}${nvidia_docker_tag:+~${nvidia_docker_tag}}" +nvidia_docker_version_tag="${nvidia_docker_version}${nvidia_docker_tag:+~${nvidia_docker_tag}}" -echo "LIBNVIDIA_CONTAINER_VERSION=${libnvidia_container_version}" +echo "LIBNVIDIA_CONTAINER_VERSION=${libnvidia_container_version_tag}" echo "NVIDIA_CONTAINER_TOOLKIT_VERSION=${nvidia_container_toolkit_version}" -if [[ "${libnvidia_container_version}" != "${nvidia_container_toolkit_version}" ]]; then +echo "NVIDIA_CONTAINER_TOOLKIT_TAG=${nvidia_container_toolkit_tag}" +if [[ "${libnvidia_container_version_tag}" != "${nvidia_container_toolkit_version_tag}" ]]; then >&2 echo "WARNING: The libnvidia-container and nvidia-container-toolkit versions do not match" fi echo "NVIDIA_CONTAINER_RUNTIME_VERSION=${nvidia_container_runtime_version}" diff --git a/scripts/release.sh b/scripts/release.sh index 7b54eea1..e436d899 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -52,6 +52,10 @@ else targets=${all[@]} fi +eval $(${SCRIPTS_DIR}/get-component-versions.sh) +export NVIDIA_CONTAINER_TOOLKIT_VERSION +export NVIDIA_CONTAINER_TOOLKIT_TAG + for target in ${targets[@]}; do ${SCRIPTS_DIR}/build-all-components.sh ${target} done From 14c641377f8fe99e612215fc9cfccf7d287ce497 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Thu, 4 Nov 2021 17:14:36 +0100 Subject: [PATCH 10/13] Update nvidia-docker submodule Signed-off-by: Evan Lezar --- third_party/nvidia-docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/nvidia-docker b/third_party/nvidia-docker index 4613cdae..1b780096 160000 --- a/third_party/nvidia-docker +++ b/third_party/nvidia-docker @@ -1 +1 @@ -Subproject commit 4613cdae34c3e106ef124c9b86e4cf998569bbd6 +Subproject commit 1b78009668765e79c2a7173680c834b6bc7f730a From 4d945e96f39e252206b20e3513f8a5d90fbf1a8c Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 5 Nov 2021 12:06:29 +0100 Subject: [PATCH 11/13] Auto update debian changelog and release date Signed-off-by: Evan Lezar --- docker/Dockerfile.debian | 2 ++ docker/Dockerfile.ubuntu | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docker/Dockerfile.debian b/docker/Dockerfile.debian index e4855f1d..04e5d13b 100644 --- a/docker/Dockerfile.debian +++ b/docker/Dockerfile.debian @@ -61,6 +61,8 @@ WORKDIR $DIST_DIR COPY packaging/debian ./debian RUN sed -i "s;@VERSION@;${REVISION};" debian/changelog && \ + dch --changelog debian/changelog --append "Bump libnvidia-container dependency to ${REVISION}}" && \ + dch --changelog debian/changelog -r "" && \ if [ "$REVISION" != "$(dpkg-parsechangelog --show-field=Version)" ]; then exit 1; fi CMD export DISTRIB="$(lsb_release -cs)" && \ diff --git a/docker/Dockerfile.ubuntu b/docker/Dockerfile.ubuntu index 4c8e5b92..a1375ed8 100644 --- a/docker/Dockerfile.ubuntu +++ b/docker/Dockerfile.ubuntu @@ -54,6 +54,8 @@ WORKDIR $DIST_DIR COPY packaging/debian ./debian RUN sed -i "s;@VERSION@;${REVISION};" debian/changelog && \ + dch --changelog debian/changelog --append "Bump libnvidia-container dependency to ${REVISION}}" && \ + dch --changelog debian/changelog -r "" && \ if [ "$REVISION" != "$(dpkg-parsechangelog --show-field=Version)" ]; then exit 1; fi CMD export DISTRIB="$(lsb_release -cs)" && \ From f2d2991651139a0f5c89d23b21e98ea851f39823 Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 5 Nov 2021 14:04:28 +0100 Subject: [PATCH 12/13] Update nvidia-docker submodule Signed-off-by: Evan Lezar --- third_party/nvidia-docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/nvidia-docker b/third_party/nvidia-docker index 1b780096..9fca9bb4 160000 --- a/third_party/nvidia-docker +++ b/third_party/nvidia-docker @@ -1 +1 @@ -Subproject commit 1b78009668765e79c2a7173680c834b6bc7f730a +Subproject commit 9fca9bb435e68a335021ad46d29bf471c2f2faac From 40032edc3bfce55ddbc6d156dd5e0b254a56508a Mon Sep 17 00:00:00 2001 From: Evan Lezar Date: Fri, 5 Nov 2021 14:55:26 +0100 Subject: [PATCH 13/13] Update submodules for packaging Signed-off-by: Evan Lezar --- third_party/nvidia-container-runtime | 2 +- third_party/nvidia-docker | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third_party/nvidia-container-runtime b/third_party/nvidia-container-runtime index 1a27fc49..037ec4c3 160000 --- a/third_party/nvidia-container-runtime +++ b/third_party/nvidia-container-runtime @@ -1 +1 @@ -Subproject commit 1a27fc49850b75d146fca3064aa5bd1b1ff85a1e +Subproject commit 037ec4c39a2fe28c3c8d4992a269a9d7bbbeafa7 diff --git a/third_party/nvidia-docker b/third_party/nvidia-docker index 9fca9bb4..9de312f5 160000 --- a/third_party/nvidia-docker +++ b/third_party/nvidia-docker @@ -1 +1 @@ -Subproject commit 9fca9bb435e68a335021ad46d29bf471c2f2faac +Subproject commit 9de312f595157d2176a8a3ada8a1b5bb62414578