Virtualization info
This commit is contained in:
3
build.sh
3
build.sh
@@ -39,6 +39,9 @@ CompilerFlags+=" -lpulse"
|
||||
# NetworkManager
|
||||
CompilerFlags+=" "$(pkg-config --libs --cflags libnm)
|
||||
|
||||
# Libvirtd
|
||||
CompilerFlags+=" -lvirt"
|
||||
|
||||
# External libs
|
||||
CompilerFlags+=" -Iexternal"
|
||||
ExternalFiles="external/*.cpp"
|
||||
|
||||
334
code/main.cpp
334
code/main.cpp
@@ -17,6 +17,7 @@
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <NetworkManager.h>
|
||||
#include <libvirt/libvirt.h>
|
||||
|
||||
|
||||
bool process_input(); // Returns true when the program needs to exit
|
||||
@@ -24,6 +25,77 @@ void process_gui();
|
||||
void app_init();
|
||||
void app_deinit();
|
||||
|
||||
struct App_Data
|
||||
{
|
||||
f64 glib_iteration_t = 0;
|
||||
f64 system_sample_t = 0;
|
||||
f64 network_sample_t = 0;
|
||||
f64 virt_sample_t = 0;
|
||||
|
||||
f64 glib_iteration_delta = 0.1;
|
||||
f64 system_sample_delta = 0.2;
|
||||
f64 network_sample_delta = 0.2;
|
||||
f64 virt_sample_delta = 0.5;
|
||||
};
|
||||
|
||||
struct System_Info
|
||||
{
|
||||
char hostname[128];
|
||||
char kernel[128];
|
||||
time_t time;
|
||||
char cached_date_string[128];
|
||||
char cached_time_string[128];
|
||||
|
||||
s32 cpus_total;
|
||||
s32 cpus_active;
|
||||
|
||||
f32 load[3];
|
||||
s64 uptime;
|
||||
|
||||
u64 ram_total;
|
||||
u64 ram_used;
|
||||
u64 ram_available;
|
||||
};
|
||||
|
||||
struct Network_Device
|
||||
{
|
||||
char name[128];
|
||||
NMDeviceType type;
|
||||
NMDeviceState state;
|
||||
};
|
||||
|
||||
struct Network_Info
|
||||
{
|
||||
s32 device_count;
|
||||
Network_Device devices[32];
|
||||
};
|
||||
|
||||
struct Virt_Domain
|
||||
{
|
||||
char name[128];
|
||||
s32 state;
|
||||
|
||||
u32 vcpus;
|
||||
f32 cpu_usage;
|
||||
u64 prev_cpuTime;
|
||||
|
||||
u64 ram_total;
|
||||
u64 ram_used;
|
||||
u64 ram_available;
|
||||
};
|
||||
|
||||
struct Virt_Info
|
||||
{
|
||||
s32 domain_count;
|
||||
Virt_Domain domains[32];
|
||||
};
|
||||
|
||||
System_Info system_info;
|
||||
Network_Info network_info;
|
||||
Virt_Info virt_info;
|
||||
App_Data app_data;
|
||||
|
||||
|
||||
u32 seconds_to_duration_text(char *text, f64 seconds, bool show_millis = false)
|
||||
{
|
||||
u32 written = 0;
|
||||
@@ -175,66 +247,27 @@ bool process_input()
|
||||
|
||||
|
||||
|
||||
NMClient *nmclient;
|
||||
void app_init()
|
||||
{
|
||||
nmclient = nm_client_new(NULL, NULL);
|
||||
}
|
||||
|
||||
void app_deinit()
|
||||
{
|
||||
}
|
||||
|
||||
void system_info_window()
|
||||
{
|
||||
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions(v2{0,0}, v2{40,10}*engine.gui_scaling, 3, 6, 0.4*engine.gui_scaling);
|
||||
gui_window_start(Rect{0.1*engine.gui_scaling, 0.1*engine.gui_scaling, layout.window_size.x, layout.window_size.y}, 0xabcdef01);
|
||||
|
||||
// Hostname
|
||||
struct utsname host_info;
|
||||
uname(&host_info);
|
||||
|
||||
char hostname[128] = "Server manager";
|
||||
if(host_info.nodename[0])
|
||||
strcpy(hostname, host_info.nodename);
|
||||
char kernel[256];
|
||||
sprintf(kernel, "%s %s", host_info.sysname, host_info.release);
|
||||
|
||||
// Clock
|
||||
time_t time_now = time(NULL);
|
||||
struct tm *time_info = localtime(&time_now);
|
||||
char date_string[128];
|
||||
strftime(date_string, 128, "%a %e %b %Y", time_info);
|
||||
char time_string[128];
|
||||
strftime(time_string, 128, "%H:%M:%S %Z", time_info);
|
||||
|
||||
|
||||
gui_text_aligned(layout.cell(), hostname, GUI_ALIGN_LEFT);
|
||||
gui_text_aligned(layout.cell(), time_string, GUI_ALIGN_CENTER);
|
||||
gui_text_aligned(layout.cell(), date_string, GUI_ALIGN_RIGHT);
|
||||
|
||||
// Host date and time
|
||||
gui_text_aligned(layout.cell(), system_info.hostname, GUI_ALIGN_LEFT);
|
||||
gui_text_aligned(layout.cell(), system_info.cached_time_string, GUI_ALIGN_CENTER);
|
||||
gui_text_aligned(layout.cell(), system_info.cached_date_string, GUI_ALIGN_RIGHT);
|
||||
|
||||
// Load, Memory, Uptime
|
||||
struct sysinfo sys_info;
|
||||
sysinfo(&sys_info);
|
||||
char uptime[128] = "Uptime: "; seconds_to_duration_text(uptime + strlen("Uptime: "), sys_info.uptime);
|
||||
f32 load_scale = 1.0f / (1 << SI_LOAD_SHIFT);
|
||||
f32 loads[3] = {
|
||||
load_scale * sys_info.loads[1],
|
||||
load_scale * sys_info.loads[1],
|
||||
load_scale * sys_info.loads[1]
|
||||
};
|
||||
for(int i = 0; i < 3; i++)
|
||||
loads[i] = round(load_scale * sys_info.loads[i] * 100) / 100;
|
||||
char load[128]; sprintf(load, "Load: %.2f %.2f %.2f", loads[0], loads[1], loads[2]);
|
||||
|
||||
int n_processors = get_nprocs();
|
||||
int n_processors_active = get_nprocs_conf();
|
||||
char processors[128]; sprintf(processors, "CPUs: %d/%d", n_processors_active, n_processors);
|
||||
char load[128]; snprintf(load, 128, "Load: %.2f %.2f %.2f", system_info.load[0], system_info.load[1], system_info.load[2]);
|
||||
|
||||
u64 ram_total = sys_info.totalram * sys_info.mem_unit;
|
||||
u64 ram_used = (sys_info.totalram - sys_info.freeram - sys_info.bufferram) * sys_info.mem_unit;
|
||||
char ram[128]; sprintf(ram, "RAM: %.2f/%.2f GiB", ram_used / (1024.0*1024.0*1024.0), ram_total / (1024.0*1024.0*1024.0));
|
||||
char processors[128]; snprintf(processors, 128, "CPUs: %d/%d", system_info.cpus_active, system_info.cpus_total);
|
||||
|
||||
char ram[128]; snprintf(ram, 128, "RAM: %.2f/%.2f GiB", system_info.ram_used / (1024.0*1024.0*1024.0), system_info.ram_total / (1024.0*1024.0*1024.0));
|
||||
|
||||
layout.row(2);
|
||||
gui_text_aligned(layout.cell(), processors, GUI_ALIGN_LEFT);
|
||||
@@ -251,17 +284,17 @@ void network_window()
|
||||
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions(v2{0,0}, v2{40,12}*engine.gui_scaling, 3, 7, 0.4*engine.gui_scaling);
|
||||
gui_window_start(Rect{0.1*engine.gui_scaling, 11*engine.gui_scaling, layout.window_size.x, layout.window_size.y}, 0xabcdef02);
|
||||
|
||||
const GPtrArray *devices = nm_client_get_devices(nmclient);
|
||||
for(int i = 0; i < devices->len; i++)
|
||||
{
|
||||
NMDevice *device = (NMDevice*)devices->pdata[i];
|
||||
const char *device_name = nm_device_get_iface(device);
|
||||
gui_button(layout.cell(), device_name);
|
||||
|
||||
Gui_Context *ctx = &global_gui_state.default_context;
|
||||
gui_id_stack_push(ctx, gui_id_from_pointer(ctx, device_name));
|
||||
|
||||
switch(nm_device_get_device_type(device))
|
||||
for(s32 i = 0; i < network_info.device_count; i++)
|
||||
{
|
||||
Network_Device *device = &network_info.devices[i];
|
||||
|
||||
gui_button(layout.cell(), device->name);
|
||||
|
||||
gui_id_stack_push(ctx, gui_id_from_pointer(ctx, device->name));
|
||||
|
||||
switch(device->type)
|
||||
{
|
||||
case NM_DEVICE_TYPE_ETHERNET: gui_button(layout.cell(), "ETHERNET"); break;
|
||||
case NM_DEVICE_TYPE_WIFI: gui_button(layout.cell(), "WIFI"); break;
|
||||
@@ -272,7 +305,7 @@ void network_window()
|
||||
default: gui_button(layout.cell(), ""); break;
|
||||
}
|
||||
|
||||
switch(nm_device_get_state(device))
|
||||
switch(device->state)
|
||||
{
|
||||
case NM_DEVICE_STATE_UNKNOWN: gui_button(layout.cell(), "UNKNOWN"); break;
|
||||
case NM_DEVICE_STATE_UNMANAGED: gui_button(layout.cell(), "UNMANAGED"); break;
|
||||
@@ -298,18 +331,201 @@ void network_window()
|
||||
|
||||
void vm_window()
|
||||
{
|
||||
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions(v2{0,0}, v2{40,8}*engine.gui_scaling, 3, 7, 0.4*engine.gui_scaling);
|
||||
Gui_Layout_Grid layout = gui_layout_grid_create_by_divisions(v2{0,0}, v2{40,7}*engine.gui_scaling, 6, 4, 0.4*engine.gui_scaling);
|
||||
gui_window_start(Rect{0.1*engine.gui_scaling, 24*engine.gui_scaling, layout.window_size.x, layout.window_size.y}, 0xabcdef03);
|
||||
|
||||
Gui_Context *ctx = &global_gui_state.default_context;
|
||||
|
||||
|
||||
Gui_Style old_style = ctx->style;
|
||||
for(s32 i = 0; i < virt_info.domain_count; i++)
|
||||
{
|
||||
Virt_Domain *domain = &virt_info.domains[i];
|
||||
|
||||
// Name and state
|
||||
switch(domain->state)
|
||||
{
|
||||
case VIR_DOMAIN_NOSTATE:
|
||||
ctx->style.button_color = old_style.button_color;
|
||||
break;
|
||||
case VIR_DOMAIN_RUNNING:
|
||||
ctx->style.button_color = v4{0,1,0,1};
|
||||
break;
|
||||
case VIR_DOMAIN_BLOCKED:
|
||||
case VIR_DOMAIN_SHUTOFF:
|
||||
case VIR_DOMAIN_CRASHED:
|
||||
ctx->style.button_color = v4{1,0,0,1};
|
||||
break;
|
||||
case VIR_DOMAIN_SHUTDOWN:
|
||||
ctx->style.button_color = v4{0,.6,0,1};
|
||||
break;
|
||||
case VIR_DOMAIN_PAUSED:
|
||||
case VIR_DOMAIN_PMSUSPENDED:
|
||||
ctx->style.button_color = v4{.7,.7,0,1};
|
||||
break;
|
||||
default:
|
||||
ctx->style.button_color = old_style.button_color;
|
||||
}
|
||||
gui_button(layout.cell(), domain->name);
|
||||
|
||||
gui_id_stack_push(ctx, gui_id_from_pointer(ctx, domain->name));
|
||||
|
||||
ctx->style = old_style;
|
||||
|
||||
// CPU usage
|
||||
char cpu[128]; snprintf(cpu, 128, "%.2f%%", domain->cpu_usage * 100);
|
||||
gui_button(layout.cell(), cpu);
|
||||
|
||||
char ram[128]; snprintf(ram, 128, "%.2f GB", domain->ram_total / (1024.0*1024.0*1024.0));
|
||||
gui_button(layout.cell(), ram);
|
||||
|
||||
char cpu_count[128]; snprintf(cpu_count, 128, "%hd vCPU", domain->vcpus);
|
||||
gui_button(layout.cell(), cpu_count);
|
||||
|
||||
gui_id_stack_pop(ctx);
|
||||
layout.row();
|
||||
}
|
||||
|
||||
ctx->style = old_style;
|
||||
|
||||
gui_window_end();
|
||||
}
|
||||
|
||||
void process_gui()
|
||||
|
||||
NMClient *nmclient;
|
||||
virConnectPtr virt_connection;
|
||||
|
||||
void collect_static_data()
|
||||
{
|
||||
// Hostname
|
||||
struct utsname host_info;
|
||||
uname(&host_info);
|
||||
|
||||
system_info.hostname[0] = 0;
|
||||
if(host_info.nodename[0])
|
||||
strncpy(system_info.hostname, host_info.nodename, 128);
|
||||
snprintf(system_info.kernel, 128, "%s %s", host_info.sysname, host_info.release);
|
||||
}
|
||||
|
||||
void collect_new_data_if_needed()
|
||||
{
|
||||
if(engine.time - app_data.glib_iteration_t >= app_data.glib_iteration_delta)
|
||||
{
|
||||
g_main_context_iteration(NULL, false);
|
||||
app_data.glib_iteration_t = engine.time;
|
||||
}
|
||||
|
||||
|
||||
if(engine.time - app_data.system_sample_t >= app_data.system_sample_delta)
|
||||
{
|
||||
// Clock
|
||||
system_info.time = time(NULL);
|
||||
struct tm *time_info = localtime(&system_info.time);
|
||||
strftime(system_info.cached_date_string, 128, "%a %e %b %Y", time_info);
|
||||
strftime(system_info.cached_time_string, 128, "%H:%M:%S %Z", time_info);
|
||||
|
||||
// CPU count
|
||||
system_info.cpus_total = get_nprocs();
|
||||
system_info.cpus_active = get_nprocs_conf();
|
||||
|
||||
// System info for later
|
||||
struct sysinfo sys_info;
|
||||
sysinfo(&sys_info);
|
||||
// Uptime
|
||||
system_info.uptime = sys_info.uptime;
|
||||
// Load
|
||||
system_info.load;
|
||||
for(int i = 0; i < 3; i++)
|
||||
system_info.load[i] = round((f32)sys_info.loads[i] / (1 << SI_LOAD_SHIFT) * 100) / 100;
|
||||
|
||||
// Memory
|
||||
system_info.ram_total = sys_info.totalram * sys_info.mem_unit;
|
||||
system_info.ram_available = (sys_info.freeram + sys_info.bufferram) * sys_info.mem_unit;
|
||||
system_info.ram_used = sys_info.totalram * sys_info.mem_unit - system_info.ram_available;
|
||||
|
||||
|
||||
app_data.system_sample_t = engine.time;
|
||||
}
|
||||
|
||||
|
||||
if(engine.time - app_data.network_sample_t >= app_data.network_sample_delta)
|
||||
{
|
||||
const GPtrArray *devices = nm_client_get_devices(nmclient);
|
||||
network_info.device_count = devices->len;
|
||||
for(int i = 0; i < devices->len; i++)
|
||||
{
|
||||
NMDevice *device = (NMDevice*)devices->pdata[i];
|
||||
|
||||
strncpy(network_info.devices[i].name, nm_device_get_iface(device), 128);
|
||||
network_info.devices[i].type = nm_device_get_device_type(device);
|
||||
network_info.devices[i].state = nm_device_get_state(device);
|
||||
}
|
||||
|
||||
|
||||
app_data.network_sample_t = engine.time;
|
||||
}
|
||||
|
||||
|
||||
if(engine.time - app_data.virt_sample_t >= app_data.virt_sample_delta)
|
||||
{
|
||||
virDomainPtr *domains;
|
||||
virt_info.domain_count = virConnectListAllDomains(virt_connection, &domains, 0);
|
||||
|
||||
for(int i = 0; i < virt_info.domain_count; i++)
|
||||
{
|
||||
Virt_Domain *dom = &virt_info.domains[i];
|
||||
// Name
|
||||
strncpy(dom->name, virDomainGetName(domains[i]), 128);
|
||||
|
||||
// State
|
||||
virDomainInfo info;
|
||||
int res = virDomainGetInfo(domains[i], &info);
|
||||
dom->state = info.state;
|
||||
|
||||
// CPU
|
||||
dom->vcpus = info.nrVirtCpu;
|
||||
|
||||
dom->cpu_usage = (info.cpuTime - dom->prev_cpuTime) / ((engine.time - app_data.virt_sample_t) * 1e9 * dom->vcpus);
|
||||
dom->prev_cpuTime = info.cpuTime;
|
||||
|
||||
dom->ram_total = info.memory * 1024; // mem * 1000 or mem * 1024 ??
|
||||
dom->ram_used = dom->ram_total;
|
||||
dom->ram_available = 0;
|
||||
}
|
||||
|
||||
p_free(domains);
|
||||
|
||||
|
||||
app_data.virt_sample_t = engine.time;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void process_gui()
|
||||
{
|
||||
collect_new_data_if_needed();
|
||||
|
||||
|
||||
system_info_window();
|
||||
network_window();
|
||||
vm_window();
|
||||
}
|
||||
|
||||
void app_init()
|
||||
{
|
||||
app_data.system_sample_t = 0;
|
||||
app_data.network_sample_t = 0;
|
||||
app_data.virt_sample_t = 0;
|
||||
app_data.glib_iteration_t = 0;
|
||||
|
||||
nmclient = nm_client_new(NULL, NULL);
|
||||
virt_connection = virConnectOpenReadOnly("qemu:///system");
|
||||
|
||||
collect_static_data();
|
||||
}
|
||||
|
||||
void app_deinit()
|
||||
{
|
||||
virConnectClose(virt_connection);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user