From 4c3306491629ca8c3787a542b9dbfe73a81227ec Mon Sep 17 00:00:00 2001 From: Nikolay Edigaryev Date: Thu, 4 Jan 2024 00:34:55 +0400 Subject: [PATCH] tart set: bring back the --disk-size command-line argument (#694) * tart set: bring back the --disk-size command-line argument * Add a --disk-size explainer --- Sources/tart/Commands/Set.swift | 13 ++++++++++++- Sources/tart/VMDirectory.swift | 12 ++++++++++-- Sources/tart/VMStorageHelper.swift | 3 +++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Sources/tart/Commands/Set.swift b/Sources/tart/Commands/Set.swift index 8fd46bb9..1ce42ca6 100644 --- a/Sources/tart/Commands/Set.swift +++ b/Sources/tart/Commands/Set.swift @@ -16,7 +16,18 @@ struct Set: AsyncParsableCommand { @Option(help: "VM display resolution in a format of x. For example, 1200x800") var display: VMDisplayConfig? - @Option(help: .hidden) + @Option(help: ArgumentHelp("Resize the VMs disk to the specified size in GB (note that the disk size can only be increased to avoid losing data", + discussion: """ + Disk resizing works on most cloud-ready Linux distributions out-of-the box (e.g. Ubuntu Cloud Images + have the \"cloud-initramfs-growroot\" package installed that runs on boot) and on the rest of the + distributions by running the \"growpart\" or \"resize2fs\" commands. + + For macOS, however, things are a bit more complicated: you need to remove the recovery partition + first and then run various \"diskutil\" commands, see Tart's packer plugin source code for more + details[1]. + + [1]: https://github.com/cirruslabs/packer-plugin-tart/blob/main/builder/tart/step_disk_resize.go + """)) var diskSize: UInt16? func run() async throws { diff --git a/Sources/tart/VMDirectory.swift b/Sources/tart/VMDirectory.swift index eb174ebc..5b9ae277 100644 --- a/Sources/tart/VMDirectory.swift +++ b/Sources/tart/VMDirectory.swift @@ -134,9 +134,17 @@ struct VMDirectory: Prunable { if !FileManager.default.fileExists(atPath: diskURL.path) { FileManager.default.createFile(atPath: diskURL.path, contents: nil, attributes: nil) } + let diskFileHandle = try FileHandle.init(forWritingTo: diskURL) - // macOS considers kilo being 1000 and not 1024 - try diskFileHandle.truncate(atOffset: UInt64(sizeGB) * 1000 * 1000 * 1000) + let currentDiskFileLength = try diskFileHandle.seekToEnd() + let desiredDiskFileLength = UInt64(sizeGB) * 1000 * 1000 * 1000 + if desiredDiskFileLength <= currentDiskFileLength { + let currentLengthHuman = ByteCountFormatter().string(fromByteCount: Int64(currentDiskFileLength)) + let desiredLengthHuman = ByteCountFormatter().string(fromByteCount: Int64(desiredDiskFileLength)) + throw RuntimeError.InvalidDiskSize("new disk size of \(desiredLengthHuman) should be larger " + + "than the current disk size of \(currentLengthHuman)") + } + try diskFileHandle.truncate(atOffset: desiredDiskFileLength) try diskFileHandle.close() } diff --git a/Sources/tart/VMStorageHelper.swift b/Sources/tart/VMStorageHelper.swift index 3bc2fe9d..5d842c33 100644 --- a/Sources/tart/VMStorageHelper.swift +++ b/Sources/tart/VMStorageHelper.swift @@ -55,6 +55,7 @@ enum RuntimeError : Error { case VMAlreadyRunning(_ message: String) case NoIPAddressFound(_ message: String) case DiskAlreadyInUse(_ message: String) + case InvalidDiskSize(_ message: String) case FailedToUpdateAccessDate(_ message: String) case PIDLockFailed(_ message: String) case FailedToParseRemoteName(_ message: String) @@ -92,6 +93,8 @@ extension RuntimeError : CustomStringConvertible { return message case .DiskAlreadyInUse(let message): return message + case .InvalidDiskSize(let message): + return message case .FailedToUpdateAccessDate(let message): return message case .PIDLockFailed(let message):