Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

set containers DockerId per task #2138

Merged
merged 1 commit into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions agent/api/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ type HealthStatus struct {
type Container struct {
// Name is the name of the container specified in the task definition
Name string
// RuntimeID is the docker id of the container
RuntimeID string
cyastella marked this conversation as resolved.
Show resolved Hide resolved
// DependsOn is the field which specifies the ordering for container startup and shutdown.
DependsOn []DependsOn `json:"dependsOn,omitempty"`
// V3EndpointID is a container identifier used to construct v3 metadata endpoint; it's unique among
Expand Down Expand Up @@ -577,6 +579,22 @@ func (c *Container) SetLabels(labels map[string]string) {
c.labels = labels
}

// SetRuntimeID sets the DockerID for a container
func (c *Container) SetRuntimeID(RuntimeID string) {
c.lock.Lock()
defer c.lock.Unlock()

c.RuntimeID = RuntimeID
}

// GetRuntimeID gets the DockerID for a container
func (c *Container) GetRuntimeID() string {
c.lock.RLock()
defer c.lock.RUnlock()

return c.RuntimeID
}

// GetLabels gets the labels for a container
func (c *Container) GetLabels() map[string]string {
c.lock.RLock()
Expand Down
7 changes: 7 additions & 0 deletions agent/api/container/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,10 @@ func TestPerContainerTimeouts(t *testing.T) {
assert.Equal(t, container.GetStartTimeout(), expectedTimeout)
assert.Equal(t, container.GetStopTimeout(), expectedTimeout)
}

func TestSetRuntimeIDInContainer(t *testing.T) {
container := Container{}
container.SetRuntimeID("asdfghjkl1234")
assert.Equal(t, "asdfghjkl1234", container.RuntimeID)
assert.Equal(t, "asdfghjkl1234", container.GetRuntimeID())
}
35 changes: 22 additions & 13 deletions agent/api/ecsclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (

const (
ecsMaxReasonLength = 255
ecsMaxRuntimeIDLength = 255
cyastella marked this conversation as resolved.
Show resolved Hide resolved
pollEndpointCacheSize = 1
pollEndpointCacheTTL = 20 * time.Minute
roundtripTimeout = 5 * time.Second
Expand Down Expand Up @@ -386,18 +387,26 @@ func (client *APIECSClient) SubmitTaskStateChange(change api.TaskStateChange) er
return nil
}

func trimString(inputString string, maxLen int) string {
if len(inputString) > maxLen {
trimmed := inputString[0:maxLen]
return trimmed
} else {
return inputString
}
}

func (client *APIECSClient) buildContainerStateChangePayload(change api.ContainerStateChange) *ecs.ContainerStateChange {
statechange := &ecs.ContainerStateChange{
ContainerName: aws.String(change.ContainerName),
}

if change.RuntimeID != "" {
trimmedRuntimeID := trimString(change.RuntimeID, ecsMaxRuntimeIDLength)
statechange.RuntimeID = aws.String(trimmedRuntimeID)
}
if change.Reason != "" {
if len(change.Reason) > ecsMaxReasonLength {
trimmed := change.Reason[0:ecsMaxReasonLength]
statechange.Reason = aws.String(trimmed)
} else {
statechange.Reason = aws.String(change.Reason)
}
trimmedReason := trimString(change.Reason, ecsMaxReasonLength)
statechange.Reason = aws.String(trimmedReason)
}
status := change.Status

Expand Down Expand Up @@ -438,13 +447,13 @@ func (client *APIECSClient) SubmitContainerStateChange(change api.ContainerState
Task: &change.TaskArn,
ContainerName: &change.ContainerName,
}
if change.RuntimeID != "" {
trimmedRuntimeID := trimString(change.RuntimeID, ecsMaxRuntimeIDLength)
req.RuntimeID = &trimmedRuntimeID
}
if change.Reason != "" {
if len(change.Reason) > ecsMaxReasonLength {
trimmed := change.Reason[0:ecsMaxReasonLength]
req.Reason = &trimmed
} else {
req.Reason = &change.Reason
}
trimmedReason := trimString(change.Reason, ecsMaxReasonLength)
req.Reason = &trimmedReason
}
stat := change.Status.String()
if stat == "DEAD" {
Expand Down
6 changes: 6 additions & 0 deletions agent/api/ecsclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ func TestSubmitContainerStateChange(t *testing.T) {
Cluster: strptr(configuredCluster),
Task: strptr("arn"),
ContainerName: strptr("cont"),
RuntimeID: strptr("runtime id"),
Status: strptr("RUNNING"),
NetworkBindings: []*ecs.NetworkBinding{
{
Expand All @@ -185,6 +186,7 @@ func TestSubmitContainerStateChange(t *testing.T) {
err := client.SubmitContainerStateChange(api.ContainerStateChange{
TaskArn: "arn",
ContainerName: "cont",
RuntimeID: "runtime id",
Status: apicontainerstatus.ContainerRunning,
PortBindings: []apicontainer.PortBinding{
{
Expand Down Expand Up @@ -217,6 +219,7 @@ func TestSubmitContainerStateChangeFull(t *testing.T) {
Cluster: strptr(configuredCluster),
Task: strptr("arn"),
ContainerName: strptr("cont"),
RuntimeID: strptr("runtime id"),
Status: strptr("STOPPED"),
ExitCode: int64ptr(&exitCode),
Reason: strptr(reason),
Expand All @@ -233,6 +236,7 @@ func TestSubmitContainerStateChangeFull(t *testing.T) {
err := client.SubmitContainerStateChange(api.ContainerStateChange{
TaskArn: "arn",
ContainerName: "cont",
RuntimeID: "runtime id",
Status: apicontainerstatus.ContainerStopped,
ExitCode: &exitCode,
Reason: reason,
Expand Down Expand Up @@ -928,6 +932,7 @@ func TestSubmitContainerStateChangeWhileTaskInPending(t *testing.T) {
{
TaskArn: "arn",
ContainerName: "container",
RuntimeID: "runtimeid",
Status: apicontainerstatus.ContainerRunning,
},
},
Expand All @@ -946,6 +951,7 @@ func TestSubmitContainerStateChangeWhileTaskInPending(t *testing.T) {
Containers: []*ecs.ContainerStateChange{
{
ContainerName: strptr("container"),
RuntimeID: strptr("runtimeid"),
Status: strptr("RUNNING"),
NetworkBindings: []*ecs.NetworkBinding{},
},
Expand Down
3 changes: 3 additions & 0 deletions agent/api/statechange.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import (
type ContainerStateChange struct {
// TaskArn is the unique identifier for the task
TaskArn string
// RuntimeID is the dockerID of the container
RuntimeID string
// ContainerName is the name of the container
ContainerName string
// Status is the status to send
Expand Down Expand Up @@ -138,6 +140,7 @@ func NewContainerStateChangeEvent(task *apitask.Task, cont *apicontainer.Contain
event = ContainerStateChange{
TaskArn: task.Arn,
ContainerName: cont.Name,
RuntimeID: cont.GetRuntimeID(),
Status: contKnownStatus.BackendStatus(cont.GetSteadyStateStatus()),
ExitCode: cont.GetKnownExitCode(),
PortBindings: cont.GetKnownPortBindings(),
Expand Down
22 changes: 22 additions & 0 deletions agent/api/statechange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"testing"
"time"

apicontainer "github.com/aws/amazon-ecs-agent/agent/api/container"
apicontainerstatus "github.com/aws/amazon-ecs-agent/agent/api/container/status"
apitask "github.com/aws/amazon-ecs-agent/agent/api/task"
apitaskstatus "github.com/aws/amazon-ecs-agent/agent/api/task/status"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -83,3 +85,23 @@ func TestSetTaskTimestamps(t *testing.T) {
assert.Equal(t, t2.UTC().String(), change.PullStoppedAt.String())
assert.Equal(t, t3.UTC().String(), change.ExecutionStoppedAt.String())
}

func TestSetContainerRuntimeID(t *testing.T) {
cyastella marked this conversation as resolved.
Show resolved Hide resolved
task := &apitask.Task{}
steadyStateStatus := apicontainerstatus.ContainerRunning
Containers := []*apicontainer.Container{
{
RuntimeID: "222",
KnownStatusUnsafe: apicontainerstatus.ContainerRunning,
SentStatusUnsafe: apicontainerstatus.ContainerStatusNone,
Type: apicontainer.ContainerNormal,
SteadyStateStatusUnsafe: &steadyStateStatus,
},
}

task.Containers = Containers
resp, ok := NewContainerStateChangeEvent(task, task.Containers[0], "")

assert.NoError(t, ok, "error create newContainerStateChangeEvent")
assert.Equal(t, "222", resp.RuntimeID)
}
3 changes: 3 additions & 0 deletions agent/ecs_client/model/api/api-2.json
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@
"containerArn":{"shape":"String"},
"taskArn":{"shape":"String"},
"name":{"shape":"String"},
"runtimeId":{"shape": "String"},
"lastStatus":{"shape":"String"},
"exitCode":{"shape":"BoxedInteger"},
"reason":{"shape":"String"},
Expand Down Expand Up @@ -856,6 +857,7 @@
"type":"structure",
"members":{
"containerName":{"shape":"String"},
"runtimeId":{"shape": "String"},
"exitCode":{"shape":"BoxedInteger"},
"networkBindings":{"shape":"NetworkBindings"},
"reason":{"shape":"String"},
Expand Down Expand Up @@ -1975,6 +1977,7 @@
"cluster":{"shape":"String"},
"task":{"shape":"String"},
"containerName":{"shape":"String"},
"runtimeId":{"shape": "String"},
"status":{"shape":"String"},
"exitCode":{"shape":"BoxedInteger"},
"reason":{"shape":"String"},
Expand Down
27 changes: 27 additions & 0 deletions agent/ecs_client/model/ecs/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4197,6 +4197,9 @@ type Container struct {
// details about a running or stopped container.
Reason *string `locationName:"reason" type:"string"`

// The RuntimeID of the container
RuntimeID *string `locationName:"runtimeId" type:"string"`

// The ARN of the task.
TaskArn *string `locationName:"taskArn" type:"string"`
}
Expand Down Expand Up @@ -4259,6 +4262,12 @@ func (s *Container) SetReason(v string) *Container {
return s
}

// SetRuntimeID sets the RuntimeID field's value.
func (s *Container) SetRuntimeID(v string) *Container {
s.RuntimeID = &v
return s
}

// SetTaskArn sets the TaskArn field's value.
func (s *Container) SetTaskArn(v string) *Container {
s.TaskArn = &v
Expand Down Expand Up @@ -5355,6 +5364,9 @@ type ContainerStateChange struct {
// The reason for the state change.
Reason *string `locationName:"reason" type:"string"`

// The docker ID of the container
RuntimeID *string `locationName:"runtimeId" type:"string"`

// The status of the container.
Status *string `locationName:"status" type:"string"`
}
Expand Down Expand Up @@ -5393,6 +5405,12 @@ func (s *ContainerStateChange) SetReason(v string) *ContainerStateChange {
return s
}

// SetRuntimeID sets the RuntimeID field's value.
func (s *ContainerStateChange) SetRuntimeID(v string) *ContainerStateChange {
s.RuntimeID = &v
return s
}

// SetStatus sets the Status field's value.
func (s *ContainerStateChange) SetStatus(v string) *ContainerStateChange {
s.Status = &v
Expand Down Expand Up @@ -10654,6 +10672,9 @@ type SubmitContainerStateChangeInput struct {
// The reason for the state change request.
Reason *string `locationName:"reason" type:"string"`

// The Docker ID of the container
RuntimeID *string `locationName:"runtimeId" type:"string"`

// The status of the state change request.
Status *string `locationName:"status" type:"string"`

Expand Down Expand Up @@ -10702,6 +10723,12 @@ func (s *SubmitContainerStateChangeInput) SetReason(v string) *SubmitContainerSt
return s
}

// SetRuntimeID sets the RuntimeID field's value.
func (s *SubmitContainerStateChangeInput) SetRuntimeID(v string) *SubmitContainerStateChangeInput {
s.RuntimeID = &v
return s
}

// SetStatus sets the Status field's value.
func (s *SubmitContainerStateChangeInput) SetStatus(v string) *SubmitContainerStateChangeInput {
s.Status = &v
Expand Down
18 changes: 18 additions & 0 deletions agent/engine/common_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,31 @@ func verifyContainerRunningStateChange(t *testing.T, taskEngine TaskEngine) {
"Expected container to be RUNNING")
}

func verifyContainerRunningStateChangeWithRuntimeID(t *testing.T, taskEngine TaskEngine) {
stateChangeEvents := taskEngine.StateChangeEvents()
event := <-stateChangeEvents
assert.Equal(t, event.(api.ContainerStateChange).Status, apicontainerstatus.ContainerRunning,
"Expected container to be RUNNING")
assert.NotEqual(t, "", event.(api.ContainerStateChange).RuntimeID,
"Expected container runtimeID should not empty")
}

func verifyContainerStoppedStateChange(t *testing.T, taskEngine TaskEngine) {
stateChangeEvents := taskEngine.StateChangeEvents()
event := <-stateChangeEvents
assert.Equal(t, event.(api.ContainerStateChange).Status, apicontainerstatus.ContainerStopped,
"Expected container to be STOPPED")
}

func verifyContainerStoppedStateChangeWithRuntimeID(t *testing.T, taskEngine TaskEngine) {
stateChangeEvents := taskEngine.StateChangeEvents()
event := <-stateChangeEvents
assert.Equal(t, event.(api.ContainerStateChange).Status, apicontainerstatus.ContainerStopped,
"Expected container to be STOPPED")
assert.NotEqual(t, "", event.(api.ContainerStateChange).RuntimeID,
"Expected container runtimeID should not empty")
}

func setup(cfg *config.Config, state dockerstate.TaskEngineState, t *testing.T) (TaskEngine, func(), credentials.Manager) {
ctx, cancel := context.WithCancel(context.TODO())
defer cancel()
Expand Down
1 change: 1 addition & 0 deletions agent/engine/docker_task_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ func (engine *DockerTaskEngine) createContainer(task *apitask.Task, container *a
container.SetLabels(config.Labels)
seelog.Infof("Task engine [%s]: created docker container for task: %s -> %s, took %s",
task.Arn, container.Name, metadata.DockerID, time.Since(createContainerBegin))
container.SetRuntimeID(metadata.DockerID)
return metadata
}

Expand Down
32 changes: 32 additions & 0 deletions agent/engine/engine_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,31 @@ func verifyTaskRunningStateChange(t *testing.T, taskEngine TaskEngine) {
"Expected task to be RUNNING")
}

func verifyTaskRunningStateChangeWithRuntimeID(t *testing.T, taskEngine TaskEngine) {
stateChangeEvents := taskEngine.StateChangeEvents()
event := <-stateChangeEvents
assert.Equal(t, event.(api.TaskStateChange).Status, apitaskstatus.TaskRunning,
"Expected task to be RUNNING")
assert.NotEqualf(t, "", event.(api.TaskStateChange).Task.Containers[0].RuntimeID,
"Expected task with runtimeID per container should not empty when Running")
}

func verifyTaskStoppedStateChange(t *testing.T, taskEngine TaskEngine) {
stateChangeEvents := taskEngine.StateChangeEvents()
event := <-stateChangeEvents
assert.Equal(t, event.(api.TaskStateChange).Status, apitaskstatus.TaskStopped,
"Expected task to be STOPPED")
}

func verifyTaskStoppedStateChangeWithRuntimeID(t *testing.T, taskEngine TaskEngine) {
stateChangeEvents := taskEngine.StateChangeEvents()
event := <-stateChangeEvents
assert.Equal(t, event.(api.TaskStateChange).Status, apitaskstatus.TaskStopped,
"Expected task to be STOPPED")
assert.NotEqual(t, "", event.(api.TaskStateChange).Task.Containers[0].RuntimeID,
"Expected task with runtimeID per container should not empty when stopped")
}

func dialWithRetries(proto string, address string, tries int, timeout time.Duration) (net.Conn, error) {
var err error
var conn net.Conn
Expand Down Expand Up @@ -264,6 +282,20 @@ func TestStartStopWithCredentials(t *testing.T) {
assert.False(t, ok, "Credentials not removed from credentials manager for stopped task")
}

// TestStartStopWithRuntimeID starts and stops a task for which runtimeID has been set.
func TestStartStopWithRuntimeID(t *testing.T) {
taskEngine, done, _ := setupWithDefaultConfig(t)
defer done()

testTask := createTestTask("testTaskWithContainerID")
go taskEngine.AddTask(testTask)

verifyContainerRunningStateChangeWithRuntimeID(t, taskEngine)
verifyTaskRunningStateChangeWithRuntimeID(t, taskEngine)
verifyContainerStoppedStateChangeWithRuntimeID(t, taskEngine)
verifyTaskStoppedStateChangeWithRuntimeID(t, taskEngine)
}

func TestTaskStopWhenPullImageFail(t *testing.T) {
cfg := defaultTestConfigIntegTest()
cfg.ImagePullBehavior = config.ImagePullAlwaysBehavior
Expand Down
3 changes: 2 additions & 1 deletion agent/statemanager/state_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ const (
// a) Add 'attachmentType' field to 'api.ENIAttachment'
// b) Add 'InterfaceAssociationProtocol' field to 'api.ENI'
// c) Add 'InterfaceVlanProperties' field to 'api.ENI'
// 23) Add 'RuntimeID' field to 'apicontainer.Container'

ECSDataVersion = 22
ECSDataVersion = 23

// ecsDataFile specifies the filename in the ECS_DATADIR
ecsDataFile = "ecs_agent_data.json"
Expand Down
Loading