mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Add handling for system restart in libpod
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
This commit is contained in:
@ -407,8 +407,54 @@ func (c *Container) teardownStorage() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refresh refreshes the container's state after a restart
|
||||||
|
func (c *Container) refresh() error {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
if !c.valid {
|
||||||
|
return errors.Wrapf(ErrCtrRemoved, "container %s has been removed from the state", c.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to get the container's temporary directory from c/storage
|
||||||
|
// It was lost in the reboot and must be recreated
|
||||||
|
dir, err := c.runtime.storageService.GetRunDir(c.ID())
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error retrieving temporary directory for container %s", c.ID())
|
||||||
|
}
|
||||||
|
c.state.RunDir = dir
|
||||||
|
|
||||||
|
// The container is no longer mounted
|
||||||
|
c.state.Mounted = false
|
||||||
|
c.state.Mountpoint = ""
|
||||||
|
|
||||||
|
// The container is no longe running
|
||||||
|
c.state.PID = 0
|
||||||
|
|
||||||
|
// Check the container's state. If it's not created in runc yet, we're
|
||||||
|
// done
|
||||||
|
if c.state.State == ContainerStateConfigured {
|
||||||
|
if err := c.runtime.state.SaveContainer(c); err != nil {
|
||||||
|
return errors.Wrapf(err, "error refreshing state for container %s", c.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// The container must be recreated in runc
|
||||||
|
if err := c.init(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.runtime.state.SaveContainer(c); err != nil {
|
||||||
|
return errors.Wrapf(err, "error refreshing state for container %s", c.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Init creates a container in the OCI runtime
|
// Init creates a container in the OCI runtime
|
||||||
func (c *Container) Init() (err error) {
|
func (c *Container) Init() error {
|
||||||
c.lock.Lock()
|
c.lock.Lock()
|
||||||
defer c.lock.Unlock()
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
@ -420,7 +466,12 @@ func (c *Container) Init() (err error) {
|
|||||||
return errors.Wrapf(ErrCtrExists, "container %s has already been created in runtime", c.ID())
|
return errors.Wrapf(ErrCtrExists, "container %s has already been created in runtime", c.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount storage for the container
|
return c.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates container in OCI runtime
|
||||||
|
// Internal only - does not lock or check state
|
||||||
|
func (c *Container) init() (err error) {
|
||||||
if err := c.mountStorage(); err != nil {
|
if err := c.mountStorage(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -436,6 +487,17 @@ func (c *Container) Init() (err error) {
|
|||||||
|
|
||||||
// Save the OCI spec to disk
|
// Save the OCI spec to disk
|
||||||
jsonPath := filepath.Join(c.bundlePath(), "config.json")
|
jsonPath := filepath.Join(c.bundlePath(), "config.json")
|
||||||
|
// If the OCI spec already exists, replace it
|
||||||
|
if _, err := os.Stat(jsonPath); err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return errors.Wrapf(err, "error doing stat on container %s spec", c.ID())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No error, the spec exists. Remove so we can replace.
|
||||||
|
if err := os.Remove(jsonPath); err != nil {
|
||||||
|
return errors.Wrapf(err, "error replacing spec of container %s", c.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
fileJSON, err := json.Marshal(c.runningSpec)
|
fileJSON, err := json.Marshal(c.runningSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error exporting runtime spec for container %s to JSON", c.ID())
|
return errors.Wrapf(err, "error exporting runtime spec for container %s to JSON", c.ID())
|
||||||
|
@ -173,6 +173,24 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
|
|||||||
runtime.state = state
|
runtime.state = state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We now need to see if the system has restarted
|
||||||
|
// We check for the presence of a file in our tmp directory to verify this
|
||||||
|
runtimeAliveFile := filepath.Join(runtime.config.TmpDir, "alive")
|
||||||
|
_, err = os.Stat(runtimeAliveFile)
|
||||||
|
if err != nil {
|
||||||
|
// If the file doesn't exist, we need to refresh the state
|
||||||
|
// This will trigger on first use as well, but refreshing an
|
||||||
|
// empty state only creates a single file
|
||||||
|
// As such, it's not really a performance concern
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
if err2 := runtime.refresh(runtimeAliveFile); err2 != nil {
|
||||||
|
return nil, err2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.Wrapf(err, "error reading runtime status file %s", runtimeAliveFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mark the runtime as valid - ready to be used, cannot be modified
|
// Mark the runtime as valid - ready to be used, cannot be modified
|
||||||
// further
|
// further
|
||||||
runtime.valid = true
|
runtime.valid = true
|
||||||
@ -238,3 +256,30 @@ func (r *Runtime) Shutdown(force bool) error {
|
|||||||
|
|
||||||
return lastError
|
return lastError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reconfigures the runtime after a reboot
|
||||||
|
// Refreshes the state, recreating temporary files
|
||||||
|
// Does not check validity as the runtime is not valid until after this has run
|
||||||
|
// TODO: there's a potential race here, where multiple libpods could be in this
|
||||||
|
// function before the runtime ready file is created
|
||||||
|
// This probably doesn't matter as the actual container operations are locked
|
||||||
|
func (r *Runtime) refresh(alivePath string) error {
|
||||||
|
// We need to refresh the state of all containers
|
||||||
|
ctrs, err := r.state.AllContainers()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error retrieving all containers from state")
|
||||||
|
}
|
||||||
|
for _, ctr := range ctrs {
|
||||||
|
if err := ctr.refresh(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.OpenFile(alivePath, os.O_RDONLY|os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error creating runtime status file %s", alivePath)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user