diff --git a/README.md b/README.md index 63070c3..0c6f6f3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ passing along to an OCI compatable runtime. This runtime can be invoked by doing -``` +```shell oci-add-hooks \ --hook-config-path --runtime-path \ @@ -18,12 +18,26 @@ oci-add-hooks \ ``` - `hook-config-path` is a json file that follows the format described [here](https://github.com/opencontainers/runtime-spec/blob/master/config.md#posix-platform-hooks). - `runtime-path` is a path to an OCI runtime binary. -- `bundle`,if present, specifies the path to the bundle directory. +- `bundle`, if present, specifies the path to the bundle directory. + +If you want to save the log of this runtime for better debug, this runtime can be invoked by doing + +```shell +oci-add-hooks \ + --hook-config-path + --runtime-path \ + --log-path \ + …\ + [--bundle \] + … +``` + +- `log-path` is a path to save the log of oci-add-hooks. ### With Docker A few things need to be done to use `oci-add-hooks` with Docker. First modify -`/etc/docker/daemon.json` to includ a "runtimes" section similiar to the following: +`/etc/docker/daemon.json` to include a "runtimes" section similiar to the following: ```json { @@ -33,13 +47,17 @@ A few things need to be done to use `oci-add-hooks` with Docker. First modify "runtimeArgs": ["--hook-config-path", "/path/to/config.json", "--runtime-path", - ""] + "", + "--log-path", + ""] } } } ``` -> note: path here should either include this binaries name when it's on the path -> or the full path/name if it's not. +> note: +> +> - Path here should either include this binaries name when it's on the path or the full path/name if it's not. You can run add_to_bin.sh to add this runtime to make it on the path. +> - "--log-path", "" is optional. And the log file name will be like path/to/logpath/20230911.log If we had a hypothetical hook config located at `/home/user/hook-config.json` @@ -68,7 +86,9 @@ look like: "runtimeArgs": ["--hook-config-path", "/home/user/hook-config.json", "--runtime-path", - "runc"] + "runc", + "--log-path", + "/home/user/log"] } } } diff --git a/add_to_bin.sh b/add_to_bin.sh new file mode 100755 index 0000000..ea09ac8 --- /dev/null +++ b/add_to_bin.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cp ./oci-add-hooks /bin/oci-add-hooks +cp ./oci-add-hooks /usr/bin/oci-add-hooks \ No newline at end of file diff --git a/go.mod b/go.mod index e64558e..36d6637 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ module github.com/awslabs/oci-add-hooks -require ( - github.com/bitly/go-simplejson v0.5.0 // indirect - github.com/joeshaw/json-lossless v0.0.0-20181204200226-e0cd1ca6349b -) +go 1.20 + +require github.com/joeshaw/json-lossless v0.0.0-20181204200226-e0cd1ca6349b + +require github.com/bitly/go-simplejson v0.5.0 // indirect diff --git a/hook.go b/hook.go index 616feb8..c903762 100644 --- a/hook.go +++ b/hook.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "io/ioutil" "os" lossless "github.com/joeshaw/json-lossless" @@ -56,7 +55,7 @@ func (c *config) writeFile(path string) error { } else { mode = info.Mode() } - return ioutil.WriteFile(path, bytes, mode.Perm()) + return os.WriteFile(path, bytes, mode.Perm()) } func (c *config) merge(in *config) { @@ -73,7 +72,7 @@ func (c *config) merge(in *config) { } func readHooks(path string) (*config, error) { - bytes, err := ioutil.ReadFile(path) + bytes, err := os.ReadFile(path) if err != nil { return nil, err } diff --git a/main.go b/main.go index 31285d1..ae7602d 100644 --- a/main.go +++ b/main.go @@ -3,23 +3,32 @@ package main import ( "errors" "fmt" + "log" "os" "os/exec" "os/signal" "path/filepath" "syscall" + "time" ) const ( // Size of the buffer for catching os.Signal sent to this process signalBufferSize = 32 + + // For the exit code, I only added createLogFailure, + // I'm not quite sure what numbers are included in runc's ExitStatus, + // I chose 111 for createLogFailure, hopefully it won't overlap with runc's ExitStatus exitCodeFailure = 1 + createLogFailure = 111 ) var ( errUnableToFindRuntime = errors.New("unable to find runtime") commit string + + logMode bool = false ) func main() { @@ -40,15 +49,38 @@ func main() { hookConfigPath := os.Args[2] runcPath := os.Args[4] passthroughArgs := os.Args[5:] + // Check if --log-path flag is provided + if len(passthroughArgs) > 0 && passthroughArgs[0] == "--log-path" { + if len(passthroughArgs) < 2 { + os.Exit(exitCodeFailure) + } + logPath := passthroughArgs[1] + passthroughArgs = passthroughArgs[2:] + if createLogFile(logPath) != 0 { + os.Exit(createLogFailure) + } + logMode = true + } + if logMode { + log.Println("Running oci-add-hooks") + log.Println("Oci-add-hooks arguments right") + } os.Exit(run(hookConfigPath, runcPath, passthroughArgs)) } func run(hookConfigPath, runcPath string, runcArgs []string) int { // If required args aren't present, bail if hookConfigPath == "" || runcPath == "" { + if logMode { + log.Println("Error: hookConfigPath or runcPath is \"\"") + } return exitCodeFailure } - + if logMode { + log.Printf("HookconfigPath: %v\n", hookConfigPath) + log.Printf("RuncPath: %v\n", runcPath) + log.Printf("RuncArgs: \n%v\n", runcArgs) + } // If a hookConfigPath passed, process the bundle and pass modified // spec to runc return processBundle(hookConfigPath, runcPath, runcArgs) @@ -62,20 +94,35 @@ func processBundle(hookPath, runcPath string, runcArgs []string) int { bundlePath := runcArgs[i+1] bundlePath = filepath.Join(bundlePath, "config.json") // Add the hooks from hookPath to our bundle/config.json + if logMode { + log.Printf("BundleFile: \n%v\n", bundlePath) + } merged, err := addHooks(bundlePath, hookPath) if err != nil { + if logMode { + log.Printf("Error: %v\n", err) + } return exitCodeFailure } err = merged.writeFile(bundlePath) if err != nil { + if logMode { + log.Printf("Error: %v\n", err) + } return exitCodeFailure } + if logMode { + log.Println("Add hooks to bundlefile success") + } break } } // launch runc path, err := verifyRuntimePath(runcPath) if err != nil { + if logMode { + log.Printf("Error: runc path is wrong: %v\n", err) + } return exitCodeFailure } return launchRunc(path, runcArgs) @@ -98,8 +145,14 @@ func launchRunc(runcPath string, runcArgs []string) int { signal.Notify(proc) err := cmd.Start() if err != nil { + if logMode { + log.Printf("Error: runc start failed: %v\n", err) + } return exitCodeFailure } + if logMode { + log.Println("Running runc") + } // Forward signals after we start command go func() { for sig := range proc { @@ -140,12 +193,40 @@ func prepareCommand(runcPath string, args []string) *exec.Cmd { func addHooks(bundlePath, hookPath string) (*config, error) { specHooks, err := readHooks(bundlePath) if err != nil { + if logMode { + log.Println("Error: read bundlePath hooks failed") + } return nil, err } addHooks, err := readHooks(hookPath) if err != nil { + if logMode { + log.Println("Error: read hookPath hooks failed") + } return nil, err } specHooks.merge(addHooks) return specHooks, nil } + +// Create log file +func createLogFile(logFilePath string) int { + if logFilePath == "" { + return 1 + } + if _, err := os.Stat(logFilePath); os.IsNotExist(err) { + err := os.MkdirAll(logFilePath, 0755) + if err != nil { + return 1 + } + } + logFileName := time.Now().Format("20060102") + ".log" + logFileName = filepath.Join(logFilePath, logFileName) + logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0755) + if err != nil { + return 1 + } + log.SetOutput(logFile) + log.SetFlags(log.Ldate | log.Ltime) + return 0 +} diff --git a/oci-add-hooks b/oci-add-hooks new file mode 100755 index 0000000..69c5bf1 Binary files /dev/null and b/oci-add-hooks differ