From 935528761676ce92c8d4f246bd1fb4c8ad981f9f Mon Sep 17 00:00:00 2001 From: Aditya Ramani Date: Tue, 16 Jun 2026 16:16:18 -0700 Subject: [PATCH] Allow setting log level for vminitd --- Sources/Containerization/Kernel.swift | 6 + Tests/ContainerizationTests/KernelTests.swift | 35 ++++++ examples/ctr-example/Package.resolved | 117 +++++++++++------- examples/ctr-example/Package.swift | 2 +- vminitd/Sources/VminitdCore/Logging.swift | 6 +- vminitd/Sources/vminitd/Application.swift | 15 ++- 6 files changed, 133 insertions(+), 48 deletions(-) diff --git a/Sources/Containerization/Kernel.swift b/Sources/Containerization/Kernel.swift index a7c91d39..c4c2468d 100644 --- a/Sources/Containerization/Kernel.swift +++ b/Sources/Containerization/Kernel.swift @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// import Foundation +import Logging /// An object representing a Linux kernel used to boot a virtual machine. /// In addition to a path to the kernel itself, this type stores relevant @@ -37,6 +38,11 @@ public struct Kernel: Sendable, Codable { self.kernelArgs.append("panic=\(level)") } + // Sets the log level for the Agent + mutating public func setAgentLogLevel(level: Logger.Level) { + self.initArgs.append(contentsOf: ["--log-level", level.description]) + } + /// Additional kernel arguments. public var kernelArgs: [String] /// Additional arguments passed to the Initial Process / Agent. diff --git a/Tests/ContainerizationTests/KernelTests.swift b/Tests/ContainerizationTests/KernelTests.swift index 66b03f0e..dcc087a0 100644 --- a/Tests/ContainerizationTests/KernelTests.swift +++ b/Tests/ContainerizationTests/KernelTests.swift @@ -17,6 +17,7 @@ // import Foundation +import Logging import Testing @testable import Containerization @@ -55,4 +56,38 @@ final class KernelTests { #expect(commandLine.kernelArgs == ["console=hvc0", "debug", "panic=10"]) } + + @Test func setAgentLogLevelAppendsFlagAndValue() { + var commandLine = Kernel.CommandLine(initArgs: []) + commandLine.setAgentLogLevel(level: .debug) + #expect(commandLine.initArgs == ["--log-level", "debug"]) + } + + @Test(arguments: [ + (Logger.Level.trace, "trace"), + (.debug, "debug"), + (.info, "info"), + (.notice, "notice"), + (.warning, "warning"), + (.error, "error"), + (.critical, "critical"), + ]) + func setAgentLogLevelForEachLevel(level: Logger.Level, expected: String) { + var commandLine = Kernel.CommandLine(initArgs: []) + commandLine.setAgentLogLevel(level: level) + #expect(commandLine.initArgs == ["--log-level", expected]) + } + + @Test func setAgentLogLevelPreservesExistingInitArgs() { + var commandLine = Kernel.CommandLine(initArgs: ["--verbose"]) + commandLine.setAgentLogLevel(level: .info) + #expect(commandLine.initArgs == ["--verbose", "--log-level", "info"]) + } + + @Test func setAgentLogLevelDoesNotAffectKernelArgs() { + var commandLine = Kernel.CommandLine(debug: true, panic: 0, initArgs: []) + let kernelArgsBefore = commandLine.kernelArgs + commandLine.setAgentLogLevel(level: .warning) + #expect(commandLine.kernelArgs == kernelArgsBefore) + } } diff --git a/examples/ctr-example/Package.resolved b/examples/ctr-example/Package.resolved index d50e3654..848cc075 100644 --- a/examples/ctr-example/Package.resolved +++ b/examples/ctr-example/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "5de11e9b526f881c570e7b65cb339765f3aa79e8646a0c1289d36f224f9f8ca0", + "originHash" : "f9b523ded39c0fa3565fd16d3b4097384449d541048751be7efee4a43af79fd4", "pins" : [ { "identity" : "async-http-client", "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/async-http-client.git", "state" : { - "revision" : "b2faff932b956df50668241d14f1b42f7bae12b4", - "version" : "1.30.0" + "revision" : "7744c2a035c68ec14726c709f031835e3e30bde1", + "version" : "1.34.0" } }, { @@ -15,17 +15,35 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/containerization.git", "state" : { - "revision" : "636eef0eff00e451de6d5d426e6a6785b90b44e2", - "version" : "0.26.5" + "revision" : "9275f365dd555c8f072e7d250d809f5eb7bdd746", + "version" : "0.33.4" } }, { - "identity" : "grpc-swift", + "identity" : "grpc-swift-2", "kind" : "remoteSourceControl", - "location" : "https://github.com/grpc/grpc-swift.git", + "location" : "https://github.com/grpc/grpc-swift-2.git", "state" : { - "revision" : "f857994e146f5146d702e9c31ac6f3c27d55d18a", - "version" : "1.27.0" + "revision" : "21fe69ab7ce0e87ac089534733c52f037e74a3eb", + "version" : "2.4.1" + } + }, + { + "identity" : "grpc-swift-nio-transport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-nio-transport.git", + "state" : { + "revision" : "e7d463749f9037b047dcd6da4e633718ddc432b8", + "version" : "2.8.0" + } + }, + { + "identity" : "grpc-swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/grpc/grpc-swift-protobuf.git", + "state" : { + "revision" : "b05885fa9bdd88f1eab2e7162f1ee81340b0da33", + "version" : "2.4.0" } }, { @@ -42,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { - "revision" : "cdd0ef3755280949551dc26dee5de9ddeda89f54", - "version" : "1.6.2" + "revision" : "6a52f3251125d74daf04fcbd5e6f08a75d074382", + "version" : "1.8.2" } }, { @@ -51,8 +69,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "40d25bbb2fc5b557a9aa8512210bded327c0f60d", - "version" : "1.5.0" + "revision" : "a9a5efd40eaf558a2bcd48d64b1d1646be686008", + "version" : "1.7.1" } }, { @@ -60,8 +78,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-async-algorithms.git", "state" : { - "revision" : "042e1c4d9d19748c9c228f8d4ebc97bb1e339b0b", - "version" : "1.0.4" + "revision" : "d0b4a06d0f173a2f3be27d3ea21b3c3aa18db440", + "version" : "1.1.4" } }, { @@ -78,8 +96,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-certificates.git", "state" : { - "revision" : "c399f90e7bbe8874f6cbfda1d5f9023d1f5ce122", - "version" : "1.15.1" + "revision" : "bde8ca32a096825dfce37467137c903418c1893d", + "version" : "1.19.1" } }, { @@ -87,8 +105,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", - "version" : "1.3.0" + "revision" : "a0cb0954ecb21e4e31b0070e6ed5674e8556685a", + "version" : "1.6.0" + } + }, + { + "identity" : "swift-configuration", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-configuration.git", + "state" : { + "revision" : "be76c4ad929eb6c4bcaf3351799f2adf9e6848a9", + "version" : "1.2.0" } }, { @@ -105,8 +132,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-distributed-tracing.git", "state" : { - "revision" : "baa932c1336f7894145cbaafcd34ce2dd0b77c97", - "version" : "1.3.1" + "revision" : "dc4030184203ffafbb2ec614352487235d747fe0", + "version" : "1.4.1" } }, { @@ -114,8 +141,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-structured-headers.git", "state" : { - "revision" : "76d7627bd88b47bf5a0f8497dd244885960dde0b", - "version" : "1.6.0" + "revision" : "933538faa42c432d385f02e07df0ace7c5ecfc47", + "version" : "1.7.0" } }, { @@ -123,8 +150,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-http-types.git", "state" : { - "revision" : "45eb0224913ea070ec4fba17291b9e7ecf4749ca", - "version" : "1.5.1" + "revision" : "db774a277f60063a32d854f2980299caf06da041", + "version" : "1.6.0" } }, { @@ -132,8 +159,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "ce592ae52f982c847a4efc0dd881cc9eb32d29f2", - "version" : "1.6.4" + "revision" : "92448c359f00ebe36ae97d3bd9086f13c7692b5a", + "version" : "1.13.2" } }, { @@ -141,8 +168,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "56724a2b6d8e2aed1b2c5f23865b9ea5c43f9977", - "version" : "2.89.0" + "revision" : "77b84ac2cd2ac9e4ac67d19f045fd5b434f56967", + "version" : "2.101.0" } }, { @@ -150,8 +177,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "7ee281d816fa8e5f3967a2c294035a318ea551c7", - "version" : "1.31.0" + "revision" : "d2eeec0339074034f11a040a74aa2a341a2c4506", + "version" : "1.34.1" } }, { @@ -159,8 +186,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "c2ba4cfbb83f307c66f5a6df6bb43e3c88dfbf80", - "version" : "1.39.0" + "revision" : "61d1b44f6e4e118792be1cff88ee2bc0267c6f9a", + "version" : "1.44.0" } }, { @@ -168,8 +195,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "173cc69a058623525a58ae6710e2f5727c663793", - "version" : "2.36.0" + "revision" : "407d82d5b6cc00e1c3fb83a81b1539b70c788c5e", + "version" : "2.37.1" } }, { @@ -177,8 +204,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "df6c28355051c72c884574a6c858bc54f7311ff9", - "version" : "1.25.2" + "revision" : "67787bb645a5e67d2edcdfbe48a216cc549222d5", + "version" : "1.28.0" } }, { @@ -195,8 +222,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "c169a5744230951031770e27e475ff6eefe51f9d", - "version" : "1.33.3" + "revision" : "f6506eaa86ed2e01cb0ae14a75035b7fdbf0918f", + "version" : "1.38.0" } }, { @@ -204,8 +231,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-service-context.git", "state" : { - "revision" : "1983448fefc717a2bc2ebde5490fe99873c5b8a6", - "version" : "1.2.1" + "revision" : "d0997351b0c7779017f88e7a93bc30a1878d7f29", + "version" : "1.3.0" } }, { @@ -213,8 +240,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/swift-service-lifecycle.git", "state" : { - "revision" : "1de37290c0ab3c5a96028e0f02911b672fd42348", - "version" : "2.9.1" + "revision" : "9829955b385e5bb88128b73f1b8389e9b9c3191a", + "version" : "2.11.0" } }, { @@ -222,8 +249,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "395a77f0aa927f0ff73941d7ac35f2b46d47c9db", - "version" : "1.6.3" + "revision" : "7502b711c92a17741fa625d722b0ccbd595d8ed1", + "version" : "1.7.2" } }, { diff --git a/examples/ctr-example/Package.swift b/examples/ctr-example/Package.swift index c90f7ebe..15b649cb 100644 --- a/examples/ctr-example/Package.swift +++ b/examples/ctr-example/Package.swift @@ -17,7 +17,7 @@ import PackageDescription -let scVersion = "0.26.5" +let scVersion = "0.33.4" let package = Package( name: "ctr-example", diff --git a/vminitd/Sources/VminitdCore/Logging.swift b/vminitd/Sources/VminitdCore/Logging.swift index 6c56da09..845d769e 100644 --- a/vminitd/Sources/VminitdCore/Logging.swift +++ b/vminitd/Sources/VminitdCore/Logging.swift @@ -23,10 +23,14 @@ import Synchronization public struct LogLevelOption: ParsableArguments { @Option(name: .long, help: "Set the log level (trace, debug, info, notice, warning, error, critical)") - var logLevel: String = "info" + public var logLevel: String = "info" public init() {} + public init(logLevel: String) { + self.logLevel = logLevel + } + public func resolvedLogLevel() -> Logger.Level { switch logLevel.lowercased() { case "trace": diff --git a/vminitd/Sources/vminitd/Application.swift b/vminitd/Sources/vminitd/Application.swift index 21009062..866f6b33 100644 --- a/vminitd/Sources/vminitd/Application.swift +++ b/vminitd/Sources/vminitd/Application.swift @@ -51,7 +51,9 @@ struct Application: AsyncParsableCommand { // so we do this synchronously before any async code runs. try mountProc() - var command = try parseAsRoot() + // When running as PID 1 with a Musl-static build, Swift's runtime + // captures argc/argv as empty. Recover argv from /proc/self/cmdline. + var command = try parseAsRoot(Self.procSelfArgv()) if let asyncCommand = command as? AsyncParsableCommand { nonisolated(unsafe) var unsafeCommand = asyncCommand try await unsafeCommand.run() @@ -85,6 +87,17 @@ struct Application: AsyncParsableCommand { try mnt.mount(createWithPerms: 0o755) } + // /proc/self/cmdline holds argv as NUL-separated bytes. Read it after + // mountProc(). Returns argv minus argv[0], suitable for parseAsRoot(_:). + private static func procSelfArgv() -> [String] { + guard let data = try? Data(contentsOf: URL(fileURLWithPath: "/proc/self/cmdline")) else { + return [] + } + let parts = data.split(separator: 0, omittingEmptySubsequences: true) + .map { String(decoding: $0, as: UTF8.self) } + return Array(parts.dropFirst()) + } + private static func isProcMounted() -> Bool { guard let data = try? String(contentsOfFile: "/proc/mounts", encoding: .utf8) else { return false