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

Commit

Permalink
Merge pull request #623 from sboeuf/move_hooks
Browse files Browse the repository at this point in the history
network: Move OCI hooks and network namespace creation out of virtcontainers
  • Loading branch information
bergwolf authored Aug 31, 2018
2 parents 7dc1a32 + 97d280e commit b982373
Show file tree
Hide file tree
Showing 27 changed files with 939 additions and 957 deletions.
25 changes: 24 additions & 1 deletion cli/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,21 @@ func createSandbox(ctx context.Context, ociSpec oci.CompatOCISpec, runtimeConfig
return vc.Process{}, err
}

// Important to create the network namespace before the sandbox is
// created, because it is not responsible for the creation of the
// netns if it does not exist.
if err := setupNetworkNamespace(&sandboxConfig.NetworkConfig); err != nil {
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 @@ -324,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
12 changes: 12 additions & 0 deletions cli/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,10 @@ func TestCreateContainerInvalid(t *testing.T) {
}

func TestCreateProcessCgroupsPathSuccessful(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}

assert := assert.New(t)

sandbox := &vcmock.Sandbox{
Expand Down Expand Up @@ -725,6 +729,10 @@ func TestCreateCreateCreatePidFileFail(t *testing.T) {
}

func TestCreate(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}

assert := assert.New(t)

sandbox := &vcmock.Sandbox{
Expand Down Expand Up @@ -891,6 +899,10 @@ func TestCreateSandboxConfigFail(t *testing.T) {
}

func TestCreateCreateSandboxFail(t *testing.T) {
if os.Geteuid() != 0 {
t.Skip(testDisabledNeedNonRoot)
}

assert := assert.New(t)

path, err := ioutil.TempDir("", "containers-mapping")
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 b982373

Please sign in to comment.