Skip to content

Commit

Permalink
Move v2 metadata models to ecs-agent module (#3705)
Browse files Browse the repository at this point in the history
  • Loading branch information
amogh09 authored May 22, 2023
1 parent 75c5d33 commit 5f9ccdb
Show file tree
Hide file tree
Showing 8 changed files with 312 additions and 99 deletions.
26 changes: 13 additions & 13 deletions agent/handlers/task_server_setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
"github.com/aws/amazon-ecs-agent/agent/ecs_client/model/ecs"
mock_dockerstate "github.com/aws/amazon-ecs-agent/agent/engine/dockerstate/mocks"
task_protection_v1 "github.com/aws/amazon-ecs-agent/agent/handlers/agentapi/taskprotection/v1/handlers"
v2 "github.com/aws/amazon-ecs-agent/agent/handlers/v2"
v3 "github.com/aws/amazon-ecs-agent/agent/handlers/v3"
v4 "github.com/aws/amazon-ecs-agent/agent/handlers/v4"
"github.com/aws/amazon-ecs-agent/agent/stats"
Expand All @@ -51,6 +50,7 @@ import (
tmdsresponse "github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/response"
"github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/utils"
tmdsv1 "github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/v1"
v2 "github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/v2"
"github.com/aws/aws-sdk-go/aws"
"github.com/docker/docker/api/types"
"github.com/golang/mock/gomock"
Expand Down Expand Up @@ -839,21 +839,21 @@ func TestV2TaskWithTagsMetadata(t *testing.T) {
state.EXPECT().TaskByArn(taskARN).Return(task, true),
state.EXPECT().ContainerMapByArn(taskARN).Return(containerNameToDockerContainer, true),
ecsClient.EXPECT().GetResourceTags(containerInstanceArn).Return([]*ecs.Tag{
&ecs.Tag{
{
Key: &contInstTag1Key,
Value: &contInstTag1Val,
},
&ecs.Tag{
{
Key: &contInstTag2Key,
Value: &contInstTag2Val,
},
}, nil),
ecsClient.EXPECT().GetResourceTags(taskARN).Return([]*ecs.Tag{
&ecs.Tag{
{
Key: &taskTag1Key,
Value: &taskTag1Val,
},
&ecs.Tag{
{
Key: &taskTag2Key,
Value: &taskTag2Val,
},
Expand Down Expand Up @@ -1127,21 +1127,21 @@ func TestV3TaskMetadataWithTags(t *testing.T) {
state.EXPECT().TaskByArn(taskARN).Return(task, true),
state.EXPECT().ContainerMapByArn(taskARN).Return(containerNameToDockerContainer, true),
ecsClient.EXPECT().GetResourceTags(containerInstanceArn).Return([]*ecs.Tag{
&ecs.Tag{
{
Key: &contInstTag1Key,
Value: &contInstTag1Val,
},
&ecs.Tag{
{
Key: &contInstTag2Key,
Value: &contInstTag2Val,
},
}, nil),
ecsClient.EXPECT().GetResourceTags(taskARN).Return([]*ecs.Tag{
&ecs.Tag{
{
Key: &taskTag1Key,
Value: &taskTag1Val,
},
&ecs.Tag{
{
Key: &taskTag2Key,
Value: &taskTag2Val,
},
Expand Down Expand Up @@ -1469,21 +1469,21 @@ func TestV4TaskMetadataWithTags(t *testing.T) {
state.EXPECT().TaskByArn(taskARN).Return(task, true).AnyTimes(),
state.EXPECT().ContainerMapByArn(taskARN).Return(containerNameToDockerContainer, true),
ecsClient.EXPECT().GetResourceTags(containerInstanceArn).Return([]*ecs.Tag{
&ecs.Tag{
{
Key: &contInstTag1Key,
Value: &contInstTag1Val,
},
&ecs.Tag{
{
Key: &contInstTag2Key,
Value: &contInstTag2Val,
},
}, nil),
ecsClient.EXPECT().GetResourceTags(taskARN).Return([]*ecs.Tag{
&ecs.Tag{
{
Key: &taskTag1Key,
Value: &taskTag1Val,
},
&ecs.Tag{
{
Key: &taskTag2Key,
Value: &taskTag2Val,
},
Expand Down
107 changes: 29 additions & 78 deletions agent/handlers/v2/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,86 +14,22 @@
package v2

import (
"time"

"github.com/aws/aws-sdk-go/aws/awserr"

"github.com/aws/amazon-ecs-agent/agent/api"
apicontainer "github.com/aws/amazon-ecs-agent/agent/api/container"
apicontainerstatus "github.com/aws/amazon-ecs-agent/agent/api/container/status"
"github.com/aws/amazon-ecs-agent/agent/engine/dockerstate"
v1 "github.com/aws/amazon-ecs-agent/agent/handlers/v1"
apieni "github.com/aws/amazon-ecs-agent/ecs-agent/api/eni"
tmdsresponse "github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/response"
"github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/utils"
tmdsv2 "github.com/aws/amazon-ecs-agent/ecs-agent/tmds/handlers/v2"
"github.com/aws/aws-sdk-go/aws"
"github.com/cihub/seelog"
"github.com/pkg/errors"
)

// TaskResponse defines the schema for the task response JSON object
type TaskResponse struct {
Cluster string `json:"Cluster"`
TaskARN string `json:"TaskARN"`
Family string `json:"Family"`
Revision string `json:"Revision"`
DesiredStatus string `json:"DesiredStatus,omitempty"`
KnownStatus string `json:"KnownStatus"`
Containers []ContainerResponse `json:"Containers,omitempty"`
Limits *LimitsResponse `json:"Limits,omitempty"`
PullStartedAt *time.Time `json:"PullStartedAt,omitempty"`
PullStoppedAt *time.Time `json:"PullStoppedAt,omitempty"`
ExecutionStoppedAt *time.Time `json:"ExecutionStoppedAt,omitempty"`
AvailabilityZone string `json:"AvailabilityZone,omitempty"`
TaskTags map[string]string `json:"TaskTags,omitempty"`
ContainerInstanceTags map[string]string `json:"ContainerInstanceTags,omitempty"`
LaunchType string `json:"LaunchType,omitempty"`
Errors []ErrorResponse `json:"Errors,omitempty"`
}

// ContainerResponse defines the schema for the container response
// JSON object
type ContainerResponse struct {
ID string `json:"DockerId"`
Name string `json:"Name"`
DockerName string `json:"DockerName"`
Image string `json:"Image"`
ImageID string `json:"ImageID"`
Ports []tmdsresponse.PortResponse `json:"Ports,omitempty"`
Labels map[string]string `json:"Labels,omitempty"`
DesiredStatus string `json:"DesiredStatus"`
KnownStatus string `json:"KnownStatus"`
ExitCode *int `json:"ExitCode,omitempty"`
Limits LimitsResponse `json:"Limits"`
CreatedAt *time.Time `json:"CreatedAt,omitempty"`
StartedAt *time.Time `json:"StartedAt,omitempty"`
FinishedAt *time.Time `json:"FinishedAt,omitempty"`
Type string `json:"Type"`
Networks []tmdsresponse.Network `json:"Networks,omitempty"`
Health *apicontainer.HealthStatus `json:"Health,omitempty"`
Volumes []tmdsresponse.VolumeResponse `json:"Volumes,omitempty"`
LogDriver string `json:"LogDriver,omitempty"`
LogOptions map[string]string `json:"LogOptions,omitempty"`
ContainerARN string `json:"ContainerARN,omitempty"`
}

// LimitsResponse defines the schema for task/cpu limits response
// JSON object
type LimitsResponse struct {
CPU *float64 `json:"CPU,omitempty"`
Memory *int64 `json:"Memory,omitempty"`
}

// ErrorResponse defined the schema for error response
// JSON object
type ErrorResponse struct {
ErrorField string `json:"ErrorField,omitempty"`
ErrorCode string `json:"ErrorCode,omitempty"`
ErrorMessage string `json:"ErrorMessage,omitempty"`
StatusCode int `json:"StatusCode,omitempty"`
RequestId string `json:"RequestId,omitempty"`
ResourceARN string `json:"ResourceARN,omitempty"`
}

// Agent versions >= 1.2.0: Null, zero, and CPU values of 1
// are passed to Docker as two CPU shares
const minimumCPUUnit = 2
Expand All @@ -108,13 +44,13 @@ func NewTaskResponse(
containerInstanceArn string,
propagateTags bool,
includeV4Metadata bool,
) (*TaskResponse, error) {
) (*tmdsv2.TaskResponse, error) {
task, ok := state.TaskByArn(taskARN)
if !ok {
return nil, errors.Errorf("v2 task response: unable to find task '%s'", taskARN)
}

resp := &TaskResponse{
resp := &tmdsv2.TaskResponse{
Cluster: cluster,
TaskARN: task.Arn,
Family: task.Family,
Expand All @@ -130,7 +66,7 @@ func NewTaskResponse(
taskCPU := task.CPU
taskMemory := task.Memory
if taskCPU != 0 || taskMemory != 0 {
taskLimits := &LimitsResponse{}
taskLimits := &tmdsv2.LimitsResponse{}
if taskCPU != 0 {
taskLimits.CPU = &taskCPU
}
Expand Down Expand Up @@ -169,7 +105,7 @@ func NewTaskResponse(
}

// propagateTagsToMetadata retrieves container instance and task tags from ECS
func propagateTagsToMetadata(ecsClient api.ECSClient, containerInstanceARN, taskARN string, resp *TaskResponse, includeV4Metadata bool) {
func propagateTagsToMetadata(ecsClient api.ECSClient, containerInstanceARN, taskARN string, resp *tmdsv2.TaskResponse, includeV4Metadata bool) {
containerInstanceTags, err := ecsClient.GetResourceTags(containerInstanceARN)

if err == nil {
Expand Down Expand Up @@ -198,7 +134,7 @@ func NewContainerResponseFromState(
containerID string,
state dockerstate.TaskEngineState,
includeV4Metadata bool,
) (*ContainerResponse, error) {
) (*tmdsv2.ContainerResponse, error) {
dockerContainer, ok := state.ContainerByID(containerID)
if !ok {
return nil, errors.Errorf(
Expand All @@ -220,17 +156,17 @@ func NewContainerResponse(
dockerContainer *apicontainer.DockerContainer,
eni *apieni.ENI,
includeV4Metadata bool,
) ContainerResponse {
) tmdsv2.ContainerResponse {
container := dockerContainer.Container
resp := ContainerResponse{
resp := tmdsv2.ContainerResponse{
ID: dockerContainer.DockerID,
Name: container.Name,
DockerName: dockerContainer.DockerName,
Image: container.Image,
ImageID: container.ImageID,
DesiredStatus: container.GetDesiredStatus().String(),
KnownStatus: container.GetKnownStatus().String(),
Limits: LimitsResponse{
Limits: tmdsv2.LimitsResponse{
CPU: aws.Float64(float64(container.CPU)),
Memory: aws.Int64(int64(container.Memory)),
},
Expand All @@ -255,7 +191,7 @@ func NewContainerResponse(
// Write the container health status inside the container
if dockerContainer.Container.HealthStatusShouldBeReported() {
health := dockerContainer.Container.GetHealthStatus()
resp.Health = &health
resp.Health = dockerContainerHealthToV2Health(health)
}

if createdAt := container.GetCreatedAt(); !createdAt.IsZero() {
Expand Down Expand Up @@ -302,9 +238,24 @@ func NewContainerResponse(
return resp
}

// Converts apicontainer HealthStatus type to v2 Metadata HealthStatus type
func dockerContainerHealthToV2Health(health apicontainer.HealthStatus) *tmdsv2.HealthStatus {
status := health.Status.String()
if health.Status == apicontainerstatus.ContainerHealthUnknown {
// Skip sending status if it is unknown
status = ""
}
return &tmdsv2.HealthStatus{
Status: status,
Since: health.Since,
ExitCode: health.ExitCode,
Output: health.Output,
}
}

// metadataErrorHandling writes an error to the logger, and append an error response
// to V4 metadata endpoint task response
func metadataErrorHandling(resp *TaskResponse, err error, field, resourceARN string, includeV4Metadata bool) {
func metadataErrorHandling(resp *tmdsv2.TaskResponse, err error, field, resourceARN string, includeV4Metadata bool) {
seelog.Errorf("Task Metadata error: unable to get '%s' for '%s': %s", field, resourceARN, err.Error())
if includeV4Metadata {
errResp := newErrorResponse(err, field, resourceARN)
Expand All @@ -313,8 +264,8 @@ func metadataErrorHandling(resp *TaskResponse, err error, field, resourceARN str
}

// newErrorResponse creates a new error response
func newErrorResponse(err error, field, resourceARN string) *ErrorResponse {
errResp := &ErrorResponse{
func newErrorResponse(err error, field, resourceARN string) *tmdsv2.ErrorResponse {
errResp := &tmdsv2.ErrorResponse{
ErrorField: field,
ErrorMessage: err.Error(),
ResourceARN: resourceARN,
Expand Down
Loading

0 comments on commit 5f9ccdb

Please sign in to comment.