Skip to content

Commit 294aba3

Browse files
committed
feat: Support for --cpus and --memory resource options
1 parent 04fd69c commit 294aba3

3 files changed

Lines changed: 62 additions & 0 deletions

File tree

Sources/Container-Compose/Commands/ComposeUp.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,14 @@ public struct ComposeUp: AsyncParsableCommand, @unchecked Sendable {
489489
runCommandArgs.append("--read-only")
490490
}
491491

492+
// Add resource limits
493+
if let cpus = service.deploy?.resources?.limits?.cpus {
494+
runCommandArgs.append(contentsOf: ["--cpus", cpus])
495+
}
496+
if let memory = service.deploy?.resources?.limits?.memory {
497+
runCommandArgs.append(contentsOf: ["--memory", memory])
498+
}
499+
492500
// Handle service-level configs (note: still only parsing/logging, not attaching)
493501
if let serviceConfigs = service.configs {
494502
print(

Tests/Container-Compose-DynamicTests/ComposeUpTests.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,39 @@ struct ComposeUpTests {
234234
#expect(webContainer.status == .running)
235235
#expect(dbContainer.status == .running)
236236
}
237+
238+
@Test("Test container created with non-default CPU and memory limits")
239+
func testCpuAndMemoryLimits() async throws {
240+
let yaml = """
241+
version: "3.8"
242+
services:
243+
app:
244+
image: nginx:alpine
245+
deploy:
246+
resources:
247+
limits:
248+
cpus: "1"
249+
memory: "512MB"
250+
"""
251+
252+
let tempLocation = URL.temporaryDirectory.appending(path: "Container-Compose_Tests_\(UUID().uuidString)/docker-compose.yaml")
253+
try? FileManager.default.createDirectory(at: tempLocation.deletingLastPathComponent(), withIntermediateDirectories: true)
254+
try yaml.write(to: tempLocation, atomically: false, encoding: .utf8)
255+
let folderName = tempLocation.deletingLastPathComponent().lastPathComponent
256+
257+
var composeUp = try ComposeUp.parse(["-d", "--cwd", tempLocation.deletingLastPathComponent().path(percentEncoded: false)])
258+
try await composeUp.run()
259+
260+
let containers = try await ClientContainer.list()
261+
.filter { $0.configuration.id.contains(folderName) }
262+
263+
guard let appContainer = containers.first(where: { $0.configuration.id == "\(folderName)-app" }) else {
264+
throw Errors.containerNotFound
265+
}
266+
267+
#expect(appContainer.configuration.resources.cpus == 1)
268+
#expect(appContainer.configuration.resources.memoryInBytes == 512.mib())
269+
}
237270

238271
enum Errors: Error {
239272
case containerNotFound

Tests/Container-Compose-StaticTests/DockerComposeParsingTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,27 @@ struct DockerComposeParsingTests {
378378

379379
#expect(compose.services["app"]??.platform == "linux/amd64")
380380
}
381+
382+
@Test("Parse deploy resources limits (cpus and memory)")
383+
func parseComposeWithDeployResources() throws {
384+
let yaml = """
385+
version: '3.8'
386+
services:
387+
app:
388+
image: alpine:latest
389+
deploy:
390+
resources:
391+
limits:
392+
cpus: "0.5"
393+
memory: "512M"
394+
"""
395+
396+
let decoder = YAMLDecoder()
397+
let compose = try decoder.decode(DockerCompose.self, from: yaml)
398+
399+
#expect(compose.services["app"]??.deploy?.resources?.limits?.cpus == "0.5")
400+
#expect(compose.services["app"]??.deploy?.resources?.limits?.memory == "512M")
401+
}
381402

382403
@Test("Service must have image or build - should fail without either")
383404
func serviceRequiresImageOrBuild() throws {

0 commit comments

Comments
 (0)