mirror of
https://github.com/apple/container.git
synced 2026-09-25 09:05:47 +00:00
Update kernel install UX (#22)
This change updates the UX when we install required dependencies at first launch ### Fresh install - respond `y` to prompt ``` ➜ bin/container system start Verifying apiserver is running... Installing base container filesystem... No default kernel configured. Install the recommended default kernel from [https://github.com/kata-containers/kata-containers/releases/download/3.17.0/kata-static-3.17.0-arm64.tar.xz]? [Y/n]: y Installing kernel... ``` ### Fresh install - respond `n` to prompt and then run the provided command ``` ➜ bin/container system start Verifying apiserver is running... Installing base container filesystem... No default kernel configured. Install the recommended default kernel from [https://github.com/kata-containers/kata-containers/releases/download/3.17.0/kata-static-3.17.0-arm64.tar.xz]? [Y/n]: n Please use the `container system kernel set --recommended` command to configure the default kernel ➜ bin/container system kernel set --recommended Installing the recommended kernel from https://github.com/kata-containers/kata-containers/releases/download/3.17.0/kata-static-3.17.0-arm64.tar.xz... ``` ### Fresh install - respond `n` to prompt and then run a container ``` ➜ bin/container system start Verifying apiserver is running... Installing base container filesystem... No default kernel configured. Install the recommended default kernel from [https://github.com/kata-containers/kata-containers/releases/download/3.17.0/kata-static-3.17.0-arm64.tar.xz]? [Y/n]: n Please use the `container system kernel set --recommended` command to configure the default kernel ➜ bin/container run alpine uname Error: notFound: "Default kernel not configured for architecture arm64. Please use the `container system kernel set` command to configure it ``` --------- Signed-off-by: Aditya Ramani <a_ramani@apple.com>
This commit is contained in:
@@ -178,6 +178,7 @@ _site:
|
||||
|
||||
.PHONY: cleancontent
|
||||
cleancontent:
|
||||
@bin/container system stop || true
|
||||
@echo Cleaning the content...
|
||||
@rm -rf ~/Library/Application\ Support/com.apple.container
|
||||
|
||||
|
||||
@@ -42,7 +42,13 @@ actor KernelService {
|
||||
let kFile = url.resolvingSymlinksInPath()
|
||||
let destPath = self.kernelDirectory.appendingPathComponent(kFile.lastPathComponent)
|
||||
try FileManager.default.copyItem(at: kFile, to: destPath)
|
||||
try self.setDefaultKernel(name: kFile.lastPathComponent, platform: platform)
|
||||
try Task.checkCancellation()
|
||||
do {
|
||||
try self.setDefaultKernel(name: kFile.lastPathComponent, platform: platform)
|
||||
} catch {
|
||||
try? FileManager.default.removeItem(at: destPath)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/// Copies a kernel binary from inside of tar file into the managed kernels directory
|
||||
|
||||
@@ -39,13 +39,14 @@ extension Application {
|
||||
@Option(name: .customLong("arch"), help: "The architecture of the kernel binary. One of (amd64, arm64)")
|
||||
var architecture: String = ContainerizationOCI.Platform.current.architecture.description
|
||||
|
||||
@Flag(name: .customLong("install-recommended"), help: "Download and install the recommended kernel as the default. This flag ignores any other arguments")
|
||||
var installRecommended: Bool = false
|
||||
@Flag(name: .customLong("recommended"), help: "Download and install the recommended kernel as the default. This flag ignores any other arguments")
|
||||
var recommended: Bool = false
|
||||
|
||||
func run() async throws {
|
||||
if installRecommended {
|
||||
if recommended {
|
||||
let url = ClientDefaults.get(key: .defaultKernelURL)
|
||||
let path = ClientDefaults.get(key: .defaultKernelBinaryPath)
|
||||
print("Installing the recommended kernel from \(url)...")
|
||||
try await Self.downloadAndInstallWithProgressBar(tarRemoteURL: url, kernelFilePath: path)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ extension Application {
|
||||
do {
|
||||
print("Verifying apiserver is running...")
|
||||
try await ClientHealthCheck.ping(timeout: .seconds(10))
|
||||
print("Done")
|
||||
} catch {
|
||||
throw ContainerizationError(
|
||||
.internalError,
|
||||
@@ -85,65 +84,50 @@ extension Application {
|
||||
)
|
||||
}
|
||||
|
||||
var kernelConfigured: Bool = true
|
||||
var missingDependencies: [Dependencies] = []
|
||||
if await !initImageExists() {
|
||||
missingDependencies.append(.initFs)
|
||||
try? await installInitialFilesystem()
|
||||
}
|
||||
if await !kernelExists() {
|
||||
kernelConfigured = false
|
||||
missingDependencies.append(.kernel)
|
||||
}
|
||||
guard missingDependencies.count > 0 else {
|
||||
|
||||
guard await !kernelExists() else {
|
||||
return
|
||||
}
|
||||
try await installDefaultKernel()
|
||||
}
|
||||
|
||||
print("Missing required runtime dependencies:")
|
||||
for (idx, dependency) in missingDependencies.enumerated() {
|
||||
print(" \(idx+1). \(dependency.rawValue)")
|
||||
private func installInitialFilesystem() async throws {
|
||||
let dep = Dependencies.initFs
|
||||
let pullCommand = ImagePull(reference: dep.source)
|
||||
print("Installing base container filesystem...")
|
||||
do {
|
||||
try await pullCommand.run()
|
||||
} catch {
|
||||
log.error("Failed to install base container filesystem: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func installDefaultKernel() async throws {
|
||||
let kernelDependency = Dependencies.kernel
|
||||
let defaultKernelURL = kernelDependency.source
|
||||
let defaultKernelBinaryPath = ClientDefaults.get(key: .defaultKernelBinaryPath)
|
||||
|
||||
print("No default kernel configured.")
|
||||
print("Install the recommended default kernel from [\(kernelDependency.source)]? [Y/n]: ", terminator: "")
|
||||
if !installDependencies {
|
||||
print("Would like to install them now? [Y/n]: ", terminator: "")
|
||||
guard let read = readLine(strippingNewline: true) else {
|
||||
throw ContainerizationError(.internalError, message: "Failed to read user input")
|
||||
}
|
||||
guard read.lowercased() == "y" || read.count == 0 else {
|
||||
if !kernelConfigured {
|
||||
print("Please use the `container system kernel set` command to configure the kernel")
|
||||
}
|
||||
print("Please use the `container system kernel set --recommended` command to configure the default kernel")
|
||||
return
|
||||
}
|
||||
}
|
||||
try await installDeps(deps: missingDependencies)
|
||||
}
|
||||
|
||||
private func installDeps(deps: [Dependencies]) async throws {
|
||||
if deps.contains(.kernel) {
|
||||
try await installDefaultKernel()
|
||||
}
|
||||
if deps.contains(.initFs) {
|
||||
try await installInitialFilesystem()
|
||||
}
|
||||
}
|
||||
|
||||
private func installInitialFilesystem() async throws {
|
||||
let reference = ClientDefaults.get(key: .defaultInitImage)
|
||||
let pullCommand = ImagePull(reference: reference)
|
||||
print("Installing initial filesystem from [\(reference)]...")
|
||||
try await pullCommand.run()
|
||||
}
|
||||
|
||||
private func installDefaultKernel() async throws {
|
||||
let defaultKernelURL = ClientDefaults.get(key: .defaultKernelURL)
|
||||
let defaultKernelBinaryPath = ClientDefaults.get(key: .defaultKernelBinaryPath)
|
||||
print("Installing default kernel from [\(defaultKernelURL)]...")
|
||||
print("Installing kernel...")
|
||||
try await KernelSet.downloadAndInstallWithProgressBar(tarRemoteURL: defaultKernelURL, kernelFilePath: defaultKernelBinaryPath)
|
||||
}
|
||||
|
||||
private func initImageExists() async -> Bool {
|
||||
do {
|
||||
let img = try await ClientImage.get(reference: ClientDefaults.get(key: .defaultInitImage))
|
||||
let img = try await ClientImage.get(reference: Dependencies.initFs.source)
|
||||
let _ = try await img.getSnapshot(platform: .current)
|
||||
return true
|
||||
} catch {
|
||||
@@ -162,7 +146,16 @@ extension Application {
|
||||
}
|
||||
|
||||
private enum Dependencies: String {
|
||||
case kernel = "Kernel"
|
||||
case initFs = "Initial filesystem"
|
||||
case kernel
|
||||
case initFs
|
||||
|
||||
var source: String {
|
||||
switch self {
|
||||
case .initFs:
|
||||
return ClientDefaults.get(key: .defaultInitImage)
|
||||
case .kernel:
|
||||
return ClientDefaults.get(key: .defaultKernelURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ extension ClientKernel {
|
||||
throw err
|
||||
}
|
||||
throw ContainerizationError(
|
||||
.notFound, message: "Default kernel not configured for architecture \(platform.architecture). Please use the `container system kernel` command to configure it")
|
||||
.notFound, message: "Default kernel not configured for architecture \(platform.architecture). Please use the `container system kernel set` command to configure it")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +93,7 @@ public enum XPCKeys: String {
|
||||
case kernel
|
||||
case kernelTarURL
|
||||
case kernelFilePath
|
||||
case setDefault
|
||||
case systemPlatform
|
||||
case kernelName
|
||||
}
|
||||
|
||||
public enum XPCRoute: String {
|
||||
|
||||
Reference in New Issue
Block a user