Skip to content

Commit

Permalink
- restart command
Browse files Browse the repository at this point in the history
- parameter for running custom script command after vm creation
- cpu cores option
- more distros. arch, fedora, centos, alma
- lost command shows more info:
  - vm state
  - cpu cores
  - memory
  - disk used
  - ping interface
  • Loading branch information
wubbl0rz committed Mar 30, 2023
1 parent e37e9ef commit 318feaa
Show file tree
Hide file tree
Showing 9 changed files with 266 additions and 33 deletions.
7 changes: 5 additions & 2 deletions AppConfig.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
namespace VmChamp;

public class AppConfig
{
public string AppDir { get; private set; }
Expand All @@ -6,8 +8,9 @@ public class AppConfig
public string DefaultVmName { get; set; } = "testvm";
public string DefaultVmDistro { get; set; } = "Debian11";
public string DefaultUser { get; set; } = "user";
public string DefaultMemorySize { get; set; } = "256MB";
public string DefaultDiskSize { get; set; } = "4GB";
public string DefaultMemorySize { get; set; } = "256MiB";
public string DefaultDiskSize { get; set; } = "4GiB";
public int DefaultCpuCount { get; set; } = 1;

public AppConfig(string appName = "VmChamp", string sessionName = "default")
{
Expand Down
48 changes: 48 additions & 0 deletions DistroInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,54 @@ public class DistroInfo
ImageName = "focal-server-cloudimg-amd64.img",
Url = "https://cloud-images.ubuntu.com/jammy/current/",
Aliases = new[] { "Jammy Jellyfish", "Jammy" }
},
new()
{
Name = "Arch",
Family = "Arch",
ImageName = "Arch-Linux-x86_64-cloudimg.qcow2",
Url = "https://geo.mirror.pkgbuild.com/images/latest/",
Aliases = Array.Empty<string>()
},
new()
{
Name = "Fedora36",
Family = "Fedora",
ImageName = "Fedora-Cloud-Base-36-1.5.x86_64.qcow2",
Url = "https://download.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/x86_64/images/",
Aliases = Array.Empty<string>()
},
new()
{
Name = "Fedora37",
Family = "Fedora",
ImageName = "Fedora-Cloud-Base-37-1.7.x86_64.qcow2",
Url = "https://download.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/x86_64/images/",
Aliases = Array.Empty<string>()
},
new()
{
Name = "CentOS7",
Family = "RHEL",
ImageName = "CentOS-7-x86_64-GenericCloud.qcow2",
Url = "https://cloud.centos.org/centos/7/images/",
Aliases = Array.Empty<string>()
},
new()
{
Name = "Alma8",
Family = "RHEL",
ImageName = "AlmaLinux-8-GenericCloud-latest.x86_64.qcow2",
Url = "https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/",
Aliases = Array.Empty<string>()
},
new()
{
Name = "Alma9",
Family = "RHEL",
ImageName = "AlmaLinux-8-GenericCloud-latest.x86_64.qcow2",
Url = "https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/",
Aliases = Array.Empty<string>()
}
};

Expand Down
47 changes: 46 additions & 1 deletion Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,36 @@ public unsafe struct VirDomainInterface
public VirDomainIpAddress* addrs;
}

[StructLayout(LayoutKind.Sequential)]
public struct VirDomainInfo
{
public byte state;
public long maxMem;
public long memory;
public ushort nrVirtCpu;
public ulong cpuTime;
}

public struct VirDomainBlockInfo
{
public ulong capacity;
public ulong allocation;
public ulong physical;
}

enum VirDomainState
{
NoState = 0,
Running = 1,
Blocked = 2,
Paused = 3,
Shutdown = 4,
Shutoff = 5,
Crashed = 6,
Suspended = 7,
Last = 8
}

public static unsafe class Interop
{
[DllImport("libvirt.so.0",
Expand Down Expand Up @@ -51,12 +81,27 @@ public static extern nint virDomainCreateXML(IntPtr conn,
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "virDomainLookupByName")]
public static extern nint virDomainLookupByName(nint conn, string name);

[DllImport("libvirt.so.0",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "virDomainDestroy")]
public static extern int virDomainDestroy(nint domain);

[DllImport("libvirt.so.0",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "virDomainGetInfo")]
public static extern int virDomainGetInfo(nint domain, VirDomainInfo* info);

[DllImport("libvirt.so.0",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "virDomainGetBlockInfo")]
public static extern int virDomainGetBlockInfo(nint domain, string disk, VirDomainBlockInfo* info, uint flags = 0);

[DllImport("libvirt.so.0",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "virDomainReset")]
public static extern int virDomainReset(nint domain, uint flags = 0);

public static string? GetFirstIpById(nint id)
{
VirDomainInterface** ifaces = null;
Expand Down
3 changes: 2 additions & 1 deletion IsoImager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ private IEnumerable<string> FindSshKeys()
return keys;
}

public FileInfo CreateImage(string hostname, DirectoryInfo outputDirectory)
public FileInfo CreateImage(string hostname, DirectoryInfo outputDirectory, string customCmd = "")
{
var keys = "[" + string.Join(",", this.FindSshKeys().Select(key => $"\"{key.Trim()}\"")) + "]";

Expand Down Expand Up @@ -49,6 +49,7 @@ public FileInfo CreateImage(string hostname, DirectoryInfo outputDirectory)
runcmd:
- systemctl stop networking && systemctl start networking
- systemctl disable cloud-init.service
- echo; {customCmd}

--==BOUNDARY==--
""";
Expand Down
45 changes: 44 additions & 1 deletion ListCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.CommandLine;
using System.Net.NetworkInformation;
using ByteSizeLib;
using Spectre.Console;
using VmChamp;

Expand All @@ -22,13 +24,54 @@ public ListCommand(AppConfig appConfig) : base("list", "list all existing vms")
var table = new Table();
table.AddColumn("VM");
table.AddColumn("IP");
table.AddColumn("State");
table.AddColumn("Memory");
table.AddColumn("Disk");
table.AddColumn("vCPUs");
foreach (var vmDir in allVmDirectories)
{
var vmName = Path.GetFileName(vmDir);
var vmId = Interop.virDomainLookupByName(libvirtConnection.NativePtr, vmName);
var pinger = new Ping();
table.AddRow(vmName, Interop.GetFirstIpById(vmId) ?? "none");
unsafe
{
var vmIpAddress = Interop.GetFirstIpById(vmId);
var stateInfo = new VirDomainInfo();
var blockInfo = new VirDomainBlockInfo();
Interop.virDomainGetInfo(vmId, &stateInfo);
Interop.virDomainGetBlockInfo(vmId, "vda", &blockInfo);
var pingAlive = "[grey]";
if (vmIpAddress is not null)
{
var pingReply = pinger.Send(vmIpAddress, 5);
pingAlive = pingReply.Status != IPStatus.Success ? "[red]" : "[green]";
}
var state = (VirDomainState)stateInfo.state;
var color = state switch
{
VirDomainState.Running => "[green]",
VirDomainState.Paused => "[yellow]",
_ => "[red]"
};
var curMemSize = ByteSize.FromKibiBytes(stateInfo.memory);
var curDiskSize = ByteSize.FromBytes(blockInfo.allocation);
var maxDiskSize = ByteSize.FromBytes(blockInfo.capacity);
table.AddRow(vmName,
$"{pingAlive}{(vmIpAddress ?? "none")}[/]",
$"{color}{state}[/]",
$"{curMemSize:MiB}",
$"{curDiskSize:GiB}/{maxDiskSize:GiB}",
stateInfo.nrVirtCpu.ToString());
}
}
AnsiConsole.Write(table);
Expand Down
1 change: 1 addition & 0 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
rootCommand.AddCommand(new RunCommand(appConfig, downloader));
rootCommand.AddCommand(new CleanCommand(appConfig));
rootCommand.AddCommand(new RemoveCommand(appConfig));
rootCommand.AddCommand(new RestartCommand(appConfig));
rootCommand.AddCommand(new SshCommand(appConfig));
rootCommand.AddCommand(new ListCommand(appConfig));
rootCommand.AddCommand(new OsCommand(appConfig));
Expand Down
2 changes: 1 addition & 1 deletion RemoveCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public RemoveCommand(AppConfig appConfig) : base("remove", "removes a vm")

Argument<string> nameArgument = new("name",
() => appConfig.DefaultVmName,
"Name of the new VM");
"Name of the VM to remove.");

this.AddAlias("rm");
this.AddArgument(nameArgument);
Expand Down
40 changes: 40 additions & 0 deletions RestartCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.CommandLine;
using System.CommandLine.Completions;
using Spectre.Console;
using VmChamp;

public class RestartCommand : Command
{
private readonly AppConfig _appConfig;

public RestartCommand(AppConfig appConfig) : base("restart", "force restarts a vm")
{
_appConfig = appConfig;

Argument<string> nameArgument = new("name",
() => appConfig.DefaultVmName,
"Name of the VM to restart.");

this.AddAlias("reboot");
this.AddAlias("reset");
this.AddArgument(nameArgument);

nameArgument.AddCompletions((ctx) =>
Helper.GetAllVmInDirectory(_appConfig.DataDir)
.Select(vmName => new CompletionItem(vmName ?? "")));

nameArgument.AddCompletions((ctx) =>
Helper.GetAllVmInDirectory(_appConfig.DataDir)
.Select(vmName => new CompletionItem(vmName ?? "")));

this.SetHandler((vmName) =>
{
using var libvirtConnection = LibvirtConnection.Create("qemu:///session");
var vmId = Interop.virDomainLookupByName(libvirtConnection.NativePtr, vmName);
AnsiConsole.MarkupLine($"[yellow]🔄 Restart VM: {vmName}[/]");
Interop.virDomainReset(vmId);
}, nameArgument);
}
}
Loading

0 comments on commit 318feaa

Please sign in to comment.