aboutsummaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state.go8
-rw-r--r--libpod/common_test.go6
-rw-r--r--libpod/container.go15
-rw-r--r--libpod/container_api.go4
-rw-r--r--libpod/container_easyjson.go14
-rw-r--r--libpod/container_internal.go30
-rw-r--r--libpod/container_internal_linux.go20
-rw-r--r--libpod/container_internal_test.go2
-rw-r--r--libpod/networking_linux.go22
-rw-r--r--libpod/oci.go6
-rw-r--r--libpod/runtime_ctr.go2
-rw-r--r--libpod/state_test.go8
12 files changed, 85 insertions, 52 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index ba8f7375a..b154d8bda 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -322,7 +322,7 @@ func (s *BoltState) Container(id string) (*Container, error) {
ctrID := []byte(id)
ctr := new(Container)
- ctr.config = new(Config)
+ ctr.config = new(ContainerConfig)
ctr.state = new(containerState)
db, err := s.getDBCon()
@@ -358,7 +358,7 @@ func (s *BoltState) LookupContainer(idOrName string) (*Container, error) {
}
ctr := new(Container)
- ctr.config = new(Config)
+ ctr.config = new(ContainerConfig)
ctr.state = new(containerState)
db, err := s.getDBCon()
@@ -751,7 +751,7 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
}
ctr := new(Container)
- ctr.config = new(Config)
+ ctr.config = new(ContainerConfig)
ctr.state = new(containerState)
if err := s.getContainerFromDB(id, ctr, ctrBucket); err != nil {
@@ -1137,7 +1137,7 @@ func (s *BoltState) PodContainers(pod *Pod) ([]*Container, error) {
// Iterate through all containers in the pod
err = podCtrs.ForEach(func(id, val []byte) error {
newCtr := new(Container)
- newCtr.config = new(Config)
+ newCtr.config = new(ContainerConfig)
newCtr.state = new(containerState)
ctrs = append(ctrs, newCtr)
diff --git a/libpod/common_test.go b/libpod/common_test.go
index 882468a3a..efbb5f404 100644
--- a/libpod/common_test.go
+++ b/libpod/common_test.go
@@ -17,7 +17,7 @@ import (
func getTestContainer(id, name string, manager lock.Manager) (*Container, error) {
ctr := &Container{
- config: &Config{
+ config: &ContainerConfig{
ID: id,
Name: name,
RootfsImageID: id,
@@ -165,8 +165,8 @@ func testContainersEqual(t *testing.T, a, b *Container, allowedEmpty bool) {
require.NotNil(t, a.state)
require.NotNil(t, b.state)
- aConfig := new(Config)
- bConfig := new(Config)
+ aConfig := new(ContainerConfig)
+ bConfig := new(ContainerConfig)
aState := new(containerState)
bState := new(containerState)
diff --git a/libpod/container.go b/libpod/container.go
index 4e5088b32..d0eb6a992 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -113,7 +113,7 @@ func (ns LinuxNS) String() string {
// syncContainer() immediately after locking.
// ffjson: skip
type Container struct {
- config *Config
+ config *ContainerConfig
state *containerState
@@ -128,6 +128,11 @@ type Container struct {
rootlessSlirpSyncR *os.File
rootlessSlirpSyncW *os.File
+
+ // A restored container should have the same IP address as before
+ // being checkpointed. If requestedIP is set it will be used instead
+ // of config.StaticIP.
+ requestedIP net.IP
}
// containerState contains the current state of the container
@@ -200,11 +205,11 @@ type ExecSession struct {
PID int `json:"pid"`
}
-// Config contains all information that was used to create the
+// ContainerConfig contains all information that was used to create the
// container. It may not be changed once created.
// It is stored, read-only, on disk
// easyjson:json
-type Config struct {
+type ContainerConfig struct {
Spec *spec.Spec `json:"spec"`
ID string `json:"id"`
Name string `json:"name"`
@@ -385,8 +390,8 @@ func (t ContainerStatus) String() string {
// Unlocked
// Config returns the configuration used to create the container
-func (c *Container) Config() *Config {
- returnConfig := new(Config)
+func (c *Container) Config() *ContainerConfig {
+ returnConfig := new(ContainerConfig)
deepcopier.Copy(c.config).To(returnConfig)
return returnConfig
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 09bc46905..4eaf737b0 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -262,7 +262,7 @@ func (c *Container) Kill(signal uint) error {
// Exec starts a new process inside the container
// TODO allow specifying streams to attach to
// TODO investigate allowing exec without attaching
-func (c *Container) Exec(tty, privileged bool, env, cmd []string, user string) error {
+func (c *Container) Exec(tty, privileged bool, env, cmd []string, user, workDir string) error {
var capList []string
locked := false
@@ -324,7 +324,7 @@ func (c *Container) Exec(tty, privileged bool, env, cmd []string, user string) e
logrus.Debugf("Creating new exec session in container %s with session id %s", c.ID(), sessionID)
- execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, hostUser, sessionID)
+ execCmd, err := c.runtime.ociRuntime.execContainer(c, cmd, capList, env, tty, workDir, hostUser, sessionID)
if err != nil {
return errors.Wrapf(err, "error exec %s", c.ID())
}
diff --git a/libpod/container_easyjson.go b/libpod/container_easyjson.go
index ae0972cf6..f1cb09bcc 100644
--- a/libpod/container_easyjson.go
+++ b/libpod/container_easyjson.go
@@ -1,6 +1,6 @@
// +build seccomp ostree selinux varlink exclude_graphdriver_devicemapper
-// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
+// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT
package libpod
@@ -1238,7 +1238,7 @@ func (v *ExecSession) UnmarshalJSON(data []byte) error {
func (v *ExecSession) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjson1dbef17bDecodeGithubComContainersLibpodLibpod1(l, v)
}
-func easyjson1dbef17bDecodeGithubComContainersLibpodLibpod2(in *jlexer.Lexer, out *Config) {
+func easyjson1dbef17bDecodeGithubComContainersLibpodLibpod2(in *jlexer.Lexer, out *ContainerConfig) {
isTopLevel := in.IsStart()
if in.IsNull() {
if isTopLevel {
@@ -1722,7 +1722,7 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodLibpod2(in *jlexer.Lexer, ou
in.Consumed()
}
}
-func easyjson1dbef17bEncodeGithubComContainersLibpodLibpod2(out *jwriter.Writer, in Config) {
+func easyjson1dbef17bEncodeGithubComContainersLibpodLibpod2(out *jwriter.Writer, in ContainerConfig) {
out.RawByte('{')
first := true
_ = first
@@ -2427,26 +2427,26 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodLibpod2(out *jwriter.Writer,
}
// MarshalJSON supports json.Marshaler interface
-func (v Config) MarshalJSON() ([]byte, error) {
+func (v ContainerConfig) MarshalJSON() ([]byte, error) {
w := jwriter.Writer{}
easyjson1dbef17bEncodeGithubComContainersLibpodLibpod2(&w, v)
return w.Buffer.BuildBytes(), w.Error
}
// MarshalEasyJSON supports easyjson.Marshaler interface
-func (v Config) MarshalEasyJSON(w *jwriter.Writer) {
+func (v ContainerConfig) MarshalEasyJSON(w *jwriter.Writer) {
easyjson1dbef17bEncodeGithubComContainersLibpodLibpod2(w, v)
}
// UnmarshalJSON supports json.Unmarshaler interface
-func (v *Config) UnmarshalJSON(data []byte) error {
+func (v *ContainerConfig) UnmarshalJSON(data []byte) error {
r := jlexer.Lexer{Data: data}
easyjson1dbef17bDecodeGithubComContainersLibpodLibpod2(&r, v)
return r.Error()
}
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
-func (v *Config) UnmarshalEasyJSON(l *jlexer.Lexer) {
+func (v *ContainerConfig) UnmarshalEasyJSON(l *jlexer.Lexer) {
easyjson1dbef17bDecodeGithubComContainersLibpodLibpod2(l, v)
}
func easyjson1dbef17bDecodeGithubComContainersLibpodVendorGithubComCriOOcicniPkgOcicni(in *jlexer.Lexer, out *ocicni.PortMapping) {
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index cc4c36bc9..69df33bc9 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1181,6 +1181,7 @@ func (c *Container) saveSpec(spec *spec.Spec) error {
return nil
}
+// Warning: precreate hooks may alter 'config' in place.
func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (extensionStageHooks map[string][]spec.Hook, err error) {
var locale string
var ok bool
@@ -1209,13 +1210,13 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten
}
}
+ allHooks := make(map[string][]spec.Hook)
if c.runtime.config.HooksDir == nil {
if rootless.IsRootless() {
return nil, nil
}
- allHooks := make(map[string][]spec.Hook)
for _, hDir := range []string{hooks.DefaultDir, hooks.OverrideDir} {
- manager, err := hooks.New(ctx, []string{hDir}, []string{"poststop"}, lang)
+ manager, err := hooks.New(ctx, []string{hDir}, []string{"precreate", "poststop"}, lang)
if err != nil {
if os.IsNotExist(err) {
continue
@@ -1233,19 +1234,32 @@ func (c *Container) setupOCIHooks(ctx context.Context, config *spec.Spec) (exten
allHooks[i] = hook
}
}
- return allHooks, nil
+ } else {
+ manager, err := hooks.New(ctx, c.runtime.config.HooksDir, []string{"precreate", "poststop"}, lang)
+ if err != nil {
+ if os.IsNotExist(err) {
+ logrus.Warnf("Requested OCI hooks directory %q does not exist", c.runtime.config.HooksDir)
+ return nil, nil
+ }
+ return nil, err
+ }
+
+ allHooks, err = manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
+ if err != nil {
+ return nil, err
+ }
}
- manager, err := hooks.New(ctx, c.runtime.config.HooksDir, []string{"poststop"}, lang)
+ hookErr, err := exec.RuntimeConfigFilter(ctx, allHooks["precreate"], config, exec.DefaultPostKillTimeout)
if err != nil {
- if os.IsNotExist(err) {
- logrus.Warnf("Requested OCI hooks directory %q does not exist", c.runtime.config.HooksDir)
- return nil, nil
+ logrus.Warnf("container %s: precreate hook: %v", c.ID(), err)
+ if hookErr != nil && hookErr != err {
+ logrus.Debugf("container %s: precreate hook (hook error): %v", c.ID(), hookErr)
}
return nil, err
}
- return manager.Hooks(config, c.Spec().Annotations, len(c.config.UserVolumes) > 0)
+ return allHooks, nil
}
// mount mounts the container's root filesystem
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 0745b7732..582a4c3e7 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -228,10 +228,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
}
- if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
- return nil, errors.Wrapf(err, "error setting up OCI Hooks")
- }
-
// Bind builtin image volumes
if c.config.Rootfs == "" && c.config.ImageVolumes {
if err := c.addLocalVolumes(ctx, &g, execUser); err != nil {
@@ -384,6 +380,12 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
logrus.Debugf("set root propagation to %q", rootPropagation)
g.SetLinuxRootPropagation(rootPropagation)
}
+
+ // Warning: precreate hooks may alter g.Config in place.
+ if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
+ return nil, errors.Wrapf(err, "error setting up OCI Hooks")
+ }
+
return g.Config, nil
}
@@ -547,10 +549,8 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
}
if IP != nil {
- env := fmt.Sprintf("IP=%s", IP)
// Tell CNI which IP address we want.
- os.Setenv("CNI_ARGS", env)
- logrus.Debugf("Restoring container with %s", env)
+ c.requestedIP = IP
}
}
@@ -566,12 +566,6 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
return err
}
- // TODO: use existing way to request static IPs, once it is merged in ocicni
- // https://github.com/cri-o/ocicni/pull/23/
-
- // CNI_ARGS was used to request a certain IP address. Unconditionally remove it.
- os.Unsetenv("CNI_ARGS")
-
// Read config
jsonPath := filepath.Join(c.bundlePath(), "config.json")
logrus.Debugf("generate.NewFromFile at %v", jsonPath)
diff --git a/libpod/container_internal_test.go b/libpod/container_internal_test.go
index 51fb58713..124f1d20e 100644
--- a/libpod/container_internal_test.go
+++ b/libpod/container_internal_test.go
@@ -28,7 +28,7 @@ func TestPostDeleteHooks(t *testing.T) {
statePath := filepath.Join(dir, "state")
copyPath := filepath.Join(dir, "copy")
c := Container{
- config: &Config{
+ config: &ContainerConfig{
ID: "123abc",
Spec: &rspec.Spec{
Annotations: map[string]string{
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 43d0a61a4..a343bee6a 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -50,7 +50,16 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
// Create and configure a new network namespace for a container
func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Result, error) {
- podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, ctr.config.StaticIP)
+ var requestedIP net.IP
+ if ctr.requestedIP != nil {
+ requestedIP = ctr.requestedIP
+ // cancel request for a specific IP in case the container is reused later
+ ctr.requestedIP = nil
+ } else {
+ requestedIP = ctr.config.StaticIP
+ }
+
+ podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
results, err := r.netPlugin.SetUpPod(podNetwork)
if err != nil {
@@ -258,7 +267,16 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
- podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, ctr.config.StaticIP)
+ var requestedIP net.IP
+ if ctr.requestedIP != nil {
+ requestedIP = ctr.requestedIP
+ // cancel request for a specific IP in case the container is reused later
+ ctr.requestedIP = nil
+ } else {
+ requestedIP = ctr.config.StaticIP
+ }
+
+ podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
// The network may have already been torn down, so don't fail here, just log
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
diff --git a/libpod/oci.go b/libpod/oci.go
index 093bfdd35..31c1a7e85 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -728,7 +728,7 @@ func (r *OCIRuntime) unpauseContainer(ctr *Container) error {
// TODO: Add --detach support
// TODO: Convert to use conmon
// TODO: add --pid-file and use that to generate exec session tracking
-func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, user, sessionID string) (*exec.Cmd, error) {
+func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty bool, cwd, user, sessionID string) (*exec.Cmd, error) {
if len(cmd) == 0 {
return nil, errors.Wrapf(ErrInvalidArg, "must provide a command to execute")
}
@@ -749,7 +749,9 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
args = append(args, "exec")
- args = append(args, "--cwd", c.config.Spec.Process.Cwd)
+ if cwd != "" {
+ args = append(args, "--cwd", cwd)
+ }
args = append(args, "--pid-file", c.execPidPath(sessionID))
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index e6f2c962f..ab79fe5fb 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -47,7 +47,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
}
ctr := new(Container)
- ctr.config = new(Config)
+ ctr.config = new(ContainerConfig)
ctr.state = new(containerState)
ctr.config.ID = stringid.GenerateNonCryptoID()
diff --git a/libpod/state_test.go b/libpod/state_test.go
index ee4201b1c..4bd00ab55 100644
--- a/libpod/state_test.go
+++ b/libpod/state_test.go
@@ -156,7 +156,7 @@ func TestGetContainerPodSameIDFails(t *testing.T) {
func TestAddInvalidContainerFails(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
- err := state.AddContainer(&Container{config: &Config{ID: "1234"}})
+ err := state.AddContainer(&Container{config: &ContainerConfig{ID: "1234"}})
assert.Error(t, err)
})
}
@@ -756,7 +756,7 @@ func TestUpdateContainerNotInDatabaseReturnsError(t *testing.T) {
func TestUpdateInvalidContainerReturnsError(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
- err := state.UpdateContainer(&Container{config: &Config{ID: "1234"}})
+ err := state.UpdateContainer(&Container{config: &ContainerConfig{ID: "1234"}})
assert.Error(t, err)
})
}
@@ -780,7 +780,7 @@ func TestUpdateContainerNotInNamespaceReturnsError(t *testing.T) {
func TestSaveInvalidContainerReturnsError(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
- err := state.SaveContainer(&Container{config: &Config{ID: "1234"}})
+ err := state.SaveContainer(&Container{config: &ContainerConfig{ID: "1234"}})
assert.Error(t, err)
})
}
@@ -2604,7 +2604,7 @@ func TestAddContainerToPodInvalidCtr(t *testing.T) {
err = state.AddPod(testPod)
assert.NoError(t, err)
- err = state.AddContainerToPod(testPod, &Container{config: &Config{ID: "1234"}})
+ err = state.AddContainerToPod(testPod, &Container{config: &ContainerConfig{ID: "1234"}})
assert.Error(t, err)
ctrs, err := state.PodContainersByID(testPod)