Skip to content

Commit aecb0ab

Browse files
authored
tstest/tailmac: add support for mounting host directories in the guest (tailscale#13957)
updates tailscale/corp#24197 tailmac run now supports the --share option which will allow you to specify a directory on the host which can be mounted in the guest using mount_virtiofs vmshare <path>. Signed-off-by: Jonathan Nobels <[email protected]>
1 parent 0f9a054 commit aecb0ab

File tree

5 files changed

+35
-14
lines changed

5 files changed

+35
-14
lines changed

tstest/tailmac/Swift/Common/Config.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class Config: Codable {
1414
var mac = "52:cc:cc:cc:cc:01"
1515
var ethermac = "52:cc:cc:cc:ce:01"
1616
var port: UInt32 = 51009
17+
var sharedDir: String?
1718

1819
// The virtual machines ID. Also double as the directory name under which
1920
// we will store configuration, block device, etc.

tstest/tailmac/Swift/Common/TailMacConfigHelper.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,18 @@ struct TailMacConfigHelper {
141141
func createKeyboardConfiguration() -> VZKeyboardConfiguration {
142142
return VZMacKeyboardConfiguration()
143143
}
144+
145+
func createDirectoryShareConfiguration(tag: String) -> VZDirectorySharingDeviceConfiguration? {
146+
guard let dir = config.sharedDir else { return nil }
147+
148+
let sharedDir = VZSharedDirectory(url: URL(fileURLWithPath: dir), readOnly: false)
149+
let share = VZSingleDirectoryShare(directory: sharedDir)
150+
151+
// Create the VZVirtioFileSystemDeviceConfiguration and assign it a unique tag.
152+
let sharingConfiguration = VZVirtioFileSystemDeviceConfiguration(tag: tag)
153+
sharingConfiguration.share = share
154+
155+
return sharingConfiguration
156+
}
144157
}
145158

tstest/tailmac/Swift/Host/HostCli.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ var config: Config = Config()
1919
extension HostCli {
2020
struct Run: ParsableCommand {
2121
@Option var id: String
22+
@Option var share: String?
2223

2324
mutating func run() {
24-
print("Running vm with identifier \(id)")
2525
config = Config(id)
26+
config.sharedDir = share
27+
print("Running vm with identifier \(id) and sharedDir \(share ?? "<none>")")
2628
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
2729
}
2830
}

tstest/tailmac/Swift/Host/VMController.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ class VMController: NSObject, VZVirtualMachineDelegate {
9595
virtualMachineConfiguration.keyboards = [helper.createKeyboardConfiguration()]
9696
virtualMachineConfiguration.socketDevices = [helper.createSocketDeviceConfiguration()]
9797

98+
if let dir = config.sharedDir, let shareConfig = helper.createDirectoryShareConfiguration(tag: "vmshare") {
99+
print("Sharing \(dir) as vmshare. Use: mount_virtiofs vmshare <path> in the guest to mount.")
100+
virtualMachineConfiguration.directorySharingDevices = [shareConfig]
101+
} else {
102+
print("No shared directory created. \(config.sharedDir ?? "none") was requested.")
103+
}
104+
98105
try! virtualMachineConfiguration.validate()
99106
try! virtualMachineConfiguration.validateSaveRestoreSupport()
100107

tstest/tailmac/Swift/TailMac/TailMac.swift

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ extension Tailmac {
9595
extension Tailmac {
9696
struct Run: ParsableCommand {
9797
@Option(help: "The vm identifier") var id: String
98+
@Option(help: "Optional share directory") var share: String?
9899
@Flag(help: "Tail the TailMac log output instead of returning immediatly") var tail
99100

100101
mutating func run() {
@@ -115,7 +116,12 @@ extension Tailmac {
115116
fatalError("Could not find Host.app at \(appPath). This must be co-located with the tailmac utility")
116117
}
117118

118-
process.arguments = ["run", "--id", id]
119+
var args = ["run", "--id", id]
120+
if let share {
121+
args.append("--share")
122+
args.append(share)
123+
}
124+
process.arguments = args
119125

120126
do {
121127
process.standardOutput = stdOutPipe
@@ -124,26 +130,18 @@ extension Tailmac {
124130
fatalError("Unable to launch the vm process")
125131
}
126132

127-
// This doesn't print until we exit which is not ideal, but at least we
128-
// get the output
129133
if tail != 0 {
134+
// (jonathan)TODO: How do we get the process output in real time?
135+
// The child process only seems to flush to stdout on completion
130136
let outHandle = stdOutPipe.fileHandleForReading
131-
132-
let queue = OperationQueue()
133-
NotificationCenter.default.addObserver(
134-
forName: NSNotification.Name.NSFileHandleDataAvailable,
135-
object: outHandle, queue: queue)
136-
{
137-
notification -> Void in
138-
let data = outHandle.availableData
137+
outHandle.readabilityHandler = { handle in
138+
let data = handle.availableData
139139
if data.count > 0 {
140140
if let str = String(data: data, encoding: String.Encoding.utf8) {
141141
print(str)
142142
}
143143
}
144-
outHandle.waitForDataInBackgroundAndNotify()
145144
}
146-
outHandle.waitForDataInBackgroundAndNotify()
147145
process.waitUntilExit()
148146
}
149147
}

0 commit comments

Comments
 (0)