mirror of
https://github.com/apple/container.git
synced 2026-08-24 10:05:43 -05:00
Use new IP/CIDR types from Containerization. (#957)
- Part of work for #460. - With CZ release 0.17.0, the IP and CIDR address types changed from String to IPv4Address and CIDRv4, respectively. This PR applies the corresponding adaptations to container.
This commit is contained in:
+3
-3
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"originHash" : "a20d52336b96991c23765c8301254aeff44ab33c0ccc7dee59191e50652f5070",
|
||||
"originHash" : "64cb422fa3914611343af4301e317573002890fea7d174e550cc937a76571515",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "async-http-client",
|
||||
@@ -15,8 +15,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/containerization.git",
|
||||
"state" : {
|
||||
"revision" : "e8aff29be3b97afa18ccc256126466ae5e611bea",
|
||||
"version" : "0.16.2"
|
||||
"revision" : "9ba8267afbdff66e5ddce180312abdb41395292f",
|
||||
"version" : "0.17.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+2
-1
@@ -23,7 +23,7 @@ import PackageDescription
|
||||
let releaseVersion = ProcessInfo.processInfo.environment["RELEASE_VERSION"] ?? "0.0.0"
|
||||
let gitCommit = ProcessInfo.processInfo.environment["GIT_COMMIT"] ?? "unspecified"
|
||||
let builderShimVersion = "0.7.0"
|
||||
let scVersion = "0.16.2"
|
||||
let scVersion = "0.17.0"
|
||||
|
||||
let package = Package(
|
||||
name: "container",
|
||||
@@ -146,6 +146,7 @@ let package = Package(
|
||||
dependencies: [
|
||||
.product(name: "Logging", package: "swift-log"),
|
||||
.product(name: "Containerization", package: "containerization"),
|
||||
.product(name: "ContainerizationExtras", package: "containerization"),
|
||||
.product(name: "ContainerizationOS", package: "containerization"),
|
||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||
"ContainerClient",
|
||||
|
||||
@@ -230,8 +230,8 @@ extension Application {
|
||||
throw ContainerizationError(.invalidState, message: "default network is not running")
|
||||
}
|
||||
config.networks = [AttachmentConfiguration(network: network.id, options: AttachmentOptions(hostname: id))]
|
||||
let subnet = try CIDRAddress(networkStatus.address)
|
||||
let nameserver = IPv4Address(fromValue: subnet.lower.value + 1).description
|
||||
let subnet = networkStatus.ipv4Subnet
|
||||
let nameserver = IPv4Address(subnet.lower.value + 1).description
|
||||
let nameservers = [nameserver]
|
||||
config.dns = ContainerConfiguration.DNSConfiguration(nameservers: nameservers)
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ extension ClientContainer {
|
||||
self.id,
|
||||
self.configuration.image.reference,
|
||||
self.status.rawValue,
|
||||
self.networks.compactMap { try? CIDRAddress($0.address).address.description }.joined(separator: ","),
|
||||
self.networks.compactMap { $0.ipv4Address.description }.joined(separator: ","),
|
||||
"\(self.configuration.resources.cpus)",
|
||||
"\(self.configuration.resources.memoryInBytes / (1024 * 1024)) MB",
|
||||
]
|
||||
|
||||
@@ -94,7 +94,7 @@ extension ClientContainer {
|
||||
self.configuration.platform.os,
|
||||
self.configuration.platform.architecture,
|
||||
self.status.rawValue,
|
||||
self.networks.compactMap { try? CIDRAddress($0.address).address.description }.joined(separator: ","),
|
||||
self.networks.compactMap { $0.ipv4Address.description }.joined(separator: ","),
|
||||
"\(self.configuration.resources.cpus)",
|
||||
"\(self.configuration.resources.memoryInBytes / (1024 * 1024)) MB",
|
||||
]
|
||||
|
||||
@@ -18,6 +18,7 @@ import ArgumentParser
|
||||
import ContainerClient
|
||||
import ContainerNetworkService
|
||||
import ContainerizationError
|
||||
import ContainerizationExtras
|
||||
import Foundation
|
||||
import TerminalProgress
|
||||
|
||||
@@ -43,7 +44,8 @@ extension Application {
|
||||
|
||||
public func run() async throws {
|
||||
let parsedLabels = Utility.parseKeyValuePairs(labels)
|
||||
let config = try NetworkConfiguration(id: self.name, mode: .nat, subnet: subnet, labels: parsedLabels)
|
||||
let ipv4Subnet = try subnet.map { try CIDRv4($0) }
|
||||
let config = try NetworkConfiguration(id: self.name, mode: .nat, ipv4Subnet: ipv4Subnet, labels: parsedLabels)
|
||||
let state = try await ClientNetwork.create(configuration: config)
|
||||
print(state.id)
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ extension NetworkState {
|
||||
case .created(_):
|
||||
return [self.id, self.state, "none"]
|
||||
case .running(_, let status):
|
||||
return [self.id, self.state, status.address]
|
||||
return [self.id, self.state, status.ipv4Subnet.description]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ extension Application {
|
||||
DefaultsStore.set(value: value, key: key)
|
||||
return
|
||||
case .defaultSubnet:
|
||||
guard (try? CIDRAddress(value)) != nil else {
|
||||
guard (try? CIDRv4(value)) != nil else {
|
||||
throw ContainerizationError(.invalidArgument, message: "invalid CIDRv4 address: \(value)")
|
||||
}
|
||||
DefaultsStore.set(value: value, key: key)
|
||||
|
||||
@@ -94,15 +94,9 @@ struct ContainerDNSHandler: DNSHandler {
|
||||
guard let ipAllocation = try await networkService.lookup(hostname: question.name) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let components = ipAllocation.address.split(separator: "/")
|
||||
guard !components.isEmpty else {
|
||||
throw DNSResolverError.serverError("invalid IP format: empty address")
|
||||
}
|
||||
|
||||
let ipString = String(components[0])
|
||||
guard let ip = IPv4(ipString) else {
|
||||
throw DNSResolverError.serverError("failed to parse IP address: \(ipString)")
|
||||
let ipv4 = ipAllocation.ipv4Address.address.description
|
||||
guard let ip = IPv4(ipv4) else {
|
||||
throw DNSResolverError.serverError("failed to parse IP address: \(ipv4)")
|
||||
}
|
||||
|
||||
return HostRecord<IPv4>(name: question.name, ttl: ttl, ip: ip)
|
||||
|
||||
@@ -50,8 +50,8 @@ extension NetworkVmnetHelper {
|
||||
|
||||
do {
|
||||
log.info("configuring XPC server")
|
||||
let subnet = try self.subnet.map { try CIDRAddress($0) }
|
||||
let configuration = try NetworkConfiguration(id: id, mode: .nat, subnet: subnet?.description)
|
||||
let ipv4Subnet = try self.subnet.map { try CIDRv4($0) }
|
||||
let configuration = try NetworkConfiguration(id: id, mode: .nat, ipv4Subnet: ipv4Subnet)
|
||||
let network = try Self.createNetwork(configuration: configuration, log: log)
|
||||
try await network.start()
|
||||
let server = try await NetworkService(network: network, log: log)
|
||||
|
||||
@@ -24,7 +24,7 @@ import Containerization
|
||||
/// works for macOS Sequoia.
|
||||
struct IsolatedInterfaceStrategy: InterfaceStrategy {
|
||||
public func toInterface(attachment: Attachment, interfaceIndex: Int, additionalData: XPCMessage?) -> Interface {
|
||||
let gateway = interfaceIndex == 0 ? attachment.gateway : nil
|
||||
return NATInterface(address: attachment.address, gateway: gateway, macAddress: attachment.macAddress)
|
||||
let ipv4Gateway = interfaceIndex == 0 ? attachment.ipv4Gateway : nil
|
||||
return NATInterface(ipv4Address: attachment.ipv4Address, ipv4Gateway: ipv4Gateway, macAddress: attachment.macAddress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ struct NonisolatedInterfaceStrategy: InterfaceStrategy {
|
||||
}
|
||||
|
||||
log.info("creating NATNetworkInterface with network reference")
|
||||
let gateway = interfaceIndex == 0 ? attachment.gateway : nil
|
||||
return NATNetworkInterface(address: attachment.address, gateway: gateway, reference: networkRef, macAddress: attachment.macAddress)
|
||||
let ipv4Gateway = interfaceIndex == 0 ? attachment.ipv4Gateway : nil
|
||||
return NATNetworkInterface(ipv4Address: attachment.ipv4Address, ipv4Gateway: ipv4Gateway, reference: networkRef, macAddress: attachment.macAddress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,19 +283,24 @@ public actor NetworksService {
|
||||
serviceIdentifier,
|
||||
]
|
||||
|
||||
if let subnet = (try configuration.subnet.map { try CIDRAddress($0) }) {
|
||||
var existingCidrs: [CIDRAddress] = []
|
||||
if let ipv4Subnet = (configuration.ipv4Subnet.map { $0 }) {
|
||||
var existingCidrs: [CIDRv4] = []
|
||||
for networkState in networkStates.values {
|
||||
if case .running(_, let status) = networkState {
|
||||
existingCidrs.append(try CIDRAddress(status.address))
|
||||
existingCidrs.append(status.ipv4Subnet)
|
||||
}
|
||||
}
|
||||
let overlap = existingCidrs.first { $0.overlaps(cidr: subnet) }
|
||||
let overlap = existingCidrs.first {
|
||||
$0.contains(ipv4Subnet.lower)
|
||||
|| $0.contains(ipv4Subnet.upper)
|
||||
|| ipv4Subnet.contains($0.lower)
|
||||
|| ipv4Subnet.contains($0.upper)
|
||||
}
|
||||
if let overlap {
|
||||
throw ContainerizationError(.exists, message: "subnet \(subnet) overlaps an existing network with subnet \(overlap)")
|
||||
throw ContainerizationError(.exists, message: "IPv4 subnet \(ipv4Subnet) overlaps an existing network with subnet \(overlap)")
|
||||
}
|
||||
|
||||
args += ["--subnet", subnet.description]
|
||||
args += ["--subnet", ipv4Subnet.description]
|
||||
}
|
||||
|
||||
try await pluginLoader.registerWithLaunchd(
|
||||
|
||||
@@ -35,8 +35,8 @@ public actor AllocationOnlyVmnetNetwork: Network {
|
||||
throw ContainerizationError(.unsupported, message: "invalid network mode \(configuration.mode)")
|
||||
}
|
||||
|
||||
guard configuration.subnet == nil else {
|
||||
throw ContainerizationError(.unsupported, message: "subnet assignment is not yet implemented")
|
||||
guard configuration.ipv4Subnet == nil else {
|
||||
throw ContainerizationError(.unsupported, message: "IPv4 subnet assignment is not yet implemented")
|
||||
}
|
||||
|
||||
self.log = log
|
||||
@@ -65,9 +65,9 @@ public actor AllocationOnlyVmnetNetwork: Network {
|
||||
)
|
||||
|
||||
let subnet = DefaultsStore.get(key: .defaultSubnet)
|
||||
let subnetCIDR = try CIDRAddress(subnet)
|
||||
let gateway = IPv4Address(fromValue: subnetCIDR.lower.value + 1)
|
||||
self._state = .running(configuration, NetworkStatus(address: subnetCIDR.description, gateway: gateway.description))
|
||||
let subnetCIDR = try CIDRv4(subnet)
|
||||
let gateway = IPv4Address(subnetCIDR.lower.value + 1)
|
||||
self._state = .running(configuration, NetworkStatus(ipv4Subnet: subnetCIDR, ipv4Gateway: gateway))
|
||||
log.info(
|
||||
"started allocation-only network",
|
||||
metadata: [
|
||||
|
||||
@@ -14,24 +14,58 @@
|
||||
// limitations under the License.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import ContainerizationExtras
|
||||
|
||||
/// A snapshot of a network interface allocated to a sandbox.
|
||||
public struct Attachment: Codable, Sendable {
|
||||
/// The network ID associated with the attachment.
|
||||
public let network: String
|
||||
/// The hostname associated with the attachment.
|
||||
public let hostname: String
|
||||
/// The subnet CIDR, where the address is the container interface IPv4 address.
|
||||
public let address: String
|
||||
/// The CIDR address describing the interface IPv4 address, with the prefix length of the subnet.
|
||||
public let ipv4Address: CIDRv4
|
||||
/// The IPv4 gateway address.
|
||||
public let gateway: String
|
||||
public let ipv4Gateway: IPv4Address
|
||||
/// The MAC address associated with the attachment (optional).
|
||||
public let macAddress: String?
|
||||
|
||||
public init(network: String, hostname: String, address: String, gateway: String, macAddress: String? = nil) {
|
||||
public init(network: String, hostname: String, ipv4Address: CIDRv4, ipv4Gateway: IPv4Address, macAddress: String? = nil) {
|
||||
self.network = network
|
||||
self.hostname = hostname
|
||||
self.address = address
|
||||
self.gateway = gateway
|
||||
self.ipv4Address = ipv4Address
|
||||
self.ipv4Gateway = ipv4Gateway
|
||||
self.macAddress = macAddress
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case network
|
||||
case hostname
|
||||
case ipv4Address
|
||||
case ipv4Gateway
|
||||
case macAddress
|
||||
}
|
||||
|
||||
/// Create an attachment from the supplied Decoder.
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
network = try container.decode(String.self, forKey: .network)
|
||||
hostname = try container.decode(String.self, forKey: .hostname)
|
||||
let addressText = try container.decode(String.self, forKey: .ipv4Address)
|
||||
ipv4Address = try CIDRv4(addressText)
|
||||
let gatewayText = try container.decode(String.self, forKey: .ipv4Gateway)
|
||||
ipv4Gateway = try IPv4Address(gatewayText)
|
||||
macAddress = try container.decodeIfPresent(String.self, forKey: .macAddress)
|
||||
}
|
||||
|
||||
/// Encode the attachment to the supplied Encoder.
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(network, forKey: .network)
|
||||
try container.encode(hostname, forKey: .hostname)
|
||||
try container.encode(ipv4Address.description, forKey: .ipv4Address)
|
||||
try container.encode(ipv4Gateway.description, forKey: .ipv4Gateway)
|
||||
try container.encodeIfPresent(macAddress, forKey: .macAddress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ public struct NetworkConfiguration: Codable, Sendable, Identifiable {
|
||||
/// When the network was created.
|
||||
public let creationDate: Date
|
||||
|
||||
/// The preferred CIDR address for the subnet, if specified
|
||||
public let subnet: String?
|
||||
/// The preferred CIDR address for the IPv4 subnet, if specified
|
||||
public let ipv4Subnet: CIDRv4?
|
||||
|
||||
/// Key-value labels for the network.
|
||||
public var labels: [String: String] = [:]
|
||||
@@ -39,13 +39,13 @@ public struct NetworkConfiguration: Codable, Sendable, Identifiable {
|
||||
public init(
|
||||
id: String,
|
||||
mode: NetworkMode,
|
||||
subnet: String? = nil,
|
||||
ipv4Subnet: CIDRv4? = nil,
|
||||
labels: [String: String] = [:]
|
||||
) throws {
|
||||
self.id = id
|
||||
self.creationDate = Date()
|
||||
self.mode = mode
|
||||
self.subnet = subnet
|
||||
self.ipv4Subnet = ipv4Subnet
|
||||
self.labels = labels
|
||||
try validate()
|
||||
}
|
||||
@@ -54,8 +54,10 @@ public struct NetworkConfiguration: Codable, Sendable, Identifiable {
|
||||
case id
|
||||
case creationDate
|
||||
case mode
|
||||
case subnet
|
||||
case ipv4Subnet
|
||||
case labels
|
||||
// TODO: retain for deserialization compatability for now, remove later
|
||||
case subnet
|
||||
}
|
||||
|
||||
/// Create a configuration from the supplied Decoder, initializing missing
|
||||
@@ -66,20 +68,30 @@ public struct NetworkConfiguration: Codable, Sendable, Identifiable {
|
||||
id = try container.decode(String.self, forKey: .id)
|
||||
creationDate = try container.decodeIfPresent(Date.self, forKey: .creationDate) ?? Date(timeIntervalSince1970: 0)
|
||||
mode = try container.decode(NetworkMode.self, forKey: .mode)
|
||||
subnet = try container.decodeIfPresent(String.self, forKey: .subnet)
|
||||
let subnetText =
|
||||
try container.decodeIfPresent(String.self, forKey: .ipv4Subnet)
|
||||
?? container.decodeIfPresent(String.self, forKey: .subnet)
|
||||
ipv4Subnet = try subnetText.map { try CIDRv4($0) }
|
||||
labels = try container.decodeIfPresent([String: String].self, forKey: .labels) ?? [:]
|
||||
try validate()
|
||||
}
|
||||
|
||||
/// Encode the configuration to the supplied Encoder.
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(id, forKey: .id)
|
||||
try container.encode(creationDate, forKey: .creationDate)
|
||||
try container.encode(mode, forKey: .mode)
|
||||
try container.encodeIfPresent(ipv4Subnet?.description, forKey: .ipv4Subnet)
|
||||
try container.encode(labels, forKey: .labels)
|
||||
}
|
||||
|
||||
private func validate() throws {
|
||||
guard id.isValidNetworkID() else {
|
||||
throw ContainerizationError(.invalidArgument, message: "invalid network ID: \(id)")
|
||||
}
|
||||
|
||||
if let subnet {
|
||||
_ = try CIDRAddress(subnet)
|
||||
}
|
||||
|
||||
for (key, value) in labels {
|
||||
try validateLabel(key: key, value: value)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public actor NetworkService: Sendable {
|
||||
throw ContainerizationError(.invalidState, message: "invalid network state - network \(state.id) must be running")
|
||||
}
|
||||
|
||||
let subnet = try CIDRAddress(status.address)
|
||||
let subnet = status.ipv4Subnet
|
||||
|
||||
let size = Int(subnet.upper.value - subnet.lower.value - 3)
|
||||
self.allocator = try AttachmentAllocator(lower: subnet.lower.value + 2, size: size)
|
||||
@@ -61,21 +61,21 @@ public actor NetworkService: Sendable {
|
||||
let hostname = try message.hostname()
|
||||
let macAddress = message.string(key: NetworkKeys.macAddress.rawValue)
|
||||
let index = try await allocator.allocate(hostname: hostname)
|
||||
let subnet = try CIDRAddress(status.address)
|
||||
let ip = IPv4Address(fromValue: index)
|
||||
let subnet = status.ipv4Subnet
|
||||
let ip = IPv4Address(index)
|
||||
let attachment = Attachment(
|
||||
network: state.id,
|
||||
hostname: hostname,
|
||||
address: try CIDRAddress(ip, prefixLength: subnet.prefixLength).description,
|
||||
gateway: status.gateway,
|
||||
ipv4Address: try CIDRv4(ip, prefix: subnet.prefix),
|
||||
ipv4Gateway: status.ipv4Gateway,
|
||||
macAddress: macAddress
|
||||
)
|
||||
log?.info(
|
||||
"allocated attachment",
|
||||
metadata: [
|
||||
"hostname": "\(hostname)",
|
||||
"address": "\(attachment.address)",
|
||||
"gateway": "\(attachment.gateway)",
|
||||
"ipv4Address": "\(attachment.ipv4Address)",
|
||||
"ipv4Gateway": "\(attachment.ipv4Gateway)",
|
||||
"macAddress": "\(macAddress ?? "auto")",
|
||||
])
|
||||
let reply = message.reply()
|
||||
@@ -110,13 +110,13 @@ public actor NetworkService: Sendable {
|
||||
return reply
|
||||
}
|
||||
|
||||
let address = IPv4Address(fromValue: index)
|
||||
let subnet = try CIDRAddress(status.address)
|
||||
let address = IPv4Address(index)
|
||||
let subnet = status.ipv4Subnet
|
||||
let attachment = Attachment(
|
||||
network: state.id,
|
||||
hostname: hostname,
|
||||
address: try CIDRAddress(address, prefixLength: subnet.prefixLength).description,
|
||||
gateway: status.gateway
|
||||
ipv4Address: try CIDRv4(address, prefix: subnet.prefix),
|
||||
ipv4Gateway: status.ipv4Gateway
|
||||
)
|
||||
log?.debug(
|
||||
"lookup attachment",
|
||||
|
||||
@@ -14,21 +14,45 @@
|
||||
// limitations under the License.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import ContainerizationExtras
|
||||
import Foundation
|
||||
|
||||
public struct NetworkStatus: Codable, Sendable {
|
||||
/// The address allocated for the network if no subnet was specified at
|
||||
/// creation time; otherwise, the subnet from the configuration.
|
||||
public let address: String
|
||||
public let ipv4Subnet: CIDRv4
|
||||
/// The gateway IPv4 address.
|
||||
public let gateway: String
|
||||
public let ipv4Gateway: IPv4Address
|
||||
|
||||
public init(
|
||||
address: String,
|
||||
gateway: String
|
||||
ipv4Subnet: CIDRv4,
|
||||
ipv4Gateway: IPv4Address
|
||||
) {
|
||||
self.address = address
|
||||
self.gateway = gateway
|
||||
self.ipv4Subnet = ipv4Subnet
|
||||
self.ipv4Gateway = ipv4Gateway
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case ipv4Subnet
|
||||
case ipv4Gateway
|
||||
}
|
||||
|
||||
/// Create a network status from the supplied Decoder.
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
let addressText = try container.decode(String.self, forKey: .ipv4Subnet)
|
||||
ipv4Subnet = try CIDRv4(addressText)
|
||||
let gatewayText = try container.decode(String.self, forKey: .ipv4Gateway)
|
||||
ipv4Gateway = try IPv4Address(gatewayText)
|
||||
}
|
||||
|
||||
/// Encode the network status to the supplied Encoder.
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(ipv4Subnet.description, forKey: .ipv4Subnet)
|
||||
try container.encode(ipv4Gateway.description, forKey: .ipv4Gateway)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ public final class ReservedVmnetNetwork: Network {
|
||||
|
||||
private struct NetworkInfo {
|
||||
let network: vmnet_network_ref
|
||||
let subnet: CIDRAddress
|
||||
let gateway: IPv4Address
|
||||
let ipv4Subnet: CIDRv4
|
||||
let ipv4Gateway: IPv4Address
|
||||
}
|
||||
|
||||
private let stateMutex: Mutex<State>
|
||||
@@ -79,7 +79,7 @@ public final class ReservedVmnetNetwork: Network {
|
||||
|
||||
let networkInfo = try startNetwork(configuration: configuration, log: log)
|
||||
|
||||
let networkStatus = NetworkStatus(address: networkInfo.subnet.description, gateway: networkInfo.gateway.description)
|
||||
let networkStatus = NetworkStatus(ipv4Subnet: networkInfo.ipv4Subnet, ipv4Gateway: networkInfo.ipv4Gateway)
|
||||
state.networkState = NetworkState.running(configuration, networkStatus)
|
||||
state.network = networkInfo.network
|
||||
}
|
||||
@@ -101,10 +101,10 @@ public final class ReservedVmnetNetwork: Network {
|
||||
"mode": "\(configuration.mode)",
|
||||
]
|
||||
)
|
||||
let subnetText = configuration.subnet ?? DefaultsStore.getOptional(key: .defaultSubnet)
|
||||
|
||||
// with the reservation API, subnet priority is CLI argument, UserDefault, auto
|
||||
let subnet = try subnetText.map { try CIDRAddress($0) }
|
||||
let defaultSubnet = try DefaultsStore.getOptional(key: .defaultSubnet).map { try CIDRv4($0) }
|
||||
let subnet = configuration.ipv4Subnet ?? defaultSubnet
|
||||
|
||||
// set up the vmnet configuration
|
||||
var status: vmnet_return_t = .VMNET_SUCCESS
|
||||
@@ -116,10 +116,10 @@ public final class ReservedVmnetNetwork: Network {
|
||||
|
||||
// set the subnet if the caller provided one
|
||||
if let subnet {
|
||||
let gateway = IPv4Address(fromValue: subnet.lower.value + 1)
|
||||
let gateway = IPv4Address(subnet.lower.value + 1)
|
||||
var gatewayAddr = in_addr()
|
||||
inet_pton(AF_INET, gateway.description, &gatewayAddr)
|
||||
let mask = IPv4Address(fromValue: subnet.prefixLength.prefixMask32)
|
||||
let mask = IPv4Address(subnet.prefix.prefixMask32)
|
||||
var maskAddr = in_addr()
|
||||
inet_pton(AF_INET, mask.description, &maskAddr)
|
||||
log.info(
|
||||
@@ -143,10 +143,10 @@ public final class ReservedVmnetNetwork: Network {
|
||||
vmnet_network_get_ipv4_subnet(network, &subnetAddr, &maskAddr)
|
||||
let subnetValue = UInt32(bigEndian: subnetAddr.s_addr)
|
||||
let maskValue = UInt32(bigEndian: maskAddr.s_addr)
|
||||
let lower = IPv4Address(fromValue: subnetValue & maskValue)
|
||||
let upper = IPv4Address(fromValue: lower.value + ~maskValue)
|
||||
let runningSubnet = try CIDRAddress(lower: lower, upper: upper)
|
||||
let runningGateway = IPv4Address(fromValue: runningSubnet.lower.value + 1)
|
||||
let lower = IPv4Address(subnetValue & maskValue)
|
||||
let upper = IPv4Address(lower.value + ~maskValue)
|
||||
let runningSubnet = try CIDRv4(lower: lower, upper: upper)
|
||||
let runningGateway = IPv4Address(runningSubnet.lower.value + 1)
|
||||
|
||||
log.info(
|
||||
"started vmnet network",
|
||||
@@ -157,6 +157,6 @@ public final class ReservedVmnetNetwork: Network {
|
||||
]
|
||||
)
|
||||
|
||||
return NetworkInfo(network: network, subnet: runningSubnet, gateway: runningGateway)
|
||||
return NetworkInfo(network: network, ipv4Subnet: runningSubnet, ipv4Gateway: runningGateway)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,11 +190,10 @@ public actor SandboxService {
|
||||
// a default /etc/hosts.
|
||||
var hostsEntries = [Hosts.Entry.localHostIPV4()]
|
||||
if !interfaces.isEmpty {
|
||||
let primaryIfaceAddr = interfaces[0].address
|
||||
let ip = primaryIfaceAddr.split(separator: "/")
|
||||
let primaryIfaceAddr = interfaces[0].ipv4Address
|
||||
hostsEntries.append(
|
||||
Hosts.Entry(
|
||||
ipAddress: String(ip[0]),
|
||||
ipAddress: primaryIfaceAddr.address.description,
|
||||
hostnames: [czConfig.hostname],
|
||||
))
|
||||
}
|
||||
@@ -215,7 +214,7 @@ public actor SandboxService {
|
||||
try await container.create()
|
||||
try await self.monitor.registerProcess(id: config.id, onExit: self.onContainerExit)
|
||||
if !container.interfaces.isEmpty {
|
||||
let firstCidr = try CIDRAddress(container.interfaces[0].address)
|
||||
let firstCidr = container.interfaces[0].ipv4Address
|
||||
let ipAddress = firstCidr.address.description
|
||||
try await self.startSocketForwarders(containerIpAddress: ipAddress, publishedPorts: config.publishedPorts)
|
||||
}
|
||||
@@ -865,7 +864,7 @@ public actor SandboxService {
|
||||
guard case .running(_, let status) = state else {
|
||||
continue
|
||||
}
|
||||
return status.gateway
|
||||
return status.ipv4Gateway.description
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -81,6 +81,11 @@ extension ConnectHandler {
|
||||
.whenComplete { result in
|
||||
switch result {
|
||||
case .success(let channel):
|
||||
guard context.channel.isActive else {
|
||||
self.log?.trace("backend - frontend channel closed, closing backend connection")
|
||||
context.channel.close(promise: nil)
|
||||
return
|
||||
}
|
||||
self.log?.trace("backend - connected")
|
||||
self.glue(channel, context: context)
|
||||
case .failure(let error):
|
||||
|
||||
@@ -61,7 +61,7 @@ class TestCLINetwork: CLITest {
|
||||
|
||||
let container = try inspectContainer(name)
|
||||
#expect(container.networks.count > 0)
|
||||
let cidrAddress = try CIDRAddress(container.networks[0].address)
|
||||
let cidrAddress = container.networks[0].ipv4Address
|
||||
let url = "http://\(cidrAddress.address):\(port)"
|
||||
var request = HTTPClientRequest(url: url)
|
||||
request.method = .GET
|
||||
|
||||
@@ -400,9 +400,8 @@ class TestCLIRunCommand: CLITest {
|
||||
.map { $0.joined(separator: " ") }
|
||||
|
||||
let inspectOutput = try inspectContainer(name)
|
||||
let ip = String(inspectOutput.networks[0].address.split(separator: "/")[0])
|
||||
let ipv4Address = try IPv4Address(ip)
|
||||
let expectedNameserver = IPv4Address(fromValue: ipv4Address.prefix(prefixLength: 24).value + 1).description
|
||||
let ip = inspectOutput.networks[0].ipv4Address.address
|
||||
let expectedNameserver = IPv4Address((ip.value & Prefix(length: 24)!.prefixMask32) + 1).description
|
||||
let defaultDomain = try getDefaultDomain()
|
||||
let expectedLines: [String] = [
|
||||
"nameserver \(expectedNameserver)",
|
||||
@@ -463,12 +462,12 @@ class TestCLIRunCommand: CLITest {
|
||||
}
|
||||
|
||||
let inspectOutput = try inspectContainer(name)
|
||||
let ip = String(inspectOutput.networks[0].address.split(separator: "/")[0])
|
||||
let ip = inspectOutput.networks[0].ipv4Address.address
|
||||
|
||||
let output = try doExec(name: name, cmd: ["cat", "/etc/hosts"])
|
||||
let lines = output.split(separator: "\n")
|
||||
|
||||
let expectedEntries = [("127.0.0.1", "localhost"), (ip, name)]
|
||||
let expectedEntries = [("127.0.0.1", "localhost"), (ip.description, name)]
|
||||
|
||||
for (i, line) in lines.enumerated() {
|
||||
let words = line.split(separator: " ").map { String($0) }
|
||||
|
||||
@@ -33,12 +33,12 @@ struct NetworkConfigurationTest {
|
||||
"0-_.1",
|
||||
]
|
||||
for id in ids {
|
||||
let subnet = "192.168.64.1/24"
|
||||
let ipv4Subnet = try CIDRv4("192.168.64.1/24")
|
||||
let labels = [
|
||||
"foo": "bar",
|
||||
"baz": String(repeating: "0", count: 4096 - "baz".count - "=".count),
|
||||
]
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, subnet: subnet, labels: labels)
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, ipv4Subnet: ipv4Subnet, labels: labels)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,13 +50,13 @@ struct NetworkConfigurationTest {
|
||||
"Foo",
|
||||
]
|
||||
for id in ids {
|
||||
let subnet = "192.168.64.1/24"
|
||||
let ipv4Subnet = try CIDRv4("192.168.64.1/24")
|
||||
let labels = [
|
||||
"foo": "bar",
|
||||
"baz": String(repeating: "0", count: 4096 - "baz".count - "=".count),
|
||||
]
|
||||
#expect {
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, subnet: subnet, labels: labels)
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, ipv4Subnet: ipv4Subnet, labels: labels)
|
||||
} throws: { error in
|
||||
guard let err = error as? ContainerizationError else { return false }
|
||||
#expect(err.code == .invalidArgument)
|
||||
@@ -66,22 +66,6 @@ struct NetworkConfigurationTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testValidationBadSubnet() throws {
|
||||
let id = "foo"
|
||||
let subnet = "192.168.64.1"
|
||||
let labels = [
|
||||
"foo": "bar",
|
||||
"baz": String(repeating: "0", count: 4096 - "baz".count - "=".count),
|
||||
]
|
||||
#expect {
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, subnet: subnet, labels: labels)
|
||||
} throws: { error in
|
||||
guard let err = error as? NetworkAddressError else { return false }
|
||||
#expect(err.description.starts(with: "invalid CIDR block"))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testValidationGoodLabels() throws {
|
||||
let allLabels = [
|
||||
["com.example.my-label": "bar"],
|
||||
@@ -91,8 +75,8 @@ struct NetworkConfigurationTest {
|
||||
]
|
||||
for labels in allLabels {
|
||||
let id = "foo"
|
||||
let subnet = "192.168.64.1/24"
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, subnet: subnet, labels: labels)
|
||||
let ipv4Subnet = try CIDRv4("192.168.64.1/24")
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, ipv4Subnet: ipv4Subnet, labels: labels)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,9 +90,9 @@ struct NetworkConfigurationTest {
|
||||
]
|
||||
for labels in allLabels {
|
||||
let id = "foo"
|
||||
let subnet = "192.168.64.1/24"
|
||||
let ipv4Subnet = try CIDRv4("192.168.64.1/24")
|
||||
#expect {
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, subnet: subnet, labels: labels)
|
||||
_ = try NetworkConfiguration(id: id, mode: .nat, ipv4Subnet: ipv4Subnet, labels: labels)
|
||||
} throws: { error in
|
||||
guard let err = error as? ContainerizationError else { return false }
|
||||
#expect(err.code == .invalidArgument)
|
||||
|
||||
Reference in New Issue
Block a user