Skip to content

Commit 6c7758d

Browse files
authored
Container transition to MANIFEST_PULLED state should happen after network pause container reaches RESOURCES_PROVISIONED state (#4286)
1 parent e37d2c0 commit 6c7758d

File tree

3 files changed

+81
-8
lines changed

3 files changed

+81
-8
lines changed

agent/api/task/task.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,7 @@ func (task *Task) addNetworkResourceProvisioningDependencyAwsvpc(cfg *config.Con
14911491
if container.IsInternal() {
14921492
continue
14931493
}
1494-
container.BuildContainerDependency(NetworkPauseContainerName, apicontainerstatus.ContainerResourcesProvisioned, apicontainerstatus.ContainerPulled)
1494+
container.BuildContainerDependency(NetworkPauseContainerName, apicontainerstatus.ContainerResourcesProvisioned, apicontainerstatus.ContainerManifestPulled)
14951495
pauseContainer.BuildContainerDependency(container.Name, apicontainerstatus.ContainerStopped, apicontainerstatus.ContainerStopped)
14961496
}
14971497

agent/engine/docker_task_engine_linux_test.go

+41-4
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,15 @@ func TestTaskWithSteadyStateResourcesProvisioned(t *testing.T) {
822822
waitForStopEvents(t, taskEngine.StateChangeEvents(), true, false)
823823
}
824824

825+
// Tests a happy case scenario for an AWSVPC task.
826+
//
827+
// This test also verifies that
828+
// any DockerClient calls that interact with an image repository (PullContainerManifest
829+
// and PullContainer, currently) happen after the pause container has reached
830+
// ContainerResourcesProvisioned state.
831+
//
832+
// If you are updating this test then make sure that you call assertPauseContainerIsRunning()
833+
// in any dockerClient expected calls that are supposed to interact with an image repository.
825834
func TestPauseContainerHappyPath(t *testing.T) {
826835
ctx, cancel := context.WithCancel(context.TODO())
827836
defer cancel()
@@ -857,6 +866,19 @@ func TestPauseContainerHappyPath(t *testing.T) {
857866
dockerClient.EXPECT().ContainerEvents(gomock.Any()).Return(eventStream, nil)
858867
serviceConnectManager.EXPECT().GetAppnetContainerTarballDir().AnyTimes()
859868

869+
// A function to assert that the network pause container in the task is in
870+
// ContainerResourcesProvisioned state. This will be used by dockerClient mock later.
871+
assertPauseContainerIsRunning := func() {
872+
assert.Len(t, sleepTask.Containers, 3, "expected pause container to be populated")
873+
pauseContainer := sleepTask.Containers[2]
874+
assert.Equal(t, apitask.NetworkPauseContainerName, pauseContainer.Name)
875+
assert.Equal(t, apicontainer.ContainerCNIPause, pauseContainer.Type)
876+
assert.Equal(t,
877+
apicontainerstatus.ContainerResourcesProvisioned,
878+
pauseContainer.GetKnownStatus(),
879+
"expected pause container to be running before image repository is called")
880+
}
881+
860882
sleepContainerID1 := containerID + "1"
861883
sleepContainerID2 := containerID + "2"
862884
pauseContainerID := "pauseContainerID"
@@ -870,8 +892,13 @@ func TestPauseContainerHappyPath(t *testing.T) {
870892
assert.True(t, ok)
871893
assert.Equal(t, apitask.NetworkPauseContainerName, name)
872894
}).Return(dockerapi.DockerContainerMetadata{DockerID: "pauseContainerID"}),
873-
dockerClient.EXPECT().StartContainer(gomock.Any(), pauseContainerID, defaultConfig.ContainerStartTimeout).Return(
874-
dockerapi.DockerContainerMetadata{DockerID: "pauseContainerID"}),
895+
dockerClient.EXPECT().
896+
StartContainer(gomock.Any(), pauseContainerID, defaultConfig.ContainerStartTimeout).
897+
Do(func(ctx interface{}, id string, timeout time.Duration) {
898+
// Simulate some startup time
899+
time.Sleep(5 * time.Millisecond)
900+
}).
901+
Return(dockerapi.DockerContainerMetadata{DockerID: "pauseContainerID"}),
875902
dockerClient.EXPECT().InspectContainer(gomock.Any(), gomock.Any(), gomock.Any()).Return(
876903
&types.ContainerJSON{
877904
ContainerJSONBase: &types.ContainerJSONBase{
@@ -892,9 +919,19 @@ func TestPauseContainerHappyPath(t *testing.T) {
892919
imageManager.EXPECT().AddAllImageStates(gomock.Any()).AnyTimes()
893920
dockerClient.EXPECT().WithVersion(dockerclient.Version_1_35).Times(2).Return(manifestPullClient, nil)
894921
manifestPullClient.EXPECT().
895-
PullImageManifest(gomock.Any(), gomock.Any(), gomock.Any()).Times(2).
922+
PullImageManifest(gomock.Any(), gomock.Any(), gomock.Any()).
923+
Times(2).
924+
Do(func(context.Context, string, *apicontainer.RegistryAuthenticationData) {
925+
assertPauseContainerIsRunning() // Ensure that pause container is already RUNNING
926+
}).
896927
Return(registry.DistributionInspect{}, nil)
897-
dockerClient.EXPECT().PullImage(gomock.Any(), gomock.Any(), nil, gomock.Any()).Return(dockerapi.DockerContainerMetadata{}).Times(2)
928+
dockerClient.EXPECT().
929+
PullImage(gomock.Any(), gomock.Any(), nil, gomock.Any()).
930+
Do(func(context.Context, string, *apicontainer.RegistryAuthenticationData, time.Duration) {
931+
assertPauseContainerIsRunning() // Ensure that pause container is already RUNNING
932+
}).
933+
Return(dockerapi.DockerContainerMetadata{}).
934+
Times(2)
898935
imageManager.EXPECT().RecordContainerReference(gomock.Any()).Return(nil).Times(2)
899936
imageManager.EXPECT().GetImageStateFromImageName(gomock.Any()).Return(nil, false).Times(2)
900937
dockerClient.EXPECT().APIVersion().Return(defaultDockerClientAPIVersion, nil).Times(2)

agent/engine/docker_task_engine_windows_test.go

+39-3
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,15 @@ func TestTaskWithSteadyStateResourcesProvisioned(t *testing.T) {
462462
waitForStopEvents(t, taskEngine.StateChangeEvents(), true, false)
463463
}
464464

465+
// Tests a happy case scenario for an AWSVPC task.
466+
//
467+
// This test also verifies that
468+
// any DockerClient calls that interact with an image repository (PullContainerManifest
469+
// and PullContainer, currently) happen after the pause container has reached
470+
// ContainerResourcesProvisioned state.
471+
//
472+
// If you are updating this test then make sure that you call assertPauseContainerIsRunning()
473+
// in any dockerClient expected calls that are supposed to interact with an image repository.
465474
func TestPauseContainerHappyPath(t *testing.T) {
466475
ctx, cancel := context.WithCancel(context.TODO())
467476
defer cancel()
@@ -509,8 +518,13 @@ func TestPauseContainerHappyPath(t *testing.T) {
509518
assert.True(t, ok)
510519
assert.Equal(t, apitask.NetworkPauseContainerName, name)
511520
}).Return(dockerapi.DockerContainerMetadata{DockerID: "pauseContainerID"}),
512-
dockerClient.EXPECT().StartContainer(gomock.Any(), pauseContainerID, defaultConfig.ContainerStartTimeout).Return(
513-
dockerapi.DockerContainerMetadata{DockerID: "pauseContainerID"}),
521+
dockerClient.EXPECT().
522+
StartContainer(gomock.Any(), pauseContainerID, defaultConfig.ContainerStartTimeout).
523+
Do(func(ctx interface{}, id string, timeout time.Duration) {
524+
// Simulate some startup time
525+
time.Sleep(5 * time.Millisecond)
526+
}).
527+
Return(dockerapi.DockerContainerMetadata{DockerID: "pauseContainerID"}),
514528
dockerClient.EXPECT().InspectContainer(gomock.Any(), gomock.Any(), gomock.Any()).Return(
515529
&types.ContainerJSON{
516530
ContainerJSONBase: &types.ContainerJSONBase{
@@ -531,6 +545,19 @@ func TestPauseContainerHappyPath(t *testing.T) {
531545
}, nil),
532546
)
533547

548+
// A function to assert that the network pause container in the task is in
549+
// ContainerResourcesProvisioned state. This will be used by dockerClient mock later.
550+
assertPauseContainerIsRunning := func() {
551+
assert.Len(t, sleepTask.Containers, 3, "expected pause container to be populated")
552+
pauseContainer := sleepTask.Containers[2]
553+
assert.Equal(t, apitask.NetworkPauseContainerName, pauseContainer.Name)
554+
assert.Equal(t, apicontainer.ContainerCNIPause, pauseContainer.Type)
555+
assert.Equal(t,
556+
apicontainerstatus.ContainerResourcesProvisioned,
557+
pauseContainer.GetKnownStatus(),
558+
"expected pause container to be running before image repository is called")
559+
}
560+
534561
// For the other container
535562
imageManager.EXPECT().AddAllImageStates(gomock.Any()).AnyTimes()
536563
manifestPullClient := mock_dockerapi.NewMockDockerClient(ctrl)
@@ -541,8 +568,17 @@ func TestPauseContainerHappyPath(t *testing.T) {
541568
manifestPullClient.EXPECT().
542569
PullImageManifest(gomock.Any(), gomock.Any(), gomock.Any()).
543570
Times(2).
571+
Do(func(context.Context, string, *apicontainer.RegistryAuthenticationData) {
572+
assertPauseContainerIsRunning() // Ensure that pause container is already RUNNING
573+
}).
544574
Return(registry.DistributionInspect{}, nil)
545-
dockerClient.EXPECT().PullImage(gomock.Any(), gomock.Any(), nil, gomock.Any()).Return(dockerapi.DockerContainerMetadata{}).Times(2)
575+
dockerClient.EXPECT().
576+
PullImage(gomock.Any(), gomock.Any(), nil, gomock.Any()).
577+
Do(func(context.Context, string, *apicontainer.RegistryAuthenticationData, time.Duration) {
578+
assertPauseContainerIsRunning() // Ensure that pause container is already RUNNING
579+
}).
580+
Return(dockerapi.DockerContainerMetadata{}).
581+
Times(2)
546582
imageManager.EXPECT().RecordContainerReference(gomock.Any()).Return(nil).Times(2)
547583
imageManager.EXPECT().GetImageStateFromImageName(gomock.Any()).Return(nil, false).Times(2)
548584
dockerClient.EXPECT().APIVersion().Return(defaultDockerClientAPIVersion, nil).Times(2)

0 commit comments

Comments
 (0)