diff --git a/aci/convert/convert.go b/aci/convert/convert.go index c3683d5c..db0545fe 100644 --- a/aci/convert/convert.go +++ b/aci/convert/convert.go @@ -353,36 +353,75 @@ func (s serviceConfigAciHelper) getAciContainer(volumesCache map[string]bool) (c volumes = &allVolumes } - memRequest := 1. // Default 1 Gb - var cpuRequest float64 = 1 - if s.Deploy != nil && s.Deploy.Resources.Reservations != nil { - if s.Deploy.Resources.Reservations.MemoryBytes != 0 { - memRequest = bytesToGb(s.Deploy.Resources.Reservations.MemoryBytes) - } - if s.Deploy.Resources.Reservations.NanoCPUs != "" { - cpuRequest, err = strconv.ParseFloat(s.Deploy.Resources.Reservations.NanoCPUs, 0) - if err != nil { - return containerinstance.Container{}, err - } - } + resource, err := s.getResourceRequestsLimits() + if err != nil { + return containerinstance.Container{}, err } + return containerinstance.Container{ Name: to.StringPtr(s.Name), ContainerProperties: &containerinstance.ContainerProperties{ Image: to.StringPtr(s.Image), Command: to.StringSlicePtr(s.Command), EnvironmentVariables: getEnvVariables(s.Environment), - Resources: &containerinstance.ResourceRequirements{ - Requests: &containerinstance.ResourceRequests{ - MemoryInGB: to.Float64Ptr(memRequest), - CPU: to.Float64Ptr(cpuRequest), - }, - }, - VolumeMounts: volumes, + Resources: resource, + VolumeMounts: volumes, }, }, nil } +func (s serviceConfigAciHelper) getResourceRequestsLimits() (*containerinstance.ResourceRequirements, error) { + memRequest := 1. // Default 1 Gb + var cpuRequest float64 = 1 + var err error + hasMemoryRequest := func() bool { + return s.Deploy != nil && s.Deploy.Resources.Reservations != nil && s.Deploy.Resources.Reservations.MemoryBytes != 0 + } + hasCPURequest := func() bool { + return s.Deploy != nil && s.Deploy.Resources.Reservations != nil && s.Deploy.Resources.Reservations.NanoCPUs != "" + } + if hasMemoryRequest() { + memRequest = bytesToGb(s.Deploy.Resources.Reservations.MemoryBytes) + } + + if hasCPURequest() { + cpuRequest, err = strconv.ParseFloat(s.Deploy.Resources.Reservations.NanoCPUs, 0) + if err != nil { + return nil, err + } + } + memLimit := memRequest + cpuLimit := cpuRequest + if s.Deploy != nil && s.Deploy.Resources.Limits != nil { + if s.Deploy.Resources.Limits.MemoryBytes != 0 { + memLimit = bytesToGb(s.Deploy.Resources.Limits.MemoryBytes) + if !hasMemoryRequest() { + memRequest = memLimit + } + } + if s.Deploy.Resources.Limits.NanoCPUs != "" { + cpuLimit, err = strconv.ParseFloat(s.Deploy.Resources.Limits.NanoCPUs, 0) + if err != nil { + return nil, err + } + if !hasCPURequest() { + cpuRequest = cpuLimit + } + } + } + resources := containerinstance.ResourceRequirements{ + Requests: &containerinstance.ResourceRequests{ + MemoryInGB: to.Float64Ptr(memRequest), + CPU: to.Float64Ptr(cpuRequest), + }, + Limits: &containerinstance.ResourceLimits{ + MemoryInGB: to.Float64Ptr(memLimit), + CPU: to.Float64Ptr(cpuLimit), + }, + } + return &resources, nil +} + func getEnvVariables(composeEnv types.MappingWithEquals) *[]containerinstance.EnvironmentVariable { result := []containerinstance.EnvironmentVariable{} for key, value := range composeEnv { diff --git a/aci/convert/convert_test.go b/aci/convert/convert_test.go index 8de973a5..d234cff9 100644 --- a/aci/convert/convert_test.go +++ b/aci/convert/convert_test.go @@ -561,6 +561,73 @@ func TestComposeContainerGroupToContainerResourceRequests(t *testing.T) { request := *((*group.Containers)[0]).Resources.Requests assert.Equal(t, *request.CPU, float64(0.1)) assert.Equal(t, *request.MemoryInGB, float64(0.1)) + limits := *((*group.Containers)[0]).Resources.Limits + assert.Equal(t, *limits.CPU, float64(0.1)) + assert.Equal(t, *limits.MemoryInGB, float64(0.1)) +} + +func TestComposeContainerGroupToContainerResourceRequestsAndLimits(t *testing.T) { + _0_1Gb := 0.1 * 1024 * 1024 * 1024 + project := types.Project{ + Services: []types.ServiceConfig{ + { + Name: "service1", + Image: "image1", + Deploy: &types.DeployConfig{ + Resources: types.Resources{ + Reservations: &types.Resource{ + NanoCPUs: "0.1", + MemoryBytes: types.UnitBytes(_0_1Gb), + }, + Limits: &types.Resource{ + NanoCPUs: "0.3", + MemoryBytes: types.UnitBytes(2 * _0_1Gb), + }, + }, + }, + }, + }, + } + + group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper) + assert.NilError(t, err) + + request := *((*group.Containers)[0]).Resources.Requests + assert.Equal(t, *request.CPU, float64(0.1)) + assert.Equal(t, *request.MemoryInGB, float64(0.1)) + limits := *((*group.Containers)[0]).Resources.Limits + assert.Equal(t, *limits.CPU, float64(0.3)) + assert.Equal(t, *limits.MemoryInGB, float64(0.2)) +} + +func TestComposeContainerGroupToContainerResourceLimitsOnly(t *testing.T) { + _0_1Gb := 0.1 * 1024 * 1024 * 1024 + project := types.Project{ + Services: []types.ServiceConfig{ + { + Name: "service1", + Image: "image1", + Deploy: &types.DeployConfig{ + Resources: types.Resources{ + Limits: &types.Resource{ + NanoCPUs: "0.3", + MemoryBytes: types.UnitBytes(2 * _0_1Gb), + }, + }, + }, + }, + }, + } + + group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper) + assert.NilError(t, err) + + request := *((*group.Containers)[0]).Resources.Requests + assert.Equal(t, *request.CPU, float64(0.3)) + assert.Equal(t, *request.MemoryInGB, float64(0.2)) + limits := *((*group.Containers)[0]).Resources.Limits + assert.Equal(t, *limits.CPU, float64(0.3)) + assert.Equal(t, *limits.MemoryInGB, float64(0.2)) } func TestComposeContainerGroupToContainerResourceRequestsDefaults(t *testing.T) {