mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-06 20:09:44 +00:00
Merge pull request #6800 from amshinde/check-vm-capability
kata-ctl: Check for vm capability
This commit is contained in:
commit
2d329125fd
@ -80,6 +80,11 @@ mod arch_specific {
|
|||||||
Some(CHECK_LIST)
|
Some(CHECK_LIST)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn host_is_vmcontainer_capable() -> Result<bool> {
|
||||||
|
// TODO: Not implemented
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
// Guest protection is not supported on ARM64.
|
// Guest protection is not supported on ARM64.
|
||||||
pub fn available_guest_protection() -> Result<check::GuestProtection, check::ProtectionError> {
|
pub fn available_guest_protection() -> Result<check::GuestProtection, check::ProtectionError> {
|
||||||
|
@ -33,6 +33,11 @@ mod arch_specific {
|
|||||||
// to the goloang implementation of function getCPUDetails()
|
// to the goloang implementation of function getCPUDetails()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn host_is_vmcontainer_capable() -> Result<bool> {
|
||||||
|
// TODO: Not implemented
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn available_guest_protection() -> Result<check::GuestProtection, check::ProtectionError> {
|
pub fn available_guest_protection() -> Result<check::GuestProtection, check::ProtectionError> {
|
||||||
if !Uid::effective().is_root() {
|
if !Uid::effective().is_root() {
|
||||||
return Err(check::ProtectionError::NoPerms);
|
return Err(check::ProtectionError::NoPerms);
|
||||||
|
@ -78,6 +78,21 @@ mod arch_specific {
|
|||||||
Some(CHECK_LIST)
|
Some(CHECK_LIST)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn host_is_vmcontainer_capable() -> Result<bool> {
|
||||||
|
let mut count = 0;
|
||||||
|
if check_cpu().is_err() {
|
||||||
|
count += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Add additional checks for kernel modules
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
return Ok(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
Err(anyhow!("System is not capable of running a VM"))
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn retrieve_cpu_facilities() -> Result<HashMap<i32, bool>> {
|
fn retrieve_cpu_facilities() -> Result<HashMap<i32, bool>> {
|
||||||
let f = std::fs::File::open(check::PROC_CPUINFO)?;
|
let f = std::fs::File::open(check::PROC_CPUINFO)?;
|
||||||
|
@ -59,17 +59,29 @@ mod arch_specific {
|
|||||||
static MODULE_LIST: &[KernelModule] = &[
|
static MODULE_LIST: &[KernelModule] = &[
|
||||||
KernelModule {
|
KernelModule {
|
||||||
name: "kvm",
|
name: "kvm",
|
||||||
parameter: KernelParam {
|
params: &[KernelParam {
|
||||||
name: "kvmclock_periodic_sync",
|
name: "kvmclock_periodic_sync",
|
||||||
value: KernelParamType::Simple("Y"),
|
value: KernelParamType::Simple("Y"),
|
||||||
},
|
}],
|
||||||
},
|
},
|
||||||
KernelModule {
|
KernelModule {
|
||||||
name: "kvm_intel",
|
name: "kvm_intel",
|
||||||
parameter: KernelParam {
|
params: &[KernelParam {
|
||||||
name: "unrestricted_guest",
|
name: "unrestricted_guest",
|
||||||
value: KernelParamType::Predicate(unrestricted_guest_param_check),
|
value: KernelParamType::Predicate(unrestricted_guest_param_check),
|
||||||
},
|
}],
|
||||||
|
},
|
||||||
|
KernelModule {
|
||||||
|
name: "vhost",
|
||||||
|
params: &[],
|
||||||
|
},
|
||||||
|
KernelModule {
|
||||||
|
name: "vhost_net",
|
||||||
|
params: &[],
|
||||||
|
},
|
||||||
|
KernelModule {
|
||||||
|
name: "vhost_vsock",
|
||||||
|
params: &[],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -226,13 +238,9 @@ mod arch_specific {
|
|||||||
|
|
||||||
let running_on_vmm_alt = running_on_vmm()?;
|
let running_on_vmm_alt = running_on_vmm()?;
|
||||||
|
|
||||||
|
// Kernel param "unrestricted_guest" is not required when running under a hypervisor
|
||||||
if running_on_vmm_alt {
|
if running_on_vmm_alt {
|
||||||
let msg = format!("You are running in a VM, where the kernel module '{}' parameter '{:}' has a value '{:}'. This causes conflict when running kata.",
|
return Ok(());
|
||||||
module,
|
|
||||||
param_name,
|
|
||||||
param_value_host
|
|
||||||
);
|
|
||||||
return Err(anyhow!(msg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if param_value_host == expected_param_value.to_string() {
|
if param_value_host == expected_param_value.to_string() {
|
||||||
@ -253,6 +261,38 @@ mod arch_specific {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_kernel_params(kernel_module: &KernelModule) -> Result<()> {
|
||||||
|
const MODULES_PATH: &str = "/sys/module";
|
||||||
|
|
||||||
|
for param in kernel_module.params {
|
||||||
|
let module_param_path = format!(
|
||||||
|
"{}/{}/parameters/{}",
|
||||||
|
MODULES_PATH, kernel_module.name, param.name
|
||||||
|
);
|
||||||
|
|
||||||
|
// Here the currently loaded kernel parameter value
|
||||||
|
// is retrieved and returned on success
|
||||||
|
let param_value_host = std::fs::read_to_string(module_param_path)
|
||||||
|
.map(|val| val.replace('\n', ""))
|
||||||
|
.map_err(|_err| {
|
||||||
|
anyhow!(
|
||||||
|
"'{:}' kernel module parameter `{:}` not found.",
|
||||||
|
kernel_module.name,
|
||||||
|
param.name
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
check_kernel_param(
|
||||||
|
kernel_module.name,
|
||||||
|
param.name,
|
||||||
|
¶m_value_host,
|
||||||
|
param.value.clone(),
|
||||||
|
)
|
||||||
|
.map_err(|e| anyhow!(e.to_string()))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn check_kernel_param(
|
fn check_kernel_param(
|
||||||
module: &str,
|
module: &str,
|
||||||
param_name: &str,
|
param_name: &str,
|
||||||
@ -282,19 +322,12 @@ mod arch_specific {
|
|||||||
info!(sl!(), "check kernel modules for: x86_64");
|
info!(sl!(), "check kernel modules for: x86_64");
|
||||||
|
|
||||||
for module in MODULE_LIST {
|
for module in MODULE_LIST {
|
||||||
let module_loaded =
|
let module_loaded = check::check_kernel_module_loaded(module);
|
||||||
check::check_kernel_module_loaded(module.name, module.parameter.name);
|
|
||||||
|
|
||||||
match module_loaded {
|
match module_loaded {
|
||||||
Ok(param_value_host) => {
|
Ok(_) => {
|
||||||
let parameter_check = check_kernel_param(
|
let check = check_kernel_params(module);
|
||||||
module.name,
|
match check {
|
||||||
module.parameter.name,
|
|
||||||
¶m_value_host,
|
|
||||||
module.parameter.value.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
match parameter_check {
|
|
||||||
Ok(_v) => info!(sl!(), "{} Ok", module.name),
|
Ok(_v) => info!(sl!(), "{} Ok", module.name),
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
@ -306,6 +339,23 @@ mod arch_specific {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn host_is_vmcontainer_capable() -> Result<bool> {
|
||||||
|
let mut count = 0;
|
||||||
|
if check_cpu("check_cpu").is_err() {
|
||||||
|
count += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
if check_kernel_modules("check_modules").is_err() {
|
||||||
|
count += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
return Ok(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
Err(anyhow!("System is not capable of running a VM"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
// Contains checks that are not architecture-specific
|
// Contains checks that are not architecture-specific
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86_64"))]
|
||||||
|
use crate::types::KernelModule;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use nix::fcntl::{open, OFlag};
|
use nix::fcntl::{open, OFlag};
|
||||||
use nix::sys::stat::Mode;
|
use nix::sys::stat::Mode;
|
||||||
@ -324,17 +327,16 @@ pub fn check_official_releases() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86_64"))]
|
||||||
pub fn check_kernel_module_loaded(module: &str, parameter: &str) -> Result<String, String> {
|
pub fn check_kernel_module_loaded(kernel_module: &KernelModule) -> Result<(), String> {
|
||||||
const MODPROBE_PARAMETERS_DRY_RUN: &str = "--dry-run";
|
const MODPROBE_PARAMETERS_DRY_RUN: &str = "--dry-run";
|
||||||
const MODPROBE_PARAMETERS_FIRST_TIME: &str = "--first-time";
|
const MODPROBE_PARAMETERS_FIRST_TIME: &str = "--first-time";
|
||||||
const MODULES_PATH: &str = "/sys/module";
|
|
||||||
|
|
||||||
let status_modinfo_success;
|
let status_modinfo_success;
|
||||||
|
|
||||||
// Partial check w/ modinfo
|
// Partial check w/ modinfo
|
||||||
// verifies that the module exists
|
// verifies that the module exists
|
||||||
match Command::new(MODINFO_PATH)
|
match Command::new(MODINFO_PATH)
|
||||||
.arg(module)
|
.arg(kernel_module.name)
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.output()
|
.output()
|
||||||
{
|
{
|
||||||
@ -361,7 +363,7 @@ pub fn check_kernel_module_loaded(module: &str, parameter: &str) -> Result<Strin
|
|||||||
match Command::new(MODPROBE_PATH)
|
match Command::new(MODPROBE_PATH)
|
||||||
.arg(MODPROBE_PARAMETERS_DRY_RUN)
|
.arg(MODPROBE_PARAMETERS_DRY_RUN)
|
||||||
.arg(MODPROBE_PARAMETERS_FIRST_TIME)
|
.arg(MODPROBE_PARAMETERS_FIRST_TIME)
|
||||||
.arg(module)
|
.arg(kernel_module.name)
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.output()
|
.output()
|
||||||
{
|
{
|
||||||
@ -371,8 +373,8 @@ pub fn check_kernel_module_loaded(module: &str, parameter: &str) -> Result<Strin
|
|||||||
|
|
||||||
if status_modprobe_success && status_modinfo_success {
|
if status_modprobe_success && status_modinfo_success {
|
||||||
// This condition is true in the case that the module exist, but is not already loaded
|
// This condition is true in the case that the module exist, but is not already loaded
|
||||||
let msg = format!("The kernel module `{:}` exist but is not already loaded. Try reloading it using 'modprobe {:}=Y'",
|
let msg = format!("The kernel module `{:}` exist but is not already loaded. Try reloading it using 'modprobe {:}'",
|
||||||
module, module
|
kernel_module.name, kernel_module.name
|
||||||
);
|
);
|
||||||
return Err(msg);
|
return Err(msg);
|
||||||
}
|
}
|
||||||
@ -386,27 +388,15 @@ pub fn check_kernel_module_loaded(module: &str, parameter: &str) -> Result<Strin
|
|||||||
return Err(msg);
|
return Err(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
let module_path = format!("{}/{}/parameters/{}", MODULES_PATH, module, parameter);
|
|
||||||
|
|
||||||
// Here the currently loaded kernel parameter value
|
|
||||||
// is retrieved and returned on success
|
|
||||||
match read_file_contents(&module_path) {
|
|
||||||
Ok(result) => Ok(result.replace('\n', "")),
|
|
||||||
Err(_e) => {
|
|
||||||
let msg = format!(
|
|
||||||
"'{:}' kernel module parameter `{:}` not found.",
|
|
||||||
module, parameter
|
|
||||||
);
|
|
||||||
Err(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_arch = "s390x", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "s390x", target_arch = "x86_64"))]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
#[cfg(any(target_arch = "x86_64"))]
|
||||||
|
use crate::types::{KernelModule, KernelParam, KernelParamType};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use slog::warn;
|
use slog::warn;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -612,12 +602,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn check_module_loaded() {
|
fn check_module_loaded() {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
|
||||||
struct TestData<'a> {
|
struct TestData<'a> {
|
||||||
module_name: &'a str,
|
module_name: &'a str,
|
||||||
param_name: &'a str,
|
param_name: &'a str,
|
||||||
|
kernel_module: &'a KernelModule<'a>,
|
||||||
param_value: &'a str,
|
param_value: &'a str,
|
||||||
result: Result<String>,
|
result: Result<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let tests = &[
|
let tests = &[
|
||||||
@ -625,45 +616,58 @@ mod tests {
|
|||||||
TestData {
|
TestData {
|
||||||
module_name: "",
|
module_name: "",
|
||||||
param_name: "",
|
param_name: "",
|
||||||
|
kernel_module: &KernelModule {
|
||||||
|
name: "",
|
||||||
|
params: &[KernelParam {
|
||||||
|
name: "",
|
||||||
|
value: KernelParamType::Simple("Y"),
|
||||||
|
}],
|
||||||
|
},
|
||||||
param_value: "",
|
param_value: "",
|
||||||
result: Err(anyhow!("modinfo: ERROR: Module {} not found.", "")),
|
result: Err(anyhow!("modinfo: ERROR: Module {} not found.", "")),
|
||||||
},
|
},
|
||||||
TestData {
|
|
||||||
module_name: "kvm",
|
|
||||||
param_name: "",
|
|
||||||
param_value: "",
|
|
||||||
result: Err(anyhow!(
|
|
||||||
"'{:}' kernel module parameter `{:}` not found.",
|
|
||||||
"kvm",
|
|
||||||
""
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
// Success scenarios
|
// Success scenarios
|
||||||
|
TestData {
|
||||||
|
module_name: "kvm",
|
||||||
|
param_name: "",
|
||||||
|
kernel_module: &KernelModule {
|
||||||
|
name: "kvm",
|
||||||
|
params: &[KernelParam {
|
||||||
|
name: "nonexistantparam",
|
||||||
|
value: KernelParamType::Simple("Y"),
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
param_value: "",
|
||||||
|
result: Ok(()),
|
||||||
|
},
|
||||||
TestData {
|
TestData {
|
||||||
module_name: "kvm",
|
module_name: "kvm",
|
||||||
param_name: "kvmclock_periodic_sync",
|
param_name: "kvmclock_periodic_sync",
|
||||||
|
kernel_module: &KernelModule {
|
||||||
|
name: "kvm",
|
||||||
|
params: &[KernelParam {
|
||||||
|
name: "kvmclock_periodic_sync",
|
||||||
|
value: KernelParamType::Simple("Y"),
|
||||||
|
}],
|
||||||
|
},
|
||||||
param_value: "Y",
|
param_value: "Y",
|
||||||
result: Ok("Y".to_string()),
|
result: Ok(()),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
for (i, d) in tests.iter().enumerate() {
|
for (i, d) in tests.iter().enumerate() {
|
||||||
let msg = format!("test[{}]: {:?}", i, d);
|
let msg = format!("test[{}]", i);
|
||||||
let result = check_kernel_module_loaded(d.module_name, d.param_name);
|
let result = check_kernel_module_loaded(d.kernel_module);
|
||||||
let msg = format!("{}, result: {:?}", msg, result);
|
let msg = format!("{}, result: {:?}", msg, result);
|
||||||
|
|
||||||
if d.result.is_ok() {
|
if d.result.is_ok() {
|
||||||
assert_eq!(
|
assert_eq!(result, Ok(()));
|
||||||
result.as_ref().unwrap(),
|
|
||||||
d.result.as_ref().unwrap(),
|
|
||||||
"{}",
|
|
||||||
msg
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let expected_error = format!("{}", &d.result.as_ref().unwrap_err());
|
let expected_error = format!("{}", &d.result.as_ref().unwrap_err());
|
||||||
let actual_error = result.unwrap_err().to_string();
|
let actual_error = result.unwrap_err().to_string();
|
||||||
|
println!("testing for {}", d.module_name);
|
||||||
assert!(actual_error == expected_error, "{}", msg);
|
assert!(actual_error == expected_error, "{}", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,6 +255,12 @@ fn get_host_info() -> Result<HostInfo> {
|
|||||||
|
|
||||||
let guest_protection = guest_protection.to_string();
|
let guest_protection = guest_protection.to_string();
|
||||||
|
|
||||||
|
let mut vm_container_capable = true;
|
||||||
|
|
||||||
|
if arch_specific::host_is_vmcontainer_capable().is_err() {
|
||||||
|
vm_container_capable = false;
|
||||||
|
}
|
||||||
|
|
||||||
let support_vsocks = utils::supports_vsocks(utils::VHOST_VSOCK_DEVICE)?;
|
let support_vsocks = utils::supports_vsocks(utils::VHOST_VSOCK_DEVICE)?;
|
||||||
|
|
||||||
Ok(HostInfo {
|
Ok(HostInfo {
|
||||||
@ -264,8 +270,7 @@ fn get_host_info() -> Result<HostInfo> {
|
|||||||
cpu: host_cpu,
|
cpu: host_cpu,
|
||||||
memory: memory_info,
|
memory: memory_info,
|
||||||
available_guest_protection: guest_protection,
|
available_guest_protection: guest_protection,
|
||||||
// TODO: See https://github.com/kata-containers/kata-containers/issues/6727
|
vm_container_capable,
|
||||||
vm_container_capable: true,
|
|
||||||
support_vsocks,
|
support_vsocks,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -69,5 +69,5 @@ pub struct KernelParam<'a> {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct KernelModule<'a> {
|
pub struct KernelModule<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub parameter: KernelParam<'a>,
|
pub params: &'a [KernelParam<'a>],
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user