Repository: opencontainers/runc
File: libcontainer/state_linux.go (Go)

Code before:
	To   string
}

func (s *stateTransitionError) Error() string {
	return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To)
}

type containerState interface {
	transition(containerState) error
	destroy() error
	status() Status
}

func destroy(c *Container) error {
	// Usually, when a container init is gone, all other processes in its
	// cgroup are killed by the kernel. This is not the case for a shared
	// PID namespace container, which may have some processes left after
	// its init is killed or exited.
	//
	// As the container without init process running is considered stopped,
	// and destroy is supposed to remove all the container resources, we need
	// to kill those processes here.
	if !c.config.Namespaces.IsPrivate(configs.NEWPID) {
		_ = signalAllProcesses(c.cgroupManager, unix.SIGKILL)
	}
	err := c.cgroupManager.Destroy()
	if c.intelRdtManager != nil {
		if ierr := c.intelRdtManager.Destroy(); err == nil {
			err = ierr
		}
	}
	if rerr := os.RemoveAll(c.stateDir); err == nil {
		err = rerr
	}
	c.initProcess = nil
	if herr := runPoststopHooks(c); err == nil {
		err = herr
	}
	c.state = &stoppedState{c: c}
	return err
}

func runPoststopHooks(c *Container) error {
	hooks := c.config.Hooks
	if hooks == nil {
		return nil
	}

	s, err := c.currentOCIState()
	if err != nil {
		return err

Review comment (suggestion):
We say we should not ignore the error from destroy, it means that we have a opportunity to destroy it again once we got an error, but if we ignore this cgroup destroy error, the state directory would be removed in next several lines, so the container disappears in runc, but leave some cgroup paths or some processes of this container in the host, we can’t delete them anymore from Runc.

Code after:
	To   string
}

func (s *stateTransitionError) Error() string {
	return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To)
}

type containerState interface {
	transition(containerState) error
	destroy() error
	status() Status
}

func destroy(c *Container) error {
	// Usually, when a container init is gone, all other processes in its
	// cgroup are killed by the kernel. This is not the case for a shared
	// PID namespace container, which may have some processes left after
	// its init is killed or exited.
	//
	// As the container without init process running is considered stopped,
	// and destroy is supposed to remove all the container resources, we need
	// to kill those processes here.
	if !c.config.Namespaces.IsPrivate(configs.NEWPID) {
		_ = signalAllProcesses(c.cgroupManager, unix.SIGKILL)
	}
	if err := c.cgroupManager.Destroy(); err != nil {
		return fmt.Errorf("unable to remove container's cgroup: %w", err)
	}
	if c.intelRdtManager != nil {
		if err := c.intelRdtManager.Destroy(); err != nil {
			return fmt.Errorf("unable to remove container's IntelRDT group: %w", err)
		}
	}
	if err := os.RemoveAll(c.stateDir); err != nil {
		return fmt.Errorf("unable to remove container state dir: %w", err)
	}
	c.initProcess = nil
	err := runPoststopHooks(c)
	c.state = &stoppedState{c: c}
	return err
}

func runPoststopHooks(c *Container) error {
	hooks := c.config.Hooks
	if hooks == nil {
		return nil
	}

	s, err := c.currentOCIState()
	if err != nil {
		return err