Skip to content

Commit

Permalink
Support customizing VM disks and mounting remote VMs in tart run (#847
Browse files Browse the repository at this point in the history
)

* Support remote VM names in --disk command-line argument

* tart set: introduce "--disk" to support replacing VM's disk contents

* Complete the code comment
  • Loading branch information
edigaryev committed Jul 2, 2024
1 parent 63e3235 commit 5eccdf7
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
31 changes: 27 additions & 4 deletions Sources/tart/Commands/Run.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,16 @@ struct Run: AsyncParsableCommand {
var vncExperimental: Bool = false

@Option(help: ArgumentHelp("""
Additional disk attachments with an optional read-only specifier\n(e.g. --disk=\"disk.bin\" --disk=\"ubuntu.iso:ro\" --disk=\"/dev/disk0\" --disk=\"nbd://localhost:10809/myDisk\")
Additional disk attachments with an optional read-only specifier\n(e.g. --disk=\"disk.bin\" --disk=\"ubuntu.iso:ro\" --disk=\"/dev/disk0\" --disk "ghcr.io/cirruslabs/xcode:16.0:ro" --disk=\"nbd://localhost:10809/myDisk\")
""", discussion: """
Can be either a disk image file, a block device like a local SSD on AWS EC2 Mac instances or a Network Block Device (NBD).
The disk attachment can be a:
Learn how to create a disk image using Disk Utility here:
https://support.apple.com/en-gb/guide/disk-utility/dskutl11888/mac
* path to a disk image file
* path to a block device (for example, a local SSD on AWS EC2 Mac instances)
* remote VM name whose disk will be mounted
* Network Block Device (NBD) URL
Learn how to create a disk image using Disk Utility here: https://support.apple.com/en-gb/guide/disk-utility/dskutl11888/mac
To work with block devices, the easiest way is to modify their permissions (e.g. by using "sudo chown $USER /dev/diskX") or to run the Tart binary as root, which affects locating Tart VMs.
Expand Down Expand Up @@ -496,6 +500,25 @@ struct Run: AsyncParsableCommand {
continue
}

// Support remote VM names in --disk command-line argument
if let remoteName = try? RemoteName(diskPath) {
let vmDir = try VMStorageOCI().open(remoteName)

// Unfortunately, VZDiskImageStorageDeviceAttachment does not support
// FileHandle, so we can't easily clone the disk, open it and unlink(2)
// to simplify the garbage collection, so use an intermediate directory.
let clonedDiskURL = try Config().tartTmpDir.appendingPathComponent("run-disk-\(UUID().uuidString)")

try FileManager.default.copyItem(at: vmDir.diskURL, to: clonedDiskURL)

let lock = try FileLock(lockURL: clonedDiskURL)
try lock.lock()

let diskImageAttachment = try VZDiskImageStorageDeviceAttachment(url: clonedDiskURL, readOnly: diskReadOnly)
result.append(VZVirtioBlockDeviceConfiguration(attachment: diskImageAttachment))
continue
}

// Error out if the disk is locked by the host (e.g. it was mounted in Finder),
// see https://github.com/cirruslabs/tart/issues/323 for more details.
if try !diskReadOnly && !FileLock(lockURL: diskFileURL).trylock() {
Expand Down
11 changes: 11 additions & 0 deletions Sources/tart/Commands/Set.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ struct Set: AsyncParsableCommand {
#endif
var randomSerial: Bool = false

@Option(help: ArgumentHelp("Replace the VM's disk contents with the disk contents at path.", valueName: "path"))
var disk: String?

@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
Expand Down Expand Up @@ -73,6 +76,14 @@ struct Set: AsyncParsableCommand {

try vmConfig.save(toURL: vmDir.configURL)

if let disk = disk {
let temporaryDiskURL = try Config().tartTmpDir.appendingPathComponent("set-disk-\(UUID().uuidString)")

try FileManager.default.copyItem(atPath: disk, toPath: temporaryDiskURL.path())

_ = try FileManager.default.replaceItemAt(vmDir.diskURL, withItemAt: temporaryDiskURL)
}

if diskSize != nil {
try vmDir.resizeDisk(diskSize!)
}
Expand Down

0 comments on commit 5eccdf7

Please sign in to comment.