From 70d53be76bffba7d1e01005260d59a7857d8dbe7 Mon Sep 17 00:00:00 2001 From: Anuj Singh Date: Tue, 26 Sep 2023 09:17:32 -0700 Subject: [PATCH] add container metadata to introspection response --- agent/handlers/v1/response.go | 16 +++ agent/handlers/v1/response_test.go | 155 +++++++++++++---------------- 2 files changed, 87 insertions(+), 84 deletions(-) diff --git a/agent/handlers/v1/response.go b/agent/handlers/v1/response.go index 57d5cb278c7..6ae9dfd9be3 100644 --- a/agent/handlers/v1/response.go +++ b/agent/handlers/v1/response.go @@ -14,6 +14,8 @@ package v1 import ( + "time" + apicontainer "github.com/aws/amazon-ecs-agent/agent/api/container" apitask "github.com/aws/amazon-ecs-agent/agent/api/task" "github.com/aws/amazon-ecs-agent/agent/engine/dockerstate" @@ -49,6 +51,10 @@ type ContainerResponse struct { DockerID string `json:"DockerId"` DockerName string `json:"DockerName"` Name string `json:"Name"` + Image string `json:"Image"` + ImageID string `json:"ImageID"` + CreatedAt *time.Time `json:"CreatedAt,omitempty"` + StartedAt *time.Time `json:"StartedAt,omitempty"` Ports []tmdsresponse.PortResponse `json:"Ports,omitempty"` Networks []tmdsresponse.Network `json:"Networks,omitempty"` Volumes []tmdsresponse.VolumeResponse `json:"Volumes,omitempty"` @@ -89,6 +95,8 @@ func NewContainerResponse(dockerContainer *apicontainer.DockerContainer, eni *ni container := dockerContainer.Container resp := ContainerResponse{ Name: container.Name, + Image: container.Image, + ImageID: container.ImageID, DockerID: dockerContainer.DockerID, DockerName: dockerContainer.DockerName, } @@ -105,6 +113,14 @@ func NewContainerResponse(dockerContainer *apicontainer.DockerContainer, eni *ni }, } } + if createdAt := container.GetCreatedAt(); !createdAt.IsZero() { + createdAt = createdAt.UTC() + resp.CreatedAt = &createdAt + } + if startedAt := container.GetStartedAt(); !startedAt.IsZero() { + startedAt = startedAt.UTC() + resp.StartedAt = &startedAt + } return resp } diff --git a/agent/handlers/v1/response_test.go b/agent/handlers/v1/response_test.go index 4a40fa242e9..9a1c3e56541 100644 --- a/agent/handlers/v1/response_test.go +++ b/agent/handlers/v1/response_test.go @@ -19,11 +19,13 @@ package v1 import ( "encoding/json" "testing" + "time" apicontainer "github.com/aws/amazon-ecs-agent/agent/api/container" apitask "github.com/aws/amazon-ecs-agent/agent/api/task" apitaskstatus "github.com/aws/amazon-ecs-agent/ecs-agent/api/task/status" ni "github.com/aws/amazon-ecs-agent/ecs-agent/netlib/model/networkinterface" + "github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/response" "github.com/docker/docker/api/types" "github.com/stretchr/testify/assert" @@ -33,53 +35,68 @@ const ( taskARN = "t1" family = "sleep" version = "1" + status = "RUNNING" containerID = "cid" containerName = "sleepy" + imageName = "busybox" + imageID = "busyboxID" + networkMode = "awsvpc" eniIPv4Address = "10.0.0.2" + port = 80 + protocol = "tcp" volName = "volume1" volSource = "/var/lib/volume1" volDestination = "/volume" ) -func TestTaskResponse(t *testing.T) { - expectedTaskResponseMap := map[string]interface{}{ - "Arn": "t1", - "DesiredStatus": "RUNNING", - "KnownStatus": "RUNNING", - "Family": "sleep", - "Version": "1", - "Containers": []interface{}{ - map[string]interface{}{ - "DockerId": "cid", - "DockerName": "sleepy", - "Name": "sleepy", - "Ports": []interface{}{ - map[string]interface{}{ - // The number should be float here, because when we unmarshal - // something and we don't specify the number type, it will be - // set to float. - "ContainerPort": float64(80), - "Protocol": "tcp", - "HostPort": float64(80), - }, - }, - "Networks": []interface{}{ - map[string]interface{}{ - "NetworkMode": "awsvpc", - "IPv4Addresses": []interface{}{"10.0.0.2"}, - }, - }, - "Volumes": []interface{}{ - map[string]interface{}{ - "DockerName": volName, - "Source": volSource, - "Destination": volDestination, - }, - }, - }, +var ( + containerTime = time.Now() + containerTimeUTC = containerTime.UTC() + expectedPortResponse = response.PortResponse{ + ContainerPort: port, + Protocol: protocol, + HostPort: port, + } + expectedNetworkResponse = response.Network{ + NetworkMode: networkMode, + IPv4Addresses: []string{eniIPv4Address}, + } + expectedVolumeResponse = response.VolumeResponse{ + DockerName: volName, + Source: volSource, + Destination: volDestination, + } + expectedContainerResponse = ContainerResponse{ + DockerID: containerID, + DockerName: containerName, + Name: containerName, + Image: imageName, + ImageID: imageID, + CreatedAt: &containerTimeUTC, + StartedAt: &containerTimeUTC, + Ports: []response.PortResponse{ + expectedPortResponse, + }, + Networks: []response.Network{ + expectedNetworkResponse, + }, + Volumes: []response.VolumeResponse{ + expectedVolumeResponse, }, } + expectedTaskResponse = TaskResponse{ + Arn: taskARN, + DesiredStatus: status, + KnownStatus: status, + Family: family, + Version: version, + Containers: []ContainerResponse{ + expectedContainerResponse, + }, + } +) +func TestTaskResponse(t *testing.T) { task := &apitask.Task{ Arn: taskARN, Family: family, @@ -98,7 +115,9 @@ func TestTaskResponse(t *testing.T) { } container := &apicontainer.Container{ - Name: containerName, + Name: containerName, + Image: imageName, + ImageID: imageID, Ports: []apicontainer.PortBinding{ { ContainerPort: 80, @@ -114,6 +133,9 @@ func TestTaskResponse(t *testing.T) { }, } + container.SetCreatedAt(containerTime) + container.SetStartedAt(containerTime) + containerNameToDockerContainer := map[string]*apicontainer.DockerContainer{ taskARN: { DockerID: containerID, @@ -124,45 +146,17 @@ func TestTaskResponse(t *testing.T) { taskResponse := NewTaskResponse(task, containerNameToDockerContainer) - taskResponseJSON, err := json.Marshal(taskResponse) + _, err := json.Marshal(taskResponse) assert.NoError(t, err) - taskResponseMap := make(map[string]interface{}) - - json.Unmarshal(taskResponseJSON, &taskResponseMap) - - assert.Equal(t, expectedTaskResponseMap, taskResponseMap) + assert.Equal(t, expectedTaskResponse, *taskResponse) } func TestContainerResponse(t *testing.T) { - expectedContainerResponseMap := map[string]interface{}{ - "DockerId": "cid", - "DockerName": "sleepy", - "Name": "sleepy", - "Ports": []interface{}{ - map[string]interface{}{ - "ContainerPort": float64(80), - "Protocol": "tcp", - "HostPort": float64(80), - }, - }, - "Networks": []interface{}{ - map[string]interface{}{ - "NetworkMode": "awsvpc", - "IPv4Addresses": []interface{}{"10.0.0.2"}, - }, - }, - "Volumes": []interface{}{ - map[string]interface{}{ - "DockerName": volName, - "Source": volSource, - "Destination": volDestination, - }, - }, - } - container := &apicontainer.Container{ - Name: containerName, + Name: containerName, + Image: imageName, + ImageID: imageID, Ports: []apicontainer.PortBinding{ { ContainerPort: 80, @@ -178,6 +172,9 @@ func TestContainerResponse(t *testing.T) { }, } + container.SetCreatedAt(containerTime) + container.SetStartedAt(containerTime) + dockerContainer := &apicontainer.DockerContainer{ DockerID: containerID, DockerName: containerName, @@ -194,14 +191,10 @@ func TestContainerResponse(t *testing.T) { containerResponse := NewContainerResponse(dockerContainer, eni) - containerResponseJSON, err := json.Marshal(containerResponse) + _, err := json.Marshal(containerResponse) assert.NoError(t, err) - containerResponseMap := make(map[string]interface{}) - - json.Unmarshal(containerResponseJSON, &containerResponseMap) - - assert.Equal(t, expectedContainerResponseMap, containerResponseMap) + assert.Equal(t, expectedContainerResponse, containerResponse) } func TestPortBindingsResponse(t *testing.T) { @@ -221,10 +214,7 @@ func TestPortBindingsResponse(t *testing.T) { } PortBindingsResponse := NewPortBindingsResponse(dockerContainer, nil) - - assert.Equal(t, uint16(80), PortBindingsResponse[0].ContainerPort) - assert.Equal(t, uint16(80), PortBindingsResponse[0].HostPort) - assert.Equal(t, "tcp", PortBindingsResponse[0].Protocol) + assert.Equal(t, expectedPortResponse, PortBindingsResponse[0]) } func TestVolumesResponse(t *testing.T) { @@ -244,8 +234,5 @@ func TestVolumesResponse(t *testing.T) { } VolumesResponse := NewVolumesResponse(dockerContainer) - - assert.Equal(t, volName, VolumesResponse[0].DockerName) - assert.Equal(t, volSource, VolumesResponse[0].Source) - assert.Equal(t, volDestination, VolumesResponse[0].Destination) + assert.Equal(t, expectedVolumeResponse, VolumesResponse[0]) }