Skip to content

Commit

Permalink
Adding adapter to have volumes/links use DependsOn field
Browse files Browse the repository at this point in the history
  • Loading branch information
ubhattacharjya committed Feb 7, 2019
1 parent e36e2c8 commit 5fbfab0
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 1 deletion.
51 changes: 50 additions & 1 deletion agent/api/task/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ const (
NvidiaVisibleDevicesEnvVar = "NVIDIA_VISIBLE_DEVICES"
GPUAssociationType = "gpu"

ContainerOrderingStartCondition = "START"

arnResourceSections = 2
arnResourceDelimiter = "/"
// networkModeNone specifies the string used to define the `none` docker networking mode
Expand Down Expand Up @@ -250,6 +252,18 @@ func (task *Task) PostUnmarshalTask(cfg *config.Config,
}
}

err := task.initializeContainerOrderingForVolumes()
if err != nil {
seelog.Errorf("Task [%s]: could not initialize volumes dependency for container: %v", task.Arn, err)
return apierrors.NewResourceInitError(task.Arn, err)
}

err = task.initializeContainerOrderingForLinks()
if err != nil {
seelog.Errorf("Task [%s]: could not initialize links dependency for container: %v", task.Arn, err)
return apierrors.NewResourceInitError(task.Arn, err)
}

if task.requiresASMDockerAuthData() {
task.initializeASMAuthResource(credentialsManager, resourceFields)
}
Expand All @@ -262,7 +276,7 @@ func (task *Task) PostUnmarshalTask(cfg *config.Config,
task.initializeASMSecretResource(credentialsManager, resourceFields)
}

err := task.initializeDockerLocalVolumes(dockerClient, ctx)
err = task.initializeDockerLocalVolumes(dockerClient, ctx)
if err != nil {
return apierrors.NewResourceInitError(task.Arn, err)
}
Expand Down Expand Up @@ -1241,6 +1255,41 @@ func (task *Task) shouldOverrideIPCMode(container *apicontainer.Container, docke
}
}

func (task *Task) initializeContainerOrderingForVolumes() error {
for _, container := range task.Containers {
if len(container.VolumesFrom) > 0 {
for _, volume := range container.VolumesFrom {
if _, ok := task.ContainerByName(volume.SourceContainer); !ok {
return fmt.Errorf("could not find container with name %s", volume.SourceContainer)
}
dependOn := apicontainer.DependsOn{Container: volume.SourceContainer, Condition: ContainerOrderingStartCondition}
container.DependsOn = append(container.DependsOn, dependOn)
}
}
}
return nil
}

func (task *Task) initializeContainerOrderingForLinks() error {
for _, container := range task.Containers {
if len(container.Links) > 0 {
for _, link := range container.Links {
linkParts := strings.Split(link, ":")
if len(linkParts) > 2 {
return fmt.Errorf("Invalid link format")
}
linkName := linkParts[0]
if _, ok := task.ContainerByName(linkName); !ok {
return fmt.Errorf("could not find container with name %s", linkName)
}
dependOn := apicontainer.DependsOn{Container: linkName, Condition: ContainerOrderingStartCondition}
container.DependsOn = append(container.DependsOn, dependOn)
}
}
}
return nil
}

func (task *Task) dockerLinks(container *apicontainer.Container, dockerContainerMap map[string]*apicontainer.DockerContainer) ([]string, error) {
dockerLinkArr := make([]string, len(container.Links))
for i, link := range container.Links {
Expand Down
97 changes: 97 additions & 0 deletions agent/api/task/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2816,3 +2816,100 @@ func TestAssociationByTypeAndName(t *testing.T) {
association, ok = task.AssociationByTypeAndName("other-type", "dev1")
assert.False(t, ok)
}

func TestInitializeContainerOrderingWithLinksAndVolumesFrom(t *testing.T) {
containerWithOnlyVolume := &apicontainer.Container{
Name: "myName",
Image: "image:tag",
VolumesFrom: []apicontainer.VolumeFrom{{SourceContainer: "myName1"}},
}

containerWithOnlyLink := &apicontainer.Container{
Name: "myName1",
Image: "image:tag",
Links: []string{"myName"},
}

containerWithBothVolumeAndLink := &apicontainer.Container{
Name: "myName2",
Image: "image:tag",
VolumesFrom: []apicontainer.VolumeFrom{{SourceContainer: "myName"}},
Links: []string{"myName1"},
}

containerWithNoVolumeOrLink := &apicontainer.Container{
Name: "myName3",
Image: "image:tag",
}

task := &Task{
Arn: "test",
ResourcesMapUnsafe: make(map[string][]taskresource.TaskResource),
Containers: []*apicontainer.Container{containerWithOnlyVolume, containerWithOnlyLink,
containerWithBothVolumeAndLink, containerWithNoVolumeOrLink},
}

err := task.initializeContainerOrderingForVolumes()
assert.NoError(t, err)
err = task.initializeContainerOrderingForLinks()
assert.NoError(t, err)

containerResultWithVolume := task.Containers[0]
assert.Equal(t, "myName1", containerResultWithVolume.DependsOn[0].Container)
assert.Equal(t, ContainerOrderingStartCondition, containerResultWithVolume.DependsOn[0].Condition)

containerResultWithLink := task.Containers[1]
assert.Equal(t, "myName", containerResultWithLink.DependsOn[0].Container)
assert.Equal(t, ContainerOrderingStartCondition, containerResultWithLink.DependsOn[0].Condition)

containerResultWithBothVolumeAndLink := task.Containers[2]
assert.Equal(t, "myName", containerResultWithBothVolumeAndLink.DependsOn[0].Container)
assert.Equal(t, ContainerOrderingStartCondition, containerResultWithBothVolumeAndLink.DependsOn[0].Condition)
assert.Equal(t, "myName1", containerResultWithBothVolumeAndLink.DependsOn[1].Container)
assert.Equal(t, ContainerOrderingStartCondition, containerResultWithBothVolumeAndLink.DependsOn[1].Condition)

containerResultWithNoVolumeOrLink := task.Containers[3]
assert.Equal(t, 0, len(containerResultWithNoVolumeOrLink.DependsOn))
}

func TestInitializeContainerOrderingWithError(t *testing.T) {
containerWithVolumeError := &apicontainer.Container{
Name: "myName",
Image: "image:tag",
VolumesFrom: []apicontainer.VolumeFrom{{SourceContainer: "dummyContainer"}},
}

containerWithLinkError1 := &apicontainer.Container{
Name: "myName1",
Image: "image:tag",
Links: []string{"dummyContainer"},
}

containerWithLinkError2 := &apicontainer.Container{
Name: "myName2",
Image: "image:tag",
Links: []string{"myName:link1:link2"},
}

task1 := &Task{
Arn: "test",
ResourcesMapUnsafe: make(map[string][]taskresource.TaskResource),
Containers: []*apicontainer.Container{containerWithVolumeError, containerWithLinkError1},
}

task2 := &Task{
Arn: "test",
ResourcesMapUnsafe: make(map[string][]taskresource.TaskResource),
Containers: []*apicontainer.Container{containerWithVolumeError, containerWithLinkError2},
}

errVolume1 := task1.initializeContainerOrderingForVolumes()
assert.Error(t, errVolume1)
errLink1 := task1.initializeContainerOrderingForLinks()
assert.Error(t, errLink1)

errVolume2 := task2.initializeContainerOrderingForVolumes()
assert.Error(t, errVolume2)
errLink2 := task2.initializeContainerOrderingForLinks()
assert.Error(t, errLink2)
}
4 changes: 4 additions & 0 deletions agent/app/agent_capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (
capabiltyPIDAndIPCNamespaceSharing = "pid-ipc-namespace-sharing"
capabilityNvidiaDriverVersionInfix = "nvidia-driver-version."
capabilityECREndpoint = "ecr-endpoint"
capabilityContainerOrdering = "container-ordering"
taskEIAAttributeSuffix = "task-eia"
)

Expand Down Expand Up @@ -141,6 +142,9 @@ func (agent *ecsAgent) capabilities() ([]*ecs.Attribute, error) {
// support elastic inference in agent
capabilities = appendNameOnlyAttribute(capabilities, attributePrefix+taskEIAAttributeSuffix)

// support container ordering in agent
capabilities = appendNameOnlyAttribute(capabilities, attributePrefix+capabilityContainerOrdering)

return capabilities, nil
}

Expand Down
3 changes: 3 additions & 0 deletions agent/app/agent_capability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ func TestCapabilities(t *testing.T) {
{
Name: aws.String(attributePrefix + taskEIAAttributeSuffix),
},
{
Name: aws.String(attributePrefix + capabilityContainerOrdering),
},
}...)

ctx, cancel := context.WithCancel(context.TODO())
Expand Down

0 comments on commit 5fbfab0

Please sign in to comment.