exec: Allow to exec a process on a ready container

If a container is not running, but created/ready instead, this means
a container process exists and that we can actually exec another
process inside this container. The container does not have to be
in running state.

Fixes #120

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2018-03-27 15:08:48 -07:00
parent 9a7813e9ea
commit aa469f4573
4 changed files with 61 additions and 10 deletions

View File

@ -210,9 +210,11 @@ func execute(context *cli.Context) error {
params.cID = status.ID params.cID = status.ID
// container MUST be running // container MUST be ready or running.
if status.State.State != vc.StateRunning { if status.State.State != vc.StateReady &&
return fmt.Errorf("Container %s is not running", params.cID) status.State.State != vc.StateRunning {
return fmt.Errorf("Container %s is not ready or running",
params.cID)
} }
envVars, err := oci.EnvVars(params.ociProcess.Env) envVars, err := oci.EnvVars(params.ociProcess.Env)

View File

@ -89,7 +89,7 @@ func TestExecuteErrors(t *testing.T) {
assert.Error(err) assert.Error(err)
assert.False(vcmock.IsMockError(err)) assert.False(vcmock.IsMockError(err))
// Container not running // Container state undefined
configPath := testConfigSetup(t) configPath := testConfigSetup(t)
configJSON, err := readOCIConfigJSON(configPath) configJSON, err := readOCIConfigJSON(configPath)
assert.NoError(err) assert.NoError(err)
@ -99,13 +99,34 @@ func TestExecuteErrors(t *testing.T) {
vcAnnotations.ConfigJSONKey: configJSON, vcAnnotations.ConfigJSONKey: configJSON,
} }
containerState := vc.State{}
testingImpl.ListPodFunc = func() ([]vc.PodStatus, error) { testingImpl.ListPodFunc = func() ([]vc.PodStatus, error) {
return newSingleContainerPodStatusList(testPodID, testContainerID, vc.State{}, vc.State{}, annotations), nil return newSingleContainerPodStatusList(testPodID, testContainerID, vc.State{}, containerState, annotations), nil
} }
defer func() { err = execute(ctx)
testingImpl.ListPodFunc = nil assert.Error(err)
}() assert.False(vcmock.IsMockError(err))
// Container paused
containerState = vc.State{
State: vc.StatePaused,
}
testingImpl.ListPodFunc = func() ([]vc.PodStatus, error) {
return newSingleContainerPodStatusList(testPodID, testContainerID, vc.State{}, containerState, annotations), nil
}
err = execute(ctx)
assert.Error(err)
assert.False(vcmock.IsMockError(err))
// Container stopped
containerState = vc.State{
State: vc.StateStopped,
}
testingImpl.ListPodFunc = func() ([]vc.PodStatus, error) {
return newSingleContainerPodStatusList(testPodID, testContainerID, vc.State{}, containerState, annotations), nil
}
err = execute(ctx) err = execute(ctx)
assert.Error(err) assert.Error(err)

View File

@ -627,8 +627,10 @@ func (c *Container) enter(cmd Cmd) (*Process, error) {
return nil, err return nil, err
} }
if c.state.State != StateRunning { if c.state.State != StateReady &&
return nil, fmt.Errorf("Container not running, impossible to enter") c.state.State != StateRunning {
return nil, fmt.Errorf("Container not ready or running, " +
"impossible to enter")
} }
process, err := c.pod.agent.exec(c.pod, *c, cmd) process, err := c.pod.agent.exec(c.pod, *c, cmd)

View File

@ -336,3 +336,29 @@ func TestContainerRemoveResources(t *testing.T) {
err = c.removeResources() err = c.removeResources()
assert.Nil(err) assert.Nil(err)
} }
func TestContainerEnterErrorsOnContainerStates(t *testing.T) {
assert := assert.New(t)
c := &Container{
pod: &Pod{
state: State{
State: StateRunning,
},
},
}
cmd := Cmd{}
// Container state undefined
_, err := c.enter(cmd)
assert.Error(err)
// Container paused
c.state.State = StatePaused
_, err = c.enter(cmd)
assert.Error(err)
// Container stopped
c.state.State = StateStopped
_, err = c.enter(cmd)
assert.Error(err)
}