require 'downloader' require 'system' require_relative 'data/resources/iso-images' require 'vm/qemu' require 'vm/archive' module VirtualMachine def self.distro(name, arch, type = :install) ISO_URLS[name][arch][type] end def self.image_id_dir(options) File.join("#{options[:distro].to_s}-#{options[:arch].to_s}", options[:name]) end def self.vm_root_path ENV["DAT_VM_DATA"] || File.join(User.cache_path, "vm") end def self.vm_dir(options) File.join(vm_root_path, "image", image_id_dir(options)) end def self.archive_dir(options) File.join(vm_root_path, "archive", image_id_dir(options)) end def self.create_archive_path(options) File.join(archive_dir(options), "archive.tar.zst") end def self.get_recent_archive_path(options) File.join(archive_dir(options), "archive.tar.zst") end # https://artur.gurgul.pro/vm/ # https://artur.gurgul.pro/vm/debian-arm64/debian/archive.tar.zst def self.vm_archive_url(options) return nil unless ENV["DAT_VM_REPO_URL"] image_id = image_id_dir(options) uri = Addressable::URI.parse(ENV["DAT_VM_REPO_URL"]) uri.path = File.join(uri.path, image_id, "archive.tar.zst") return uri.to_s end def self.root_img_path(options) File.join(vm_dir(options), "root.img") end def self.fill_defaults(options) if options[:name] == nil options[:name] = options[:distro] end if options[:arch] == nil options[:arch] = System::ARCH else options[:arch] = System.arch_to_symbol(options[:arch]) end if options[:detached] == nil options[:detached] = false end if options[:tpm] == nil options[:tpm] = false end unless options[:vars_fd] options[:vars_fd] = File.join(vm_dir(options), "vars.fd") end unless options[:code_fd] options[:code_fd] = File.join(vm_dir(options), "code.fd") end end def self.archive(options) fill_defaults(options) Archive.create(vm_dir(options), out: create_archive_path(options)) end def self.restore(options) fill_defaults(options) Archive.restore(get_recent_archive_path(options), vm_dir(options)) end def self.run(options) fill_defaults(options) disk_img_path = root_img_path(options) unless File.exist?(disk_img_path) url = vm_archive_url(options) Downloader.get(url, use_cache: false) do |path| Archive.restore(path, vm_dir(options)) end #raise "file do not exists" end # TODO: # - if image path not exists, check the cache # - if cache do not exists try to download puts "Starting image: #{disk_img_path}" Qemu.launch( options[:arch], disk_img_path, code_fd: options[:code_fd], vars_fd: options[:vars_fd], cpus: [1, System.cpus - 2].max, detach: options[:detached], tpm: options[:tpm], shell: options[:shell] ) end # vm setup windows --arch arm64 --iso /Users/agurgul/Downloads/win.iso --tpm # vm setup windows --tpm --cdrom /Users/agurgul/Downloads/win.iso def self.setup(options) fill_defaults(options) # puts options # exit -1 get_cdrom_image(options) do |path| disk_img_path = root_img_path(options) create_disk_image(disk_img_path, 64000 * 4) Qemu.launch( options[:arch], disk_img_path, code_fd: options[:code_fd], vars_fd: options[:vars_fd], cpus: [1, System.cpus - 2].max, cdrom: path, detach: options[:detached], display: DisplayMode.window, tpm: options[:tpm] ) end end def self.get_cdrom_image(options) if options[:cdrom] == nil url = distro(options[:name], options[:arch], :install) Downloader.get(url) do |path| yield path end else yield options[:cdrom] end end # size in MB # lsof /Users/artur/.cache/dat/vm/debian/arm64/debian/root.img def self.create_disk_image(path, size) size_in_bytes = 1024 * 1024 * size # Ensure the directory exists dir = File.dirname(path) FileUtils.mkdir_p(dir) unless Dir.exist?(dir) File.open(path, "wb") do |f| f.truncate(size_in_bytes) # f.seek(size_in_bytes - 1) # f.write("\0") end end end