提交 f66e0b51 编写于 作者: E Evan Lezar

Merge branch 'make-nvidia-container-runtime-installable' into 'master'

Make nvidia-container-runtime go installable

See merge request nvidia/container-toolkit/container-runtime!49
dist
*.swp
*.swo
nvidia-container-runtime
test/output
runc
......@@ -29,10 +29,10 @@ docker-native:
include $(CURDIR)/docker/docker.mk
binary:
go build -ldflags "-s -w" -o "$(LIB_NAME)" $(MODULE)/cmd/...
go build -ldflags "-s -w" -o "$(LIB_NAME)" $(MODULE)/cmd/nvidia-container-runtime/...
build:
@go build -o $(LIB_NAME) $(MODULE)/...
@go build -ldflags "-s -w" $(MODULE)/...
# Define the check targets for the Golang codebase
MODULE := .
......
......@@ -18,6 +18,7 @@ package main
import (
"fmt"
"io"
"os"
"github.com/sirupsen/logrus"
......@@ -26,7 +27,8 @@ import (
type Logger struct {
*logrus.Logger
logFile *os.File
previousOutput io.Writer
logFile *os.File
}
func NewLogger() *Logger {
......@@ -52,6 +54,7 @@ func (l *Logger) LogToFile(filename string) error {
}
l.logFile = logFile
l.previousOutput = l.Out
l.SetOutput(logFile)
return nil
......@@ -61,5 +64,9 @@ func (l *Logger) CloseFile() error {
if l.logFile == nil {
return nil
}
return l.logFile.Close()
logFile := l.logFile
l.SetOutput(l.previousOutput)
l.logFile = nil
return logFile.Close()
}
......@@ -174,14 +174,16 @@ func addNVIDIAHook(spec *specs.Spec) error {
}
func main() {
err := run()
err := run(os.Args)
if err != nil {
logger.Errorf("Error running %v: %v", os.Args, err)
os.Exit(1)
}
}
func run() error {
// run is an entry point that allows for idiomatic handling of errors
// when calling from the main function.
func run(argv []string) (err error) {
cfg, err := getConfig()
if err != nil {
return fmt.Errorf("error loading config: %v", err)
......@@ -191,10 +193,16 @@ func run() error {
if err != nil {
return fmt.Errorf("error opening debug log file: %v", err)
}
defer logger.CloseFile()
defer func() {
// We capture and log a returning error before closing the log file.
if err != nil {
logger.Errorf("Error running %v: %v", argv, err)
}
logger.CloseFile()
}()
logger.Printf("Running %s\n", os.Args[0])
args, err := getArgs(os.Args)
logger.Printf("Running %s\n", argv[0])
args, err := getArgs(argv)
if err != nil {
return fmt.Errorf("error getting processing command line arguments: %v", err)
}
......
......@@ -19,30 +19,44 @@ import (
)
const (
nvidiaRuntime = "nvidia-container-runtime"
nvidiaHook = "nvidia-container-runtime-hook"
bundlePath = "../test/output/bundle/"
specFile = "config.json"
unmodifiedSpecFile = "../test/input/test_spec.json"
nvidiaRuntime = "nvidia-container-runtime"
nvidiaHook = "nvidia-container-runtime-hook"
bundlePathSuffix = "test/output/bundle/"
specFile = "config.json"
unmodifiedSpecFileSuffix = "test/input/test_spec.json"
)
type testConfig struct {
root string
}
var cfg *testConfig
func TestMain(m *testing.M) {
// TEST SETUP
// Update PATH to execute mock runc in current directory
_, filename, _, _ := runtime.Caller(0)
workingDir := path.Dir(filename)
parentDir := path.Dir(workingDir)
var err error
moduleRoot, err := getModuleRoot(filename)
if err != nil {
log.Fatalf("error in test setup: could not get module root: %v", err)
}
paths := strings.Split(os.Getenv("PATH"), ":")
paths = append([]string{parentDir, workingDir}, paths...)
paths = append([]string{moduleRoot}, paths...)
os.Setenv("PATH", strings.Join(paths, ":"))
// Confirm path setup correctly
runcPath, err := exec.LookPath("runc")
if err != nil || !strings.HasPrefix(runcPath, parentDir) {
if err != nil || !strings.HasPrefix(runcPath, moduleRoot) {
log.Fatal("error in test setup: mock runc path set incorrectly in TestMain()")
}
cfg = &testConfig{
root: moduleRoot,
}
// RUN TESTS
exitCode := m.Run()
......@@ -52,11 +66,25 @@ func TestMain(m *testing.M) {
os.Exit(exitCode)
}
func getModuleRoot(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 getModuleRoot(filepath.Dir(dir))
}
// go.mod was found in dir
return dir, nil
}
// case 1) nvidia-container-runtime run --bundle
// case 2) nvidia-container-runtime create --bundle
// - Confirm the runtime handles bad input correctly
func TestBadInput(t *testing.T) {
err := generateNewRuntimeSpec()
err := cfg.generateNewRuntimeSpec()
if err != nil {
t.Fatal(err)
}
......@@ -77,28 +105,28 @@ func TestBadInput(t *testing.T) {
// case 2) nvidia-container-runtime create --bundle <bundle-name> <ctr-name>
// - Confirm the runtime inserts the NVIDIA prestart hook correctly
func TestGoodInput(t *testing.T) {
err := generateNewRuntimeSpec()
err := cfg.generateNewRuntimeSpec()
if err != nil {
t.Fatal(err)
t.Fatalf("error generating runtime spec: %v", err)
}
cmdRun := exec.Command(nvidiaRuntime, "run", "--bundle", bundlePath, "testcontainer")
cmdRun := exec.Command(nvidiaRuntime, "run", "--bundle", cfg.bundlePath(), "testcontainer")
t.Logf("executing: %s\n", strings.Join(cmdRun.Args, " "))
err = cmdRun.Run()
require.NoError(t, err, "runtime should not return an error")
// Check config.json and confirm there are no hooks
spec, err := getRuntimeSpec(filepath.Join(bundlePath, specFile))
spec, err := cfg.getRuntimeSpec()
require.NoError(t, err, "should be no errors when reading and parsing spec from config.json")
require.Empty(t, spec.Hooks, "there should be no hooks in config.json")
cmdCreate := exec.Command(nvidiaRuntime, "create", "--bundle", bundlePath, "testcontainer")
cmdCreate := exec.Command(nvidiaRuntime, "create", "--bundle", cfg.bundlePath(), "testcontainer")
t.Logf("executing: %s\n", strings.Join(cmdCreate.Args, " "))
err = cmdCreate.Run()
require.NoError(t, err, "runtime should not return an error")
// Check config.json for NVIDIA prestart hook
spec, err = getRuntimeSpec(filepath.Join(bundlePath, specFile))
spec, err = cfg.getRuntimeSpec()
require.NoError(t, err, "should be no errors when reading and parsing spec from config.json")
require.NotEmpty(t, spec.Hooks, "there should be hooks in config.json")
require.Equal(t, 1, nvidiaHookCount(spec.Hooks), "exactly one nvidia prestart hook should be inserted correctly into config.json")
......@@ -106,13 +134,13 @@ func TestGoodInput(t *testing.T) {
// NVIDIA prestart hook already present in config file
func TestDuplicateHook(t *testing.T) {
err := generateNewRuntimeSpec()
err := cfg.generateNewRuntimeSpec()
if err != nil {
t.Fatal(err)
}
var spec specs.Spec
spec, err = getRuntimeSpec(filepath.Join(bundlePath, specFile))
spec, err = cfg.getRuntimeSpec()
if err != nil {
t.Fatal(err)
}
......@@ -127,7 +155,7 @@ func TestDuplicateHook(t *testing.T) {
t.Fatal(err)
}
jsonFile, err := os.OpenFile(bundlePath+specFile, os.O_RDWR, 0644)
jsonFile, err := os.OpenFile(cfg.specFilePath(), os.O_RDWR, 0644)
if err != nil {
t.Fatal(err)
}
......@@ -137,19 +165,21 @@ func TestDuplicateHook(t *testing.T) {
}
// Test how runtime handles already existing prestart hook in config.json
cmdCreate := exec.Command(nvidiaRuntime, "create", "--bundle", bundlePath, "testcontainer")
cmdCreate := exec.Command(nvidiaRuntime, "create", "--bundle", cfg.bundlePath(), "testcontainer")
t.Logf("executing: %s\n", strings.Join(cmdCreate.Args, " "))
err = cmdCreate.Run()
require.NoError(t, err, "runtime should not return an error")
// Check config.json for NVIDIA prestart hook
spec, err = getRuntimeSpec(filepath.Join(bundlePath, specFile))
spec, err = cfg.getRuntimeSpec()
require.NoError(t, err, "should be no errors when reading and parsing spec from config.json")
require.NotEmpty(t, spec.Hooks, "there should be hooks in config.json")
require.Equal(t, 1, nvidiaHookCount(spec.Hooks), "exactly one nvidia prestart hook should be inserted correctly into config.json")
}
func getRuntimeSpec(filePath string) (specs.Spec, error) {
func (c testConfig) getRuntimeSpec() (specs.Spec, error) {
filePath := c.specFilePath()
var spec specs.Spec
jsonFile, err := os.OpenFile(filePath, os.O_RDWR, 0644)
if err != nil {
......@@ -175,15 +205,27 @@ func getRuntimeSpec(filePath string) (specs.Spec, error) {
return spec, err
}
func generateNewRuntimeSpec() error {
func (c testConfig) bundlePath() string {
return filepath.Join(c.root, bundlePathSuffix)
}
func (c testConfig) specFilePath() string {
return filepath.Join(c.bundlePath(), specFile)
}
func (c testConfig) unmodifiedSpecFile() string {
return filepath.Join(c.root, unmodifiedSpecFileSuffix)
}
func (c testConfig) generateNewRuntimeSpec() error {
var err error
err = os.MkdirAll(bundlePath, 0755)
err = os.MkdirAll(c.bundlePath(), 0755)
if err != nil {
return err
}
cmd := exec.Command("cp", unmodifiedSpecFile, filepath.Join(bundlePath, specFile))
cmd := exec.Command("cp", c.unmodifiedSpecFile(), c.specFilePath())
err = cmd.Run()
if err != nil {
return err
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册