use indexmap::IndexMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use super::Resources;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct DockerImpl {
#[serde(default)]
pub image: Option<String>,
#[serde(default)]
pub build: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub dockerfile: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub target: Option<String>,
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
pub args: IndexMap<String, String>,
#[serde(default)]
pub init: Vec<String>,
#[serde(default)]
pub idle: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub appliance: Option<Appliance>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub config: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub firmware: Option<String>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub lxc: bool,
#[serde(skip)]
#[schemars(skip)]
pub generated: Option<Generated>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Generated {
pub os: String,
pub base: String,
pub from: BaseImage,
pub after_start: Option<OwnProcess>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct OwnProcess {
pub entrypoint: Vec<String>,
pub command: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum BaseImage {
#[default]
Os,
Entry,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
pub enum Appliance {
CiscoIol,
CiscoIolL2,
CiscoVios,
CiscoViosL2,
CiscoCsr1000v,
CiscoC8000v,
CiscoDynamips,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct VmImpl {
#[serde(default)]
pub os: String,
#[serde(default)]
pub provision: Vec<String>,
#[serde(default)]
pub image: Option<VmImage>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tpm: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub boot: Option<super::Boot>,
#[serde(skip)]
#[schemars(skip)]
pub setup: Vec<String>,
}
pub const REBOOT_STEP: &str = "reboot";
#[must_use]
pub fn is_reboot(step: &str) -> bool {
step == REBOOT_STEP
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum Winrm {
#[default]
Plaintext,
Ssl,
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Dns {
#[serde(default)]
pub servers: Vec<String>,
#[serde(default)]
pub search: Vec<String>,
#[serde(default)]
pub domain: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub options: Vec<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct VmImage {
#[serde(default)]
pub vagrant: Option<String>,
#[serde(default)]
pub vagrant_version: Option<String>,
#[serde(default)]
pub qemu: Option<String>,
#[serde(default)]
pub hyperv: Option<String>,
#[serde(default)]
pub winrm: Option<Winrm>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub winssh: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub box_url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub box_server_url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub proxmox: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub aws: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub azure: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub gcp: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub digitalocean: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub linode: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub oci: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Controller {
#[serde(default)]
#[schemars(skip)] pub image: Option<VmImage>,
#[serde(default)]
pub resources: Option<Resources>,
#[serde(default)]
pub keep_running: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct Provision {
pub ansible: String,
#[serde(default)]
pub inventory: Vec<String>,
#[serde(default)]
pub groups: IndexMap<String, Vec<String>>,
#[serde(default)]
pub vars: IndexMap<String, serde_json::Value>,
#[serde(default)]
pub host_vars: IndexMap<String, IndexMap<String, serde_json::Value>>,
#[serde(default)]
pub requirements: Option<String>,
}
pub const KNOWN_OS: &[&str] = &[
"debian-11",
"debian-12",
"debian-13",
"ubuntu-14.04",
"ubuntu-16.04",
"ubuntu-18.04",
"ubuntu-20.04",
"ubuntu-22.04",
"ubuntu-24.04",
"rocky-9",
"almalinux-9",
"alpine-3.19",
"alpine-3.24",
"kali",
"fedora-42",
"centos-7",
"windows-10",
"windows-11",
"windows-server-2008r2",
"windows-server-2012r2",
"windows-server-2016",
"windows-server-2019",
"windows-server-2022",
"windows-server-2025",
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_the_reboot_step_restarts_the_machine() {
assert_eq!([is_reboot("reboot"), is_reboot("provision/reboot.sh")], [true, false]);
}
}