Skip to content

Commit

Permalink
Merge pull request #1271 from adnxn/eni-metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
adnxn committed Mar 2, 2018
2 parents 0ac31c4 + 64a0760 commit 0fb8ab5
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 15 deletions.
20 changes: 18 additions & 2 deletions agent/api/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ type Container struct {
// and `SetKnownExitCode`.
KnownExitCodeUnsafe *int `json:"KnownExitCode"`

// KnownPortBindings is an array of port bindings for the container.
KnownPortBindings []PortBinding
// KnownPortBindingsUnsafe is an array of port bindings for the container.
KnownPortBindingsUnsafe []PortBinding `json:"KnownPortBindings"`

// SteadyStateStatusUnsafe specifies the steady state status for the container
// If uninitialized, it's assumed to be set to 'ContainerRunning'. Even though
Expand Down Expand Up @@ -493,6 +493,22 @@ func (c *Container) GetLabels() map[string]string {
return c.labels
}

// SetKnownPortBindings sets the ports for a container
func (c *Container) SetKnownPortBindings(ports []PortBinding) {
c.lock.Lock()
defer c.lock.Unlock()

c.KnownPortBindingsUnsafe = ports
}

// GetKnownPortBindings gets the ports for a container
func (c *Container) GetKnownPortBindings() []PortBinding {
c.lock.RLock()
defer c.lock.RUnlock()

return c.KnownPortBindingsUnsafe
}

// HealthStatusShouldBeReported returns true if the health check is defined in
// the task definition
func (c *Container) HealthStatusShouldBeReported() bool {
Expand Down
2 changes: 1 addition & 1 deletion agent/api/statechange.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func NewContainerStateChangeEvent(task *Task, cont *Container, reason string) (C
ContainerName: cont.Name,
Status: contKnownStatus.BackendStatus(cont.GetSteadyStateStatus()),
ExitCode: cont.GetKnownExitCode(),
PortBindings: cont.KnownPortBindings,
PortBindings: cont.GetKnownPortBindings(),
Reason: reason,
Container: cont,
}
Expand Down
2 changes: 1 addition & 1 deletion agent/api/testutils/container_equal.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func ContainersEqual(lhs, rhs *api.Container) bool {
if !utils.SlicesDeepEqual(lhs.Ports, rhs.Ports) {
return false
}
if !utils.SlicesDeepEqual(lhs.KnownPortBindings, rhs.KnownPortBindings) {
if !utils.SlicesDeepEqual(lhs.KnownPortBindingsUnsafe, rhs.KnownPortBindingsUnsafe) {
return false
}
if lhs.Essential != rhs.Essential {
Expand Down
4 changes: 2 additions & 2 deletions agent/engine/docker_task_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,8 @@ func updateContainerMetadata(metadata *DockerContainerMetadata, container *api.C
}

// Set port mappings
if len(metadata.PortBindings) != 0 && len(container.KnownPortBindings) == 0 {
container.KnownPortBindings = metadata.PortBindings
if len(metadata.PortBindings) != 0 && len(container.GetKnownPortBindings()) == 0 {
container.SetKnownPortBindings(metadata.PortBindings)
}
// update the container health information
if container.HealthStatusShouldBeReported() {
Expand Down
2 changes: 1 addition & 1 deletion agent/engine/docker_task_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1858,7 +1858,7 @@ func TestContainerMetadataUpdatedOnRestart(t *testing.T) {
assert.Equal(t, "tmp", task.Volumes[0].Volume.SourcePath())
}
if tc.stage == "started" {
assert.Equal(t, uint16(80), dockerContainer.Container.KnownPortBindings[0].ContainerPort)
assert.Equal(t, uint16(80), dockerContainer.Container.KnownPortBindingsUnsafe[0].ContainerPort)
}
if tc.stage == "finished" {
assert.False(t, task.GetExecutionStoppedAt().IsZero())
Expand Down
8 changes: 4 additions & 4 deletions agent/engine/dockerstate/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const (
"AppliedStatus": "NONE",
"ApplyingError": null,
"SentStatus": "NONE",
"KnownPortBindings": []
"KnownPortBindingsUnsafe": []
},
{
"Name": "~internal~ecs~pause",
Expand Down Expand Up @@ -110,7 +110,7 @@ const (
"AppliedStatus": "NONE",
"ApplyingError": null,
"SentStatus": "NONE",
"KnownPortBindings": [],
"KnownPortBindingsUnsafe": [],
"SteadyStateStatus": "RESOURCES_PROVISIONED"
}
],
Expand Down Expand Up @@ -171,7 +171,7 @@ const (
"AppliedStatus": "NONE",
"ApplyingError": null,
"SentStatus": "NONE",
"KnownPortBindings": [],
"KnownPortBindingsUnsafe": [],
"SteadyStateStatus": "RESOURCES_PROVISIONED"
}
},
Expand Down Expand Up @@ -224,7 +224,7 @@ const (
"AppliedStatus": "NONE",
"ApplyingError": null,
"SentStatus": "NONE",
"KnownPortBindings": []
"KnownPortBindingsUnsafe": []
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion agent/engine/testdata/test_tasks/sleep5.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"ApplyingError":null,
"SentStatus":"NONE",
"KnownExitCode":null,
"KnownPortBindings":null,
"KnownPortBindingsUnsafe":null,
"StatusLock":{}
}
],
Expand Down
2 changes: 1 addition & 1 deletion agent/engine/testdata/test_tasks/sleep5TaskCgroup.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"ApplyingError":null,
"SentStatus":"NONE",
"KnownExitCode":null,
"KnownPortBindings":null,
"KnownPortBindingsUnsafe":null,
"StatusLock":{}
}
],
Expand Down
7 changes: 7 additions & 0 deletions agent/handlers/types/v1/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@

package v1

import (
"github.com/aws/amazon-ecs-agent/agent/containermetadata"
"github.com/aws/amazon-ecs-agent/agent/handlers/types/v2"
)

// MetadataResponse is the schema for the metadata response JSON object
type MetadataResponse struct {
Cluster string
Expand Down Expand Up @@ -40,4 +45,6 @@ type ContainerResponse struct {
DockerId string
DockerName string
Name string
Ports []v2.PortResponse `json:",omitempty"`
Networks []containermetadata.Network `json:",omitempty"`
}
59 changes: 57 additions & 2 deletions agent/handlers/v1_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import (

"github.com/aws/amazon-ecs-agent/agent/api"
"github.com/aws/amazon-ecs-agent/agent/config"
"github.com/aws/amazon-ecs-agent/agent/containermetadata"
"github.com/aws/amazon-ecs-agent/agent/engine"
"github.com/aws/amazon-ecs-agent/agent/engine/dockerstate"
"github.com/aws/amazon-ecs-agent/agent/handlers/types/v1"
"github.com/aws/amazon-ecs-agent/agent/handlers/types/v2"
"github.com/aws/amazon-ecs-agent/agent/logger"
"github.com/aws/amazon-ecs-agent/agent/utils"
"github.com/aws/amazon-ecs-agent/agent/version"
Expand All @@ -37,6 +39,7 @@ const (
dockerIdQueryField = "dockerid"
taskArnQueryField = "taskarn"
dockerShortIdLen = 12
networkModeAwsvpc = "awsvpc"
)

type rootResponse struct {
Expand Down Expand Up @@ -66,11 +69,12 @@ func metadataV1RequestHandlerMaker(containerInstanceArn *string, cfg *config.Con

func newTaskResponse(task *api.Task, containerMap map[string]*api.DockerContainer) *v1.TaskResponse {
containers := []v1.ContainerResponse{}
for containerName, container := range containerMap {
for _, container := range containerMap {
if container.Container.IsInternal() {
continue
}
containers = append(containers, v1.ContainerResponse{DockerId: container.DockerID, DockerName: container.DockerName, Name: containerName})
containerResponse := newContainerResponse(container, task.GetTaskENI())
containers = append(containers, containerResponse)
}

knownStatus := task.GetKnownStatus()
Expand All @@ -92,6 +96,57 @@ func newTaskResponse(task *api.Task, containerMap map[string]*api.DockerContaine
}
}

func newContainerResponse(dockerContainer *api.DockerContainer, eni *api.ENI) v1.ContainerResponse {
container := dockerContainer.Container
resp := v1.ContainerResponse{
Name: container.Name,
DockerId: dockerContainer.DockerID,
DockerName: dockerContainer.DockerName,
}

resp.Ports = newPortBindingsResponse(dockerContainer, eni)

if eni != nil {
resp.Networks = []containermetadata.Network{
{
NetworkMode: networkModeAwsvpc,
IPv4Addresses: eni.GetIPV4Addresses(),
IPv6Addresses: eni.GetIPV6Addresses(),
},
}
}
return resp
}

func newPortBindingsResponse(dockerContainer *api.DockerContainer, eni *api.ENI) []v2.PortResponse {
container := dockerContainer.Container
resp := []v2.PortResponse{}

bindings := container.GetKnownPortBindings()

// if KnownPortBindings list is empty, then we use the port mapping
// information that was passed down from ACS.
if len(bindings) == 0 {
bindings = container.Ports
}

for _, binding := range bindings {
port := v2.PortResponse{
ContainerPort: binding.ContainerPort,
Protocol: binding.Protocol.String(),
}

if eni == nil {
port.HostPort = binding.HostPort
} else {
port.HostPort = port.ContainerPort
}

resp = append(resp, port)
}
return resp
}

func newTasksResponse(state dockerstate.TaskEngineState) *v1.TasksResponse {
allTasks := state.AllTasks()
taskResponses := make([]*v1.TaskResponse, len(allTasks))
Expand Down
107 changes: 107 additions & 0 deletions agent/handlers/v1_handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (

const testContainerInstanceArn = "test_container_instance_arn"
const testClusterArn = "test_cluster_arn"
const eniIPV4Address = "10.0.0.2"

func TestMetadataHandler(t *testing.T) {
metadataHandler := metadataV1RequestHandlerMaker(utils.Strptr(testContainerInstanceArn), &config.Config{Cluster: testClusterArn})
Expand Down Expand Up @@ -125,6 +126,55 @@ func TestGetTaskByTaskArn(t *testing.T) {
taskDiffHelper(t, []*api.Task{testTasks[0]}, v1.TasksResponse{Tasks: []*v1.TaskResponse{&taskResponse}})
}

func TestGetAWSVPCTaskByTaskArn(t *testing.T) {
recorder := performMockRequest(t, "/v1/tasks?taskarn=awsvpcTask")

var taskResponse v1.TaskResponse
err := json.Unmarshal(recorder.Body.Bytes(), &taskResponse)
if err != nil {
t.Fatal(err)
}

resp := v1.TasksResponse{Tasks: []*v1.TaskResponse{&taskResponse}}

assert.Equal(t, eniIPV4Address, resp.Tasks[0].Containers[0].Networks[0].IPv4Addresses[0])
taskDiffHelper(t, []*api.Task{testTasks[3]}, resp)
}

func TestGetHostNeworkingTaskByTaskArn(t *testing.T) {
recorder := performMockRequest(t, "/v1/tasks?taskarn=hostModeNetworkingTask")

var taskResponse v1.TaskResponse
err := json.Unmarshal(recorder.Body.Bytes(), &taskResponse)
if err != nil {
t.Fatal(err)
}

resp := v1.TasksResponse{Tasks: []*v1.TaskResponse{&taskResponse}}

assert.Equal(t, uint16(80), resp.Tasks[0].Containers[0].Ports[0].ContainerPort)
assert.Equal(t, "tcp", resp.Tasks[0].Containers[0].Ports[0].Protocol)

taskDiffHelper(t, []*api.Task{testTasks[4]}, resp)
}

func TestGetBridgeNeworkingTaskByTaskArn(t *testing.T) {
recorder := performMockRequest(t, "/v1/tasks?taskarn=bridgeModeNetworkingTask")

var taskResponse v1.TaskResponse
err := json.Unmarshal(recorder.Body.Bytes(), &taskResponse)
if err != nil {
t.Fatal(err)
}

resp := v1.TasksResponse{Tasks: []*v1.TaskResponse{&taskResponse}}

assert.Equal(t, uint16(80), resp.Tasks[0].Containers[0].Ports[0].ContainerPort)
assert.Equal(t, "tcp", resp.Tasks[0].Containers[0].Ports[0].Protocol)

taskDiffHelper(t, []*api.Task{testTasks[5]}, resp)
}

func TestGetTaskByTaskArnNotFound(t *testing.T) {
recorder := performMockRequest(t, "/v1/tasks?taskarn=doesnotexist")

Expand Down Expand Up @@ -303,6 +353,63 @@ var testTasks = []*api.Task{
},
},
},
{
Arn: "awsvpcTask",
DesiredStatusUnsafe: api.TaskRunning,
KnownStatusUnsafe: api.TaskRunning,
Family: "test",
Version: "1",
Containers: []*api.Container{
{
Name: "awsvpc",
},
},
ENI: &api.ENI{
IPV4Addresses: []*api.ENIIPV4Address{
{
Address: eniIPV4Address,
},
},
},
},
{
Arn: "hostModeNetworkingTask",
DesiredStatusUnsafe: api.TaskRunning,
KnownStatusUnsafe: api.TaskRunning,
Family: "test",
Version: "1",
Containers: []*api.Container{
{
Name: "awsvpc",
Ports: []api.PortBinding{
{
ContainerPort: 80,
HostPort: 80,
Protocol: api.TransportProtocolTCP,
},
},
},
},
},
{
Arn: "bridgeModeNetworkingTask",
DesiredStatusUnsafe: api.TaskRunning,
KnownStatusUnsafe: api.TaskRunning,
Family: "test",
Version: "1",
Containers: []*api.Container{
{
Name: "awsvpc",
KnownPortBindingsUnsafe: []api.PortBinding{
{
ContainerPort: 80,
HostPort: 80,
Protocol: api.TransportProtocolTCP,
},
},
},
},
},
}

func stateSetupHelper(state dockerstate.TaskEngineState, tasks []*api.Task) {
Expand Down

0 comments on commit 0fb8ab5

Please sign in to comment.