Initial commit: Comprehensive Debian bootc documentation
- Complete documentation for all bootc commands and subcommands - Debian-specific adaptations and workarounds - Manual installation methods to bypass bootc reliability issues - Technical guides with Rust source code analysis - Flowcharts and external command references - Hidden command documentation (bootc internals, state, etc.) - Composefs integration analysis - Base image creation guides (with and without bootc binary) - Management scripts and automation - Comprehensive troubleshooting and examples
This commit is contained in:
commit
526f1c1afd
67 changed files with 34174 additions and 0 deletions
733
internals/bootc-internals-architecture.md
Normal file
733
internals/bootc-internals-architecture.md
Normal file
|
|
@ -0,0 +1,733 @@
|
|||
# bootc internals - Architecture and Implementation
|
||||
|
||||
## Overview
|
||||
|
||||
This document provides a deep dive into the architecture and implementation details of the `bootc internals` system, covering the Rust code structure, design patterns, and integration points.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The bootc internals system is built on a modular architecture that provides internal-only operations for system maintenance, debugging, and integration. The system is designed to be:
|
||||
|
||||
- **Hidden**: Commands are not visible in regular help output
|
||||
- **Internal**: Intended for system administrators and developers
|
||||
- **Modular**: Each command is self-contained with clear responsibilities
|
||||
- **Integrated**: Seamlessly integrates with existing bootc infrastructure
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. Command Structure
|
||||
|
||||
The internals system is built around the `InternalsOpts` enum, which defines all available internal commands:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
|
||||
pub(crate) enum InternalsOpts {
|
||||
SystemdGenerator {
|
||||
normal_dir: Utf8PathBuf,
|
||||
early_dir: Option<Utf8PathBuf>,
|
||||
late_dir: Option<Utf8PathBuf>,
|
||||
},
|
||||
FixupEtcFstab,
|
||||
PrintJsonSchema {
|
||||
#[clap(long)]
|
||||
of: SchemaType,
|
||||
},
|
||||
#[clap(subcommand)]
|
||||
Fsverity(FsverityOpts),
|
||||
Fsck,
|
||||
Cleanup,
|
||||
Relabel {
|
||||
#[clap(long)]
|
||||
as_path: Option<Utf8PathBuf>,
|
||||
path: Utf8PathBuf,
|
||||
},
|
||||
OstreeExt { args: Vec<OsString> },
|
||||
Cfs { args: Vec<OsString> },
|
||||
OstreeContainer { args: Vec<OsString> },
|
||||
TestComposefs,
|
||||
LoopbackCleanupHelper { device: String },
|
||||
AllocateCleanupLoopback { file_path: Utf8PathBuf },
|
||||
BootcInstallCompletion { sysroot: Utf8PathBuf, stateroot: String },
|
||||
Reboot,
|
||||
#[cfg(feature = "rhsm")]
|
||||
PublishRhsmFacts,
|
||||
#[cfg(feature = "docgen")]
|
||||
DumpCliJson,
|
||||
DirDiff {
|
||||
pristine_etc: Utf8PathBuf,
|
||||
current_etc: Utf8PathBuf,
|
||||
new_etc: Utf8PathBuf,
|
||||
perform_merge: bool,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Command Routing
|
||||
|
||||
Commands are routed through the main CLI dispatcher in `cli.rs`:
|
||||
|
||||
```rust
|
||||
match opt {
|
||||
Opt::Internals(opts) => match opts {
|
||||
InternalsOpts::SystemdGenerator { normal_dir, early_dir, late_dir } => {
|
||||
let unit_dir = &Dir::open_ambient_dir(normal_dir, cap_std::ambient_authority())?;
|
||||
crate::generator::generator(root, unit_dir)
|
||||
}
|
||||
InternalsOpts::Fsck => {
|
||||
let sysroot = &get_storage().await?;
|
||||
crate::fsck::fsck(&sysroot, std::io::stdout().lock()).await?;
|
||||
Ok(())
|
||||
}
|
||||
// ... other commands
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Module Architecture
|
||||
|
||||
### 1. Generator Module (`generator.rs`)
|
||||
|
||||
**Purpose**: Systemd integration and unit generation
|
||||
|
||||
**Key Functions**:
|
||||
- `fstab_generator_impl()` - Generate fstab editor service
|
||||
- `generate_fstab_editor()` - Create systemd unit file
|
||||
- `generator()` - Main generator entry point
|
||||
|
||||
**Implementation**:
|
||||
```rust
|
||||
pub(crate) fn fstab_generator_impl(root: &Dir, unit_dir: &Dir) -> Result<bool> {
|
||||
// Check if system is ostree-booted
|
||||
if !is_ostree_booted_in(root)? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Check /etc/fstab for anaconda stamp
|
||||
if let Some(fd) = root.open_optional("etc/fstab")? {
|
||||
let mut from_anaconda = false;
|
||||
for line in fd.lines() {
|
||||
let line = line?;
|
||||
if line.contains(BOOTC_EDITED_STAMP) {
|
||||
return Ok(false); // Already processed
|
||||
}
|
||||
if line.contains(FSTAB_ANACONDA_STAMP) {
|
||||
from_anaconda = true;
|
||||
}
|
||||
}
|
||||
|
||||
if from_anaconda {
|
||||
generate_fstab_editor(unit_dir)?;
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**:
|
||||
- `ostree_ext::container_utils::is_ostree_booted_in`
|
||||
- `cap_std::fs::Dir`
|
||||
- `rustix::fs::StatVfsMountFlags`
|
||||
|
||||
### 2. Filesystem Check Module (`fsck.rs`)
|
||||
|
||||
**Purpose**: System consistency checking
|
||||
|
||||
**Key Functions**:
|
||||
- `fsck()` - Main consistency check entry point
|
||||
- `fsck_ok()` - Return success result
|
||||
- `fsck_err()` - Return error result
|
||||
|
||||
**Implementation**:
|
||||
```rust
|
||||
pub async fn fsck(sysroot: &Storage, mut out: impl Write) -> Result<()> {
|
||||
let ostree = sysroot.get_ostree()?;
|
||||
let repo = ostree.repo();
|
||||
|
||||
// Run all registered fsck checks
|
||||
for check in FSCK_CHECKS {
|
||||
match check(sysroot).await {
|
||||
Ok(Ok(())) => writeln!(out, "✓ {}", check.name())?,
|
||||
Ok(Err(e)) => writeln!(out, "✗ {}: {}", check.name(), e)?,
|
||||
Err(e) => writeln!(out, "✗ {}: {}", check.name(), e)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**:
|
||||
- `linkme::distributed_slice` - For check registration
|
||||
- `ostree_ext::composefs` - For composefs operations
|
||||
- `ostree_ext::ostree` - For OSTree operations
|
||||
|
||||
### 3. Composefs Control Module (`cfsctl.rs`)
|
||||
|
||||
**Purpose**: Composefs repository management
|
||||
|
||||
**Key Functions**:
|
||||
- `run_from_iter()` - Parse and execute cfsctl commands
|
||||
- `App::parse()` - Parse command line arguments
|
||||
- `Command` enum - Define available commands
|
||||
|
||||
**Implementation**:
|
||||
```rust
|
||||
pub async fn run_from_iter<I>(args: I) -> Result<()>
|
||||
where
|
||||
I: IntoIterator<Item = impl AsRef<OsStr>>,
|
||||
{
|
||||
let app = App::parse_from(args);
|
||||
let repo = if app.user {
|
||||
Repository::open_user()?
|
||||
} else if app.system {
|
||||
Repository::open_system()?
|
||||
} else if let Some(repo_path) = app.repo {
|
||||
Repository::open(repo_path)?
|
||||
} else {
|
||||
Repository::open_default()?
|
||||
};
|
||||
|
||||
match app.cmd {
|
||||
Command::Oci(oci_cmd) => match oci_cmd {
|
||||
OciCommand::ImportLayer { sha256, name } => {
|
||||
// Import layer implementation
|
||||
}
|
||||
OciCommand::LsLayer { name } => {
|
||||
// List layer implementation
|
||||
}
|
||||
// ... other OCI commands
|
||||
}
|
||||
Command::CreateFs { name, output } => {
|
||||
// Create filesystem implementation
|
||||
}
|
||||
Command::WriteBoot { name, output } => {
|
||||
// Write boot entries implementation
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**:
|
||||
- `composefs::repository::Repository`
|
||||
- `composefs::fsverity::FsVerityHashValue`
|
||||
- `composefs_boot::write_boot`
|
||||
|
||||
### 4. Deploy Module (`deploy.rs`)
|
||||
|
||||
**Purpose**: Deployment operations and cleanup
|
||||
|
||||
**Key Functions**:
|
||||
- `fixup_etc_fstab()` - Fix /etc/fstab for composefs
|
||||
- `cleanup()` - Perform system cleanup
|
||||
- `switch_origin_inplace()` - In-place origin switching
|
||||
|
||||
**Implementation**:
|
||||
```rust
|
||||
pub(crate) fn fixup_etc_fstab(root: &Dir) -> Result<()> {
|
||||
let fstab_path = root.open("etc/fstab")?;
|
||||
let mut fstab_content = String::new();
|
||||
fstab_path.read_to_string(&mut fstab_content)?;
|
||||
|
||||
let mut lines = fstab_content.lines().collect::<Vec<_>>();
|
||||
let mut modified = false;
|
||||
|
||||
for line in lines.iter_mut() {
|
||||
if line.contains("ro") && !line.contains("ro,") {
|
||||
*line = line.replace("ro", "ro,");
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if modified {
|
||||
let mut fstab_file = root.create("etc/fstab")?;
|
||||
for line in lines {
|
||||
writeln!(fstab_file, "{}", line)?;
|
||||
}
|
||||
writeln!(fstab_file, "# {}", BOOTC_EDITED_STAMP)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**:
|
||||
- `cap_std::fs::Dir`
|
||||
- `std::io::Write`
|
||||
- `ostree_ext::ostree`
|
||||
|
||||
### 5. Block Device Module (`blockdev.rs`)
|
||||
|
||||
**Purpose**: Loopback device management
|
||||
|
||||
**Key Functions**:
|
||||
- `LoopbackDevice::new()` - Create loopback device
|
||||
- `run_loopback_cleanup_helper()` - Cleanup helper
|
||||
- `run_allocate_cleanup_loopback()` - Test allocation
|
||||
|
||||
**Implementation**:
|
||||
```rust
|
||||
pub struct LoopbackDevice {
|
||||
device: String,
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
impl LoopbackDevice {
|
||||
pub fn new(file_path: &Path) -> Result<Self> {
|
||||
let output = Command::new("losetup")
|
||||
.args(["-f", "--show", file_path.to_str().unwrap()])
|
||||
.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow::anyhow!("Failed to create loopback device"));
|
||||
}
|
||||
|
||||
let device = String::from_utf8(output.stdout)?;
|
||||
let device = device.trim().to_string();
|
||||
|
||||
Ok(Self {
|
||||
device,
|
||||
file: file_path.to_path_buf(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn path(&self) -> &str {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LoopbackDevice {
|
||||
fn drop(&mut self) {
|
||||
let _ = Command::new("losetup")
|
||||
.args(["-d", &self.device])
|
||||
.output();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**:
|
||||
- `std::process::Command`
|
||||
- `std::path::Path`
|
||||
- `anyhow::Result`
|
||||
|
||||
## Design Patterns
|
||||
|
||||
### 1. Command Pattern
|
||||
|
||||
Each internals command follows the command pattern, encapsulating a request as an object:
|
||||
|
||||
```rust
|
||||
trait InternalCommand {
|
||||
fn execute(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl InternalCommand for SystemdGenerator {
|
||||
fn execute(&self) -> Result<()> {
|
||||
let unit_dir = &Dir::open_ambient_dir(&self.normal_dir, cap_std::ambient_authority())?;
|
||||
crate::generator::generator(&self.root, unit_dir)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Strategy Pattern
|
||||
|
||||
Different commands use different strategies for execution:
|
||||
|
||||
```rust
|
||||
enum ExecutionStrategy {
|
||||
Direct(DirectCommand),
|
||||
Proxy(ProxyCommand),
|
||||
Generator(GeneratorCommand),
|
||||
Test(TestCommand),
|
||||
}
|
||||
|
||||
impl ExecutionStrategy {
|
||||
fn execute(&self) -> Result<()> {
|
||||
match self {
|
||||
ExecutionStrategy::Direct(cmd) => cmd.execute_direct(),
|
||||
ExecutionStrategy::Proxy(cmd) => cmd.execute_proxy(),
|
||||
ExecutionStrategy::Generator(cmd) => cmd.execute_generator(),
|
||||
ExecutionStrategy::Test(cmd) => cmd.execute_test(),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Factory Pattern
|
||||
|
||||
Commands are created using a factory pattern:
|
||||
|
||||
```rust
|
||||
struct CommandFactory;
|
||||
|
||||
impl CommandFactory {
|
||||
fn create_command(opts: &InternalsOpts) -> Box<dyn InternalCommand> {
|
||||
match opts {
|
||||
InternalsOpts::SystemdGenerator { .. } => {
|
||||
Box::new(SystemdGenerator::new(opts))
|
||||
}
|
||||
InternalsOpts::Fsck => {
|
||||
Box::new(FsckCommand::new())
|
||||
}
|
||||
// ... other commands
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### 1. Error Types
|
||||
|
||||
The system uses a hierarchical error structure:
|
||||
|
||||
```rust
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum InternalError {
|
||||
#[error("System error: {0}")]
|
||||
System(String),
|
||||
|
||||
#[error("Permission error: {0}")]
|
||||
Permission(String),
|
||||
|
||||
#[error("Resource error: {0}")]
|
||||
Resource(String),
|
||||
|
||||
#[error("Configuration error: {0}")]
|
||||
Configuration(String),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for InternalError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
InternalError::System(err.to_string())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Error Context
|
||||
|
||||
All operations use error context for better debugging:
|
||||
|
||||
```rust
|
||||
#[context("Systemd generator")]
|
||||
pub(crate) fn generator(root: &Dir, unit_dir: &Dir) -> Result<()> {
|
||||
// Implementation with automatic error context
|
||||
}
|
||||
|
||||
#[context("Filesystem check")]
|
||||
pub async fn fsck(sysroot: &Storage, out: impl Write) -> Result<()> {
|
||||
// Implementation with automatic error context
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Error Recovery
|
||||
|
||||
The system implements error recovery strategies:
|
||||
|
||||
```rust
|
||||
pub async fn execute_with_retry<F, T>(mut operation: F, max_retries: usize) -> Result<T>
|
||||
where
|
||||
F: FnMut() -> Result<T>,
|
||||
{
|
||||
let mut last_error = None;
|
||||
|
||||
for attempt in 0..max_retries {
|
||||
match operation() {
|
||||
Ok(result) => return Ok(result),
|
||||
Err(e) => {
|
||||
last_error = Some(e);
|
||||
if attempt < max_retries - 1 {
|
||||
tokio::time::sleep(Duration::from_millis(100 * (attempt + 1) as u64)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(last_error.unwrap())
|
||||
}
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### 1. Privilege Escalation
|
||||
|
||||
All internals commands require root privileges:
|
||||
|
||||
```rust
|
||||
pub(crate) fn require_root(is_container: bool) -> Result<()> {
|
||||
ensure!(
|
||||
rustix::process::getuid().is_root(),
|
||||
if is_container {
|
||||
"The user inside the container from which you are running this command must be root"
|
||||
} else {
|
||||
"This command must be executed as the root user"
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Input Validation
|
||||
|
||||
All inputs are validated before processing:
|
||||
|
||||
```rust
|
||||
pub(crate) fn validate_path(path: &Path) -> Result<()> {
|
||||
// Check for path traversal
|
||||
if path.components().any(|c| c == Component::ParentDir) {
|
||||
return Err(anyhow::anyhow!("Path traversal detected"));
|
||||
}
|
||||
|
||||
// Check for absolute paths
|
||||
if !path.is_absolute() {
|
||||
return Err(anyhow::anyhow!("Path must be absolute"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Resource Limits
|
||||
|
||||
Operations are limited to prevent resource exhaustion:
|
||||
|
||||
```rust
|
||||
pub(crate) fn with_resource_limits<F, T>(operation: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce() -> Result<T>,
|
||||
{
|
||||
// Set memory limit
|
||||
let memory_limit = 1024 * 1024 * 1024; // 1GB
|
||||
let mut limits = rlimit::ResourceLimits::default();
|
||||
limits.set_memory_limit(memory_limit)?;
|
||||
limits.apply()?;
|
||||
|
||||
// Execute operation
|
||||
operation()
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### 1. Async Operations
|
||||
|
||||
All I/O operations are asynchronous:
|
||||
|
||||
```rust
|
||||
pub async fn cleanup_async(sysroot: &Storage) -> Result<()> {
|
||||
let ostree = sysroot.get_ostree()?;
|
||||
let repo = ostree.repo();
|
||||
|
||||
// Async repository operations
|
||||
let deployments = repo.list_deployments().await?;
|
||||
let unused_deployments = find_unused_deployments(deployments).await?;
|
||||
|
||||
for deployment in unused_deployments {
|
||||
repo.remove_deployment(deployment).await?;
|
||||
}
|
||||
|
||||
// Async garbage collection
|
||||
repo.garbage_collect().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Parallel Processing
|
||||
|
||||
Operations that can be parallelized are:
|
||||
|
||||
```rust
|
||||
pub async fn parallel_checks(sysroot: &Storage) -> Result<()> {
|
||||
let checks = vec![
|
||||
check_ostree_repo(sysroot),
|
||||
check_composefs_repo(sysroot),
|
||||
check_deployments(sysroot),
|
||||
check_configuration(sysroot),
|
||||
];
|
||||
|
||||
let results = futures::future::join_all(checks).await;
|
||||
|
||||
for result in results {
|
||||
result?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Caching
|
||||
|
||||
Frequently accessed data is cached:
|
||||
|
||||
```rust
|
||||
pub struct Cache {
|
||||
deployments: Option<Vec<Deployment>>,
|
||||
images: Option<Vec<Image>>,
|
||||
last_update: Option<Instant>,
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
pub async fn get_deployments(&mut self, sysroot: &Storage) -> Result<&Vec<Deployment>> {
|
||||
if self.deployments.is_none() || self.should_refresh() {
|
||||
self.deployments = Some(sysroot.get_deployments().await?);
|
||||
self.last_update = Some(Instant::now());
|
||||
}
|
||||
|
||||
Ok(self.deployments.as_ref().unwrap())
|
||||
}
|
||||
|
||||
fn should_refresh(&self) -> bool {
|
||||
self.last_update
|
||||
.map(|last| last.elapsed() > Duration::from_secs(60))
|
||||
.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### 1. Unit Tests
|
||||
|
||||
Each module has comprehensive unit tests:
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_systemd_generator() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let unit_dir = Dir::open_ambient_dir(temp_dir.path(), cap_std::ambient_authority()).unwrap();
|
||||
|
||||
// Test generator functionality
|
||||
let result = fstab_generator_impl(&root, &unit_dir);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fsck_operations() {
|
||||
let temp_sysroot = create_test_sysroot().unwrap();
|
||||
|
||||
// Test fsck functionality
|
||||
let result = fsck(&temp_sysroot, Vec::new()).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Integration Tests
|
||||
|
||||
End-to-end integration tests:
|
||||
|
||||
```rust
|
||||
#[tokio::test]
|
||||
async fn test_internals_integration() {
|
||||
// Setup test environment
|
||||
let test_env = TestEnvironment::new().await.unwrap();
|
||||
|
||||
// Test systemd generator
|
||||
let result = test_env.run_internals_command("systemd-generator", &["/tmp"]).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test fsck
|
||||
let result = test_env.run_internals_command("fsck", &[]).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test cleanup
|
||||
let result = test_env.run_internals_command("cleanup", &[]).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Performance Tests
|
||||
|
||||
Performance benchmarks:
|
||||
|
||||
```rust
|
||||
#[bench]
|
||||
fn bench_fsck_operations(b: &mut Bencher) {
|
||||
let sysroot = create_test_sysroot().unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(fsck(&sysroot, Vec::new()))
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### 1. Plugin System
|
||||
|
||||
A plugin system for extending internals functionality:
|
||||
|
||||
```rust
|
||||
pub trait InternalPlugin {
|
||||
fn name(&self) -> &str;
|
||||
fn execute(&self, args: &[String]) -> Result<()>;
|
||||
fn help(&self) -> &str;
|
||||
}
|
||||
|
||||
pub struct PluginManager {
|
||||
plugins: Vec<Box<dyn InternalPlugin>>,
|
||||
}
|
||||
|
||||
impl PluginManager {
|
||||
pub fn register_plugin(&mut self, plugin: Box<dyn InternalPlugin>) {
|
||||
self.plugins.push(plugin);
|
||||
}
|
||||
|
||||
pub fn execute_plugin(&self, name: &str, args: &[String]) -> Result<()> {
|
||||
let plugin = self.plugins.iter()
|
||||
.find(|p| p.name() == name)
|
||||
.ok_or_else(|| anyhow::anyhow!("Plugin not found: {}", name))?;
|
||||
|
||||
plugin.execute(args)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Configuration Management
|
||||
|
||||
Centralized configuration for internals commands:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct InternalsConfig {
|
||||
pub fsck: FsckConfig,
|
||||
pub cleanup: CleanupConfig,
|
||||
pub generator: GeneratorConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FsckConfig {
|
||||
pub enabled_checks: Vec<String>,
|
||||
pub timeout_seconds: u64,
|
||||
pub parallel_checks: bool,
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Monitoring Integration
|
||||
|
||||
Integration with monitoring systems:
|
||||
|
||||
```rust
|
||||
pub trait MetricsCollector {
|
||||
fn record_command_execution(&self, command: &str, duration: Duration, success: bool);
|
||||
fn record_error(&self, command: &str, error: &str);
|
||||
fn record_resource_usage(&self, command: &str, memory: u64, cpu: f64);
|
||||
}
|
||||
|
||||
pub struct PrometheusCollector {
|
||||
registry: Registry,
|
||||
}
|
||||
|
||||
impl MetricsCollector for PrometheusCollector {
|
||||
fn record_command_execution(&self, command: &str, duration: Duration, success: bool) {
|
||||
// Record metrics in Prometheus format
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This architecture document provides a comprehensive understanding of the bootc internals system's design, implementation, and future direction.
|
||||
Loading…
Add table
Add a link
Reference in a new issue