mirror of
https://github.com/containers/podman.git
synced 2025-10-17 03:04:21 +08:00
Add Refresh() to ctrs to refresh state after db change
The Refresh() function is used to reset a container's state after a database format change to state is made that requires migration Signed-off-by: Matthew Heon <matthew.heon@gmail.com> Closes: #981 Approved by: baude
This commit is contained in:
@ -174,15 +174,9 @@ func (s *BoltState) Refresh() error {
|
|||||||
return errors.Wrapf(err, "error unmarshalling state for container %s", string(id))
|
return errors.Wrapf(err, "error unmarshalling state for container %s", string(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
state.PID = 0
|
if err := resetState(state); err != nil {
|
||||||
state.Mountpoint = ""
|
return errors.Wrapf(err, "error resetting state for container %s", string(id))
|
||||||
state.Mounted = false
|
}
|
||||||
state.State = ContainerStateConfigured
|
|
||||||
state.ExecSessions = make(map[string]*ExecSession)
|
|
||||||
state.IPs = nil
|
|
||||||
state.Interfaces = nil
|
|
||||||
state.Routes = nil
|
|
||||||
state.BindMounts = make(map[string]string)
|
|
||||||
|
|
||||||
newStateBytes, err := json.Marshal(state)
|
newStateBytes, err := json.Marshal(state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -477,15 +477,8 @@ func (c *Container) Pause() error {
|
|||||||
if c.state.State != ContainerStateRunning {
|
if c.state.State != ContainerStateRunning {
|
||||||
return errors.Wrapf(ErrCtrStateInvalid, "%q is not running, can't pause", c.state.State)
|
return errors.Wrapf(ErrCtrStateInvalid, "%q is not running, can't pause", c.state.State)
|
||||||
}
|
}
|
||||||
if err := c.runtime.ociRuntime.pauseContainer(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf("Paused container %s", c.ID())
|
return c.pause()
|
||||||
|
|
||||||
c.state.State = ContainerStatePaused
|
|
||||||
|
|
||||||
return c.save()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpause unpauses a container
|
// Unpause unpauses a container
|
||||||
@ -502,15 +495,8 @@ func (c *Container) Unpause() error {
|
|||||||
if c.state.State != ContainerStatePaused {
|
if c.state.State != ContainerStatePaused {
|
||||||
return errors.Wrapf(ErrCtrStateInvalid, "%q is not paused, can't unpause", c.ID())
|
return errors.Wrapf(ErrCtrStateInvalid, "%q is not paused, can't unpause", c.ID())
|
||||||
}
|
}
|
||||||
if err := c.runtime.ociRuntime.unpauseContainer(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf("Unpaused container %s", c.ID())
|
return c.unpause()
|
||||||
|
|
||||||
c.state.State = ContainerStateRunning
|
|
||||||
|
|
||||||
return c.save()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export exports a container's root filesystem as a tar archive
|
// Export exports a container's root filesystem as a tar archive
|
||||||
@ -753,3 +739,106 @@ func (c *Container) RestartWithTimeout(ctx context.Context, timeout uint) (err e
|
|||||||
|
|
||||||
return c.start()
|
return c.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refresh refreshes a container's state in the database, restarting the
|
||||||
|
// container if it is running
|
||||||
|
func (c *Container) Refresh(ctx context.Context) error {
|
||||||
|
if !c.batched {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
if err := c.syncContainer(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wasCreated := false
|
||||||
|
if c.state.State == ContainerStateCreated {
|
||||||
|
wasCreated = true
|
||||||
|
}
|
||||||
|
wasRunning := false
|
||||||
|
if c.state.State == ContainerStateRunning {
|
||||||
|
wasRunning = true
|
||||||
|
}
|
||||||
|
wasPaused := false
|
||||||
|
if c.state.State == ContainerStatePaused {
|
||||||
|
wasPaused = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, unpause the container if it's paused
|
||||||
|
if c.state.State == ContainerStatePaused {
|
||||||
|
if err := c.unpause(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, if the container is running, stop it
|
||||||
|
if c.state.State == ContainerStateRunning {
|
||||||
|
if err := c.stop(c.config.StopTimeout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are active exec sessions, we need to kill them
|
||||||
|
if len(c.state.ExecSessions) > 0 {
|
||||||
|
logrus.Infof("Killing %d exec sessions in container %s. They will not be restored after refresh.",
|
||||||
|
len(c.state.ExecSessions), c.ID())
|
||||||
|
if err := c.runtime.ociRuntime.execStopContainer(c, c.config.StopTimeout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the container is in ContainerStateStopped, we need to delete it
|
||||||
|
// from the runtime and clear conmon state
|
||||||
|
if c.state.State == ContainerStateStopped {
|
||||||
|
if err := c.delete(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.removeConmonFiles(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire cleanup code one more time unconditionally to ensure we are good
|
||||||
|
// to refresh
|
||||||
|
if err := c.cleanup(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've finished unwinding the container back to its initial state
|
||||||
|
// Now safe to refresh container state
|
||||||
|
if err := resetState(c.state); err != nil {
|
||||||
|
return errors.Wrapf(err, "error resetting state of container %s", c.ID())
|
||||||
|
}
|
||||||
|
if err := c.refresh(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("Successfully refresh container %s state")
|
||||||
|
|
||||||
|
// Initialize the container if it was created in runc
|
||||||
|
if wasCreated || wasRunning || wasPaused {
|
||||||
|
if err := c.prepare(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.init(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the container was running before, start it
|
||||||
|
if wasRunning || wasPaused {
|
||||||
|
if err := c.start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the container was paused before, re-pause it
|
||||||
|
if wasPaused {
|
||||||
|
if err := c.pause(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -316,6 +316,23 @@ func (c *Container) teardownStorage() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset resets state fields to default values
|
||||||
|
// It is performed before a refresh and clears the state after a reboot
|
||||||
|
// It does not save the results - assumes the database will do that for us
|
||||||
|
func resetState(state *containerState) error {
|
||||||
|
state.PID = 0
|
||||||
|
state.Mountpoint = ""
|
||||||
|
state.Mounted = false
|
||||||
|
state.State = ContainerStateConfigured
|
||||||
|
state.ExecSessions = make(map[string]*ExecSession)
|
||||||
|
state.IPs = nil
|
||||||
|
state.Interfaces = nil
|
||||||
|
state.Routes = nil
|
||||||
|
state.BindMounts = make(map[string]string)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh refreshes the container's state after a restart
|
// Refresh refreshes the container's state after a restart
|
||||||
func (c *Container) refresh() error {
|
func (c *Container) refresh() error {
|
||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
@ -681,6 +698,32 @@ func (c *Container) stop(timeout uint) error {
|
|||||||
return c.cleanup()
|
return c.cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal, non-locking function to pause a container
|
||||||
|
func (c *Container) pause() error {
|
||||||
|
if err := c.runtime.ociRuntime.pauseContainer(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("Paused container %s", c.ID())
|
||||||
|
|
||||||
|
c.state.State = ContainerStatePaused
|
||||||
|
|
||||||
|
return c.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal, non-locking function to unpause a container
|
||||||
|
func (c *Container) unpause() error {
|
||||||
|
if err := c.runtime.ociRuntime.unpauseContainer(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("Unpaused container %s", c.ID())
|
||||||
|
|
||||||
|
c.state.State = ContainerStateRunning
|
||||||
|
|
||||||
|
return c.save()
|
||||||
|
}
|
||||||
|
|
||||||
// mountStorage sets up the container's root filesystem
|
// mountStorage sets up the container's root filesystem
|
||||||
// It mounts the image and any other requested mounts
|
// It mounts the image and any other requested mounts
|
||||||
// TODO: Add ability to override mount label so we can use this for Mount() too
|
// TODO: Add ability to override mount label so we can use this for Mount() too
|
||||||
|
Reference in New Issue
Block a user