diff --git a/aci/convert/convert.go b/aci/convert/convert.go index 0cb89162..324e72c5 100644 --- a/aci/convert/convert.go +++ b/aci/convert/convert.go @@ -470,17 +470,26 @@ func fqdn(group containerinstance.ContainerGroup, region string) string { // ContainerGroupToContainer composes a Container from an ACI container definition func ContainerGroupToContainer(containerID string, cg containerinstance.ContainerGroup, cc containerinstance.Container, region string) containers.Container { memLimits := 0. - if cc.Resources != nil && - cc.Resources.Limits != nil && - cc.Resources.Limits.MemoryInGB != nil { - memLimits = *cc.Resources.Limits.MemoryInGB * 1024 * 1024 * 1024 - } - + memRequest := 0. cpuLimit := 0. - if cc.Resources != nil && - cc.Resources.Limits != nil && - cc.Resources.Limits.CPU != nil { - cpuLimit = *cc.Resources.Limits.CPU + cpuReservation := 0. + if cc.Resources != nil { + if cc.Resources.Limits != nil { + if cc.Resources.Limits.MemoryInGB != nil { + memLimits = *cc.Resources.Limits.MemoryInGB * 1024 * 1024 * 1024 + } + if cc.Resources.Limits.CPU != nil { + cpuLimit = *cc.Resources.Limits.CPU + } + } + if cc.Resources.Requests != nil { + if cc.Resources.Requests.MemoryInGB != nil { + memRequest = *cc.Resources.Requests.MemoryInGB * 1024 * 1024 * 1024 + } + if cc.Resources.Requests.CPU != nil { + cpuReservation = *cc.Resources.Requests.CPU + } + } } command := "" @@ -504,9 +513,11 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe Env: envVars, } hostConfig := &containers.HostConfig{ - CPULimit: cpuLimit, - MemoryLimit: uint64(memLimits), - RestartPolicy: toContainerRestartPolicy(cg.RestartPolicy), + CPULimit: cpuLimit, + CPUReservation: cpuReservation, + MemoryLimit: uint64(memLimits), + MemoryReservation: uint64(memRequest), + RestartPolicy: toContainerRestartPolicy(cg.RestartPolicy), } c := containers.Container{ ID: containerID, diff --git a/aci/convert/convert_test.go b/aci/convert/convert_test.go index 6932e3a0..f45fe6a7 100644 --- a/aci/convert/convert_test.go +++ b/aci/convert/convert_test.go @@ -83,6 +83,10 @@ func TestContainerGroupToContainer(t *testing.T) { Resources: &containerinstance.ResourceRequirements{ Limits: &containerinstance.ResourceLimits{ CPU: to.Float64Ptr(3), + MemoryInGB: to.Float64Ptr(0.2), + }, + Requests: &containerinstance.ResourceRequests{ + CPU: to.Float64Ptr(2), MemoryInGB: to.Float64Ptr(0.1), }, }, @@ -105,9 +109,11 @@ func TestContainerGroupToContainer(t *testing.T) { FQDN: "myapp.eastus.azurecontainer.io", }, HostConfig: &containers.HostConfig{ - CPULimit: 3, - MemoryLimit: 107374182, - RestartPolicy: "any", + CPULimit: 3, + CPUReservation: 2, + MemoryLimit: 214748364, + MemoryReservation: 107374182, + RestartPolicy: "any", }, } diff --git a/api/containers/api.go b/api/containers/api.go index 7e064390..dd1eee4d 100644 --- a/api/containers/api.go +++ b/api/containers/api.go @@ -61,9 +61,11 @@ type RuntimeConfig struct { // HostConfig config of the container host type HostConfig struct { - RestartPolicy string - CPULimit float64 - MemoryLimit uint64 + RestartPolicy string + CPUReservation float64 + CPULimit float64 + MemoryReservation uint64 + MemoryLimit uint64 } // Port represents a published port of a container diff --git a/cli/cmd/testdata/inspect-out-id.golden b/cli/cmd/testdata/inspect-out-id.golden index 5b13d058..2d8fe356 100644 --- a/cli/cmd/testdata/inspect-out-id.golden +++ b/cli/cmd/testdata/inspect-out-id.golden @@ -9,7 +9,9 @@ "PidsLimit": 0, "HostConfig": { "RestartPolicy": "none", + "CPUReservation": 0, "CPULimit": 0, + "MemoryReservation": 0, "MemoryLimit": 0 }, "Platform": "Linux" diff --git a/tests/aci-e2e/e2e-aci_test.go b/tests/aci-e2e/e2e-aci_test.go index 44add2d0..572aa7a3 100644 --- a/tests/aci-e2e/e2e-aci_test.go +++ b/tests/aci-e2e/e2e-aci_test.go @@ -250,6 +250,7 @@ func TestRunVolume(t *testing.T) { assert.NilError(t, err) assert.Equal(t, containerInspect.Platform, "Linux") assert.Equal(t, containerInspect.HostConfig.CPULimit, 1.0) + assert.Equal(t, containerInspect.HostConfig.CPUReservation, 1.0) assert.Equal(t, containerInspect.HostConfig.RestartPolicy, containers.RestartPolicyNone) assert.Assert(t, is.Len(containerInspect.Ports, 1)) @@ -388,7 +389,7 @@ func TestContainerRunAttached(t *testing.T) { } return poll.Continue("waiting for container to be running, current inspect result: \n%s", res.Combined()) } - poll.WaitOn(t, checkRunning, poll.WithDelay(5*time.Second), poll.WithTimeout(60*time.Second)) + poll.WaitOn(t, checkRunning, poll.WithDelay(5*time.Second), poll.WithTimeout(90*time.Second)) inspectRes := c.RunDockerCmd("inspect", container) @@ -397,6 +398,8 @@ func TestContainerRunAttached(t *testing.T) { assert.Equal(t, containerInspect.Platform, "Linux") assert.Equal(t, containerInspect.HostConfig.CPULimit, 0.1) assert.Equal(t, containerInspect.HostConfig.MemoryLimit, uint64(107374182)) + assert.Equal(t, containerInspect.HostConfig.CPUReservation, 0.1) + assert.Equal(t, containerInspect.HostConfig.MemoryReservation, uint64(107374182)) assert.Equal(t, containerInspect.HostConfig.RestartPolicy, containers.RestartPolicyOnFailure) assert.Assert(t, is.Len(containerInspect.Ports, 1)) @@ -480,6 +483,39 @@ func overwriteFileStorageAccount(t *testing.T, absComposefileName string, storag assert.NilError(t, err) } +func TestUpResources(t *testing.T) { + const ( + composeProjectName = "testresources" + serverContainer = composeProjectName + "_web" + wordsContainer = composeProjectName + "_words" + ) + + c := NewParallelE2eCLI(t, binDir) + setupTestResourceGroup(t, c) + + t.Run("compose up", func(t *testing.T) { + c.RunDockerCmd("compose", "up", "-f", "../composefiles/aci-demo/aci_demo_port_resources.yaml", "--project-name", composeProjectName) + + res := c.RunDockerCmd("inspect", serverContainer) + + webInspect, err := ParseContainerInspect(res.Stdout()) + assert.NilError(t, err) + assert.Equal(t, webInspect.HostConfig.CPULimit, 0.7) + assert.Equal(t, webInspect.HostConfig.MemoryLimit, uint64(1073741824)) + assert.Equal(t, webInspect.HostConfig.CPUReservation, 0.5) + assert.Equal(t, webInspect.HostConfig.MemoryReservation, uint64(536870912)) + + res = c.RunDockerCmd("inspect", wordsContainer) + + wordsInspect, err := ParseContainerInspect(res.Stdout()) + assert.NilError(t, err) + assert.Equal(t, wordsInspect.HostConfig.CPULimit, 0.5) + assert.Equal(t, wordsInspect.HostConfig.MemoryLimit, uint64(751619276)) + assert.Equal(t, wordsInspect.HostConfig.CPUReservation, 0.5) + assert.Equal(t, wordsInspect.HostConfig.MemoryReservation, uint64(751619276)) + }) +} + func TestUpUpdate(t *testing.T) { const ( composeProjectName = "acidemo" diff --git a/tests/composefiles/aci-demo/aci_demo_port.yaml b/tests/composefiles/aci-demo/aci_demo_port.yaml deleted file mode 100644 index 4212bb48..00000000 --- a/tests/composefiles/aci-demo/aci_demo_port.yaml +++ /dev/null @@ -1,14 +0,0 @@ -services: - db: - build: db - image: gtardif/sentences-db - - words: - build: words - image: gtardif/sentences-api - - web: - build: web - image: gtardif/sentences-web - ports: - - "80:80" \ No newline at end of file diff --git a/tests/composefiles/aci-demo/aci_demo_port_resources.yaml b/tests/composefiles/aci-demo/aci_demo_port_resources.yaml new file mode 100644 index 00000000..8735121d --- /dev/null +++ b/tests/composefiles/aci-demo/aci_demo_port_resources.yaml @@ -0,0 +1,24 @@ +services: + db: + image: gtardif/sentences-db + + words: + image: gtardif/sentences-api + deploy: + resources: + reservations: + cpus: '0.5' + memory: 0.7G + + web: + image: gtardif/sentences-web + ports: + - "80:80" + deploy: + resources: + limits: + cpus: '0.7' + memory: 1G + reservations: + cpus: '0.5' + memory: 0.5G \ No newline at end of file diff --git a/tests/e2e/testdata/inspect-id.golden b/tests/e2e/testdata/inspect-id.golden index 5b13d058..2d8fe356 100644 --- a/tests/e2e/testdata/inspect-id.golden +++ b/tests/e2e/testdata/inspect-id.golden @@ -9,7 +9,9 @@ "PidsLimit": 0, "HostConfig": { "RestartPolicy": "none", + "CPUReservation": 0, "CPULimit": 0, + "MemoryReservation": 0, "MemoryLimit": 0 }, "Platform": "Linux"