Skip to content

Commit 1de01b3

Browse files
committed
Add container.cpus and container.memory system properties
1 parent 0760791 commit 1de01b3

4 files changed

Lines changed: 67 additions & 0 deletions

File tree

Sources/ContainerCommands/System/Property/PropertySet.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ extension Application {
6969
}
7070
DefaultsStore.set(value: value, key: key)
7171
return
72+
case .defaultContainerCPUs:
73+
guard let cpuCount = Int(value), cpuCount > 0 else {
74+
throw ContainerizationError(.invalidArgument, message: "invalid CPU count: \(value)")
75+
}
76+
DefaultsStore.set(value: value, key: key)
77+
case .defaultContainerMemory:
78+
guard let memoryMiB = try? Parser.memoryString(value), memoryMiB > 0 else {
79+
throw ContainerizationError(.invalidArgument, message: "invalid memory value: \(value)")
80+
}
81+
DefaultsStore.set(value: value, key: key)
7282
case .defaultSubnet:
7383
guard (try? CIDRv4(value)) != nil else {
7484
throw ContainerizationError(.invalidArgument, message: "invalid CIDRv4 address: \(value)")

Sources/ContainerPersistence/DefaultsStore.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public enum DefaultsStore {
2424

2525
public enum Keys: String {
2626
case buildRosetta = "build.rosetta"
27+
case defaultContainerCPUs = "container.cpus"
28+
case defaultContainerMemory = "container.memory"
2729
case defaultDNSDomain = "dns.domain"
2830
case defaultBuilderImage = "image.builder"
2931
case defaultInitImage = "image.init"
@@ -69,6 +71,8 @@ public enum DefaultsStore {
6971
public static func allValues() -> [DefaultsStoreValue] {
7072
let allKeys: [(Self.Keys, (Self.Keys) -> Any?)] = [
7173
(.buildRosetta, { Self.getBool(key: $0) }),
74+
(.defaultContainerCPUs, { Self.getOptional(key: $0) }),
75+
(.defaultContainerMemory, { Self.getOptional(key: $0) }),
7276
(.defaultBuilderImage, { Self.get(key: $0) }),
7377
(.defaultInitImage, { Self.get(key: $0) }),
7478
(.defaultKernelBinaryPath, { Self.get(key: $0) }),
@@ -122,6 +126,10 @@ extension DefaultsStore.Keys {
122126
switch self {
123127
case .buildRosetta:
124128
return "Build amd64 images on arm64 using Rosetta, instead of QEMU."
129+
case .defaultContainerCPUs:
130+
return "If defined, the default number of CPUs to allocate to a container."
131+
case .defaultContainerMemory:
132+
return "If defined, the default amount of memory to allocate to a container."
125133
case .defaultDNSDomain:
126134
return "If defined, the local DNS domain to use for containers with unqualified names."
127135
case .defaultBuilderImage:
@@ -145,6 +153,10 @@ extension DefaultsStore.Keys {
145153
switch self {
146154
case .buildRosetta:
147155
return Bool.self
156+
case .defaultContainerCPUs:
157+
return String.self
158+
case .defaultContainerMemory:
159+
return String.self
148160
case .defaultDNSDomain:
149161
return String.self
150162
case .defaultBuilderImage:
@@ -169,6 +181,12 @@ extension DefaultsStore.Keys {
169181
case .buildRosetta:
170182
// This is a boolean key, not used with the string get() method
171183
return "true"
184+
case .defaultContainerCPUs:
185+
// This key is read with getOptional(), not get(); this value is never used
186+
return "4"
187+
case .defaultContainerMemory:
188+
// This key is read with getOptional(), not get(); this value is never used
189+
return "1g"
172190
case .defaultDNSDomain:
173191
return "test"
174192
case .defaultBuilderImage:

Sources/Services/ContainerAPIService/Client/Parser.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// limitations under the License.
1515
//===----------------------------------------------------------------------===//
1616

17+
import ContainerPersistence
1718
import ContainerResource
1819
import Containerization
1920
import ContainerizationError
@@ -90,9 +91,15 @@ public struct Parser {
9091
var resource = ContainerConfiguration.Resources()
9192
if let cpus {
9293
resource.cpus = Int(cpus)
94+
} else if let cpuStr = DefaultsStore.getOptional(key: .defaultContainerCPUs),
95+
let cpuVal = Int(cpuStr), cpuVal > 0
96+
{
97+
resource.cpus = cpuVal
9398
}
9499
if let memory {
95100
resource.memoryInBytes = try Parser.memoryString(memory).mib()
101+
} else if let memStr = DefaultsStore.getOptional(key: .defaultContainerMemory) {
102+
resource.memoryInBytes = try Parser.memoryString(memStr).mib()
96103
}
97104
return resource
98105
}

Tests/ContainerAPIClientTests/ParserTest.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import ContainerizationError
1818
import ContainerizationExtras
19+
import ContainerPersistence
1920
import Foundation
2021
import Testing
2122

@@ -1043,4 +1044,35 @@ struct ParserTest {
10431044
#expect(result[0].soft == UInt64.max - 1)
10441045
#expect(result[0].hard == UInt64.max)
10451046
}
1047+
1048+
// MARK: - Parser.resources
1049+
1050+
@Test
1051+
func testResourcesCPUsFromProperty() throws {
1052+
DefaultsStore.set(value: "8", key: .defaultContainerCPUs)
1053+
defer { DefaultsStore.unset(key: .defaultContainerCPUs) }
1054+
let result = try Parser.resources(cpus: nil, memory: nil)
1055+
#expect(result.cpus == 8)
1056+
}
1057+
1058+
@Test
1059+
func testResourcesMemoryFromProperty() throws {
1060+
DefaultsStore.set(value: "2g", key: .defaultContainerMemory)
1061+
defer { DefaultsStore.unset(key: .defaultContainerMemory) }
1062+
let result = try Parser.resources(cpus: nil, memory: nil)
1063+
#expect(result.memoryInBytes == 2048.mib())
1064+
}
1065+
1066+
@Test
1067+
func testResourcesFlagOverridesProperty() throws {
1068+
DefaultsStore.set(value: "8", key: .defaultContainerCPUs)
1069+
DefaultsStore.set(value: "2g", key: .defaultContainerMemory)
1070+
defer {
1071+
DefaultsStore.unset(key: .defaultContainerCPUs)
1072+
DefaultsStore.unset(key: .defaultContainerMemory)
1073+
}
1074+
let result = try Parser.resources(cpus: 1, memory: "256m")
1075+
#expect(result.cpus == 1)
1076+
#expect(result.memoryInBytes == 256.mib())
1077+
}
10461078
}

0 commit comments

Comments
 (0)