mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 08:11:32 +01:00 
			
		
		
		
	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 <jonathan@tailscale.com>
		
			
				
	
	
		
			127 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| import Foundation
 | |
| 
 | |
| let kDefaultDiskSizeGb: Int64 = 72
 | |
| let kDefaultMemSizeGb: UInt64 = 72
 | |
| 
 | |
| 
 | |
| /// Represents a configuration for a virtual machine
 | |
| class Config: Codable {
 | |
|     var serverSocket = "/tmp/qemu-dgram.sock"
 | |
|     var memorySize = (kDefaultMemSizeGb * 1024 * 1024 * 1024) as UInt64
 | |
|     var mac = "52:cc:cc:cc:cc:01"
 | |
|     var ethermac = "52:cc:cc:cc:ce:01"
 | |
|     var port: UInt32 = 51009
 | |
|     var sharedDir: String?
 | |
| 
 | |
|     // The virtual machines ID.  Also double as the directory name under which
 | |
|     // we will store configuration, block device, etc.
 | |
|     let vmID: String
 | |
| 
 | |
|     required init(from decoder: Decoder) throws {
 | |
|         let container = try decoder.container(keyedBy: CodingKeys.self)
 | |
|         if let ethermac = try container.decodeIfPresent(String.self, forKey: .ethermac) {
 | |
|             self.ethermac = ethermac
 | |
|         }
 | |
|         if let serverSocket = try container.decodeIfPresent(String.self, forKey: .serverSocket) {
 | |
|             self.serverSocket = serverSocket
 | |
|         }
 | |
|         if let memorySize = try container.decodeIfPresent(UInt64.self, forKey: .memorySize) {
 | |
|             self.memorySize = memorySize
 | |
|         }
 | |
|         if let port = try container.decodeIfPresent(UInt32.self, forKey: .port) {
 | |
|             self.port = port
 | |
|         }
 | |
|         if let mac = try container.decodeIfPresent(String.self, forKey: .mac) {
 | |
|             self.mac = mac
 | |
|         }
 | |
|         if let vmID = try container.decodeIfPresent(String.self, forKey: .vmID) {
 | |
|             self.vmID = vmID
 | |
|         } else {
 | |
|             self.vmID = "default"
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     init(_ vmID: String = "default") {
 | |
|         self.vmID = vmID
 | |
|         let configFile = vmDataURL.appendingPathComponent("config.json")
 | |
|         if FileManager.default.fileExists(atPath: configFile.path()) {
 | |
|             print("Using config file at path \(configFile)")
 | |
|             if let jsonData = try? Data(contentsOf: configFile) {
 | |
|                 let config = try! JSONDecoder().decode(Config.self, from: jsonData)
 | |
|                 self.serverSocket = config.serverSocket
 | |
|                 self.memorySize = config.memorySize
 | |
|                 self.mac = config.mac
 | |
|                 self.port = config.port
 | |
|                 self.ethermac = config.ethermac
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     func persist() {
 | |
|         let configFile = vmDataURL.appendingPathComponent("config.json")
 | |
|         let data = try! JSONEncoder().encode(self)
 | |
|         try! data.write(to: configFile)
 | |
|     }
 | |
| 
 | |
|     lazy var restoreImageURL: URL = {
 | |
|         vmBundleURL.appendingPathComponent("RestoreImage.ipsw")
 | |
|     }()
 | |
| 
 | |
|     // The VM Data URL holds the specific files composing a unique VM guest instance
 | |
|     // By default, VM's are persisted at ~/VM.bundle/<vmID>
 | |
|     lazy var vmDataURL =  {
 | |
|         let dataURL = vmBundleURL.appendingPathComponent(vmID)
 | |
|         return dataURL
 | |
|     }()
 | |
| 
 | |
|     lazy var auxiliaryStorageURL = {
 | |
|         vmDataURL.appendingPathComponent("AuxiliaryStorage")
 | |
|     }()
 | |
| 
 | |
|     lazy var diskImageURL = {
 | |
|         vmDataURL.appendingPathComponent("Disk.img")
 | |
|     }()
 | |
| 
 | |
|     lazy var diskSize: Int64 = {
 | |
|         kDefaultDiskSizeGb * 1024 * 1024 * 1024
 | |
|     }()
 | |
| 
 | |
|     lazy var hardwareModelURL = {
 | |
|         vmDataURL.appendingPathComponent("HardwareModel")
 | |
|     }()
 | |
| 
 | |
|     lazy var machineIdentifierURL = {
 | |
|         vmDataURL.appendingPathComponent("MachineIdentifier")
 | |
|     }()
 | |
| 
 | |
|     lazy var saveFileURL = {
 | |
|         vmDataURL.appendingPathComponent("SaveFile.vzvmsave")
 | |
|     }()
 | |
| 
 | |
| }
 | |
| 
 | |
| // The VM Bundle URL holds the restore image and a set of VM images
 | |
| // By default, VM's are persisted at ~/VM.bundle
 | |
| var vmBundleURL: URL = {
 | |
|     let vmBundlePath = NSHomeDirectory() + "/VM.bundle/"
 | |
|     createDir(vmBundlePath)
 | |
|     let bundleURL = URL(fileURLWithPath: vmBundlePath)
 | |
|     return bundleURL
 | |
| }()
 | |
| 
 | |
| 
 | |
| func createDir(_ path: String) {
 | |
|     do {
 | |
|         try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true)
 | |
|     } catch {
 | |
|         fatalError("Unable to create dir at \(path) \(error)")
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 |