mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Multi Container: Add IsRunning() control message for the container.
- Adds IsRunning() control message which returns true if the container is running. - Adds a test to verify the result of IsRunning(). PiperOrigin-RevId: 461759652
This commit is contained in:
committed by
gVisor bot
parent
ee0e725b60
commit
4bc44eac9b
+102
-11
@@ -46,9 +46,35 @@ type Lifecycle struct {
|
||||
// namespaces.
|
||||
MountNamespacesMap map[string]*vfs.MountNamespace
|
||||
|
||||
// containerInitProcessMap is a map of container ID and the init(PID 1)
|
||||
// threadgroup of the container.
|
||||
containerInitProcessMap map[string]*kernel.ThreadGroup
|
||||
// containerMap is a map of the container id and the container.
|
||||
containerMap map[string]*Container
|
||||
}
|
||||
|
||||
// containerState is the state of the container.
|
||||
type containerState int
|
||||
|
||||
const (
|
||||
// stateCreated is the state when the container was created. It is the
|
||||
// initial state.
|
||||
stateCreated containerState = iota
|
||||
|
||||
// stateRunning is the state when the container/application is running.
|
||||
stateRunning
|
||||
|
||||
// stateStopped is the state when the container has exited.
|
||||
stateStopped
|
||||
)
|
||||
|
||||
// Container contains the set of parameters to represent a container.
|
||||
type Container struct {
|
||||
// containerID.
|
||||
containerID string
|
||||
|
||||
// tg is the init(PID 1) threadgroup of the container.
|
||||
tg *kernel.ThreadGroup
|
||||
|
||||
// state is the current state of the container.
|
||||
state containerState
|
||||
}
|
||||
|
||||
// StartContainerArgs is the set of arguments to start a container.
|
||||
@@ -104,6 +130,38 @@ func (args StartContainerArgs) String() string {
|
||||
return strings.Join(a, " ")
|
||||
}
|
||||
|
||||
func (l *Lifecycle) updateContainerState(containerID string, newState containerState) error {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
c, ok := l.containerMap[containerID]
|
||||
if !ok {
|
||||
return fmt.Errorf("container %v not started", containerID)
|
||||
}
|
||||
|
||||
switch newState {
|
||||
case stateCreated:
|
||||
// Impossible.
|
||||
panic(fmt.Sprintf("invalid state transition: %v => %v", c.state, newState))
|
||||
|
||||
case stateRunning:
|
||||
if c.state != stateCreated {
|
||||
// Impossible.
|
||||
panic(fmt.Sprintf("invalid state transition: %v => %v", c.state, newState))
|
||||
}
|
||||
|
||||
case stateStopped:
|
||||
// Valid state transition.
|
||||
|
||||
default:
|
||||
// Invalid new state.
|
||||
panic(fmt.Sprintf("invalid new state: %v", newState))
|
||||
}
|
||||
|
||||
c.state = newState
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartContainer will start a new container in the sandbox.
|
||||
func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
|
||||
// Import file descriptors.
|
||||
@@ -177,16 +235,24 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
c := &Container{
|
||||
containerID: initArgs.ContainerID,
|
||||
tg: tg,
|
||||
state: stateCreated,
|
||||
}
|
||||
|
||||
l.mu.Lock()
|
||||
if l.containerMap == nil {
|
||||
l.containerMap = make(map[string]*Container)
|
||||
}
|
||||
l.containerMap[initArgs.ContainerID] = c
|
||||
l.mu.Unlock()
|
||||
|
||||
// Start the newly created process.
|
||||
l.Kernel.StartProcess(tg)
|
||||
log.Infof("Started the new container %v ", initArgs.ContainerID)
|
||||
|
||||
l.mu.Lock()
|
||||
if l.containerInitProcessMap == nil {
|
||||
l.containerInitProcessMap = make(map[string]*kernel.ThreadGroup)
|
||||
}
|
||||
l.containerInitProcessMap[initArgs.ContainerID] = tg
|
||||
l.mu.Unlock()
|
||||
l.updateContainerState(initArgs.ContainerID, stateRunning)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -212,11 +278,11 @@ func (l *Lifecycle) getInitContainerProcess(containerID string) (*kernel.ThreadG
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
tg, ok := l.containerInitProcessMap[containerID]
|
||||
c, ok := l.containerMap[containerID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("container %v not started", containerID)
|
||||
}
|
||||
return tg, nil
|
||||
return c.tg, nil
|
||||
}
|
||||
|
||||
// ContainerArgs is the set of arguments for container related APIs after
|
||||
@@ -235,5 +301,30 @@ func (l *Lifecycle) WaitContainer(args *ContainerArgs, waitStatus *uint32) error
|
||||
|
||||
tg.WaitExited()
|
||||
*waitStatus = uint32(tg.ExitStatus())
|
||||
if err := l.updateContainerState(args.ContainerID, stateStopped); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsContainerRunning returns true if the container is running.
|
||||
func (l *Lifecycle) IsContainerRunning(args *ContainerArgs, isRunning *bool) error {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
c, ok := l.containerMap[args.ContainerID]
|
||||
if !ok || c.state != stateRunning {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The state will not be updated to "stopped" if the
|
||||
// WaitContainer(...) method is not called. In this case, check
|
||||
// whether the number of non-exited tasks in tg is zero to get
|
||||
// the correct state of the container.
|
||||
if c.tg.Count() == 0 {
|
||||
c.state = stateStopped
|
||||
return nil
|
||||
}
|
||||
*isRunning = true
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user