use crate::errors::{AnsibleError, Result};
use std::process::Command;
pub struct PlatformValidator;
impl PlatformValidator {
pub fn check_platform() -> Result<()> {
#[cfg(not(any(
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd"
)))]
{
return Err(AnsibleError::unsupported_platform(format!(
"ansible-rs only supports Unix-like systems. Current platform: {}",
std::env::consts::OS
)));
}
Ok(())
}
pub fn check_ansible_installation() -> Result<String> {
Self::check_platform()?;
let output = Command::new("ansible")
.arg("--version")
.output()
.map_err(|e| {
AnsibleError::command_not_found(format!(
"Ansible command not found. Please install Ansible first. Error: {}",
e
))
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AnsibleError::command_failed(
"Failed to get Ansible version",
output.status.code(),
None,
Some(stderr.to_string()),
));
}
let version_output = String::from_utf8_lossy(&output.stdout);
Ok(version_output.to_string())
}
pub fn check_ansible_playbook() -> Result<String> {
Self::check_platform()?;
let output = Command::new("ansible-playbook")
.arg("--version")
.output()
.map_err(|e| {
AnsibleError::command_not_found(format!(
"ansible-playbook command not found. Please install Ansible first. Error: {}",
e
))
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AnsibleError::command_failed(
"Failed to get ansible-playbook version",
output.status.code(),
None,
Some(stderr.to_string()),
));
}
let version_output = String::from_utf8_lossy(&output.stdout);
Ok(version_output.to_string())
}
pub fn check_ansible_vault() -> Result<String> {
Self::check_platform()?;
let output = Command::new("ansible-vault")
.arg("--help")
.output()
.map_err(|e| {
AnsibleError::command_not_found(format!(
"ansible-vault command not found. Please install Ansible first. Error: {}",
e
))
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AnsibleError::command_failed(
"Failed to check ansible-vault availability",
output.status.code(),
None,
Some(stderr.to_string()),
));
}
Ok("ansible-vault is available".to_string())
}
pub fn check_ansible_config() -> Result<String> {
Self::check_platform()?;
let output = Command::new("ansible-config")
.arg("--help")
.output()
.map_err(|e| {
AnsibleError::command_not_found(format!(
"ansible-config command not found. Please install Ansible first. Error: {}",
e
))
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AnsibleError::command_failed(
"Failed to check ansible-config availability",
output.status.code(),
None,
Some(stderr.to_string()),
));
}
Ok("ansible-config is available".to_string())
}
pub fn check_ansible_inventory() -> Result<String> {
Self::check_platform()?;
let output = Command::new("ansible-inventory")
.arg("--help")
.output()
.map_err(|e| {
AnsibleError::command_not_found(format!(
"ansible-inventory command not found. Please install Ansible first. Error: {}",
e
))
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(AnsibleError::command_failed(
"Failed to check ansible-inventory availability",
output.status.code(),
None,
Some(stderr.to_string()),
));
}
Ok("ansible-inventory is available".to_string())
}
pub fn check_all_requirements() -> Result<SystemInfo> {
Self::check_platform()?;
let ansible_version = Self::check_ansible_installation()?;
let playbook_available = Self::check_ansible_playbook().is_ok();
let vault_available = Self::check_ansible_vault().is_ok();
let config_available = Self::check_ansible_config().is_ok();
let inventory_available = Self::check_ansible_inventory().is_ok();
Ok(SystemInfo {
platform: std::env::consts::OS.to_string(),
architecture: std::env::consts::ARCH.to_string(),
ansible_version,
playbook_available,
vault_available,
config_available,
inventory_available,
})
}
pub fn minimum_ansible_version() -> &'static str {
"2.9"
}
pub fn supported_platforms() -> Vec<&'static str> {
vec![
"linux",
"macos",
"freebsd",
"openbsd",
"netbsd",
]
}
pub fn is_platform_supported() -> bool {
Self::supported_platforms().contains(&std::env::consts::OS)
}
}
#[derive(Debug, Clone)]
pub struct SystemInfo {
pub platform: String,
pub architecture: String,
pub ansible_version: String,
pub playbook_available: bool,
pub vault_available: bool,
pub config_available: bool,
pub inventory_available: bool,
}
impl SystemInfo {
pub fn is_fully_supported(&self) -> bool {
self.playbook_available
&& self.vault_available
&& self.config_available
&& self.inventory_available
}
pub fn feature_summary(&self) -> Vec<(String, bool)> {
vec![
("ansible".to_string(), !self.ansible_version.is_empty()),
("ansible-playbook".to_string(), self.playbook_available),
("ansible-vault".to_string(), self.vault_available),
("ansible-config".to_string(), self.config_available),
("ansible-inventory".to_string(), self.inventory_available),
]
}
pub fn missing_features(&self) -> Vec<String> {
let mut missing = Vec::new();
if self.ansible_version.is_empty() {
missing.push("ansible".to_string());
}
if !self.playbook_available {
missing.push("ansible-playbook".to_string());
}
if !self.vault_available {
missing.push("ansible-vault".to_string());
}
if !self.config_available {
missing.push("ansible-config".to_string());
}
if !self.inventory_available {
missing.push("ansible-inventory".to_string());
}
missing
}
}
impl std::fmt::Display for SystemInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "System Information:")?;
writeln!(f, " Platform: {} ({})", self.platform, self.architecture)?;
writeln!(f, " Ansible Version: {}", self.ansible_version.trim())?;
writeln!(f, " Available Features:")?;
for (feature, available) in self.feature_summary() {
let status = if available { "✅" } else { "❌" };
writeln!(f, " {} {}", status, feature)?;
}
if !self.is_fully_supported() {
writeln!(f, " Missing Features: {:?}", self.missing_features())?;
}
Ok(())
}
}
pub fn validate_system() -> Result<()> {
PlatformValidator::check_platform()?;
PlatformValidator::check_ansible_installation()?;
Ok(())
}
pub fn get_system_info() -> Result<SystemInfo> {
PlatformValidator::check_all_requirements()
}