mirror of
https://github.com/apple/container.git
synced 2026-08-28 03:16:29 +00:00
Remove network variant computation from API server. (#1814)
- Closes #1812. - The network plugin is the source of truth for the variant, if any, that applies to the network. Resolving a missing variant configuration option in the API server can create a situation where the variant the runtime uses for interface selection is incorrect. - Adds serial suites trait to tests to see whether it helps current CI issues. ## Type of Change - [x] Bug fix - [ ] New feature - [ ] Breaking change - [ ] Documentation update ## Motivation and Context Fixes a flaw in our interface strategy logic. ## Testing - [x] Tested locally - [ ] Added/updated tests - [ ] Added/updated docs
This commit is contained in:
@@ -33,6 +33,8 @@ public struct Attachment: Codable, Sendable {
|
||||
public let macAddress: MACAddress?
|
||||
/// The MTU for the network interface.
|
||||
public let mtu: UInt32?
|
||||
/// The network plugin variant, used by the runtime to select an interface strategy.
|
||||
public let variant: String?
|
||||
|
||||
public init(
|
||||
network: String,
|
||||
@@ -41,7 +43,8 @@ public struct Attachment: Codable, Sendable {
|
||||
ipv4Gateway: IPv4Address,
|
||||
ipv6Address: CIDRv6?,
|
||||
macAddress: MACAddress?,
|
||||
mtu: UInt32? = nil
|
||||
mtu: UInt32? = nil,
|
||||
variant: String? = nil
|
||||
) {
|
||||
self.network = network
|
||||
self.hostname = hostname
|
||||
@@ -50,6 +53,7 @@ public struct Attachment: Codable, Sendable {
|
||||
self.ipv6Address = ipv6Address
|
||||
self.macAddress = macAddress
|
||||
self.mtu = mtu
|
||||
self.variant = variant
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
@@ -60,6 +64,7 @@ public struct Attachment: Codable, Sendable {
|
||||
case ipv6Address
|
||||
case macAddress
|
||||
case mtu
|
||||
case variant
|
||||
// TODO: retain for deserialization compatibility for now, remove later
|
||||
case address
|
||||
case gateway
|
||||
@@ -85,6 +90,7 @@ public struct Attachment: Codable, Sendable {
|
||||
ipv6Address = try container.decodeIfPresent(CIDRv6.self, forKey: .ipv6Address)
|
||||
macAddress = try container.decodeIfPresent(MACAddress.self, forKey: .macAddress)
|
||||
mtu = try container.decodeIfPresent(UInt32.self, forKey: .mtu)
|
||||
variant = try container.decodeIfPresent(String.self, forKey: .variant)
|
||||
}
|
||||
|
||||
/// Encode the configuration to the supplied Encoder.
|
||||
@@ -98,5 +104,6 @@ public struct Attachment: Codable, Sendable {
|
||||
try container.encodeIfPresent(ipv6Address, forKey: .ipv6Address)
|
||||
try container.encodeIfPresent(macAddress, forKey: .macAddress)
|
||||
try container.encodeIfPresent(mtu, forKey: .mtu)
|
||||
try container.encodeIfPresent(variant, forKey: .variant)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,10 +422,10 @@ public actor ContainersService {
|
||||
|
||||
var networkBootstrapInfos = [NetworkBootstrapInfo]()
|
||||
for n in config.networks {
|
||||
guard let (plugin, options) = try await self.networksService?.pluginConfiguration(id: n.network) else {
|
||||
throw ContainerizationError(.internalError, message: "failed to get plugin configuration for network \(n.network)")
|
||||
guard let plugin = try await self.networksService?.plugin(for: n.network) else {
|
||||
throw ContainerizationError(.internalError, message: "failed to get plugin for network \(n.network)")
|
||||
}
|
||||
networkBootstrapInfos.append(NetworkBootstrapInfo(plugin: plugin, options: options))
|
||||
networkBootstrapInfos.append(NetworkBootstrapInfo(plugin: plugin))
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
@@ -314,19 +314,11 @@ public actor NetworksService {
|
||||
}
|
||||
}
|
||||
|
||||
public func pluginConfiguration(id: String) throws -> (plugin: String, options: [String: String]) {
|
||||
public func plugin(for id: String) throws -> String {
|
||||
guard let serviceState = serviceStates[id] else {
|
||||
throw ContainerizationError(.notFound, message: "no network for id \(id)")
|
||||
}
|
||||
var options = serviceState.configuration.options
|
||||
if options["variant"] == nil {
|
||||
if #available(macOS 26, *) {
|
||||
options["variant"] = "reserved"
|
||||
} else {
|
||||
options["variant"] = "allocationOnly"
|
||||
}
|
||||
}
|
||||
return (plugin: serviceState.configuration.plugin, options: options)
|
||||
return serviceState.configuration.plugin
|
||||
}
|
||||
|
||||
private static func getClient(configuration: NetworkConfiguration) throws -> ContainerNetworkClient.NetworkClient {
|
||||
|
||||
@@ -77,7 +77,8 @@ public actor DefaultNetworkService: NetworkService {
|
||||
ipv4Address: try CIDRv4(ip, prefix: status.ipv4Subnet.prefix),
|
||||
ipv4Gateway: status.ipv4Gateway,
|
||||
ipv6Address: ipv6Address,
|
||||
macAddress: macAddress
|
||||
macAddress: macAddress,
|
||||
variant: network.variant
|
||||
)
|
||||
log.info(
|
||||
"allocated attachment",
|
||||
@@ -146,7 +147,8 @@ public actor DefaultNetworkService: NetworkService {
|
||||
ipv4Address: ipv4Address,
|
||||
ipv4Gateway: status.ipv4Gateway,
|
||||
ipv6Address: ipv6Address,
|
||||
macAddress: macAddress
|
||||
macAddress: macAddress,
|
||||
variant: network.variant
|
||||
)
|
||||
log.debug(
|
||||
"lookup attachment",
|
||||
|
||||
@@ -22,6 +22,12 @@ public protocol Network: Sendable {
|
||||
/// The network's identifier.
|
||||
var id: String { get }
|
||||
|
||||
/// An operational hint passed back to the runtime in the allocate response.
|
||||
/// Together with the plugin name, the runtime uses this to select the appropriate
|
||||
/// interface strategy for the sandbox. A `nil` value indicates that the plugin
|
||||
/// has only a single, default variant.
|
||||
nonisolated var variant: String? { get }
|
||||
|
||||
/// The network's runtime status. `nil` before ``start()`` completes.
|
||||
var status: NetworkStatus? { get async }
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ public actor AllocationOnlyVmnetNetwork: Network {
|
||||
|
||||
public nonisolated var id: String { configuration.id }
|
||||
|
||||
public nonisolated var variant: String? { "allocationOnly" }
|
||||
|
||||
public var status: NetworkStatus? { _status }
|
||||
|
||||
public nonisolated func withAdditionalData(_ handler: (XPCMessage?) throws -> Void) throws {
|
||||
|
||||
@@ -63,6 +63,8 @@ public final class ReservedVmnetNetwork: ContainerNetworkServer.Network {
|
||||
|
||||
public nonisolated var id: String { configuration.id }
|
||||
|
||||
public nonisolated var variant: String? { "reserved" }
|
||||
|
||||
public var status: NetworkStatus? {
|
||||
stateMutex.withLock { $0.status }
|
||||
}
|
||||
|
||||
@@ -17,16 +17,12 @@
|
||||
import ContainerResource
|
||||
|
||||
/// Plugin info passed from the API server in the sandbox bootstrap message so the
|
||||
/// runtime can connect to the correct network helper and configure the interface.
|
||||
/// runtime can connect to the correct network helper.
|
||||
public struct NetworkBootstrapInfo: Codable, Sendable {
|
||||
/// The network plugin name identifying which network helper to contact.
|
||||
public let plugin: String
|
||||
|
||||
/// Plugin-specific options, including `variant` which selects the interface strategy.
|
||||
public let options: [String: String]
|
||||
|
||||
public init(plugin: String, options: [String: String] = [:]) {
|
||||
public init(plugin: String) {
|
||||
self.plugin = plugin
|
||||
self.options = options
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,13 +193,14 @@ public actor RuntimeService {
|
||||
ipv4Gateway: attachment.ipv4Gateway,
|
||||
ipv6Address: attachment.ipv6Address,
|
||||
macAddress: attachment.macAddress,
|
||||
mtu: mtu
|
||||
mtu: mtu,
|
||||
variant: attachment.variant
|
||||
)
|
||||
}
|
||||
guard let iStrategy = self.interfaceStrategies[NetworkInterfaceKey(plugin: info.plugin, variant: info.options["variant"])] else {
|
||||
guard let iStrategy = self.interfaceStrategies[NetworkInterfaceKey(plugin: info.plugin, variant: attachment.variant)] else {
|
||||
throw ContainerizationError(
|
||||
.internalError,
|
||||
message: "no available interface strategy for network \(attachment.network), plugin=\(info.plugin) variant=\(info.options["variant"] ?? "nil")")
|
||||
message: "no available interface strategy for network \(attachment.network), plugin=\(info.plugin) variant=\(attachment.variant ?? "nil")")
|
||||
}
|
||||
let interface = try iStrategy.toInterface(
|
||||
attachment: attachment,
|
||||
|
||||
Reference in New Issue
Block a user