diff --git a/server/src/libvirt.zig b/server/src/libvirt.zig index 6d82f3e..3a50848 100644 --- a/server/src/libvirt.zig +++ b/server/src/libvirt.zig @@ -12,7 +12,7 @@ pub const c = @cImport({ fn handleError() VirError { const err = c.virGetLastError(); - std.debug.print("err: {any}\n", .{err}); + // std.debug.print("err: {any}\n", .{err}); return switch (err.*.code) { c.VIR_ERR_OK => VirError.OK, c.VIR_ERR_INTERNAL_ERROR => VirError.InternalError, @@ -239,6 +239,27 @@ pub const VirError = error{ NoNetworkMetadata, }; +// Helper struct for allocating null-terminated strings +pub const String = struct { + allocator: mem.Allocator, + slice: []u8, + str: [:0]const u8, + + pub fn init(allocator: mem.Allocator, in_str: []const u8) !String { + const str = try allocator.alloc(u8, in_str.len + 1); + @memcpy(str[0..in_str.len], in_str); + str[str.len - 1] = 0; + return .{ + .allocator = allocator, + .slice = str, + .str = @ptrCast(str), + }; + } + pub fn deinit(self: *const String) void { + self.allocator.free(self.slice); + } +}; + fn string(str: [*c]const u8) []const u8 { return mem.span(str); } @@ -348,12 +369,12 @@ pub const Connection = struct { ); } - pub fn createPool(self: *const Connection, xml: []const u8, flags: []const Pool.CreateFlags) !Pool { - const pool = c.virStoragePoolCreateXML(self.ptr, @ptrCast(xml), intFromFlags(Pool.CreateFlags, flags)); + pub fn createPool(self: *const Connection, xml: String, flags: []const Pool.CreateFlags) !Pool { + const pool = c.virStoragePoolCreateXML(self.ptr, @ptrCast(xml.str), intFromFlags(Pool.CreateFlags, flags)); return if (pool) |p| Pool.init(p, self.allocator) else handleError(); } - pub fn definePoolFlags(self: *const Connection, xml: []const u8, flags: []const Pool.DefineFlags) !Pool { - const pool = c.virStoragePoolCreateXML(self.ptr, @ptrCast(xml), intFromFlags(Pool.DefineFlags, flags)); + pub fn definePoolFlags(self: *const Connection, xml: String, flags: []const Pool.DefineFlags) !Pool { + const pool = c.virStoragePoolCreateXML(self.ptr, @ptrCast(xml.str), intFromFlags(Pool.DefineFlags, flags)); return if (pool) |p| Pool.init(p, self.allocator) else handleError(); } @@ -376,16 +397,16 @@ pub const Connection = struct { ); } - pub fn createDomain(self: *const Connection, xml: []const u8, flags: []const Domain.CreateFlags) !Domain { - const domain = c.virDomainCreateXML(self.ptr, @ptrCast(xml), intFromFlags(Domain.CreateFlags, flags)); + pub fn createDomain(self: *const Connection, xml: String, flags: []const Domain.CreateFlags) !Domain { + const domain = c.virDomainCreateXML(self.ptr, @ptrCast(xml.str), intFromFlags(Domain.CreateFlags, flags)); return if (domain) |d| Domain.init(d, self.allocator) else handleError(); } - pub fn defineDomain(self: *const Connection, xml: []const u8) !Domain { - const domain = c.virDomainDefineXML(self.ptr, @ptrCast(xml)); + pub fn defineDomain(self: *const Connection, xml: String) !Domain { + const domain = c.virDomainDefineXML(self.ptr, @ptrCast(xml.str)); return if (domain) |d| Domain.init(d, self.allocator) else handleError(); } - pub fn defineDomainFlags(self: *const Connection, xml: []const u8, flags: []const Domain.DefineFlags) !Domain { - const domain = c.virDomainDefineXMLFlags(self.ptr, @ptrCast(xml), intFromFlags(Domain.DefineFlags, flags)); + pub fn defineDomainFlags(self: *const Connection, xml: String, flags: []const Domain.DefineFlags) !Domain { + const domain = c.virDomainDefineXMLFlags(self.ptr, @ptrCast(xml.str), intFromFlags(Domain.DefineFlags, flags)); return if (domain) |d| Domain.init(d, self.allocator) else handleError(); } }; @@ -413,8 +434,13 @@ pub const Pool = struct { // return if (str.len == 0) handleError() else try self.arena.allocator().dupe(u8, str); } - pub fn createVolume(self: *const Pool, xml: []const u8, flags: []const Volume.CreateFlags) !Volume { - const volume = c.virStorageVolCreateXML(self.ptr, @ptrCast(xml), intFromFlags(Volume.CreateFlags, flags)); + pub fn createVolume(self: *const Pool, xml: String, flags: []const Volume.CreateFlags) !Volume { + const volume = c.virStorageVolCreateXML(self.ptr, @ptrCast(xml.str), intFromFlags(Volume.CreateFlags, flags)); + return if (volume) |v| Volume.init(v, self.arena.allocator()) else handleError(); + } + + pub fn lookupVolumeByName(self: *const Pool, name: []const u8) !Volume { + const volume = c.virStorageVolLookupByName(self.ptr, @ptrCast(name)); return if (volume) |v| Volume.init(v, self.arena.allocator()) else handleError(); } diff --git a/server/src/main.zig b/server/src/main.zig index 8b02370..13fdd90 100644 --- a/server/src/main.zig +++ b/server/src/main.zig @@ -6,9 +6,9 @@ const fs = std.fs; const libvirt = @import("libvirt.zig"); pub fn main() !void { - var gpa = heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); + var arena = heap.ArenaAllocator.init(heap.raw_c_allocator); + defer arena.deinit(); + const allocator = arena.allocator(); const connection = try libvirt.Connection.connect("qemu:///system", allocator); defer connection.close(); @@ -20,7 +20,7 @@ pub fn main() !void { nix.cwd_dir = flake_dir; _ = try nix.spawnAndWait(); nix.argv = &[_][]const u8{ "nix", "build", ".#beforeInstall", "-o", "beforeInstall" }; - // _ = try nix.spawnAndWait(); + _ = try nix.spawnAndWait(); nix.argv = &[_][]const u8{ "nix", "build", ".#afterInstall", "-o", "afterInstall" }; // _ = try nix.spawnAndWait(); nix.argv = &[_][]const u8{ "nix", "build", ".#beforeBoot", "-o", "beforeBoot" }; @@ -32,7 +32,11 @@ pub fn main() !void { defer volume_def.close(); const volume_xml = try volume_def.readToEndAlloc(allocator, 1024 * 1024); defer allocator.free(volume_xml); - // const volume = try connection.defineVolume(volume_xml); + + const domain_beforeinstall_def = try flake_dir.openFile("beforeInstall", .{}); + defer domain_beforeinstall_def.close(); + const domain_beforeinstall_xml = try domain_beforeinstall_def.readToEndAlloc(allocator, 1024 * 1024 * 1024); + defer allocator.free(domain_beforeinstall_xml); // -------------- @@ -68,22 +72,22 @@ pub fn main() !void { const name = try pool.getName(); // std.debug.print("name: {s}\n", .{name}); if (mem.eql(u8, name, "default")) { - // std.debug.print("xml: {s}\n\n", .{volume_xml}); - const xml_str = - \\ - \\ wintest.qcow2 - \\ 16 - \\ - \\ - \\ - \\ - ; - const volume = try pool.createVolume(xml_str, &[_]libvirt.Pool.Volume.CreateFlags{ - libvirt.Pool.Volume.CreateFlags.Validate, - }); - std.debug.print("pool: {any}\n", .{volume}); + const vol_str = try libvirt.String.init(allocator, volume_xml); + defer vol_str.deinit(); + const volume = pool.createVolume(vol_str, &[_]libvirt.Pool.Volume.CreateFlags{}) catch |err| blk: { + if (err == libvirt.VirError.StorageVolExist) { + break :blk try pool.lookupVolumeByName("wintest.qcow2"); + } else return err; + }; + _ = volume; + break; } } + + const dom_str = try libvirt.String.init(allocator, domain_beforeinstall_xml); + defer dom_str.deinit(); + const domain = try connection.createDomain(dom_str, &[_]libvirt.Domain.CreateFlags{}); + _ = domain; } pub const DomainSpec = struct {