Merge pull request #724 from cloudfoundry-incubator/hookstate-bundlepath
HookState adhears to OCI
This commit is contained in:
commit
4023fe0fb9
3
exec.go
3
exec.go
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/opencontainers/specs/specs-go"
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1068,9 +1068,15 @@ 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
|
||||
|
@ -1078,8 +1084,21 @@ func TestHook(t *testing.T) {
|
|||
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"))
|
||||
}),
|
||||
},
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
@ -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 ""
|
||||
}
|
||||
|
|
|
@ -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
list.go
17
list.go
|
@ -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`
|
||||
|
@ -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
state.go
3
state.go
|
@ -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
|
||||
|
@ -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, "", " ")
|
||||
|
|
Loading…
Reference in New Issue