Skip to content

Commit fa18f84

Browse files
Rename AllocatedNetwork and address PR feedback
1 parent 1aa51d7 commit fa18f84

8 files changed

Lines changed: 92 additions & 67 deletions

File tree

Sources/ContainerResource/Network/AllocatedNetwork.swift renamed to Sources/ContainerResource/Network/AllocatedAttachment.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616

1717
import ContainerXPC
1818

19-
/// AllocatedNetwork represents an allocated network attachment and additional
20-
/// relevant data needed for a sandbox to properly configure a network interface
21-
/// on bootstrap.
22-
public struct AllocatedNetwork: Sendable {
19+
/// AllocatedAttachment represents a network attachment that has been allocated for use
20+
/// by a container and any additional relevant data needed for a sandbox to properly
21+
/// configure networking on container bootstrap.
22+
public struct AllocatedAttachment: Sendable {
2323
public let attachment: Attachment
2424
public let additionalData: XPCMessage?
2525
public let pluginInfo: NetworkPluginInfo

Sources/ContainerResource/Network/Attachment.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
import ContainerizationExtras
1818

19-
/// A snapshot of a network interface allocated to a sandbox.
19+
/// A snapshot of a network interface for a sandbox.
2020
public struct Attachment: Codable, Sendable {
2121
/// The network ID associated with the attachment.
2222
public let network: String

Sources/ContainerResource/Network/NetworkConfiguration.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ public struct NetworkConfiguration: Codable, Sendable, Identifiable {
4949
public var labels: [String: String] = [:]
5050

5151
/// Details about the network plugin that manages this network.
52-
public var pluginInfo: NetworkPluginInfo
52+
/// FIXME: This field only needs to be optional while we wait for the field
53+
/// to be proliferated to most users when they update container.
54+
public var pluginInfo: NetworkPluginInfo?
5355

5456
/// Creates a network configuration
5557
public init(
@@ -97,7 +99,7 @@ public struct NetworkConfiguration: Codable, Sendable, Identifiable {
9799
ipv6Subnet = try container.decodeIfPresent(String.self, forKey: .ipv6Subnet)
98100
.map { try CIDRv6($0) }
99101
labels = try container.decodeIfPresent([String: String].self, forKey: .labels) ?? [:]
100-
pluginInfo = try container.decode(NetworkPluginInfo.self, forKey: .pluginInfo)
102+
pluginInfo = try container.decodeIfPresent(NetworkPluginInfo.self, forKey: .pluginInfo)
101103
try validate()
102104
}
103105

@@ -111,7 +113,7 @@ public struct NetworkConfiguration: Codable, Sendable, Identifiable {
111113
try container.encodeIfPresent(ipv4Subnet, forKey: .ipv4Subnet)
112114
try container.encodeIfPresent(ipv6Subnet, forKey: .ipv6Subnet)
113115
try container.encode(labels, forKey: .labels)
114-
try container.encode(pluginInfo, forKey: .pluginInfo)
116+
try container.encodeIfPresent(pluginInfo, forKey: .pluginInfo)
115117
}
116118

117119
private func validate() throws {

Sources/ContainerResource/Network/NetworkState.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public enum NetworkState: Codable, Sendable {
7373
}
7474
}
7575

76-
public var pluginInfo: NetworkPluginInfo {
76+
public var pluginInfo: NetworkPluginInfo? {
7777
switch self {
7878
case .created(let configuration), .running(let configuration, _): configuration.pluginInfo
7979
}

Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public actor ContainersService {
3232
struct ContainerState {
3333
var snapshot: ContainerSnapshot
3434
var client: SandboxClient?
35-
var allocatedNetworks: [AllocatedNetwork]
35+
var allocatedAttachments: [AllocatedAttachment]
3636

3737
func getClient() throws -> SandboxClient {
3838
guard let client else {
@@ -98,7 +98,7 @@ public actor ContainersService {
9898
networks: [],
9999
startedDate: nil
100100
),
101-
allocatedNetworks: []
101+
allocatedAttachments: []
102102
)
103103
results[config.id] = state
104104
guard runtimePlugins.first(where: { $0.name == config.runtimeHandler }) != nil else {
@@ -262,7 +262,7 @@ public actor ContainersService {
262262
networks: [],
263263
startedDate: nil
264264
)
265-
await self.setContainerState(configuration.id, ContainerState(snapshot: snapshot, allocatedNetworks: []), context: context)
265+
await self.setContainerState(configuration.id, ContainerState(snapshot: snapshot, allocatedAttachments: []), context: context)
266266
} catch {
267267
do {
268268
try bundle.delete()
@@ -291,18 +291,18 @@ public actor ContainersService {
291291
let bundle = ContainerResource.Bundle(path: path)
292292
let config = try bundle.configuration
293293

294-
var allocatedNetworks = [AllocatedNetwork]()
294+
var allocatedAttachments = [AllocatedAttachment]()
295295
do {
296296
for n in config.networks {
297-
let allocatedNet = try await self.networksService?.allocate(
297+
let allocatedAttach = try await self.networksService?.allocate(
298298
id: n.network,
299299
hostname: n.options.hostname,
300300
macAddress: n.options.macAddress
301301
)
302-
guard let allocatedNet = allocatedNet else {
302+
guard let allocatedAttach = allocatedAttach else {
303303
throw ContainerizationError(.internalError, message: "failed to allocate a network")
304304
}
305-
allocatedNetworks.append(allocatedNet)
305+
allocatedAttachments.append(allocatedAttach)
306306
}
307307

308308
try Self.registerService(
@@ -317,22 +317,22 @@ public actor ContainersService {
317317
id: id,
318318
runtime: runtime
319319
)
320-
try await sandboxClient.bootstrap(stdio: stdio, allocatedNetworks: allocatedNetworks)
320+
try await sandboxClient.bootstrap(stdio: stdio, allocatedAttachments: allocatedAttachments)
321321

322322
try await self.exitMonitor.registerProcess(
323323
id: id,
324324
onExit: self.handleContainerExit
325325
)
326326

327327
state.client = sandboxClient
328-
state.allocatedNetworks = allocatedNetworks
328+
state.allocatedAttachments = allocatedAttachments
329329
await self.setContainerState(id, state, context: context)
330330
} catch {
331-
for allocatedNet in allocatedNetworks {
331+
for allocatedAttach in allocatedAttachments {
332332
do {
333-
try await self.networksService?.deallocate(attachment: allocatedNet.attachment)
333+
try await self.networksService?.deallocate(attachment: allocatedAttach.attachment)
334334
} catch {
335-
self.log.error("failed to deallocate network attachment in \(id) for \(allocatedNet.attachment.network): \(error)")
335+
self.log.error("failed to deallocate network attachment in \(id) for \(allocatedAttach.attachment.network): \(error)")
336336
}
337337
}
338338

@@ -605,18 +605,18 @@ public actor ContainersService {
605605
// Best effort deallocate network attachments for the container. Don't throw on
606606
// failure so we can continue with state cleanup.
607607
self.log.info("Deallocating network attachments for \(id)")
608-
for allocatedNet in state.allocatedNetworks {
608+
for allocatedAttach in state.allocatedAttachments {
609609
do {
610-
try await self.networksService?.deallocate(attachment: allocatedNet.attachment)
610+
try await self.networksService?.deallocate(attachment: allocatedAttach.attachment)
611611
} catch {
612-
self.log.error("failed to deallocate network attachment in \(id) for \(allocatedNet.attachment.network): \(error)")
612+
self.log.error("failed to deallocate network attachment in \(id) for \(allocatedAttach.attachment.network): \(error)")
613613
}
614614
}
615615

616616
state.snapshot.status = .stopped
617617
state.snapshot.networks = []
618618
state.client = nil
619-
state.allocatedNetworks = []
619+
state.allocatedAttachments = []
620620
await self.setContainerState(id, state, context: context)
621621

622622
let options = try getContainerCreationOptions(id: id)

Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swift

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ public actor NetworksService {
8383
}
8484
}
8585

86+
// Ensure that the network always has plugin information.
87+
// Before this field was added, the code always assumed we were using the
88+
// container-network-vmnet network plugin, so it should be safe to fallback to that
89+
// if no info was found in an on disk configuration.
90+
if configuration.pluginInfo == nil {
91+
configuration.pluginInfo = NetworkPluginInfo(plugin: "container-network-vmnet")
92+
try await store.update(configuration)
93+
}
94+
8695
// Start up the network.
8796
do {
8897
try await registerService(configuration: configuration)
@@ -94,7 +103,7 @@ public actor NetworksService {
94103
])
95104
}
96105

97-
let client = Self.getClient(configuration: configuration)
106+
let client = try Self.getClient(configuration: configuration)
98107
var networkState = try await client.state()
99108

100109
// FIXME: Temporary workaround for persisted configuration being overwritten
@@ -167,7 +176,7 @@ public actor NetworksService {
167176

168177
// Create and start the network.
169178
try await self.registerService(configuration: configuration)
170-
let client = Self.getClient(configuration: configuration)
179+
let client = try Self.getClient(configuration: configuration)
171180

172181
// Ensure the network is running, and set up the persistent network state
173182
// using our configuration data
@@ -303,15 +312,18 @@ public actor NetworksService {
303312
}
304313
}
305314

306-
public func allocate(id: String, hostname: String, macAddress: MACAddress?) async throws -> AllocatedNetwork {
315+
public func allocate(id: String, hostname: String, macAddress: MACAddress?) async throws -> AllocatedAttachment {
307316
guard let serviceState = serviceStates[id] else {
308317
throw ContainerizationError(.notFound, message: "no network for id \(id)")
309318
}
319+
guard let pluginInfo = serviceState.networkState.pluginInfo else {
320+
throw ContainerizationError(.internalError, message: "network \(id) missing plugin information")
321+
}
310322
let (attach, additionalData) = try await serviceState.client.allocate(hostname: hostname, macAddress: macAddress?.description)
311-
return AllocatedNetwork(
323+
return AllocatedAttachment(
312324
attachment: attach,
313325
additionalData: additionalData,
314-
pluginInfo: serviceState.networkState.pluginInfo
326+
pluginInfo: pluginInfo
315327
)
316328
}
317329

@@ -322,19 +334,26 @@ public actor NetworksService {
322334
return try await serviceState.client.deallocate(hostname: attachment.hostname)
323335
}
324336

325-
private static func getClient(configuration: NetworkConfiguration) -> NetworkClient {
326-
NetworkClient(id: configuration.id, plugin: configuration.pluginInfo.plugin)
337+
private static func getClient(configuration: NetworkConfiguration) throws -> NetworkClient {
338+
guard let pluginInfo = configuration.pluginInfo else {
339+
throw ContainerizationError(.internalError, message: "network \(configuration.id) missing plugin information")
340+
}
341+
return NetworkClient(id: configuration.id, plugin: pluginInfo.plugin)
327342
}
328343

329344
private func registerService(configuration: NetworkConfiguration) async throws {
330345
guard configuration.mode == .nat || configuration.mode == .hostOnly else {
331346
throw ContainerizationError(.invalidArgument, message: "unsupported network mode \(configuration.mode.rawValue)")
332347
}
333348

334-
guard let networkPlugin = self.networkPlugins.first(where: { $0.name == configuration.pluginInfo.plugin }) else {
349+
guard let pluginInfo = configuration.pluginInfo else {
350+
throw ContainerizationError(.internalError, message: "network \(configuration.id) missing plugin information")
351+
}
352+
353+
guard let networkPlugin = self.networkPlugins.first(where: { $0.name == pluginInfo.plugin }) else {
335354
throw ContainerizationError(
336355
.notFound,
337-
message: "unable to locate network plugin \(configuration.pluginInfo.plugin)"
356+
message: "unable to locate network plugin \(pluginInfo.plugin)"
338357
)
339358
}
340359

@@ -391,7 +410,7 @@ public actor NetworksService {
391410
args += ["--subnet-v6", ipv6Subnet.description]
392411
}
393412

394-
if let variant = configuration.pluginInfo.variant {
413+
if let variant = configuration.pluginInfo?.variant {
395414
args += ["--variant", variant]
396415
}
397416

@@ -404,10 +423,13 @@ public actor NetworksService {
404423
}
405424

406425
private func deregisterService(configuration: NetworkConfiguration) async throws {
407-
guard let networkPlugin = self.networkPlugins.first(where: { $0.name == configuration.pluginInfo.plugin }) else {
426+
guard let pluginInfo = configuration.pluginInfo else {
427+
throw ContainerizationError(.internalError, message: "network \(configuration.id) missing plugin information")
428+
}
429+
guard let networkPlugin = self.networkPlugins.first(where: { $0.name == pluginInfo.plugin }) else {
408430
throw ContainerizationError(
409431
.notFound,
410-
message: "unable to locate network plugin \(configuration.pluginInfo.plugin)"
432+
message: "unable to locate network plugin \(pluginInfo.plugin)"
411433
)
412434
}
413435
try self.pluginLoader.deregisterWithLaunchd(plugin: networkPlugin, instanceId: configuration.id)

Sources/Services/ContainerSandboxService/Client/SandboxClient.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public struct SandboxClient: Sendable {
7777

7878
// Runtime Methods
7979
extension SandboxClient {
80-
public func bootstrap(stdio: [FileHandle?], allocatedNetworks: [AllocatedNetwork]) async throws {
80+
public func bootstrap(stdio: [FileHandle?], allocatedAttachments: [AllocatedAttachment]) async throws {
8181
let request = XPCMessage(route: SandboxRoutes.bootstrap.rawValue)
8282

8383
for (i, h) in stdio.enumerated() {
@@ -97,7 +97,7 @@ extension SandboxClient {
9797
}
9898

9999
do {
100-
try request.setAllocatedNetworks(allocatedNetworks)
100+
try request.setAllocatedAttachments(allocatedAttachments)
101101
try await self.client.send(request)
102102
} catch {
103103
throw ContainerizationError(
@@ -325,23 +325,23 @@ extension XPCMessage {
325325
return try JSONDecoder().decode(SandboxSnapshot.self, from: data)
326326
}
327327

328-
func setAllocatedNetworks(_ networks: [AllocatedNetwork]) throws {
328+
func setAllocatedAttachments(_ allocatedAttachments: [AllocatedAttachment]) throws {
329329
let encoder = JSONEncoder()
330-
for net in networks {
330+
for allocatedAttach in allocatedAttachments {
331331
let xpcObject: xpc_object_t = xpc_dictionary_create_empty()
332332
let networkXPC = XPCMessage(object: xpcObject)
333333

334-
let attachmentEncoded = try encoder.encode(net.attachment)
334+
let attachmentEncoded = try encoder.encode(allocatedAttach.attachment)
335335
networkXPC.set(key: SandboxKeys.networkAttachment.rawValue, value: attachmentEncoded)
336336

337-
let pluginInfoEncoded = try encoder.encode(net.pluginInfo)
337+
let pluginInfoEncoded = try encoder.encode(allocatedAttach.pluginInfo)
338338
networkXPC.set(key: SandboxKeys.networkPluginInfo.rawValue, value: pluginInfoEncoded)
339339

340-
if let additionalData = net.additionalData {
340+
if let additionalData = allocatedAttach.additionalData {
341341
xpc_dictionary_set_value(networkXPC.underlying, SandboxKeys.networkAdditionalData.rawValue, additionalData.underlying)
342342
}
343343

344-
self.set(key: "\(SandboxKeys.networkAllocated.rawValue)_\(net.attachment.network)", value: networkXPC.underlying)
344+
self.set(key: "\(SandboxKeys.networkAllocated.rawValue)_\(allocatedAttach.attachment.network)", value: networkXPC.underlying)
345345
}
346346
}
347347
}

0 commit comments

Comments
 (0)