compose/ecs/pkg/convert/convert.go

358 lines
9.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package convert
import (
"github.com/docker/ecs-plugin/pkg/compose"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/opts"
)
func Convert(project *compose.Project, service types.ServiceConfig) (*ecs.RegisterTaskDefinitionInput, error) {
_, err := toCPULimits(service)
if err != nil {
return nil, err
}
foo := int64(256)
logDriver := "awslogs" // FIXME could be set by service.Logging, especially to enable use of firelens
return &ecs.RegisterTaskDefinitionInput{
ContainerDefinitions: []*ecs.ContainerDefinition{
// Here we can declare sidecars and init-containers using https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#container_definition_dependson
{
Command: toStringPtrSlice(service.Command),
Cpu: &foo,
DependsOn: nil,
DisableNetworking: toBoolPtr(service.NetworkMode == "none"),
DnsSearchDomains: toStringPtrSlice(service.DNSSearch),
DnsServers: toStringPtrSlice(service.DNS),
DockerLabels: nil,
DockerSecurityOptions: toStringPtrSlice(service.SecurityOpt),
EntryPoint: toStringPtrSlice(service.Entrypoint),
Environment: toKeyValuePairPtr(service.Environment),
Essential: toBoolPtr(true),
ExtraHosts: toHostEntryPtr(service.ExtraHosts),
FirelensConfiguration: nil,
HealthCheck: toHealthCheck(service.HealthCheck),
Hostname: toStringPtr(service.Hostname),
Image: toStringPtr(service.Image),
Interactive: nil,
Links: nil,
LinuxParameters: toLinuxParameters(service),
LogConfiguration: &ecs.LogConfiguration{
LogDriver: &logDriver,
Options: map[string]*string{},
SecretOptions: nil,
},
Memory: toMemoryLimits(service.Deploy),
MemoryReservation: toMemoryReservation(service.Deploy),
MountPoints: nil,
Name: toStringPtr(service.Name),
PortMappings: toPortMappings(service.Ports),
Privileged: toBoolPtr(service.Privileged),
PseudoTerminal: toBoolPtr(service.Tty),
ReadonlyRootFilesystem: toBoolPtr(service.ReadOnly),
RepositoryCredentials: nil,
ResourceRequirements: nil,
Secrets: nil,
StartTimeout: nil,
StopTimeout: durationToInt64Ptr(service.StopGracePeriod),
SystemControls: nil,
Ulimits: toUlimits(service.Ulimits),
User: toStringPtr(service.User),
VolumesFrom: nil,
WorkingDirectory: toStringPtr(service.WorkingDir),
},
},
Cpu: toCPU(service),
ExecutionRoleArn: nil,
Family: toStringPtr(project.Name),
IpcMode: toStringPtr(service.Ipc),
Memory: toMemory(service),
NetworkMode: toStringPtr("awsvpc"), // FIXME could be set by service.NetworkMode, Fargate only supports network mode awsvpc.
PidMode: toStringPtr(service.Pid),
PlacementConstraints: toPlacementConstraints(service.Deploy),
ProxyConfiguration: nil,
RequiresCompatibilities: toRequiresCompatibilities(ecs.LaunchTypeFargate),
Tags: nil,
Volumes: []*ecs.Volume{
{
/* ONLY supported when using EC2 launch type
DockerVolumeConfiguration: {
Autoprovision: nil,
Driver: nil,
DriverOpts: nil,
Labels: nil,
Scope: nil,
}, */
/* Beta and ONLY supported when using EC2 launch type
EfsVolumeConfiguration: {
FileSystemId: nil,
RootDirectory: nil,
}, */
/* Bind mount host volume
Host: {
SourcePath:
}, */
Name: aws.String("MyVolume"),
},
},
}, nil
}
func toCPU(service types.ServiceConfig) *string {
// FIXME based on service's memory/cpu requirements, select the adequate Fargate CPU
v := "256"
return &v
}
func toMemory(service types.ServiceConfig) *string {
// FIXME based on service's memory/cpu requirements, select the adequate Fargate CPU
v := "512"
return &v
}
func toCPULimits(service types.ServiceConfig) (*int64, error) {
if service.Deploy == nil {
return nil, nil
}
res := service.Deploy.Resources.Limits
if res == nil {
return nil, nil
}
if res.NanoCPUs == "" {
return nil, nil
}
v, err := opts.ParseCPUs(res.NanoCPUs)
if err != nil {
return nil, err
}
return &v, nil
}
func toRequiresCompatibilities(isolation string) []*string {
if isolation == "" {
return nil
}
return []*string{&isolation}
}
func hasMemoryOrMemoryReservation(service types.ServiceConfig) bool {
if service.Deploy == nil {
return false
}
if service.Deploy.Resources.Reservations != nil {
return true
}
if service.Deploy.Resources.Limits != nil {
return true
}
return false
}
func toPlacementConstraints(deploy *types.DeployConfig) []*ecs.TaskDefinitionPlacementConstraint {
if deploy == nil || deploy.Placement.Constraints == nil || len(deploy.Placement.Constraints) == 0 {
return nil
}
pl := []*ecs.TaskDefinitionPlacementConstraint{}
for _, c := range deploy.Placement.Constraints {
pl = append(pl, &ecs.TaskDefinitionPlacementConstraint{
Expression: toStringPtr(c),
Type: nil,
})
}
return pl
}
func toPortMappings(ports []types.ServicePortConfig) []*ecs.PortMapping {
if len(ports) == 0 {
return nil
}
m := []*ecs.PortMapping{}
for _, p := range ports {
m = append(m, &ecs.PortMapping{
ContainerPort: uint32Toint64Ptr(p.Target),
HostPort: uint32Toint64Ptr(p.Published),
Protocol: toStringPtr(p.Protocol),
})
}
return m
}
func toUlimits(ulimits map[string]*types.UlimitsConfig) []*ecs.Ulimit {
if len(ulimits) == 0 {
return nil
}
u := []*ecs.Ulimit{}
for k, v := range ulimits {
u = append(u, &ecs.Ulimit{
Name: toStringPtr(k),
SoftLimit: intToInt64Ptr(v.Soft),
HardLimit: intToInt64Ptr(v.Hard),
})
}
return u
}
func uint32Toint64Ptr(i uint32) *int64 {
v := int64(i)
return &v
}
func intToInt64Ptr(i int) *int64 {
v := int64(i)
return &v
}
const Mb = 1024 * 1024
func toMemoryLimits(deploy *types.DeployConfig) *int64 {
if deploy == nil {
return nil
}
res := deploy.Resources.Limits
if res == nil {
return nil
}
v := int64(res.MemoryBytes) / Mb
return &v
}
func toMemoryReservation(deploy *types.DeployConfig) *int64 {
if deploy == nil {
return nil
}
res := deploy.Resources.Reservations
if res == nil {
return nil
}
v := int64(res.MemoryBytes) / Mb
return &v
}
func toLinuxParameters(service types.ServiceConfig) *ecs.LinuxParameters {
return &ecs.LinuxParameters{
Capabilities: toKernelCapabilities(service.CapAdd, service.CapDrop),
Devices: nil,
InitProcessEnabled: service.Init,
MaxSwap: nil,
// FIXME SharedMemorySize: service.ShmSize,
Swappiness: nil,
Tmpfs: toTmpfs(service.Tmpfs),
}
}
func toTmpfs(tmpfs types.StringList) []*ecs.Tmpfs {
if tmpfs == nil || len(tmpfs) == 0 {
return nil
}
o := []*ecs.Tmpfs{}
for _, t := range tmpfs {
path := t
o = append(o, &ecs.Tmpfs{
ContainerPath: &path,
MountOptions: nil,
Size: nil,
})
}
return o
}
func toKernelCapabilities(add []string, drop []string) *ecs.KernelCapabilities {
if len(add) == 0 && len(drop) == 0 {
return nil
}
return &ecs.KernelCapabilities{
Add: toStringPtrSlice(add),
Drop: toStringPtrSlice(drop),
}
}
func toHealthCheck(check *types.HealthCheckConfig) *ecs.HealthCheck {
if check == nil {
return nil
}
return &ecs.HealthCheck{
Command: toStringPtrSlice(check.Test),
Interval: durationToInt64Ptr(check.Interval),
Retries: uint64ToInt64Ptr(check.Retries),
StartPeriod: durationToInt64Ptr(check.StartPeriod),
Timeout: durationToInt64Ptr(check.Timeout),
}
}
func uint64ToInt64Ptr(i *uint64) *int64 {
if i == nil {
return nil
}
v := int64(*i)
return &v
}
func durationToInt64Ptr(interval *types.Duration) *int64 {
if interval == nil {
return nil
}
v := int64(time.Duration(*interval).Seconds())
return &v
}
func toHostEntryPtr(hosts types.HostsList) []*ecs.HostEntry {
if hosts == nil || len(hosts) == 0 {
return nil
}
e := []*ecs.HostEntry{}
for _, h := range hosts {
host := h
e = append(e, &ecs.HostEntry{
Hostname: &host,
})
}
return e
}
func toKeyValuePairPtr(environment types.MappingWithEquals) []*ecs.KeyValuePair {
if environment == nil || len(environment) == 0 {
return nil
}
pairs := []*ecs.KeyValuePair{}
for k, v := range environment {
name := k
value := v
pairs = append(pairs, &ecs.KeyValuePair{
Name: &name,
Value: value,
})
}
return pairs
}
func toStringPtr(s string) *string {
if s == "" {
return nil
}
return &s
}
func toStringPtrSlice(s []string) []*string {
if len(s) == 0 {
return nil
}
v := []*string{}
for _, x := range s {
value := x
v = append(v, &value)
}
return v
}
func toBoolPtr(b bool) *bool {
if !b {
return nil
}
return &b
}