tools: split off common helpers for host validate tool

The common messaging helpers will be reused in the new impl of the
virt-pki-validate tool.

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2024-06-06 17:07:24 +01:00
parent 05f7559b1f
commit 8ee395d843
11 changed files with 327 additions and 274 deletions

View File

@ -391,6 +391,7 @@ tools/virt-host-validate-qemu.c
tools/virt-host-validate.c tools/virt-host-validate.c
tools/virt-login-shell-helper.c tools/virt-login-shell-helper.c
tools/virt-pki-query-dn.c tools/virt-pki-query-dn.c
tools/virt-validate-common.c
tools/vsh-table.c tools/vsh-table.c
tools/vsh.c tools/vsh.c
tools/vsh.h tools/vsh.h

View File

@ -40,6 +40,7 @@ libvirt_shell_lib = static_library(
if conf.has('WITH_HOST_VALIDATE') if conf.has('WITH_HOST_VALIDATE')
virt_host_validate_sources = [ virt_host_validate_sources = [
'virt-validate-common.c',
'virt-host-validate.c', 'virt-host-validate.c',
'virt-host-validate-common.c', 'virt-host-validate-common.c',
] ]

View File

@ -28,21 +28,21 @@
#include "virt-host-validate-common.h" #include "virt-host-validate-common.h"
#define MODULE_STATUS(mod, err_msg, err_code) \ #define MODULE_STATUS(mod, err_msg, err_code) \
virHostMsgCheck("BHYVE", _("Checking for %1$s module"), #mod); \ virValidateCheck("BHYVE", _("Checking for %1$s module"), #mod); \
if (mod ## _loaded) { \ if (mod ## _loaded) { \
virHostMsgPass(); \ virValidatePass(); \
} else { \ } else { \
virHostMsgFail(err_code, \ virValidateFail(err_code, \
_("%1$s module is not loaded, " err_msg), \ _("%1$s module is not loaded, " err_msg), \
#mod); \ #mod); \
ret = -1; \ ret = -1; \
} }
#define MODULE_STATUS_FAIL(mod, err_msg) \ #define MODULE_STATUS_FAIL(mod, err_msg) \
MODULE_STATUS(mod, err_msg, VIR_HOST_VALIDATE_FAIL) MODULE_STATUS(mod, err_msg, VIR_VALIDATE_FAIL)
#define MODULE_STATUS_WARN(mod, err_msg) \ #define MODULE_STATUS_WARN(mod, err_msg) \
MODULE_STATUS(mod, err_msg, VIR_HOST_VALIDATE_WARN) MODULE_STATUS(mod, err_msg, VIR_VALIDATE_WARN)
int virHostValidateBhyve(void) int virHostValidateBhyve(void)

View File

@ -57,21 +57,21 @@ int virHostValidateCh(void)
} }
if (hasVirtFlag) { if (hasVirtFlag) {
virHostMsgCheck("CH", "%s", _("Checking for hardware virtualization")); virValidateCheck("CH", "%s", _("Checking for hardware virtualization"));
if (hasHwVirt) { if (hasHwVirt) {
virHostMsgPass(); virValidatePass();
} else { } else {
virHostMsgFail(VIR_HOST_VALIDATE_FAIL, virValidateFail(VIR_VALIDATE_FAIL,
_("Only emulated CPUs are available, performance will be significantly limited")); _("Only emulated CPUs are available, performance will be significantly limited"));
ret = -1; ret = -1;
} }
} }
if (hasHwVirt || !hasVirtFlag) { if (hasHwVirt || !hasVirtFlag) {
if (virHostValidateDeviceExists("CH", "/dev/kvm", VIR_HOST_VALIDATE_FAIL, if (virHostValidateDeviceExists("CH", "/dev/kvm", VIR_VALIDATE_FAIL,
kvmhint) < 0) kvmhint) < 0)
ret = -1; ret = -1;
else if (virHostValidateDeviceAccessible("CH", "/dev/kvm", VIR_HOST_VALIDATE_FAIL, else if (virHostValidateDeviceAccessible("CH", "/dev/kvm", VIR_VALIDATE_FAIL,
_("Check /dev/kvm is world writable or you are in a group that is allowed to access it")) < 0) _("Check /dev/kvm is world writable or you are in a group that is allowed to access it")) < 0)
ret = -1; ret = -1;
} }

View File

@ -45,144 +45,58 @@ VIR_ENUM_IMPL(virHostValidateCPUFlag,
"158", "158",
"sev"); "sev");
static bool quiet;
void virHostMsgSetQuiet(bool quietFlag)
{
quiet = quietFlag;
}
void virHostMsgCheck(const char *prefix,
const char *format,
...)
{
va_list args;
g_autofree char *msg = NULL;
if (quiet)
return;
va_start(args, format);
msg = g_strdup_vprintf(format, args);
va_end(args);
fprintf(stdout, "%1$6s: %2$-69s: ", prefix, msg);
}
static bool virHostMsgWantEscape(void)
{
static bool detectTty = true;
static bool wantEscape;
if (detectTty) {
if (isatty(STDOUT_FILENO))
wantEscape = true;
detectTty = false;
}
return wantEscape;
}
void virHostMsgPass(void)
{
if (quiet)
return;
if (virHostMsgWantEscape())
fprintf(stdout, "\033[32m%s\033[0m\n", _("PASS"));
else
fprintf(stdout, "%s\n", _("PASS"));
}
static const char * failMessages[] = {
N_("FAIL"),
N_("WARN"),
N_("NOTE"),
};
G_STATIC_ASSERT(G_N_ELEMENTS(failMessages) == VIR_HOST_VALIDATE_LAST);
static const char *failEscapeCodes[] = {
"\033[31m",
"\033[33m",
"\033[34m",
};
G_STATIC_ASSERT(G_N_ELEMENTS(failEscapeCodes) == VIR_HOST_VALIDATE_LAST);
void virHostMsgFail(virHostValidateLevel level,
const char *format,
...)
{
va_list args;
g_autofree char *msg = NULL;
if (quiet)
return;
va_start(args, format);
msg = g_strdup_vprintf(format, args);
va_end(args);
if (virHostMsgWantEscape())
fprintf(stdout, "%s%s\033[0m (%s)\n",
failEscapeCodes[level], _(failMessages[level]), msg);
else
fprintf(stdout, "%s (%s)\n",
_(failMessages[level]), msg);
}
int virHostValidateDeviceExists(const char *hvname, int virHostValidateDeviceExists(const char *hvname,
const char *dev_name, const char *dev_name,
virHostValidateLevel level, virValidateLevel level,
const char *hint) const char *hint)
{ {
virHostMsgCheck(hvname, _("Checking if device '%1$s' exists"), dev_name); virValidateCheck(hvname, _("Checking if device '%1$s' exists"), dev_name);
if (access(dev_name, F_OK) < 0) { if (access(dev_name, F_OK) < 0) {
virHostMsgFail(level, "%s", hint); virValidateFail(level, "%s", hint);
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
virHostMsgPass(); virValidatePass();
return 0; return 0;
} }
int virHostValidateDeviceAccessible(const char *hvname, int virHostValidateDeviceAccessible(const char *hvname,
const char *dev_name, const char *dev_name,
virHostValidateLevel level, virValidateLevel level,
const char *hint) const char *hint)
{ {
virHostMsgCheck(hvname, _("Checking if device '%1$s' is accessible"), dev_name); virValidateCheck(hvname, _("Checking if device '%1$s' is accessible"), dev_name);
if (access(dev_name, R_OK|W_OK) < 0) { if (access(dev_name, R_OK|W_OK) < 0) {
virHostMsgFail(level, "%s", hint); virValidateFail(level, "%s", hint);
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
virHostMsgPass(); virValidatePass();
return 0; return 0;
} }
int virHostValidateNamespace(const char *hvname, int virHostValidateNamespace(const char *hvname,
const char *ns_name, const char *ns_name,
virHostValidateLevel level, virValidateLevel level,
const char *hint) const char *hint)
{ {
char nspath[100]; char nspath[100];
virHostMsgCheck(hvname, _("Checking for namespace '%1$s'"), ns_name); virValidateCheck(hvname, _("Checking for namespace '%1$s'"), ns_name);
g_snprintf(nspath, sizeof(nspath), "/proc/self/ns/%s", ns_name); g_snprintf(nspath, sizeof(nspath), "/proc/self/ns/%s", ns_name);
if (access(nspath, F_OK) < 0) { if (access(nspath, F_OK) < 0) {
virHostMsgFail(level, "%s", hint); virValidateFail(level, "%s", hint);
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
virHostMsgPass(); virValidatePass();
return 0; return 0;
} }
@ -248,7 +162,7 @@ virBitmap *virHostValidateGetCPUFlags(void)
int virHostValidateLinuxKernel(const char *hvname, int virHostValidateLinuxKernel(const char *hvname,
int version, int version,
virHostValidateLevel level, virValidateLevel level,
const char *hint) const char *hint)
{ {
struct utsname uts; struct utsname uts;
@ -256,26 +170,26 @@ int virHostValidateLinuxKernel(const char *hvname,
uname(&uts); uname(&uts);
virHostMsgCheck(hvname, _("Checking for Linux >= %1$d.%2$d.%3$d"), virValidateCheck(hvname, _("Checking for Linux >= %1$d.%2$d.%3$d"),
((version >> 16) & 0xff), ((version >> 16) & 0xff),
((version >> 8) & 0xff), ((version >> 8) & 0xff),
(version & 0xff)); (version & 0xff));
if (STRNEQ(uts.sysname, "Linux")) { if (STRNEQ(uts.sysname, "Linux")) {
virHostMsgFail(level, "%s", hint); virValidateFail(level, "%s", hint);
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
if (virStringParseVersion(&thisversion, uts.release, true) < 0) { if (virStringParseVersion(&thisversion, uts.release, true) < 0) {
virHostMsgFail(level, "%s", hint); virValidateFail(level, "%s", hint);
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
if (thisversion < version) { if (thisversion < version) {
virHostMsgFail(level, "%s", hint); virValidateFail(level, "%s", hint);
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} else { } else {
virHostMsgPass(); virValidatePass();
return 0; return 0;
} }
} }
@ -283,7 +197,7 @@ int virHostValidateLinuxKernel(const char *hvname,
#ifdef __linux__ #ifdef __linux__
int virHostValidateCGroupControllers(const char *hvname, int virHostValidateCGroupControllers(const char *hvname,
int controllers, int controllers,
virHostValidateLevel level) virValidateLevel level)
{ {
g_autoptr(virCgroup) group = NULL; g_autoptr(virCgroup) group = NULL;
int ret = 0; int ret = 0;
@ -292,7 +206,7 @@ int virHostValidateCGroupControllers(const char *hvname,
if (virCgroupNew("/", -1, &group) < 0) { if (virCgroupNew("/", -1, &group) < 0) {
fprintf(stderr, "Unable to initialize cgroups: %s\n", fprintf(stderr, "Unable to initialize cgroups: %s\n",
virGetLastErrorMessage()); virGetLastErrorMessage());
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) {
@ -302,15 +216,15 @@ int virHostValidateCGroupControllers(const char *hvname,
if (!(controllers & flag)) if (!(controllers & flag))
continue; continue;
virHostMsgCheck(hvname, _("Checking for cgroup '%1$s' controller support"), cg_name); virValidateCheck(hvname, _("Checking for cgroup '%1$s' controller support"), cg_name);
if (!virCgroupHasController(group, i)) { if (!virCgroupHasController(group, i)) {
ret = VIR_HOST_VALIDATE_FAILURE(level); ret = VIR_VALIDATE_FAILURE(level);
virHostMsgFail(level, "Enable '%s' in kernel Kconfig file or " virValidateFail(level, "Enable '%s' in kernel Kconfig file or "
"mount/enable cgroup controller in your system", "mount/enable cgroup controller in your system",
cg_name); cg_name);
} else { } else {
virHostMsgPass(); virValidatePass();
} }
} }
@ -319,15 +233,15 @@ int virHostValidateCGroupControllers(const char *hvname,
#else /* !__linux__ */ #else /* !__linux__ */
int virHostValidateCGroupControllers(const char *hvname G_GNUC_UNUSED, int virHostValidateCGroupControllers(const char *hvname G_GNUC_UNUSED,
int controllers G_GNUC_UNUSED, int controllers G_GNUC_UNUSED,
virHostValidateLevel level) virValidateLevel level)
{ {
virHostMsgFail(level, "%s", "This platform does not support cgroups"); virValidateFail(level, "%s", "This platform does not support cgroups");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
#endif /* !__linux__ */ #endif /* !__linux__ */
int virHostValidateIOMMU(const char *hvname, int virHostValidateIOMMU(const char *hvname,
virHostValidateLevel level) virValidateLevel level)
{ {
g_autoptr(virBitmap) flags = NULL; g_autoptr(virBitmap) flags = NULL;
struct stat sb; struct stat sb;
@ -337,7 +251,7 @@ int virHostValidateIOMMU(const char *hvname,
struct dirent *dent; struct dirent *dent;
int rc; int rc;
virHostMsgCheck(hvname, "%s", _("Checking for device assignment IOMMU support")); virValidateCheck(hvname, "%s", _("Checking for device assignment IOMMU support"));
flags = virHostValidateGetCPUFlags(); flags = virHostValidateGetCPUFlags();
@ -348,28 +262,28 @@ int virHostValidateIOMMU(const char *hvname,
if (isIntel) { if (isIntel) {
if (access("/sys/firmware/acpi/tables/DMAR", F_OK) == 0) { if (access("/sys/firmware/acpi/tables/DMAR", F_OK) == 0) {
virHostMsgPass(); virValidatePass();
bootarg = "intel_iommu=on"; bootarg = "intel_iommu=on";
} else { } else {
virHostMsgFail(level, virValidateFail(level,
"No ACPI DMAR table found, IOMMU either " "No ACPI DMAR table found, IOMMU either "
"disabled in BIOS or not supported by this " "disabled in BIOS or not supported by this "
"hardware platform"); "hardware platform");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
} else if (isAMD) { } else if (isAMD) {
if (access("/sys/firmware/acpi/tables/IVRS", F_OK) == 0) { if (access("/sys/firmware/acpi/tables/IVRS", F_OK) == 0) {
virHostMsgPass(); virValidatePass();
bootarg = "iommu=pt iommu=1"; bootarg = "iommu=pt iommu=1";
} else { } else {
virHostMsgFail(level, virValidateFail(level,
"No ACPI IVRS table found, IOMMU either " "No ACPI IVRS table found, IOMMU either "
"disabled in BIOS or not supported by this " "disabled in BIOS or not supported by this "
"hardware platform"); "hardware platform");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
} else if (ARCH_IS_PPC64(arch)) { } else if (ARCH_IS_PPC64(arch)) {
virHostMsgPass(); virValidatePass();
} else if (ARCH_IS_S390(arch)) { } else if (ARCH_IS_S390(arch)) {
g_autoptr(DIR) dir = NULL; g_autoptr(DIR) dir = NULL;
@ -378,41 +292,41 @@ int virHostValidateIOMMU(const char *hvname,
* no PCI devices the directory is still there but is * no PCI devices the directory is still there but is
* empty. */ * empty. */
if (!virDirOpen(&dir, "/sys/bus/pci/devices")) { if (!virDirOpen(&dir, "/sys/bus/pci/devices")) {
virHostMsgFail(VIR_HOST_VALIDATE_NOTE, virValidateFail(VIR_VALIDATE_NOTE,
"Skipped - PCI support disabled"); "Skipped - PCI support disabled");
return VIR_HOST_VALIDATE_FAILURE(VIR_HOST_VALIDATE_NOTE); return VIR_VALIDATE_FAILURE(VIR_VALIDATE_NOTE);
} }
rc = virDirRead(dir, &dent, NULL); rc = virDirRead(dir, &dent, NULL);
if (rc <= 0) { if (rc <= 0) {
virHostMsgFail(VIR_HOST_VALIDATE_NOTE, virValidateFail(VIR_VALIDATE_NOTE,
"Skipped - No PCI devices are online"); "Skipped - No PCI devices are online");
return VIR_HOST_VALIDATE_FAILURE(VIR_HOST_VALIDATE_NOTE); return VIR_VALIDATE_FAILURE(VIR_VALIDATE_NOTE);
} }
virHostMsgPass(); virValidatePass();
} else if (ARCH_IS_ARM(arch)) { } else if (ARCH_IS_ARM(arch)) {
if (access("/sys/firmware/acpi/tables/IORT", F_OK) != 0) { if (access("/sys/firmware/acpi/tables/IORT", F_OK) != 0) {
virHostMsgFail(level, virValidateFail(level,
"No ACPI IORT table found, IOMMU not " "No ACPI IORT table found, IOMMU not "
"supported by this hardware platform"); "supported by this hardware platform");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} else { } else {
rc = virAcpiHasSMMU(); rc = virAcpiHasSMMU();
if (rc < 0) { if (rc < 0) {
virHostMsgFail(level, virValidateFail(level,
"Failed to parse ACPI IORT table"); "Failed to parse ACPI IORT table");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} else if (rc == 0) { } else if (rc == 0) {
virHostMsgFail(level, virValidateFail(level,
"No SMMU found"); "No SMMU found");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} else { } else {
virHostMsgPass(); virValidatePass();
} }
} }
} else { } else {
virHostMsgFail(level, virValidateFail(level,
"Unknown if this platform has IOMMU support"); "Unknown if this platform has IOMMU support");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
@ -423,17 +337,17 @@ int virHostValidateIOMMU(const char *hvname,
if (!S_ISDIR(sb.st_mode)) if (!S_ISDIR(sb.st_mode))
return 0; return 0;
virHostMsgCheck(hvname, "%s", _("Checking if IOMMU is enabled by kernel")); virValidateCheck(hvname, "%s", _("Checking if IOMMU is enabled by kernel"));
if (sb.st_nlink <= 2) { if (sb.st_nlink <= 2) {
if (bootarg) if (bootarg)
virHostMsgFail(level, virValidateFail(level,
"IOMMU appears to be disabled in kernel. " "IOMMU appears to be disabled in kernel. "
"Add %s to kernel cmdline arguments", bootarg); "Add %s to kernel cmdline arguments", bootarg);
else else
virHostMsgFail(level, "IOMMU capability not compiled into kernel."); virValidateFail(level, "IOMMU capability not compiled into kernel.");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
virHostMsgPass(); virValidatePass();
return 0; return 0;
} }
@ -466,7 +380,7 @@ bool virHostKernelModuleIsLoaded(const char *module)
int virHostValidateSecureGuests(const char *hvname, int virHostValidateSecureGuests(const char *hvname,
virHostValidateLevel level) virValidateLevel level)
{ {
g_autoptr(virBitmap) flags = NULL; g_autoptr(virBitmap) flags = NULL;
bool hasFac158 = false; bool hasFac158 = false;
@ -483,13 +397,13 @@ int virHostValidateSecureGuests(const char *hvname,
else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_SEV)) else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_SEV))
hasAMDSev = true; hasAMDSev = true;
virHostMsgCheck(hvname, "%s", _("Checking for secure guest support")); virValidateCheck(hvname, "%s", _("Checking for secure guest support"));
if (ARCH_IS_S390(arch)) { if (ARCH_IS_S390(arch)) {
if (hasFac158) { if (hasFac158) {
if (!virFileIsDir("/sys/firmware/uv")) { if (!virFileIsDir("/sys/firmware/uv")) {
virHostMsgFail(level, "IBM Secure Execution not supported by " virValidateFail(level, "IBM Secure Execution not supported by "
"the currently used kernel"); "the currently used kernel");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
/* we're prefix matching rather than equality matching here, because /* we're prefix matching rather than equality matching here, because
@ -501,47 +415,47 @@ int virHostValidateSecureGuests(const char *hvname,
G_N_ELEMENTS(kIBMValues), G_N_ELEMENTS(kIBMValues),
VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST | VIR_KERNEL_CMDLINE_FLAGS_SEARCH_FIRST |
VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX)) { VIR_KERNEL_CMDLINE_FLAGS_CMP_PREFIX)) {
virHostMsgPass(); virValidatePass();
return 1; return 1;
} else { } else {
virHostMsgFail(level, virValidateFail(level,
"IBM Secure Execution appears to be disabled " "IBM Secure Execution appears to be disabled "
"in kernel. Add prot_virt=1 to kernel cmdline " "in kernel. Add prot_virt=1 to kernel cmdline "
"arguments"); "arguments");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
} else { } else {
virHostMsgFail(level, "Hardware or firmware does not provide " virValidateFail(level, "Hardware or firmware does not provide "
"support for IBM Secure Execution"); "support for IBM Secure Execution");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
} else if (hasAMDSev) { } else if (hasAMDSev) {
if (virFileReadValueString(&mod_value, "/sys/module/kvm_amd/parameters/sev") < 0) { if (virFileReadValueString(&mod_value, "/sys/module/kvm_amd/parameters/sev") < 0) {
virHostMsgFail(level, "AMD Secure Encrypted Virtualization not " virValidateFail(level, "AMD Secure Encrypted Virtualization not "
"supported by the currently used kernel"); "supported by the currently used kernel");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
if (mod_value[0] != '1' && mod_value[0] != 'Y' && mod_value[0] != 'y') { if (mod_value[0] != '1' && mod_value[0] != 'Y' && mod_value[0] != 'y') {
virHostMsgFail(level, virValidateFail(level,
"AMD Secure Encrypted Virtualization appears to be " "AMD Secure Encrypted Virtualization appears to be "
"disabled in kernel. Add kvm_amd.sev=1 " "disabled in kernel. Add kvm_amd.sev=1 "
"to the kernel cmdline arguments"); "to the kernel cmdline arguments");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
if (virFileExists("/dev/sev")) { if (virFileExists("/dev/sev")) {
virHostMsgPass(); virValidatePass();
return 1; return 1;
} else { } else {
virHostMsgFail(level, virValidateFail(level,
"AMD Secure Encrypted Virtualization appears to be " "AMD Secure Encrypted Virtualization appears to be "
"disabled in firmware."); "disabled in firmware.");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }
} }
virHostMsgFail(level, virValidateFail(level,
"Unknown if this platform has Secure Guest support"); "Unknown if this platform has Secure Guest support");
return VIR_HOST_VALIDATE_FAILURE(level); return VIR_VALIDATE_FAILURE(level);
} }

View File

@ -24,14 +24,7 @@
#include "internal.h" #include "internal.h"
#include "virbitmap.h" #include "virbitmap.h"
#include "virenum.h" #include "virenum.h"
#include "virt-validate-common.h"
typedef enum {
VIR_HOST_VALIDATE_FAIL,
VIR_HOST_VALIDATE_WARN,
VIR_HOST_VALIDATE_NOTE,
VIR_HOST_VALIDATE_LAST,
} virHostValidateLevel;
typedef enum { typedef enum {
VIR_HOST_VALIDATE_CPU_FLAG_VMX = 0, VIR_HOST_VALIDATE_CPU_FLAG_VMX = 0,
@ -45,61 +38,36 @@ typedef enum {
VIR_ENUM_DECL(virHostValidateCPUFlag); VIR_ENUM_DECL(virHostValidateCPUFlag);
/**
* VIR_HOST_VALIDATE_FAILURE
* @level: the virHostValidateLevel to be checked
*
* This macro is to be used in to return a failures based on the
* virHostValidateLevel use in the function.
*
* If the virHostValidateLevel is VIR_HOST_VALIDATE_FAIL, -1 is returned.
* 0 is returned otherwise (as the virHosValidateLevel is then either a
* Warn or a Note).
*/
#define VIR_HOST_VALIDATE_FAILURE(level) (level == VIR_HOST_VALIDATE_FAIL) ? -1 : 0
void virHostMsgSetQuiet(bool quietFlag);
void virHostMsgCheck(const char *prefix,
const char *format,
...) G_GNUC_PRINTF(2, 3);
void virHostMsgPass(void);
void virHostMsgFail(virHostValidateLevel level,
const char *format,
...) G_GNUC_PRINTF(2, 3);
int virHostValidateDeviceExists(const char *hvname, int virHostValidateDeviceExists(const char *hvname,
const char *dev_name, const char *dev_name,
virHostValidateLevel level, virValidateLevel level,
const char *hint); const char *hint);
int virHostValidateDeviceAccessible(const char *hvname, int virHostValidateDeviceAccessible(const char *hvname,
const char *dev_name, const char *dev_name,
virHostValidateLevel level, virValidateLevel level,
const char *hint); const char *hint);
virBitmap *virHostValidateGetCPUFlags(void); virBitmap *virHostValidateGetCPUFlags(void);
int virHostValidateLinuxKernel(const char *hvname, int virHostValidateLinuxKernel(const char *hvname,
int version, int version,
virHostValidateLevel level, virValidateLevel level,
const char *hint); const char *hint);
int virHostValidateNamespace(const char *hvname, int virHostValidateNamespace(const char *hvname,
const char *ns_name, const char *ns_name,
virHostValidateLevel level, virValidateLevel level,
const char *hint); const char *hint);
int virHostValidateCGroupControllers(const char *hvname, int virHostValidateCGroupControllers(const char *hvname,
int controllers, int controllers,
virHostValidateLevel level); virValidateLevel level);
int virHostValidateIOMMU(const char *hvname, int virHostValidateIOMMU(const char *hvname,
virHostValidateLevel level); virValidateLevel level);
int virHostValidateSecureGuests(const char *hvname, int virHostValidateSecureGuests(const char *hvname,
virHostValidateLevel level); virValidateLevel level);
bool virHostKernelModuleIsLoaded(const char *module); bool virHostKernelModuleIsLoaded(const char *module);

View File

@ -30,37 +30,37 @@ int virHostValidateLXC(void)
int ret = 0; int ret = 0;
if (virHostValidateLinuxKernel("LXC", (2 << 16) | (6 << 8) | 26, if (virHostValidateLinuxKernel("LXC", (2 << 16) | (6 << 8) | 26,
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("Upgrade to a kernel supporting namespaces")) < 0) _("Upgrade to a kernel supporting namespaces")) < 0)
ret = -1; ret = -1;
if (virHostValidateNamespace("LXC", "ipc", if (virHostValidateNamespace("LXC", "ipc",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("IPC namespace support is required")) < 0) _("IPC namespace support is required")) < 0)
ret = -1; ret = -1;
if (virHostValidateNamespace("LXC", "mnt", if (virHostValidateNamespace("LXC", "mnt",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("Mount namespace support is required")) < 0) _("Mount namespace support is required")) < 0)
ret = -1; ret = -1;
if (virHostValidateNamespace("LXC", "pid", if (virHostValidateNamespace("LXC", "pid",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("PID namespace support is required")) < 0) _("PID namespace support is required")) < 0)
ret = -1; ret = -1;
if (virHostValidateNamespace("LXC", "uts", if (virHostValidateNamespace("LXC", "uts",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("UTS namespace support is required")) < 0) _("UTS namespace support is required")) < 0)
ret = -1; ret = -1;
if (virHostValidateNamespace("LXC", "net", if (virHostValidateNamespace("LXC", "net",
VIR_HOST_VALIDATE_WARN, VIR_VALIDATE_WARN,
_("Network namespace support is recommended")) < 0) _("Network namespace support is recommended")) < 0)
ret = -1; ret = -1;
if (virHostValidateNamespace("LXC", "user", if (virHostValidateNamespace("LXC", "user",
VIR_HOST_VALIDATE_WARN, VIR_VALIDATE_WARN,
_("User namespace support is recommended")) < 0) _("User namespace support is recommended")) < 0)
ret = -1; ret = -1;
@ -72,13 +72,13 @@ int virHostValidateLXC(void)
(1 << VIR_CGROUP_CONTROLLER_DEVICES) | (1 << VIR_CGROUP_CONTROLLER_DEVICES) |
(1 << VIR_CGROUP_CONTROLLER_FREEZER) | (1 << VIR_CGROUP_CONTROLLER_FREEZER) |
(1 << VIR_CGROUP_CONTROLLER_BLKIO), (1 << VIR_CGROUP_CONTROLLER_BLKIO),
VIR_HOST_VALIDATE_FAIL) < 0) { VIR_VALIDATE_FAIL) < 0) {
ret = -1; ret = -1;
} }
#if WITH_FUSE #if WITH_FUSE
if (virHostValidateDeviceExists("LXC", "/sys/fs/fuse/connections", if (virHostValidateDeviceExists("LXC", "/sys/fs/fuse/connections",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("Load the 'fuse' module to enable /proc/ overrides")) < 0) _("Load the 'fuse' module to enable /proc/ overrides")) < 0)
ret = -1; ret = -1;
#endif #endif

View File

@ -64,11 +64,11 @@ int virHostValidateQEMU(void)
} }
if (hasVirtFlag) { if (hasVirtFlag) {
virHostMsgCheck("QEMU", "%s", _("Checking for hardware virtualization")); virValidateCheck("QEMU", "%s", _("Checking for hardware virtualization"));
if (hasHwVirt) { if (hasHwVirt) {
virHostMsgPass(); virValidatePass();
} else { } else {
virHostMsgFail(VIR_HOST_VALIDATE_FAIL, virValidateFail(VIR_VALIDATE_FAIL,
_("Host not compatible with KVM; HW virtualization CPU features not found. Only emulated CPUs are available; performance will be significantly limited")); _("Host not compatible with KVM; HW virtualization CPU features not found. Only emulated CPUs are available; performance will be significantly limited"));
ret = -1; ret = -1;
} }
@ -76,32 +76,32 @@ int virHostValidateQEMU(void)
if (hasHwVirt || !hasVirtFlag) { if (hasHwVirt || !hasVirtFlag) {
if (virHostValidateDeviceExists("QEMU", "/dev/kvm", if (virHostValidateDeviceExists("QEMU", "/dev/kvm",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
kvmhint) <0) kvmhint) <0)
ret = -1; ret = -1;
else if (virHostValidateDeviceAccessible("QEMU", "/dev/kvm", else if (virHostValidateDeviceAccessible("QEMU", "/dev/kvm",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("Check /dev/kvm is world writable or you are in a group that is allowed to access it")) < 0) _("Check /dev/kvm is world writable or you are in a group that is allowed to access it")) < 0)
ret = -1; ret = -1;
} }
if (arch == VIR_ARCH_PPC64 || arch == VIR_ARCH_PPC64LE) { if (arch == VIR_ARCH_PPC64 || arch == VIR_ARCH_PPC64LE) {
virHostMsgCheck("QEMU", "%s", _("Checking for PowerPC KVM module loaded")); virValidateCheck("QEMU", "%s", _("Checking for PowerPC KVM module loaded"));
if (!virHostKernelModuleIsLoaded("kvm_hv")) if (!virHostKernelModuleIsLoaded("kvm_hv"))
virHostMsgFail(VIR_HOST_VALIDATE_WARN, virValidateFail(VIR_VALIDATE_WARN,
_("Load kvm_hv for better performance")); _("Load kvm_hv for better performance"));
else else
virHostMsgPass(); virValidatePass();
} }
if (virHostValidateDeviceExists("QEMU", "/dev/vhost-net", if (virHostValidateDeviceExists("QEMU", "/dev/vhost-net",
VIR_HOST_VALIDATE_WARN, VIR_VALIDATE_WARN,
_("Load the 'vhost_net' module to improve performance of virtio networking")) < 0) _("Load the 'vhost_net' module to improve performance of virtio networking")) < 0)
ret = -1; ret = -1;
if (virHostValidateDeviceExists("QEMU", "/dev/net/tun", if (virHostValidateDeviceExists("QEMU", "/dev/net/tun",
VIR_HOST_VALIDATE_FAIL, VIR_VALIDATE_FAIL,
_("Load the 'tun' module to enable networking for QEMU guests")) < 0) _("Load the 'tun' module to enable networking for QEMU guests")) < 0)
ret = -1; ret = -1;
@ -112,16 +112,16 @@ int virHostValidateQEMU(void)
(1 << VIR_CGROUP_CONTROLLER_CPUSET) | (1 << VIR_CGROUP_CONTROLLER_CPUSET) |
(1 << VIR_CGROUP_CONTROLLER_DEVICES) | (1 << VIR_CGROUP_CONTROLLER_DEVICES) |
(1 << VIR_CGROUP_CONTROLLER_BLKIO), (1 << VIR_CGROUP_CONTROLLER_BLKIO),
VIR_HOST_VALIDATE_WARN) < 0) { VIR_VALIDATE_WARN) < 0) {
ret = -1; ret = -1;
} }
if (virHostValidateIOMMU("QEMU", if (virHostValidateIOMMU("QEMU",
VIR_HOST_VALIDATE_WARN) < 0) VIR_VALIDATE_WARN) < 0)
ret = -1; ret = -1;
if (virHostValidateSecureGuests("QEMU", if (virHostValidateSecureGuests("QEMU",
VIR_HOST_VALIDATE_WARN) < 0) VIR_VALIDATE_WARN) < 0)
ret = -1; ret = -1;
return ret; return ret;

View File

@ -124,7 +124,7 @@ main(int argc, char **argv)
if (argc > 1) if (argc > 1)
hvname = argv[optind]; hvname = argv[optind];
virHostMsgSetQuiet(quiet); virValidateSetQuiet(quiet);
#if WITH_QEMU #if WITH_QEMU
if (!hvname || STREQ(hvname, "qemu")) { if (!hvname || STREQ(hvname, "qemu")) {

View File

@ -0,0 +1,112 @@
/*
* virt-validate-common.c: Sanity check helper APIs
*
* Copyright (C) 2012-2024 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include <unistd.h>
#include "virt-validate-common.h"
static bool quiet;
void virValidateSetQuiet(bool quietFlag)
{
quiet = quietFlag;
}
void virValidateCheck(const char *prefix,
const char *format,
...)
{
va_list args;
g_autofree char *msg = NULL;
if (quiet)
return;
va_start(args, format);
msg = g_strdup_vprintf(format, args);
va_end(args);
fprintf(stdout, "%1$6s: %2$-69s: ", prefix, msg);
}
static bool virValidateWantEscape(void)
{
static bool detectTty = true;
static bool wantEscape;
if (detectTty) {
if (isatty(STDOUT_FILENO))
wantEscape = true;
detectTty = false;
}
return wantEscape;
}
void virValidatePass(void)
{
if (quiet)
return;
if (virValidateWantEscape())
fprintf(stdout, "\033[32m%s\033[0m\n", _("PASS"));
else
fprintf(stdout, "%s\n", _("PASS"));
}
static const char * failMessages[] = {
N_("FAIL"),
N_("WARN"),
N_("NOTE"),
};
G_STATIC_ASSERT(G_N_ELEMENTS(failMessages) == VIR_VALIDATE_LAST);
static const char *failEscapeCodes[] = {
"\033[31m",
"\033[33m",
"\033[34m",
};
G_STATIC_ASSERT(G_N_ELEMENTS(failEscapeCodes) == VIR_VALIDATE_LAST);
void virValidateFail(virValidateLevel level,
const char *format,
...)
{
va_list args;
g_autofree char *msg = NULL;
if (quiet)
return;
va_start(args, format);
msg = g_strdup_vprintf(format, args);
va_end(args);
if (virValidateWantEscape())
fprintf(stdout, "%s%s\033[0m (%s)\n",
failEscapeCodes[level], _(failMessages[level]), msg);
else
fprintf(stdout, "%s (%s)\n",
_(failMessages[level]), msg);
}

View File

@ -0,0 +1,57 @@
/*
* virt-validate-common.h: Sanity check helper APIs
*
* Copyright (C) 2012-2024 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "internal.h"
typedef enum {
VIR_VALIDATE_FAIL,
VIR_VALIDATE_WARN,
VIR_VALIDATE_NOTE,
VIR_VALIDATE_LAST,
} virValidateLevel;
/**
* VIR_VALIDATE_FAILURE
* @level: the virValidateLevel to be checked
*
* This macro is to be used in to return a failures based on the
* virValidateLevel use in the function.
*
* If the virValidateLevel is VIR_VALIDATE_FAIL, -1 is returned.
* 0 is returned otherwise (as the virValidateLevel is then either a
* Warn or a Note).
*/
#define VIR_VALIDATE_FAILURE(level) (level == VIR_VALIDATE_FAIL) ? -1 : 0
void virValidateSetQuiet(bool quietFlag);
void virValidateCheck(const char *prefix,
const char *format,
...) G_GNUC_PRINTF(2, 3);
void virValidatePass(void);
void virValidateFail(virValidateLevel level,
const char *format,
...) G_GNUC_PRINTF(2, 3);