//===----------------------------------------------------------------------===// // Copyright © 2026 Apple Inc. and the container project authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //===----------------------------------------------------------------------===// import AsyncHTTPClient import ContainerResource import Foundation // MARK: - Network inspect output public struct NetworkInspectOutput: Codable { public struct Status: Codable { public let ipv4Subnet: String? public let ipv4Gateway: String? public let ipv6Subnet: String? } public let id: String public let configuration: NetworkConfiguration public let status: Status } // MARK: - Network lifecycle helpers extension ContainerFixture { /// Creates a named network, throwing on failure. public func doNetworkCreate(_ name: String, args: [String] = []) throws { var arguments = ["network", "create"] arguments += args arguments.append(name) try run(arguments).check() } /// Deletes a named network, throwing on failure. public func doNetworkDelete(_ name: String) throws { try run(["network", "delete", name]).check() } /// Deletes a named network, silently ignoring errors. public func doNetworkDeleteIfExists(_ name: String) { _ = try? run(["network", "delete", name]) } /// Inspects a network and returns decoded output. public func inspectNetwork(_ name: String) throws -> NetworkInspectOutput { let result = try run(["network", "inspect", name]).check() let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 let networks = try decoder.decode([NetworkInspectOutput].self, from: result.outputData) guard let network = networks.first else { throw CommandError.executionFailed("network inspect returned empty array") } return network } /// Returns an `HTTPClient` for use in network connectivity tests. public func makeHTTPClient() -> HTTPClient { HTTPClient(eventLoopGroupProvider: .singleton) } /// Polls `url` via HTTP GET until it returns a 2xx status. /// /// Useful after a container reaches `running` state, since that only proves /// the container's init process is up — a server inside may still be starting. public func waitForHTTPOk( _ url: String, using client: HTTPClient, attempts: Int = 10, delay: Duration = .seconds(1) ) async throws { try await retry(attempts: attempts, delay: delay) { do { var req = HTTPClientRequest(url: url) req.method = .GET let resp = try await client.execute(req, timeout: .seconds(3)) return resp.status.code >= 200 && resp.status.code < 300 } catch { return false } } } }