func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error { if c.Network == nil { return nil } if c.Network.ContainerID != "" { d.Lock() active := d.activeContainers[c.Network.ContainerID] d.Unlock() if active == nil { return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID) } state, err := active.State() if err != nil { return err } container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET]) return nil } if c.Network.NamespacePath != "" { container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath) return nil } // only set up prestart hook if the namespace path is not set (this should be // all cases *except* for --net=host shared networking) container.Hooks = &configs.Hooks{ Prestart: []configs.Hook{ configs.NewFunctionHook(func(s configs.HookState) error { if len(hooks.PreStart) > 0 { for _, fnHook := range hooks.PreStart { // A closed channel for OOM is returned here as it will be // non-blocking and return the correct result when read. chOOM := make(chan struct{}) close(chOOM) if err := fnHook(&c.ProcessConfig, s.Pid, chOOM); err != nil { return err } } } return nil }), }, } return nil }
func TestFuncHookRun(t *testing.T) { state := configs.HookState{ Version: "1", ID: "1", Pid: 1, Root: "root", } fHook := configs.NewFunctionHook(func(s configs.HookState) error { if !reflect.DeepEqual(state, s) { t.Errorf("Expected state %+v to equal %+v", state, s) } return nil }) fHook.Run(state) }
func TestMarshalHooksWithUnexpectedType(t *testing.T) { fHook := configs.NewFunctionHook(func(configs.HookState) error { return nil }) hook := configs.Hooks{ Prestart: []configs.Hook{fHook}, } hooks, err := hook.MarshalJSON() if err != nil { t.Fatal(err) } h := `{"poststart":null,"poststop":null,"prestart":null}` if string(hooks) != h { t.Errorf("Expected hooks %s to equal %s", string(hooks), h) } }
func TestHook(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() ok(t, err) defer os.RemoveAll(root) rootfs, err := newRootfs() ok(t, err) defer remove(rootfs) config := newTemplateConfig(rootfs) config.Hooks = &configs.Hooks{ Prestart: []configs.Hook{ configs.NewFunctionHook(func(s configs.HookState) error { f, err := os.Create(filepath.Join(s.Root, "test")) if err != nil { return err } return f.Close() }), }, Poststop: []configs.Hook{ configs.NewFunctionHook(func(s configs.HookState) error { return os.RemoveAll(filepath.Join(s.Root, "test")) }), }, } container, err := factory.Create("test", config) ok(t, err) var stdout bytes.Buffer pconfig := libcontainer.Process{ Args: []string{"sh", "-c", "ls /test"}, Env: standardEnvironment, Stdin: nil, Stdout: &stdout, } err = container.Start(&pconfig) ok(t, err) // Wait for process waitProcess(&pconfig, t) outputLs := string(stdout.Bytes()) // Check that the ls output has the expected file touched by the prestart hook if !strings.Contains(outputLs, "/test") { container.Destroy() t.Fatalf("ls output doesn't have the expected file: %s", outputLs) } if err := container.Destroy(); err != nil { t.Fatalf("container destory %s", err) } fi, err := os.Stat(filepath.Join(rootfs, "test")) if err == nil || !os.IsNotExist(err) { t.Fatalf("expected file to not exist, got %s", fi.Name()) } }
func TestHook(t *testing.T) { if testing.Short() { return } root, err := newTestRoot() ok(t, err) defer os.RemoveAll(root) rootfs, err := newRootfs() ok(t, err) 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")) }), }, } container, err := factory.Create("test", config) ok(t, err) var stdout bytes.Buffer pconfig := libcontainer.Process{ Cwd: "/", Args: []string{"sh", "-c", "ls /test"}, Env: standardEnvironment, Stdin: nil, Stdout: &stdout, } err = container.Run(&pconfig) ok(t, err) // Wait for process waitProcess(&pconfig, t) outputLs := string(stdout.Bytes()) // Check that the ls output has the expected file touched by the prestart hook if !strings.Contains(outputLs, "/test") { container.Destroy() 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 destroy %s", err) } fi, err := os.Stat(filepath.Join(rootfs, "test")) if err == nil || !os.IsNotExist(err) { t.Fatalf("expected file to not exist, got %s", fi.Name()) } }