Skip to content

Commit

Permalink
containermetadata: use iotas for status
Browse files Browse the repository at this point in the history
  • Loading branch information
adnxn committed Oct 6, 2017
1 parent 508d9e5 commit de5fa33
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 23 deletions.
15 changes: 0 additions & 15 deletions agent/containermetadata/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,8 @@ const (
inspectContainerTimeout = 30 * time.Second
metadataFile = "ecs-container-metadata.json"
metadataPerm = 0644
// MetadataInitial is the initial state of the metadata file which
// contains metadata provided by the ECS Agent
MetadataInitial = "INITIAL"
// MetadataReady is the final state of the metadata file which indicates
// it has acquired all the data it needs (Currently from the Agent and Docker)
MetadataReady = "READY"
)

// MetadataStatus specifies the current update status of the metadata file.
// The purpose of this status is for users to check if the metadata file has
// reached the stage they need before they read the rest of the file to avoid
// race conditions (Since the final stage will need to be after the container
// starts up
// In the future the metadata may require multiple stages of update and these
// statuses should amended/appended accordingly.
type MetadataStatus string

// Manager is an interface that allows us to abstract away the metadata
// operations
type Manager interface {
Expand Down
28 changes: 21 additions & 7 deletions agent/containermetadata/parse_metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ func TestParseContainerCreate(t *testing.T) {
mockCluster := cluster
mockContainerInstanceARN := containerInstanceARN

expectedStatus := string(MetadataInitial)

newManager := &metadataManager{
cluster: mockCluster,
containerInstanceARN: mockContainerInstanceARN,
Expand All @@ -42,7 +44,7 @@ func TestParseContainerCreate(t *testing.T) {
assert.Equal(t, metadata.taskMetadata.containerName, mockContainerName, "Expcted container name "+mockContainerName)
assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expcted task ARN "+mockTaskARN)
assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expcted container instance ARN "+mockContainerInstanceARN)
assert.Equal(t, string(metadata.metadataStatus), "INITIAL", "Expected status "+MetadataInitial)
assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus)
}

func TestParseHasNoContainer(t *testing.T) {
Expand All @@ -51,6 +53,8 @@ func TestParseHasNoContainer(t *testing.T) {
mockCluster := cluster
mockContainerInstanceARN := containerInstanceARN

expectedStatus := string(MetadataReady)

newManager := &metadataManager{
cluster: mockCluster,
containerInstanceARN: mockContainerInstanceARN,
Expand All @@ -61,7 +65,7 @@ func TestParseHasNoContainer(t *testing.T) {
assert.Equal(t, metadata.taskMetadata.containerName, mockContainerName, "Expcted container name "+mockContainerName)
assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expcted task ARN "+mockTaskARN)
assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expcted container instance ARN "+mockContainerInstanceARN)
assert.Equal(t, string(metadata.metadataStatus), "READY", "Expected status "+MetadataInitial)
assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus)
assert.Equal(t, metadata.dockerContainerMetadata.containerID, "", "Expected empty container metadata")
assert.Equal(t, metadata.dockerContainerMetadata.dockerContainerName, "", "Expected empty container metadata")
assert.Equal(t, metadata.dockerContainerMetadata.imageID, "", "Expected empty container metadata")
Expand All @@ -77,6 +81,8 @@ func TestParseHasConfig(t *testing.T) {
mockConfig := &docker.Config{Image: "image"}
mockContainer := &docker.Container{Config: mockConfig}

expectedStatus := string(MetadataReady)

newManager := &metadataManager{
cluster: mockCluster,
containerInstanceARN: mockContainerInstanceARN,
Expand All @@ -87,7 +93,7 @@ func TestParseHasConfig(t *testing.T) {
assert.Equal(t, metadata.taskMetadata.containerName, mockContainerName, "Expcted container name "+mockContainerName)
assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expcted task ARN "+mockTaskARN)
assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expcted container instance ARN "+mockContainerInstanceARN)
assert.Equal(t, string(metadata.metadataStatus), "READY", "Expected status "+MetadataInitial)
assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus)
assert.Equal(t, metadata.dockerContainerMetadata.imageName, "image", "Expected nonempty imageID")
}

Expand All @@ -104,6 +110,8 @@ func TestParseHasHostConfigPortBindsError(t *testing.T) {
mockHostConfig := &docker.HostConfig{PortBindings: mockPorts}
mockContainer := &docker.Container{HostConfig: mockHostConfig}

expectedStatus := string(MetadataReady)

newManager := &metadataManager{
cluster: mockCluster,
containerInstanceARN: mockContainerInstanceARN,
Expand All @@ -114,7 +122,7 @@ func TestParseHasHostConfigPortBindsError(t *testing.T) {
assert.Equal(t, metadata.taskMetadata.containerName, mockContainerName, "Expcted container name "+mockContainerName)
assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expcted task ARN "+mockTaskARN)
assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expcted container instance ARN "+mockContainerInstanceARN)
assert.Equal(t, string(metadata.metadataStatus), "READY", "Expected status "+MetadataInitial)
assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus)
assert.Equal(t, len(metadata.dockerContainerMetadata.ports), 0, "Expected empty list of ports")
}

Expand All @@ -131,6 +139,8 @@ func TestParseHasHostConfigPortBindsNoError(t *testing.T) {
mockHostConfig := &docker.HostConfig{PortBindings: mockPorts}
mockContainer := &docker.Container{HostConfig: mockHostConfig}

expectedStatus := string(MetadataReady)

newManager := &metadataManager{
cluster: mockCluster,
containerInstanceARN: mockContainerInstanceARN,
Expand All @@ -141,7 +151,7 @@ func TestParseHasHostConfigPortBindsNoError(t *testing.T) {
assert.Equal(t, metadata.taskMetadata.containerName, mockContainerName, "Expcted container name "+mockContainerName)
assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expcted task ARN "+mockTaskARN)
assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expcted container instance ARN "+mockContainerInstanceARN)
assert.Equal(t, string(metadata.metadataStatus), "READY", "Expected status "+MetadataInitial)
assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus)
assert.Equal(t, len(metadata.dockerContainerMetadata.ports), 1, "Expected empty list of ports")
}

Expand All @@ -155,6 +165,8 @@ func TestParseHasNetworkSettingsNetworksEmpty(t *testing.T) {
mockNetworkSettings := &docker.NetworkSettings{IPAddress: "0.0.0.0"}
mockContainer := &docker.Container{HostConfig: mockHostConfig, NetworkSettings: mockNetworkSettings}

expectedStatus := string(MetadataReady)

newManager := &metadataManager{
cluster: mockCluster,
containerInstanceARN: mockContainerInstanceARN,
Expand All @@ -165,7 +177,7 @@ func TestParseHasNetworkSettingsNetworksEmpty(t *testing.T) {
assert.Equal(t, metadata.taskMetadata.containerName, mockContainerName, "Expcted container name "+mockContainerName)
assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expcted task ARN "+mockTaskARN)
assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expcted container instance ARN "+mockContainerInstanceARN)
assert.Equal(t, string(metadata.metadataStatus), "READY", "Expected status "+MetadataInitial)
assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus)
assert.Equal(t, len(metadata.dockerContainerMetadata.networkInfo.networks), 1, "Expected one network")
}

Expand All @@ -182,6 +194,8 @@ func TestParseHasNetworkSettingsNetworksNonEmpty(t *testing.T) {
mockNetworkSettings := &docker.NetworkSettings{Networks: mockNetworks}
mockContainer := &docker.Container{HostConfig: mockHostConfig, NetworkSettings: mockNetworkSettings}

expectedStatus := string(MetadataReady)

newManager := &metadataManager{
cluster: mockCluster,
containerInstanceARN: mockContainerInstanceARN,
Expand All @@ -192,6 +206,6 @@ func TestParseHasNetworkSettingsNetworksNonEmpty(t *testing.T) {
assert.Equal(t, metadata.taskMetadata.containerName, mockContainerName, "Expcted container name "+mockContainerName)
assert.Equal(t, metadata.taskMetadata.taskARN, mockTaskARN, "Expcted task ARN "+mockTaskARN)
assert.Equal(t, metadata.containerInstanceARN, mockContainerInstanceARN, "Expcted container instance ARN "+mockContainerInstanceARN)
assert.Equal(t, string(metadata.metadataStatus), "READY", "Expected status "+MetadataInitial)
assert.Equal(t, string(metadata.metadataStatus), expectedStatus, "Expected status "+expectedStatus)
assert.Equal(t, len(metadata.dockerContainerMetadata.networkInfo.networks), 2, "Expected two networks")
}
51 changes: 51 additions & 0 deletions agent/containermetadata/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,64 @@ package containermetadata

import (
"encoding/json"
"fmt"
"time"

"github.com/aws/amazon-ecs-agent/agent/api"

docker "github.com/fsouza/go-dockerclient"
)

const (
// MetadataInitial is the initial state of the metadata file which
// contains metadata provided by the ECS Agent
MetadataInitialText = "INITIAL"
// MetadataReady is the final state of the metadata file which indicates
// it has acquired all the data it needs (Currently from the Agent and Docker)
MetadataReadyText = "READY"
)

const (
MetadataInitial MetadataStatus = iota
MetadataReady
)

// MetadataStatus specifies the current update status of the metadata file.
// The purpose of this status is for users to check if the metadata file has
// reached the stage they need before they read the rest of the file to avoid
// race conditions (Since the final stage will need to be after the container
// starts up
// In the future the metadata may require multiple stages of update and these
// statuses should amended/appended accordingly.
type MetadataStatus int32

func (status MetadataStatus) MarshalText() (text []byte, err error) {
switch status {
case MetadataInitial:
text = []byte(MetadataInitialText)
case MetadataReady:
text = []byte(MetadataReadyText)
default:
return nil, fmt.Errorf("failed marshalling MetadataStatus %v", status)
}
return
}

func (status *MetadataStatus) UnmarshalText(text []byte) error {
var err error
t := string(text)

switch t {
case MetadataInitialText:
*status = MetadataInitial
case MetadataReadyText:
*status = MetadataReady
default:
return fmt.Errorf("failed unmarshalling MetadataStatus %s", text)
}
return err
}

// DockerMetadataClient is a wrapper for the docker interface functions we need
// We use this as a dummy type to be able to pass in engine.DockerClient to
// our functions without creating import cycles
Expand Down
2 changes: 1 addition & 1 deletion agent/engine/docker_task_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ func (engine *DockerTaskEngine) sweepTask(task *api.Task) {
if engine.cfg.ContainerMetadataEnabled {
err := engine.metadataManager.Clean(task.Arn)
if err != nil {
seelog.Warnf("Clean task metadata failed for task %s: %v", task, err)
seelog.Warnf("Clean task metadata failed for task %s: %v", task.Arn, err)
}
}
engine.saver.Save()
Expand Down

0 comments on commit de5fa33

Please sign in to comment.