Skip to content

Commit

Permalink
Support for docker engine 25+
Browse files Browse the repository at this point in the history
- adds support for docker engine 25+, which has deprecated docker API
  versions less than 1.24.
- dynamically determines which docker versions are available and what to
  use to call docker API, as well as advertising correct version support
  capabilities to the ECS backend
  • Loading branch information
sparrc committed Jan 26, 2024
1 parent f3208a9 commit 62708fd
Show file tree
Hide file tree
Showing 20 changed files with 485 additions and 267 deletions.
12 changes: 5 additions & 7 deletions agent/app/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -1097,26 +1097,24 @@ func (agent *ecsAgent) startACSSession(
return exitcodes.ExitSuccess
}

// validateRequiredVersion validates docker version.
// verifyRequiredDockerVersion validates docker version.
// Minimum docker version supported is 1.9.0, maps to api version 1.21
// see https://docs.docker.com/develop/sdk/#api-version-matrix
func (agent *ecsAgent) verifyRequiredDockerVersion() (int, bool) {
supportedVersions := agent.dockerClient.SupportedVersions()
supportedVersions := dockerclient.SupportedVersionsExtended(agent.dockerClient.SupportedVersions)
if len(supportedVersions) == 0 {
seelog.Critical("Could not get supported docker versions.")
return exitcodes.ExitError, false
}

// if api version 1.21 is supported, it means docker version is at least 1.9.0
for _, version := range supportedVersions {
if version == dockerclient.Version_1_21 {
if version == dockerclient.MinDockerAPIVersion {
return -1, true
}
}

// api 1.21 is not supported, docker version is older than 1.9.0
seelog.Criticalf("Required minimum docker API verion %s is not supported",
dockerclient.Version_1_21)
seelog.Criticalf("Required minimum docker API version %s is not supported",
dockerclient.MinDockerAPIVersion)
return exitcodes.ExitTerminal, false
}

Expand Down
20 changes: 6 additions & 14 deletions agent/app/agent_capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,14 @@ func (agent *ecsAgent) capabilities() ([]*ecs.Attribute, error) {
}

supportedVersions := make(map[dockerclient.DockerVersion]bool)
// Determine API versions to report as supported. Supported versions are also used for capability-enablement, except
// logging drivers.
for _, version := range agent.dockerClient.SupportedVersions() {
// Determine API versions to report as supported via com.amazonaws.ecs.capability.docker-remote-api.X.XX capabilities
// and for determining which features we support that depend on specific docker API versions
for _, version := range dockerclient.SupportedVersionsExtended(agent.dockerClient.SupportedVersions) {
capabilities = appendNameOnlyAttribute(capabilities, capabilityPrefix+"docker-remote-api."+string(version))
supportedVersions[version] = true
}

capabilities = agent.appendLoggingDriverCapabilities(capabilities)
capabilities = agent.appendLoggingDriverCapabilities(capabilities, supportedVersions)

if agent.cfg.SELinuxCapable.Enabled() {
capabilities = appendNameOnlyAttribute(capabilities, capabilityPrefix+"selinux")
Expand Down Expand Up @@ -315,7 +315,6 @@ func (agent *ecsAgent) appendDockerDependentCapabilities(capabilities []*ecs.Att
capabilities = appendNameOnlyAttribute(capabilities, capabilityPrefix+"ecr-auth")
capabilities = appendNameOnlyAttribute(capabilities, attributePrefix+"execution-role-ecr-pull")
}

if _, ok := supportedVersions[dockerclient.Version_1_24]; ok && !agent.cfg.DisableDockerHealthCheck.Enabled() {
// Docker health check was added in API 1.24
capabilities = appendNameOnlyAttribute(capabilities, attributePrefix+"container-health-check")
Expand All @@ -339,17 +338,10 @@ func (agent *ecsAgent) appendGMSADomainlessCapabilities(capabilities []*ecs.Attr
return capabilities
}

func (agent *ecsAgent) appendLoggingDriverCapabilities(capabilities []*ecs.Attribute) []*ecs.Attribute {
knownVersions := make(map[dockerclient.DockerVersion]struct{})
// Determine known API versions. Known versions are used exclusively for logging-driver enablement, since none of
// the structural API elements change.
for _, version := range agent.dockerClient.KnownVersions() {
knownVersions[version] = struct{}{}
}

func (agent *ecsAgent) appendLoggingDriverCapabilities(capabilities []*ecs.Attribute, supportedVersions map[dockerclient.DockerVersion]bool) []*ecs.Attribute {
for _, loggingDriver := range agent.cfg.AvailableLoggingDrivers {
requiredVersion := dockerclient.LoggingDriverMinimumVersion[loggingDriver]
if _, ok := knownVersions[requiredVersion]; ok {
if _, ok := supportedVersions[requiredVersion]; ok {
capabilities = appendNameOnlyAttribute(capabilities, capabilityPrefix+"logging-driver."+string(loggingDriver))
}
}
Expand Down
33 changes: 0 additions & 33 deletions agent/app/agent_capability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@ func TestCapabilities(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
dockerclient.Version_1_19,
}),
// CNI plugins are platform dependent.
Expand Down Expand Up @@ -255,11 +251,6 @@ func getCapabilitiesWithConfig(cfg *config.Config, t *testing.T) []*ecs.Attribut
dockerclient.Version_1_17,
dockerclient.Version_1_18,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
dockerclient.Version_1_19,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -295,7 +286,6 @@ func TestCapabilitiesECR(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_19,
})
client.EXPECT().KnownVersions().Return(nil)
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil)
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil)
Expand Down Expand Up @@ -352,7 +342,6 @@ func TestCapabilitiesTaskIAMRoleForSupportedDockerVersion(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_19,
})
client.EXPECT().KnownVersions().Return(nil)
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil)
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil)
Expand Down Expand Up @@ -407,7 +396,6 @@ func TestCapabilitiesTaskIAMRoleForUnSupportedDockerVersion(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_18,
})
client.EXPECT().KnownVersions().Return(nil)
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil)
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil)
Expand Down Expand Up @@ -462,7 +450,6 @@ func TestCapabilitiesTaskIAMRoleNetworkHostForSupportedDockerVersion(t *testing.
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_19,
})
client.EXPECT().KnownVersions().Return(nil)
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil)
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil)
Expand Down Expand Up @@ -517,7 +504,6 @@ func TestCapabilitiesTaskIAMRoleNetworkHostForUnSupportedDockerVersion(t *testin
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_18,
})
client.EXPECT().KnownVersions().Return(nil)
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil)
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil)
Expand Down Expand Up @@ -591,11 +577,6 @@ func TestAWSVPCBlockInstanceMetadataWhenTaskENIIsDisabled(t *testing.T) {
dockerclient.Version_1_17,
dockerclient.Version_1_18,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
dockerclient.Version_1_19,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -660,7 +641,6 @@ func TestCapabilitiesExecutionRoleAWSLogs(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
})
client.EXPECT().KnownVersions().Return(nil)
// CNI plugins are platform dependent.
// Therefore, for any version query for any plugin return an error
cniClient.EXPECT().Version(gomock.Any()).Return("v1", errors.New("some error happened"))
Expand Down Expand Up @@ -727,7 +707,6 @@ func TestCapabilitiesTaskResourceLimit(t *testing.T) {

gomock.InOrder(
client.EXPECT().SupportedVersions().Return(versionList),
client.EXPECT().KnownVersions().Return(versionList),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -781,7 +760,6 @@ func TestCapabilitesTaskResourceLimitDisabledByMissingDockerVersion(t *testing.T

gomock.InOrder(
client.EXPECT().SupportedVersions().Return(versionList),
client.EXPECT().KnownVersions().Return(versionList),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -834,7 +812,6 @@ func TestCapabilitesTaskResourceLimitErrorCase(t *testing.T) {

gomock.InOrder(
client.EXPECT().SupportedVersions().Return(versionList),
client.EXPECT().KnownVersions().Return(versionList),
)
ctx, cancel := context.WithCancel(context.TODO())
// Cancel the context to cancel async routines
Expand Down Expand Up @@ -904,7 +881,6 @@ func TestCapabilitiesIncreasedTaskCPULimit(t *testing.T) {

gomock.InOrder(
client.EXPECT().SupportedVersions().Return(versionList),
client.EXPECT().KnownVersions().Return(versionList),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -947,7 +923,6 @@ func TestCapabilitiesContainerHealth(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_24,
})
client.EXPECT().KnownVersions().Return(nil)
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil)
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil)
Expand Down Expand Up @@ -998,7 +973,6 @@ func TestCapabilitiesContainerHealthDisabled(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_24,
})
client.EXPECT().KnownVersions().Return(nil)
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil)
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil)
Expand Down Expand Up @@ -1058,7 +1032,6 @@ func TestCapabilitesListPluginsErrorCase(t *testing.T) {

gomock.InOrder(
client.EXPECT().SupportedVersions().Return(versionList),
client.EXPECT().KnownVersions().Return(versionList),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return(nil, errors.New("listPlugins error happened")),
Expand Down Expand Up @@ -1106,7 +1079,6 @@ func TestCapabilitesScanPluginsErrorCase(t *testing.T) {

gomock.InOrder(
client.EXPECT().SupportedVersions().Return(versionList),
client.EXPECT().KnownVersions().Return(versionList),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return(nil, errors.New("Scan plugins error happened")),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -1224,7 +1196,6 @@ func TestCapabilitiesExecuteCommand(t *testing.T) {

gomock.InOrder(
client.EXPECT().SupportedVersions().Return(versionList),
client.EXPECT().KnownVersions().Return(versionList),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return(nil, errors.New("Scan plugins error happened")),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -1310,10 +1281,6 @@ func TestCapabilitiesNoServiceConnect(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
dockerclient.Version_1_19,
}),
// CNI plugins are platform dependent.
Expand Down
37 changes: 0 additions & 37 deletions agent/app/agent_capability_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,6 @@ func TestVolumeDriverCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
dockerclient.Version_1_18,
dockerclient.Version_1_19,
}),
cniClient.EXPECT().Version(ecscni.VPCENIPluginName).Return("v1", nil),
Expand Down Expand Up @@ -183,9 +179,6 @@ func TestNvidiaDriverCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -269,9 +262,6 @@ func TestEmptyNvidiaDriverCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -349,9 +339,6 @@ func TestENITrunkingCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
cniClient.EXPECT().Version(ecscni.VPCENIPluginName).Return("v1", nil),
cniClient.EXPECT().Version(ecscni.ECSBranchENIPluginName).Return("v2", nil),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -444,9 +431,6 @@ func TestNoENITrunkingCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
cniClient.EXPECT().Version(ecscni.VPCENIPluginName).Return("v1", nil),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
Expand Down Expand Up @@ -527,9 +511,6 @@ func TestPIDAndIPCNamespaceSharingCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -606,9 +587,6 @@ func TestPIDAndIPCNamespaceSharingCapabilitiesNoPauseContainer(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -683,9 +661,6 @@ func TestAppMeshCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -769,9 +744,6 @@ func TestTaskEIACapabilitiesNoOptimizedCPU(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -828,9 +800,6 @@ func TestTaskEIACapabilitiesWithOptimizedCPU(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -884,9 +853,6 @@ func TestCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down Expand Up @@ -969,9 +935,6 @@ func TestFirelensConfigCapabilitiesUnix(t *testing.T) {
client.EXPECT().SupportedVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
client.EXPECT().KnownVersions().Return([]dockerclient.DockerVersion{
dockerclient.Version_1_17,
}),
mockMobyPlugins.EXPECT().Scan().AnyTimes().Return([]string{}, nil),
client.EXPECT().ListPluginsWithFilters(gomock.Any(), gomock.Any(), gomock.Any(),
gomock.Any()).AnyTimes().Return([]string{}, nil),
Expand Down
Loading

0 comments on commit 62708fd

Please sign in to comment.