zig libvirt: implement most error codes as zig errors

This commit is contained in:
Jeeves 2024-06-25 08:50:37 -06:00
parent 05969155df
commit 8ae3069450
2 changed files with 232 additions and 27 deletions

View file

@ -13,14 +13,117 @@ pub const c = @cImport({
fn handleError() VirError { fn handleError() VirError {
const err = c.virGetLastError(); const err = c.virGetLastError();
std.debug.print("err: {any}\n", .{err}); std.debug.print("err: {any}\n", .{err});
return VirError.OK; return switch (err.*.code) {
// switch (err.*.code) { c.VIR_ERR_OK => VirError.OK,
// 0 => return VirError.OK, c.VIR_ERR_INTERNAL_ERROR => VirError.InternalError,
// 1 => return VirError.InternalError, c.VIR_ERR_NO_MEMORY => VirError.NoMemory,
// 2 => return VirError.NoMemory, c.VIR_ERR_NO_SUPPORT => VirError.NoSupport,
// // TODO rest c.VIR_ERR_UNKNOWN_HOST => VirError.UnknownHost,
// else => VirError.OK, c.VIR_ERR_NO_CONNECT => VirError.NoConnect,
// } c.VIR_ERR_INVALID_CONN => VirError.InvalidConn,
c.VIR_ERR_INVALID_DOMAIN => VirError.InvalidDomain,
c.VIR_ERR_INVALID_ARG => VirError.InvalidArg,
c.VIR_ERR_OPERATION_FAILED => VirError.OperationFailed,
c.VIR_ERR_GET_FAILED => VirError.GetFailed,
c.VIR_ERR_POST_FAILED => VirError.PostFailed,
c.VIR_ERR_HTTP_ERROR => VirError.HttpError,
c.VIR_ERR_SEXPR_SERIAL => VirError.SexprSerial,
c.VIR_ERR_NO_XEN => VirError.NoXen,
c.VIR_ERR_XEN_CALL => VirError.XenCall,
c.VIR_ERR_OS_TYPE => VirError.OsType,
c.VIR_ERR_NO_KERNEL => VirError.NoKernel,
c.VIR_ERR_NO_ROOT => VirError.NoRoot,
c.VIR_ERR_NO_TARGET => VirError.NoTarget,
c.VIR_ERR_NO_NAME => VirError.NoName,
c.VIR_ERR_NO_OS => VirError.NoOs,
c.VIR_ERR_NO_DEVICE => VirError.NoDevice,
c.VIR_ERR_DRIVER_FULL => VirError.DriverFull,
c.VIR_ERR_CALL_FAILED => VirError.CallFailed,
c.VIR_ERR_XML_ERROR => VirError.XmlError,
c.VIR_ERR_DOM_EXIST => VirError.DomExist,
c.VIR_ERR_OPERATION_DENIED => VirError.OperationDenied,
c.VIR_ERR_OPEN_FAILED => VirError.OpenFailed,
c.VIR_ERR_READ_FAILED => VirError.ReadFailed,
c.VIR_ERR_PARSE_FAILED => VirError.ParseFailed,
c.VIR_ERR_CONF_SYNTAX => VirError.ConfSyntax,
c.VIR_ERR_WRITE_FAILED => VirError.WriteFailed,
c.VIR_ERR_XML_DETAIL => VirError.XmlDetail,
c.VIR_ERR_INVALID_NETWORK => VirError.InvalidNetwork,
c.VIR_ERR_NETWORK_EXIST => VirError.NetworkExist,
c.VIR_ERR_SYSTEM_ERROR => VirError.SystemError,
c.VIR_ERR_RPC => VirError.Rpc,
c.VIR_ERR_GNUTLS_ERROR => VirError.GnutlsError,
c.VIR_WAR_NO_NETWORK => VirError.WarNoNetwork, // ???
c.VIR_ERR_NO_DOMAIN => VirError.NoDomain,
c.VIR_ERR_NO_NETWORK => VirError.NoNetwork,
c.VIR_ERR_INVALID_MAC => VirError.InvalidMac,
c.VIR_ERR_AUTH_FAILED => VirError.AuthFailed,
c.VIR_ERR_INVALID_STORAGE_POOL => VirError.InvalidStoragePool,
c.VIR_ERR_INVALID_STORAGE_VOL => VirError.InvalidStorageVol,
c.VIR_WAR_NO_STORAGE => VirError.WarNoStorage, // ???
c.VIR_ERR_NO_STORAGE_POOL => VirError.NoStoragePool,
c.VIR_ERR_NO_STORAGE_VOL => VirError.NoStorageVol,
c.VIR_WAR_NO_NODE => VirError.WarNoNode, // ???
c.VIR_ERR_INVALID_NODE_DEVICE => VirError.InvalidNodeDevice,
c.VIR_ERR_NO_NODE_DEVICE => VirError.NoNodeDevice,
c.VIR_ERR_NO_SECURITY_MODEL => VirError.NoSecurityModel,
c.VIR_ERR_OPERATION_INVALID => VirError.OperationInvalid,
c.VIR_WAR_NO_INTERFACE => VirError.WarNoInterface, // ???
c.VIR_ERR_NO_INTERFACE => VirError.NoInterface,
c.VIR_ERR_INVALID_INTERFACE => VirError.InvalidInterface,
c.VIR_ERR_MULTIPLE_INTERFACES => VirError.MultipleInterfaces,
c.VIR_WAR_NO_NWFILTER => VirError.WarNoNwfilter, // ???
c.VIR_ERR_INVALID_NWFILTER => VirError.InvalidNwfilter,
c.VIR_ERR_BUILD_FIREWALL => VirError.BuildFirewall,
c.VIR_WAR_NO_SECRET => VirError.WarNoSecret, // ???
c.VIR_ERR_INVALID_SECRET => VirError.InvalidSecret,
c.VIR_ERR_CONFIG_UNSUPPORTED => VirError.ConfigUnsupported,
c.VIR_ERR_OPERATION_TIMEOUT => VirError.OperationTimeout,
c.VIR_ERR_MIGRATE_PERSIST_FAILED => VirError.MigratePersistFailed,
c.VIR_ERR_HOOK_SCRIPT_FAILED => VirError.HookScriptFailed,
c.VIR_ERR_INVALID_DOMAIN_SNAPSHOT => VirError.InvalidDomainSnapshot,
c.VIR_ERR_NO_DOMAIN_SNAPSHOT => VirError.NoDomainSnapshot,
c.VIR_ERR_INVALID_STREAM => VirError.InvalidStream,
c.VIR_ERR_ARGUMENT_UNSUPPORTED => VirError.ArgumentUnsupported,
c.VIR_ERR_STORAGE_PROBE_FAILED => VirError.StorageProbeFailed,
c.VIR_ERR_STORAGE_POOL_BUILT => VirError.StoragePoolBuilt,
c.VIR_ERR_SNAPSHOT_REVERT_RISKY => VirError.SnapshotReverRisky,
c.VIR_ERR_OPERATION_ABORTED => VirError.OperationAborted,
c.VIR_ERR_AUTH_CANCELLED => VirError.AuthCancelled,
c.VIR_ERR_NO_DOMAIN_METADATA => VirError.NoDomainMetadata,
c.VIR_ERR_MIGRATE_UNSAFE => VirError.MigrateUnsafe,
c.VIR_ERR_OVERFLOW => VirError.Overflow,
c.VIR_ERR_BLOCK_COPY_ACTIVE => VirError.BlockCopyActive,
c.VIR_ERR_OPERATION_UNSUPPORTED => VirError.OperationUnsupported,
c.VIR_ERR_SSH => VirError.Ssh,
c.VIR_ERR_AGENT_UNRESPONSIVE => VirError.AgentUnresponsive,
c.VIR_ERR_RESOURCE_BUSY => VirError.ResourceBusy,
c.VIR_ERR_ACCESS_DENIED => VirError.AccessDenied,
c.VIR_ERR_DBUS_SERVICE => VirError.DbusService,
c.VIR_ERR_STORAGE_VOL_EXIST => VirError.StorageVolExist,
c.VIR_ERR_CPU_INCOMPATIBLE => VirError.CpuIncompatible,
c.VIR_ERR_XML_INVALID_SCHEMA => VirError.XmlInvalidSchema,
c.VIR_ERR_MIGRATE_FINISH_OK => VirError.MigrateFinishOk,
c.VIR_ERR_AUTH_UNAVAILABLE => VirError.AuthUnavailable,
c.VIR_ERR_NO_SERVER => VirError.NoServer,
c.VIR_ERR_NO_CLIENT => VirError.NoClient,
c.VIR_ERR_AGENT_UNSYNCED => VirError.AgentUnsynced,
c.VIR_ERR_LIBSSH => VirError.Libssh,
c.VIR_ERR_DEVICE_MISSING => VirError.DeviceMissing,
c.VIR_ERR_INVALID_NWFILTER_BINDING => VirError.InvalidNwfilterBinding,
c.VIR_ERR_NO_NWFILTER_BINDING => VirError.NoNwfilterBinding,
c.VIR_ERR_INVALID_DOMAIN_CHECKPOINT => VirError.InvalidDomainCheckpoint,
c.VIR_ERR_NO_DOMAIN_CHECKPOINT => VirError.NoDomainCheckpoint,
c.VIR_ERR_NO_DOMAIN_BACKUP => VirError.NoDomainBackup,
c.VIR_ERR_INVALID_NETWORK_PORT => VirError.InvalidNetworkPort,
c.VIR_ERR_NETWORK_PORT_EXIST => VirError.NetworkPortExist,
c.VIR_ERR_NO_NETWORK_PORT => VirError.NoNetworkPort,
c.VIR_ERR_NO_HOSTNAME => VirError.NoHostname,
c.VIR_ERR_CHECKPOINT_INCONSISTENT => VirError.CheckpointInconsistent,
c.VIR_ERR_MULTIPLE_DOMAINS => VirError.MultipleDomains,
c.VIR_ERR_NO_NETWORK_METADATA => VirError.NoNetworkMetadata,
else => VirError.OK,
};
} }
pub const VirError = error{ pub const VirError = error{
@ -37,7 +140,7 @@ pub const VirError = error{
GetFailed, GetFailed,
PostFailed, PostFailed,
HttpError, HttpError,
SExprError, SexprSerial,
NoXen, NoXen,
XenCall, XenCall,
OsType, OsType,
@ -58,7 +161,82 @@ pub const VirError = error{
ReadFailed, ReadFailed,
ParseFailed, ParseFailed,
ConfSyntax, ConfSyntax,
// TODO rest WriteFailed,
XmlDetail,
InvalidNetwork,
NetworkExist,
SystemError,
Rpc,
GnutlsError,
WarNoNetwork, // ???
NoDomain,
NoNetwork,
InvalidMac,
AuthFailed,
InvalidStoragePool,
InvalidStorageVol,
WarNoStorage, // ???
NoStoragePool,
NoStorageVol,
WarNoNode, // ???
InvalidNodeDevice,
NoNodeDevice,
NoSecurityModel,
OperationInvalid,
WarNoInterface, // ???
NoInterface,
InvalidInterface,
MultipleInterfaces,
WarNoNwfilter, // ???
InvalidNwfilter,
BuildFirewall,
WarNoSecret, // ???
InvalidSecret,
ConfigUnsupported,
OperationTimeout,
MigratePersistFailed,
HookScriptFailed,
InvalidDomainSnapshot,
NoDomainSnapshot,
InvalidStream,
ArgumentUnsupported,
StorageProbeFailed,
StoragePoolBuilt,
SnapshotReverRisky,
OperationAborted,
AuthCancelled,
NoDomainMetadata,
MigrateUnsafe,
Overflow,
BlockCopyActive,
OperationUnsupported,
Ssh,
AgentUnresponsive,
ResourceBusy,
AccessDenied,
DbusService,
StorageVolExist,
CpuIncompatible,
XmlInvalidSchema,
MigrateFinishOk,
AuthUnavailable,
NoServer,
NoClient,
AgentUnsynced,
Libssh,
DeviceMissing,
InvalidNwfilterBinding,
NoNwfilterBinding,
InvalidDomainCheckpoint,
NoDomainCheckpoint,
NoDomainBackup,
InvalidNetworkPort,
NetworkPortExist,
NoNetworkPort,
NoHostname,
CheckpointInconsistent,
MultipleDomains,
NoNetworkMetadata,
}; };
fn string(str: [*c]const u8) []const u8 { fn string(str: [*c]const u8) []const u8 {
@ -147,7 +325,6 @@ pub const Connection = struct {
const str = string(uri); const str = string(uri);
return if (str.len == 0) handleError() else try self.allocator.dupe(u8, str); return if (str.len == 0) handleError() else try self.allocator.dupe(u8, str);
} }
pub fn freeURI(self: *const Connection, uri: []u8) void { pub fn freeURI(self: *const Connection, uri: []u8) void {
self.allocator.free(uri); self.allocator.free(uri);
} }
@ -236,9 +413,9 @@ pub const Pool = struct {
// return if (str.len == 0) handleError() else try self.arena.allocator().dupe(u8, str); // return if (str.len == 0) handleError() else try self.arena.allocator().dupe(u8, str);
} }
pub fn createVolume(pool: *const Pool, xml: []const u8, flags: []Volume.Flags) !Volume { pub fn createVolume(self: *const Pool, xml: []const u8, flags: []const Volume.CreateFlags) !Volume {
const volume = c.virStorageVolCreateXML(pool, xml, intFromFlags(Volume.CreateFlags, flags)); const volume = c.virStorageVolCreateXML(self.ptr, @ptrCast(xml), intFromFlags(Volume.CreateFlags, flags));
return .{ .ptr = volume }; return if (volume) |v| Volume.init(v, self.arena.allocator()) else handleError();
} }
pub fn iterateVolumes(self: *const Pool, flags: []const ListFlags) Volume.VolumeIterator { pub fn iterateVolumes(self: *const Pool, flags: []const ListFlags) Volume.VolumeIterator {
@ -316,6 +493,17 @@ pub const Pool = struct {
ptr: c.virStorageVolPtr, ptr: c.virStorageVolPtr,
arena: *heap.ArenaAllocator, arena: *heap.ArenaAllocator,
pub fn init(ptr: c.virStorageVolPtr, allocator: mem.Allocator) Volume {
var arena = heap.ArenaAllocator.init(allocator);
return .{
.ptr = ptr,
.arena = &arena,
};
}
pub fn deinit(self: *const Volume) void {
self.arena.deinit();
}
pub fn getName(self: *const Volume) ![]const u8 { pub fn getName(self: *const Volume) ![]const u8 {
const name = c.virStorageVolGetName(self.ptr); const name = c.virStorageVolGetName(self.ptr);
// defer std.c.free(name); // defer std.c.free(name);

View file

@ -20,29 +20,30 @@ pub fn main() !void {
nix.cwd_dir = flake_dir; nix.cwd_dir = flake_dir;
_ = try nix.spawnAndWait(); _ = try nix.spawnAndWait();
nix.argv = &[_][]const u8{ "nix", "build", ".#beforeInstall", "-o", "beforeInstall" }; nix.argv = &[_][]const u8{ "nix", "build", ".#beforeInstall", "-o", "beforeInstall" };
_ = try nix.spawnAndWait(); // _ = try nix.spawnAndWait();
nix.argv = &[_][]const u8{ "nix", "build", ".#afterInstall", "-o", "afterInstall" }; nix.argv = &[_][]const u8{ "nix", "build", ".#afterInstall", "-o", "afterInstall" };
_ = try nix.spawnAndWait(); // _ = try nix.spawnAndWait();
nix.argv = &[_][]const u8{ "nix", "build", ".#beforeBoot", "-o", "beforeBoot" }; nix.argv = &[_][]const u8{ "nix", "build", ".#beforeBoot", "-o", "beforeBoot" };
_ = try nix.spawnAndWait(); // _ = try nix.spawnAndWait();
nix.argv = &[_][]const u8{ "nix", "build", ".#afterBoot", "-o", "afterBoot" }; nix.argv = &[_][]const u8{ "nix", "build", ".#afterBoot", "-o", "afterBoot" };
_ = try nix.spawnAndWait(); // _ = try nix.spawnAndWait();
// const volume_def = try flake_dir.openFile("volume", .{}); const volume_def = try flake_dir.openFile("volume", .{});
// defer volume_def.close(); defer volume_def.close();
// const volume_xml = try volume_def.readToEndAlloc(allocator, 1024 * 1024); const volume_xml = try volume_def.readToEndAlloc(allocator, 1024 * 1024);
// defer allocator.free(volume_xml); defer allocator.free(volume_xml);
// const volume = try connection.defineVolume(volume_xml); // const volume = try connection.defineVolume(volume_xml);
// -------------- // --------------
const uri = try connection.getURI(); const uri = try connection.getURI();
defer connection.freeURI(uri); defer connection.freeURI(uri);
std.debug.print("uri: {s}\n", .{uri}); // std.debug.print("uri: {s}\n", .{uri});
const num_active = try connection.numOfDomains(); const num_active = try connection.numOfDomains();
const num_inactive = try connection.numOfDefinedDomains(); const num_inactive = try connection.numOfDefinedDomains();
std.debug.print("active: {d}, inactive: {d}\n", .{ num_active, num_inactive }); // std.debug.print("active: {d}, inactive: {d}\n", .{ num_active, num_inactive });
_ = .{ num_active, num_inactive };
var domain_iter = try connection.iterateDomains(&[_]libvirt.Domain.ListFlags{ var domain_iter = try connection.iterateDomains(&[_]libvirt.Domain.ListFlags{
libvirt.Domain.ListFlags.Active, libvirt.Domain.ListFlags.Active,
@ -53,7 +54,8 @@ pub fn main() !void {
while (domain_iter.next()) |domain| { while (domain_iter.next()) |domain| {
const active = domain.isActive(); const active = domain.isActive();
const name = domain.getName(); const name = domain.getName();
std.debug.print("name: {s}, active: {any}\n", .{ name, active }); // std.debug.print("name: {s}, active: {any}\n", .{ name, active });
_ = .{ name, active };
} }
var pool_iter = try connection.iteratePools(&[_]libvirt.Pool.ListFlags{ var pool_iter = try connection.iteratePools(&[_]libvirt.Pool.ListFlags{
@ -63,9 +65,24 @@ pub fn main() !void {
defer pool_iter.deinit(); defer pool_iter.deinit();
while (pool_iter.next()) |pool| { while (pool_iter.next()) |pool| {
// const active = pool.isActive();
const name = try pool.getName(); const name = try pool.getName();
std.debug.print("name: {s}\n", .{name}); // 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 =
\\<volume>
\\ <name>wintest.qcow2</name>
\\ <capacity unit='GB'>16</capacity>
\\ <target>
\\ <format type='qcow2'/>
\\ </target>
\\</volume>
;
const volume = try pool.createVolume(xml_str, &[_]libvirt.Pool.Volume.CreateFlags{
libvirt.Pool.Volume.CreateFlags.Validate,
});
std.debug.print("pool: {any}\n", .{volume});
}
} }
} }