vmm: Start splitting configuration parsing and validation

The configuration comes from a variety of places (commandline, REST API
and restore) however some validation was only happening on the command
line parsing path.  Therefore introduce a new ability to validate the
configuration before proceeding so that this can be used for commandline
and API boots.

For now move just the console and serial output mode validation under
the new validation API.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-04-06 16:20:27 +01:00
parent 0ea706faf5
commit 99b2ada4d0

View File

@ -40,8 +40,6 @@ pub enum Error {
ParsePmemFileMissing,
/// Missing persistant memory size parameter.
ParsePmemSizeMissing,
/// Both console and serial are tty.
ParseTTYParam,
/// Missing vsock socket path parameter.
ParseVsockSockMissing,
/// Missing vsock cid parameter.
@ -76,6 +74,25 @@ pub enum Error {
ParseVsock(OptionParserError),
/// Failed to parse restore parameters
ParseRestore(OptionParserError),
/// Failed to validate configuration
Validation(ValidationError),
}
#[derive(Debug)]
pub enum ValidationError {
/// Both console and serial are tty.
DoubleTtyMode,
}
type ValidationResult<T> = std::result::Result<T, ValidationError>;
impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::ValidationError::*;
match self {
DoubleTtyMode => write!(f, "Console mode tty specified for both serial and console"),
}
}
}
impl fmt::Display for Error {
@ -108,10 +125,7 @@ impl fmt::Display for Error {
ParsePersistentMemory(o) => write!(f, "Error parsing --pmem: {}", o),
ParsePmemFileMissing => write!(f, "Error parsing --pmem: file missing"),
ParsePmemSizeMissing => write!(f, "Error parsing --pmem: size missing"),
ParseTTYParam => write!(
f,
"Console mode tty specified for both --serial and --console"
),
ParseVsock(o) => write!(f, "Error parsing --vsock: {}", o),
ParseVsockCidMissing => write!(f, "Error parsing --vsock: cid missing"),
ParseVsockSockMissing => write!(f, "Error parsing --vsock: sock missing"),
@ -123,6 +137,7 @@ impl fmt::Display for Error {
ParseRestoreSourceUrlMissing => {
write!(f, "Error parsing --restore: source_url missing")
}
Validation(v) => write!(f, "Error validating configuration: {}", v),
}
}
}
@ -1179,6 +1194,15 @@ impl VmConfig {
self.kernel.is_some()
}
pub fn validate(&self) -> ValidationResult<()> {
if self.console.mode == ConsoleOutputMode::Tty && self.serial.mode == ConsoleOutputMode::Tty
{
return Err(ValidationError::DoubleTtyMode);
}
Ok(())
}
pub fn parse(vm_params: VmParams) -> Result<Self> {
let mut iommu = false;
@ -1240,9 +1264,6 @@ impl VmConfig {
iommu = true;
}
let serial = ConsoleConfig::parse(vm_params.serial)?;
if console.mode == ConsoleOutputMode::Tty && serial.mode == ConsoleOutputMode::Tty {
return Err(Error::ParseTTYParam);
}
let mut devices: Option<Vec<DeviceConfig>> = None;
if let Some(device_list) = &vm_params.devices {
@ -1284,7 +1305,7 @@ impl VmConfig {
});
}
Ok(VmConfig {
let config = VmConfig {
cpus: CpusConfig::parse(vm_params.cpus)?,
memory: MemoryConfig::parse(vm_params.memory)?,
kernel,
@ -1300,7 +1321,9 @@ impl VmConfig {
devices,
vsock,
iommu,
})
};
config.validate().map_err(Error::Validation)?;
Ok(config)
}
}
@ -1777,4 +1800,56 @@ mod tests {
);
Ok(())
}
#[test]
fn test_config_validation() -> Result<()> {
let valid_config = VmConfig {
cpus: CpusConfig {
boot_vcpus: 1,
max_vcpus: 1,
},
memory: MemoryConfig {
size: 536_870_912,
file: None,
mergeable: false,
hotplug_method: HotplugMethod::Acpi,
hotplug_size: None,
},
kernel: None,
initramfs: None,
cmdline: CmdlineConfig {
args: String::from(""),
},
disks: None,
net: None,
rng: RngConfig {
src: PathBuf::from("/dev/urandom"),
iommu: false,
},
fs: None,
pmem: None,
serial: ConsoleConfig {
file: None,
mode: ConsoleOutputMode::Null,
iommu: false,
},
console: ConsoleConfig {
file: None,
mode: ConsoleOutputMode::Tty,
iommu: false,
},
devices: None,
vsock: None,
iommu: false,
};
assert!(valid_config.validate().is_ok());
let mut invalid_config = valid_config.clone();
invalid_config.serial.mode = ConsoleOutputMode::Tty;
invalid_config.console.mode = ConsoleOutputMode::Tty;
assert!(invalid_config.validate().is_err());
Ok(())
}
}