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

handlers/v1: add json tags to response structs #1473

Merged
merged 5 commits into from
Jul 26, 2018
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## 1.19.1
* Bug - Fixed a bug where responses of introspection API break backward compatibility [#1473](https://github.com/aws/amazon-ecs-agent/pull/1473)

## 1.19.0
* Feature - Private registry can be authenticated through task definition using AWS Secrets Manager [#1427](https://github.com/aws/amazon-ecs-agent/pull/1427)

Expand Down
36 changes: 18 additions & 18 deletions agent/handlers/v1/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,41 +24,41 @@ import (

// MetadataResponse is the schema for the metadata response JSON object
type MetadataResponse struct {
Cluster string
ContainerInstanceArn *string
Version string
Cluster string `json:"Cluster"`
ContainerInstanceArn *string `json:"ContainerInstanceArn"`
Version string `json:"Version"`
}

// TaskResponse is the schema for the task response JSON object
type TaskResponse struct {
Arn string
DesiredStatus string `json:",omitempty"`
KnownStatus string
Family string
Version string
Containers []ContainerResponse
Arn string `json:"Arn"`
DesiredStatus string `json:"DesiredStatus,omitempty"`
KnownStatus string `json:"KnownStatus"`
Family string `json:"Family"`
Version string `json:"Version"`
Containers []ContainerResponse `json:"Containers"`
}

// TasksResponse is the schema for the tasks response JSON object
type TasksResponse struct {
Tasks []*TaskResponse
Tasks []*TaskResponse `json:"Tasks"`
}

// ContainerResponse is the schema for the container response JSON object
type ContainerResponse struct {
DockerID string
DockerName string
Name string
Ports []PortResponse `json:",omitempty"`
Networks []containermetadata.Network `json:",omitempty"`
DockerID string `json:"DockerId"`
DockerName string `json:"DockerName"`
Name string `json:"Name"`
Ports []PortResponse `json:"Ports,omitempty"`
Networks []containermetadata.Network `json:"Networks,omitempty"`
}

// PortResponse defines the schema for portmapping response JSON
// object.
type PortResponse struct {
ContainerPort uint16
Protocol string
HostPort uint16 `json:",omitempty"`
ContainerPort uint16 `json:"ContainerPort,omitempty"`
Protocol string `json:"Protocol,omitempty"`
HostPort uint16 `json:"HostPort,omitempty"`
}

// NewTaskResponse creates a TaskResponse for a task.
Expand Down
190 changes: 190 additions & 0 deletions agent/handlers/v1/response_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.

package v1

import (
"encoding/json"
"testing"

apicontainer "github.com/aws/amazon-ecs-agent/agent/api/container"
apieni "github.com/aws/amazon-ecs-agent/agent/api/eni"
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"
)

const (
taskARN = "t1"
family = "sleep"
version = "1"
containerID = "cid"
containerName = "sleepy"
eniIPv4Address = "10.0.0.2"
)

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"},
},
},
},
},
}

task := &apitask.Task{
Arn: taskARN,
Family: family,
Version: version,
DesiredStatusUnsafe: apitaskstatus.TaskRunning,
KnownStatusUnsafe: apitaskstatus.TaskRunning,
ENI: &apieni.ENI{
IPV4Addresses: []*apieni.ENIIPV4Address{
{
Address: eniIPv4Address,
},
},
},
}

container := &apicontainer.Container{
Name: containerName,
Ports: []apicontainer.PortBinding{
{
ContainerPort: 80,
Protocol: apicontainer.TransportProtocolTCP,
},
},
}

containerNameToDockerContainer := map[string]*apicontainer.DockerContainer{
taskARN: &apicontainer.DockerContainer{
DockerID: containerID,
DockerName: containerName,
Container: container,
},
}

taskResponse := NewTaskResponse(task, containerNameToDockerContainer)

taskResponseJSON, err := json.Marshal(taskResponse)
assert.NoError(t, err)

taskResponseMap := make(map[string]interface{})

json.Unmarshal(taskResponseJSON, &taskResponseMap)

assert.Equal(t, expectedTaskResponseMap, taskResponseMap)
}

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"},
},
},
}

container := &apicontainer.Container{
Name: containerName,
Ports: []apicontainer.PortBinding{
{
ContainerPort: 80,
Protocol: apicontainer.TransportProtocolTCP,
},
},
}

dockerContainer := &apicontainer.DockerContainer{
DockerID: containerID,
DockerName: containerName,
Container: container,
}

eni := &apieni.ENI{
IPV4Addresses: []*apieni.ENIIPV4Address{
{
Address: eniIPv4Address,
},
},
}

containerResponse := NewContainerResponse(dockerContainer, eni)

containerResponseJSON, err := json.Marshal(containerResponse)
assert.NoError(t, err)

containerResponseMap := make(map[string]interface{})

json.Unmarshal(containerResponseJSON, &containerResponseMap)

assert.Equal(t, expectedContainerResponseMap, containerResponseMap)
}

func TestPortBindingsResponse(t *testing.T) {
container := &apicontainer.Container{
Name: containerName,
Ports: []apicontainer.PortBinding{
{
ContainerPort: 80,
HostPort: 80,
Protocol: apicontainer.TransportProtocolTCP,
},
},
}

dockerContainer := &apicontainer.DockerContainer{
Container: container,
}

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)
}
60 changes: 30 additions & 30 deletions agent/handlers/v2/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,46 +29,46 @@ import (

// TaskResponse defines the schema for the task response JSON object
type TaskResponse struct {
Cluster string
TaskARN string
Family string
Revision string
DesiredStatus string `json:",omitempty"`
KnownStatus string
Containers []ContainerResponse `json:",omitempty"`
Limits *LimitsResponse `json:",omitempty"`
PullStartedAt *time.Time `json:",omitempty"`
PullStoppedAt *time.Time `json:",omitempty"`
ExecutionStoppedAt *time.Time `json:",omitempty"`
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"`
}

// ContainerResponse defines the schema for the container response
// JSON object
type ContainerResponse struct {
ID string `json:"DockerId"`
Name string
DockerName string
Image string
ImageID string
Ports []v1.PortResponse `json:",omitempty"`
Labels map[string]string `json:",omitempty"`
DesiredStatus string
KnownStatus string
ExitCode *int `json:",omitempty"`
Limits LimitsResponse
CreatedAt *time.Time `json:",omitempty"`
StartedAt *time.Time `json:",omitempty"`
FinishedAt *time.Time `json:",omitempty"`
Type string
Networks []containermetadata.Network `json:",omitempty"`
Health *apicontainer.HealthStatus `json:",omitempty"`
ID string `json:"DockerId"`
Name string `json:"Name"`
DockerName string `json:"DockerName"`
Image string `json:"Image"`
ImageID string `json:"ImageID"`
Ports []v1.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 []containermetadata.Network `json:"Networks,omitempty"`
Health *apicontainer.HealthStatus `json:"Health,omitempty"`
}

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

// NewTaskResponse creates a new response object for the task
Expand Down