- Fix feature gate placement for development commands - Make struct definitions always available, only gate implementations - Fix Self constructor usage in unit structs - Ensure development commands compile without development feature enabled - Fix CLI argument handling for development commands - Project now compiles successfully in CI/CD environment
382 lines
13 KiB
Rust
382 lines
13 KiB
Rust
//! Internal system commands for advanced operations
|
|
|
|
use crate::commands::Command;
|
|
use apt_ostree::lib::error::{AptOstreeError, AptOstreeResult};
|
|
use apt_ostree::lib::ostree::OstreeManager;
|
|
use apt_ostree::lib::apt::AptManager;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
use std::process::Command as ProcessCommand;
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
/// Internals command - Internal system commands for advanced operations
|
|
pub struct InternalsCommand;
|
|
|
|
impl InternalsCommand {
|
|
pub fn new() -> Self {
|
|
InternalsCommand
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "development")]
|
|
impl Command for InternalsCommand {
|
|
fn execute(&self, args: &[String]) -> AptOstreeResult<()> {
|
|
if args.is_empty() || args.contains(&"--help".to_string()) || args.contains(&"-h".to_string()) {
|
|
self.show_help();
|
|
return Ok(());
|
|
}
|
|
|
|
let subcommand = &args[0];
|
|
let sub_args = &args[1..];
|
|
|
|
match subcommand.as_str() {
|
|
"diagnostics" => self.handle_diagnostics(sub_args),
|
|
"validate-state" => self.handle_validate_state(sub_args),
|
|
"debug-dump" => self.handle_debug_dump(sub_args),
|
|
_ => {
|
|
println!("Unknown internals subcommand: {}", subcommand);
|
|
println!("Use 'apt-ostree internals --help' for available subcommands");
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
fn name(&self) -> &'static str {
|
|
"internals"
|
|
}
|
|
|
|
fn description(&self) -> &'static str {
|
|
"Internal system commands for advanced operations"
|
|
}
|
|
|
|
fn show_help(&self) {
|
|
println!("Usage: apt-ostree internals <SUBCOMMAND> [OPTIONS]");
|
|
println!();
|
|
println!("Internal system commands for apt-ostree.");
|
|
println!("These commands are for advanced system operations and diagnostics.");
|
|
println!();
|
|
println!("Subcommands:");
|
|
println!(" diagnostics Internal system diagnostics");
|
|
println!(" validate-state System state validation");
|
|
println!(" debug-dump Debug information dump");
|
|
println!();
|
|
println!("Options:");
|
|
println!(" --help, -h Show this help message");
|
|
println!();
|
|
println!("Examples:");
|
|
println!(" apt-ostree internals diagnostics");
|
|
println!(" apt-ostree internals validate-state");
|
|
println!(" apt-ostree internals debug-dump");
|
|
}
|
|
}
|
|
|
|
impl InternalsCommand {
|
|
fn handle_diagnostics(&self, _args: &[String]) -> AptOstreeResult<()> {
|
|
println!("🔍 Running Internal Diagnostics");
|
|
println!("===============================");
|
|
|
|
// Check system components
|
|
self.check_ostree_system()?;
|
|
self.check_apt_system()?;
|
|
self.check_daemon_status()?;
|
|
self.check_file_permissions()?;
|
|
|
|
println!("Diagnostics completed successfully");
|
|
Ok(())
|
|
}
|
|
|
|
fn handle_validate_state(&self, _args: &[String]) -> AptOstreeResult<()> {
|
|
println!("✅ Validating System State");
|
|
println!("===========================");
|
|
|
|
// Validate OSTree state
|
|
let ostree_manager = OstreeManager::new();
|
|
if ostree_manager.is_available() {
|
|
println!("OSTree: Available");
|
|
self.validate_ostree_state(&ostree_manager)?;
|
|
} else {
|
|
println!("OSTree: Not available");
|
|
}
|
|
|
|
// Validate APT state
|
|
let apt_manager = AptManager::new();
|
|
self.validate_apt_state(&apt_manager)?;
|
|
|
|
println!("System state validation completed");
|
|
Ok(())
|
|
}
|
|
|
|
fn handle_debug_dump(&self, _args: &[String]) -> AptOstreeResult<()> {
|
|
println!("🐛 Debug Information Dump");
|
|
println!("=========================");
|
|
|
|
// System information
|
|
self.dump_system_info()?;
|
|
|
|
// OSTree information
|
|
self.dump_ostree_info()?;
|
|
|
|
// APT information
|
|
self.dump_apt_info()?;
|
|
|
|
// Daemon information
|
|
self.dump_daemon_info()?;
|
|
|
|
println!("Debug information dump completed");
|
|
Ok(())
|
|
}
|
|
|
|
fn check_ostree_system(&self) -> AptOstreeResult<()> {
|
|
println!("Checking OSTree system...");
|
|
|
|
let ostree_manager = OstreeManager::new();
|
|
if ostree_manager.is_available() {
|
|
println!(" ✓ OSTree is available");
|
|
if ostree_manager.is_ostree_booted() {
|
|
println!(" ✓ System is booted from OSTree");
|
|
} else {
|
|
println!(" ⚠ System is not booted from OSTree");
|
|
}
|
|
} else {
|
|
println!(" ❌ OSTree is not available");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn check_apt_system(&self) -> AptOstreeResult<()> {
|
|
println!("Checking APT system...");
|
|
|
|
let _apt_manager = AptManager::new();
|
|
|
|
// Check if apt-get is available
|
|
if ProcessCommand::new("apt-get").arg("--version").output().is_ok() {
|
|
println!(" ✓ apt-get is available");
|
|
} else {
|
|
println!(" ❌ apt-get is not available");
|
|
}
|
|
|
|
// Check APT cache directory
|
|
let cache_dir = "/var/cache/apt";
|
|
if Path::new(cache_dir).exists() {
|
|
println!(" ✓ APT cache directory exists: {}", cache_dir);
|
|
} else {
|
|
println!(" ❌ APT cache directory missing: {}", cache_dir);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn check_daemon_status(&self) -> AptOstreeResult<()> {
|
|
println!("Checking daemon status...");
|
|
|
|
// Check if daemon service is running
|
|
let output = ProcessCommand::new("systemctl")
|
|
.arg("is-active")
|
|
.arg("apt-ostreed")
|
|
.output();
|
|
|
|
match output {
|
|
Ok(output) => {
|
|
let status = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
if status == "active" {
|
|
println!(" ✓ apt-ostreed service is active");
|
|
} else {
|
|
println!(" ⚠ apt-ostreed service status: {}", status);
|
|
}
|
|
}
|
|
Err(_) => {
|
|
println!(" ❌ Could not check apt-ostreed service status");
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn check_file_permissions(&self) -> AptOstreeResult<()> {
|
|
println!("Checking file permissions...");
|
|
|
|
// Check key directories
|
|
let dirs = [
|
|
("/etc/apt", "APT configuration"),
|
|
("/var/lib/apt", "APT state"),
|
|
("/var/cache/apt", "APT cache"),
|
|
("/var/lib/ostree", "OSTree data"),
|
|
];
|
|
|
|
for (path, description) in &dirs {
|
|
if Path::new(path).exists() {
|
|
let metadata = fs::metadata(path)
|
|
.map_err(|_| AptOstreeError::System(format!("Could not read metadata for {}", path)))?;
|
|
|
|
let permissions = metadata.permissions();
|
|
let mode = permissions.mode();
|
|
|
|
println!(" ✓ {}: {:o}", description, mode & 0o777);
|
|
} else {
|
|
println!(" ❌ {}: directory does not exist", description);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn validate_ostree_state(&self, ostree_manager: &OstreeManager) -> AptOstreeResult<()> {
|
|
println!("Validating OSTree state...");
|
|
|
|
// Check deployments
|
|
match ostree_manager.list_deployments() {
|
|
Ok(deployments) => {
|
|
println!(" ✓ Found {} deployments", deployments.len());
|
|
for deployment in &deployments {
|
|
let status = if deployment.booted { "Booted" } else { "Available" };
|
|
println!(" - {}: {} ({})", deployment.id, status, deployment.commit);
|
|
}
|
|
}
|
|
Err(e) => {
|
|
println!(" ❌ Failed to list deployments: {}", e);
|
|
}
|
|
}
|
|
|
|
// Check current deployment
|
|
match ostree_manager.get_current_deployment() {
|
|
Ok(Some(current)) => {
|
|
println!(" ✓ Current deployment: {} ({})", current.id, current.commit);
|
|
}
|
|
Ok(None) => {
|
|
println!(" ⚠ No current deployment found");
|
|
}
|
|
Err(e) => {
|
|
println!(" ❌ Failed to get current deployment: {}", e);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn validate_apt_state(&self, _apt_manager: &AptManager) -> AptOstreeResult<()> {
|
|
println!("Validating APT state...");
|
|
|
|
// Check APT sources
|
|
let sources_list = "/etc/apt/sources.list";
|
|
if Path::new(sources_list).exists() {
|
|
println!(" ✓ APT sources list exists");
|
|
} else {
|
|
println!(" ⚠ APT sources list missing");
|
|
}
|
|
|
|
// Check APT cache
|
|
let cache_dir = "/var/cache/apt";
|
|
if Path::new(cache_dir).exists() {
|
|
let entries = fs::read_dir(cache_dir)
|
|
.map_err(|_| AptOstreeError::System("Could not read APT cache directory".to_string()))?;
|
|
|
|
let count = entries.count();
|
|
println!(" ✓ APT cache contains {} entries", count);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn dump_system_info(&self) -> AptOstreeResult<()> {
|
|
println!("System Information:");
|
|
println!("===================");
|
|
|
|
// OS information
|
|
if let Ok(os_release) = fs::read_to_string("/etc/os-release") {
|
|
for line in os_release.lines() {
|
|
if line.starts_with("PRETTY_NAME=") || line.starts_with("VERSION=") {
|
|
println!(" {}", line);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Architecture
|
|
if let Ok(output) = ProcessCommand::new("uname").arg("-m").output() {
|
|
let arch = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
println!(" Architecture: {}", arch);
|
|
}
|
|
|
|
// Kernel version
|
|
if let Ok(output) = ProcessCommand::new("uname").arg("-r").output() {
|
|
let kernel = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
println!(" Kernel: {}", kernel);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn dump_ostree_info(&self) -> AptOstreeResult<()> {
|
|
println!("OSTree Information:");
|
|
println!("===================");
|
|
|
|
let ostree_manager = OstreeManager::new();
|
|
if ostree_manager.is_available() {
|
|
let system_info = ostree_manager.get_system_info();
|
|
println!(" OS: {}", system_info.os);
|
|
println!(" Kernel: {}", system_info.kernel);
|
|
println!(" Architecture: {}", system_info.architecture);
|
|
|
|
match ostree_manager.get_repo_info() {
|
|
Ok(repo_info) => {
|
|
println!(" Repository: {}", repo_info.path);
|
|
println!(" Available refs: {}", repo_info.refs.len());
|
|
}
|
|
Err(e) => {
|
|
println!(" ❌ Failed to get repo info: {}", e);
|
|
}
|
|
}
|
|
} else {
|
|
println!(" OSTree not available");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn dump_apt_info(&self) -> AptOstreeResult<()> {
|
|
println!("APT Information:");
|
|
println!("================");
|
|
|
|
// APT version
|
|
if let Ok(output) = ProcessCommand::new("apt-get").arg("--version").output() {
|
|
let version = String::from_utf8_lossy(&output.stdout).lines().next().unwrap_or("Unknown").to_string();
|
|
println!(" Version: {}", version);
|
|
}
|
|
|
|
// APT configuration
|
|
let config_dirs = ["/etc/apt/apt.conf.d", "/etc/apt/sources.list.d"];
|
|
for dir in &config_dirs {
|
|
if Path::new(dir).exists() {
|
|
if let Ok(entries) = fs::read_dir(dir) {
|
|
let count = entries.count();
|
|
println!(" Config files in {}: {}", dir, count);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn dump_daemon_info(&self) -> AptOstreeResult<()> {
|
|
println!("Daemon Information:");
|
|
println!("===================");
|
|
|
|
// Service status
|
|
if let Ok(output) = ProcessCommand::new("systemctl").arg("show").arg("apt-ostreed").arg("--property=ActiveState").output() {
|
|
let status = String::from_utf8_lossy(&output.stdout).lines().next().unwrap_or("Unknown").to_string();
|
|
println!(" Service status: {}", status);
|
|
}
|
|
|
|
// Process information
|
|
if let Ok(output) = ProcessCommand::new("pgrep").arg("-f").arg("apt-ostreed").output() {
|
|
let pids: Vec<String> = String::from_utf8_lossy(&output.stdout).lines().map(|s| s.to_string()).collect();
|
|
if !pids.is_empty() {
|
|
println!(" Running processes: {}", pids.join(", "));
|
|
} else {
|
|
println!(" No running processes found");
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|