Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/codegangsta/cli"
"github.com/opencontainers/runc/libcontainer/utils"
"github.com/opencontainers/specs/specs-go"
)

Expand Down Expand Up @@ -103,7 +104,7 @@ func execProcess(context *cli.Context) (int, error) {
if err != nil {
return -1, err
}
bundle := searchLabels(state.Config.Labels, "bundle")
bundle := utils.SearchLabels(state.Config.Labels, "bundle")
p, err := getProcess(context, bundle)
if err != nil {
return -1, err
Expand Down
9 changes: 5 additions & 4 deletions libcontainer/configs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,11 @@ func (hooks Hooks) MarshalJSON() ([]byte, error) {

// HookState is the payload provided to a hook on execution.
type HookState struct {
Version string `json:"version"`
ID string `json:"id"`
Pid int `json:"pid"`
Root string `json:"root"`
Version string `json:"ociVersion"`
ID string `json:"id"`
Pid int `json:"pid"`
Root string `json:"root"`
BundlePath string `json:"bundlePath"`
}

type Hook interface {
Expand Down
9 changes: 5 additions & 4 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,11 @@ func (c *linuxContainer) Start(process *Process) error {
}
if c.config.Hooks != nil {
s := configs.HookState{
Version: c.config.Version,
ID: c.id,
Pid: parent.pid(),
Root: c.config.Rootfs,
Version: c.config.Version,
ID: c.id,
Pid: parent.pid(),
Root: c.config.Rootfs,
BundlePath: utils.SearchLabels(c.config.Labels, "bundle"),
}
for _, hook := range c.config.Hooks.Poststart {
if err := hook.Run(s); err != nil {
Expand Down
29 changes: 29 additions & 0 deletions libcontainer/integration/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1068,18 +1068,37 @@ func TestHook(t *testing.T) {
defer remove(rootfs)

config := newTemplateConfig(rootfs)
expectedBundlePath := "/path/to/bundle/path"
config.Labels = append(config.Labels, fmt.Sprintf("bundle=%s", expectedBundlePath))
config.Hooks = &configs.Hooks{
Prestart: []configs.Hook{
configs.NewFunctionHook(func(s configs.HookState) error {
if s.BundlePath != expectedBundlePath {
t.Fatalf("Expected prestart hook bundlePath '%s'; got '%s'", expectedBundlePath, s.BundlePath)
}

f, err := os.Create(filepath.Join(s.Root, "test"))
if err != nil {
return err
}
return f.Close()
}),
},
Poststart: []configs.Hook{
configs.NewFunctionHook(func(s configs.HookState) error {
if s.BundlePath != expectedBundlePath {
t.Fatalf("Expected poststart hook bundlePath '%s'; got '%s'", expectedBundlePath, s.BundlePath)
}

return ioutil.WriteFile(filepath.Join(s.Root, "test"), []byte("hello world"), 0755)
}),
},
Poststop: []configs.Hook{
configs.NewFunctionHook(func(s configs.HookState) error {
if s.BundlePath != expectedBundlePath {
t.Fatalf("Expected poststop hook bundlePath '%s'; got '%s'", expectedBundlePath, s.BundlePath)
}

return os.RemoveAll(filepath.Join(s.Root, "test"))
}),
},
Expand Down Expand Up @@ -1109,6 +1128,16 @@ func TestHook(t *testing.T) {
t.Fatalf("ls output doesn't have the expected file: %s", outputLs)
}

// Check that the file is written by the poststart hook
testFilePath := filepath.Join(rootfs, "test")
contents, err := ioutil.ReadFile(testFilePath)
if err != nil {
t.Fatalf("cannot read file '%s': %s", testFilePath, err)
}
if string(contents) != "hello world" {
t.Fatalf("Expected test file to contain 'hello world'; got '%s'", string(contents))
}

if err := container.Destroy(); err != nil {
t.Fatalf("container destory %s", err)
}
Expand Down
9 changes: 5 additions & 4 deletions libcontainer/process_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,11 @@ loop:
case procHooks:
if p.config.Config.Hooks != nil {
s := configs.HookState{
Version: p.container.config.Version,
ID: p.container.id,
Pid: p.pid(),
Root: p.config.Config.Rootfs,
Version: p.container.config.Version,
ID: p.container.id,
Pid: p.pid(),
Root: p.config.Config.Rootfs,
BundlePath: utils.SearchLabels(p.config.Config.Labels, "bundle"),
}
for _, hook := range p.config.Config.Hooks.Prestart {
if err := hook.Run(s); err != nil {
Expand Down
8 changes: 5 additions & 3 deletions libcontainer/state_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/utils"
)

func newStateTransitionError(from, to containerState) error {
Expand Down Expand Up @@ -56,9 +57,10 @@ func destroy(c *linuxContainer) error {
func runPoststopHooks(c *linuxContainer) error {
if c.config.Hooks != nil {
s := configs.HookState{
Version: c.config.Version,
ID: c.id,
Root: c.config.Rootfs,
Version: c.config.Version,
ID: c.id,
Root: c.config.Rootfs,
BundlePath: utils.SearchLabels(c.config.Labels, "bundle"),
}
for _, hook := range c.config.Hooks.Poststop {
if err := hook.Run(s); err != nil {
Expand Down
16 changes: 16 additions & 0 deletions libcontainer/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"os"
"path/filepath"
"strings"
"syscall"
)

Expand Down Expand Up @@ -84,3 +85,18 @@ func CleanPath(path string) string {
// Clean the path again for good measure.
return filepath.Clean(path)
}

// SearchLabels searches a list of key-value pairs for the provided key and
// returns the corresponding value. The pairs must be separated with '='.
func SearchLabels(labels []string, query string) string {
for _, l := range labels {
parts := strings.SplitN(l, "=", 2)
if len(parts) < 2 {
continue
}
if parts[0] == query {
return parts[1]
}
}
return ""
}
21 changes: 21 additions & 0 deletions libcontainer/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,24 @@ func TestGenerateName(t *testing.T) {
t.Fatalf("expected name to be %d chars but received %d", expected, len(name))
}
}

var labelTest = []struct {
labels []string
query string
expectedValue string
}{
{[]string{"bundle=/path/to/bundle"}, "bundle", "/path/to/bundle"},
{[]string{"test=a", "test=b"}, "bundle", ""},
{[]string{"bundle=a", "test=b", "bundle=c"}, "bundle", "a"},
{[]string{"", "test=a", "bundle=b"}, "bundle", "b"},
{[]string{"test", "bundle=a"}, "bundle", "a"},
{[]string{"test=a", "bundle="}, "bundle", ""},
}

func TestSearchLabels(t *testing.T) {
for _, tt := range labelTest {
if v := SearchLabels(tt.labels, tt.query); v != tt.expectedValue {
t.Errorf("expected value '%s' for query '%s'; got '%s'", tt.expectedValue, tt.query, v)
}
}
}
17 changes: 2 additions & 15 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"text/tabwriter"
"time"

"encoding/json"

"github.com/codegangsta/cli"
"github.com/opencontainers/runc/libcontainer/utils"
)

const formatOptions = `table or json`
Expand Down Expand Up @@ -116,22 +116,9 @@ func getContainers(context *cli.Context) ([]containerState, error) {
ID: state.BaseState.ID,
InitProcessPid: state.BaseState.InitProcessPid,
Status: containerStatus.String(),
Bundle: searchLabels(state.Config.Labels, "bundle"),
Bundle: utils.SearchLabels(state.Config.Labels, "bundle"),
Created: state.BaseState.Created})
}
}
return s, nil
}

func searchLabels(labels []string, query string) string {
for _, l := range labels {
parts := strings.SplitN(l, "=", 2)
if len(parts) < 2 {
continue
}
if parts[0] == query {
return parts[1]
}
}
return ""
}
3 changes: 2 additions & 1 deletion state.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/codegangsta/cli"
"github.com/opencontainers/runc/libcontainer/utils"
)

// cState represents the platform agnostic pieces relating to a running
Expand Down Expand Up @@ -57,7 +58,7 @@ instance of a container.`,
ID: state.BaseState.ID,
InitProcessPid: state.BaseState.InitProcessPid,
Status: containerStatus.String(),
Bundle: searchLabels(state.Config.Labels, "bundle"),
Bundle: utils.SearchLabels(state.Config.Labels, "bundle"),
Rootfs: state.BaseState.Config.Rootfs,
Created: state.BaseState.Created}
data, err := json.MarshalIndent(cs, "", " ")
Expand Down