diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/boltdb_state.go | 8 | ||||
-rw-r--r-- | libpod/common_test.go | 6 | ||||
-rw-r--r-- | libpod/container.go | 15 | ||||
-rw-r--r-- | libpod/container_api.go | 4 | ||||
-rw-r--r-- | libpod/container_easyjson.go | 14 | ||||
-rw-r--r-- | libpod/container_internal.go | 30 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 20 | ||||
-rw-r--r-- | libpod/container_internal_test.go | 2 | ||||
-rw-r--r-- | libpod/networking_linux.go | 22 | ||||
-rw-r--r-- | libpod/oci.go | 6 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 2 | ||||
-rw-r--r-- | libpod/state_test.go | 8 |
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) |