Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
hook: Move OCI hooks handling to the CLI
Browse files Browse the repository at this point in the history
The CLI being the implementation of the OCI specification, and the
hooks being OCI specific, it makes sense to move the handling of any
OCI hooks to the CLI level. This changes allows the Kata API to
become OCI agnostic.

Fixes #599

Signed-off-by: Sebastien Boeuf <[email protected]>
  • Loading branch information
Sebastien Boeuf committed Aug 24, 2018
1 parent ec0fd1b commit 9c6ed93
Show file tree
Hide file tree
Showing 13 changed files with 463 additions and 543 deletions.
18 changes: 17 additions & 1 deletion cli/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ func createSandbox(ctx context.Context, ociSpec oci.CompatOCISpec, runtimeConfig
return vc.Process{}, err
}

// Run pre-start OCI hooks.
err = enterNetNS(sandboxConfig.NetworkConfig.NetNSPath, func() error {
return preStartHooks(ctx, ociSpec, containerID, bundlePath)
})
if err != nil {
return vc.Process{}, err
}

sandbox, err := vci.CreateSandbox(ctx, sandboxConfig)
if err != nil {
return vc.Process{}, err
Expand Down Expand Up @@ -331,7 +339,15 @@ func createContainer(ctx context.Context, ociSpec oci.CompatOCISpec, containerID
setExternalLoggers(ctx, kataLog)
span.SetTag("sandbox", sandboxID)

_, c, err := vci.CreateContainer(ctx, sandboxID, contConfig)
s, c, err := vci.CreateContainer(ctx, sandboxID, contConfig)
if err != nil {
return vc.Process{}, err
}

// Run pre-start OCI hooks.
err = enterNetNS(s.GetNetNs(), func() error {
return preStartHooks(ctx, ociSpec, containerID, bundlePath)
})
if err != nil {
return vc.Process{}, err
}
Expand Down
6 changes: 6 additions & 0 deletions cli/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"os"

vc "github.com/kata-containers/runtime/virtcontainers"
vcAnnot "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
Expand Down Expand Up @@ -117,6 +118,11 @@ func delete(ctx context.Context, containerID string, force bool) error {
return fmt.Errorf("Invalid container type found")
}

// Run post-stop OCI hooks.
if err := postStopHooks(ctx, ociSpec, sandboxID, status.Annotations[vcAnnot.BundlePathKey]); err != nil {
return err
}

// In order to prevent any file descriptor leak related to cgroups files
// that have been previously created, we have to remove them before this
// function returns.
Expand Down
138 changes: 138 additions & 0 deletions cli/hook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"
"syscall"
"time"

"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opentracing/opentracing-go/log"
"github.com/sirupsen/logrus"
)

// Logger returns a logrus logger appropriate for logging hook messages
func hookLogger() *logrus.Entry {
return kataLog.WithField("subsystem", "hook")
}

func runHook(ctx context.Context, hook specs.Hook, cid, bundlePath string) error {
span, _ := trace(ctx, "hook")
defer span.Finish()

span.SetTag("subsystem", "runHook")

span.LogFields(
log.String("hook-name", hook.Path),
log.String("hook-args", strings.Join(hook.Args, " ")))

state := specs.State{
Pid: os.Getpid(),
Bundle: bundlePath,
ID: cid,
}

stateJSON, err := json.Marshal(state)
if err != nil {
return err
}

var stdout, stderr bytes.Buffer
cmd := &exec.Cmd{
Path: hook.Path,
Args: hook.Args,
Env: hook.Env,
Stdin: bytes.NewReader(stateJSON),
Stdout: &stdout,
Stderr: &stderr,
}

if err := cmd.Start(); err != nil {
return err
}

if hook.Timeout == nil {
if err := cmd.Wait(); err != nil {
return fmt.Errorf("%s: stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
}
} else {
done := make(chan error, 1)
go func() {
done <- cmd.Wait()
close(done)
}()

select {
case err := <-done:
if err != nil {
return fmt.Errorf("%s: stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
}
case <-time.After(time.Duration(*hook.Timeout) * time.Second):
if err := syscall.Kill(cmd.Process.Pid, syscall.SIGKILL); err != nil {
return err
}

return fmt.Errorf("Hook timeout")
}
}

return nil
}

func runHooks(ctx context.Context, hooks []specs.Hook, cid, bundlePath, hookType string) error {
span, _ := trace(ctx, "hooks")
defer span.Finish()

span.SetTag("subsystem", hookType)

for _, hook := range hooks {
if err := runHook(ctx, hook, cid, bundlePath); err != nil {
hookLogger().WithFields(logrus.Fields{
"hook-type": hookType,
"error": err,
}).Error("hook error")

return err
}
}

return nil
}

func preStartHooks(ctx context.Context, spec oci.CompatOCISpec, cid, bundlePath string) error {
// If no hook available, nothing needs to be done.
if spec.Hooks == nil {
return nil
}

return runHooks(ctx, spec.Hooks.Prestart, cid, bundlePath, "pre-start")
}

func postStartHooks(ctx context.Context, spec oci.CompatOCISpec, cid, bundlePath string) error {
// If no hook available, nothing needs to be done.
if spec.Hooks == nil {
return nil
}

return runHooks(ctx, spec.Hooks.Poststart, cid, bundlePath, "post-start")
}

func postStopHooks(ctx context.Context, spec oci.CompatOCISpec, cid, bundlePath string) error {
// If no hook available, nothing needs to be done.
if spec.Hooks == nil {
return nil
}

return runHooks(ctx, spec.Hooks.Poststop, cid, bundlePath, "post-stop")
}
Loading

0 comments on commit 9c6ed93

Please sign in to comment.