# bootc status - Technical Guide ## Overview `bootc status` is a command for displaying the current state of a bootc-managed system. It provides comprehensive information about deployments, boot order, image references, and system configuration. The command supports multiple output formats and can be used both interactively and programmatically. ## Purpose The status command serves several critical functions: 1. **System State Display**: Show current bootc system state 2. **Deployment Information**: Display staged, booted, and rollback deployments 3. **Image References**: Show container image information and metadata 4. **Boot Order Status**: Indicate current boot order configuration 5. **Programmatic Access**: Provide structured data for automation 6. **Troubleshooting**: Help diagnose system issues ## Command Syntax ```bash bootc status [OPTIONS...] ``` ### Basic Usage ```bash # Show current system status bootc status # Show status in JSON format bootc status --format=json # Show detailed status with verbose output bootc status --verbose # Show only booted deployment status bootc status --booted # Show status in YAML format bootc status --format=yaml ``` ## Command Options | Option | Description | Default | Required | |--------|-------------|---------|----------| | `--format` | Output format (humanreadable, yaml, json) | `auto` | No | | `--format-version` | Format version (0, 1) | `1` | No | | `--booted` | Only display booted deployment | `false` | No | | `--verbose`, `-v` | Include additional fields | `false` | No | | `--json` | Output in JSON format (deprecated) | `false` | No | ### Output Formats | Format | Description | Use Case | |--------|-------------|----------| | `humanreadable` | Human-friendly text output | Interactive use | | `yaml` | YAML-formatted output | Programmatic parsing | | `json` | JSON-formatted output | Programmatic parsing | ## Architecture Overview ### 1. Status Command Structure ```rust pub(crate) struct StatusOpts { pub(crate) json: bool, // JSON output (deprecated) pub(crate) format: Option, // Output format pub(crate) format_version: Option, // Format version pub(crate) booted: bool, // Only booted deployment pub(crate) verbose: bool, // Verbose output } ``` ### 2. Status Process Flow ```rust pub(crate) async fn status(opts: StatusOpts) -> Result<()> { // 1. Validate format version match opts.format_version.unwrap_or_default() { 0 | 1 => {} // Both 0 and 1 mean "v1" o => anyhow::bail!("Unsupported format version: {o}"), }; // 2. Get system status let mut host = if !ostree_booted()? { Default::default() } else { let sysroot = super::cli::get_storage().await?; let ostree = sysroot.get_ostree()?; let booted_deployment = ostree.booted_deployment(); let (_deployments, host) = get_status(&ostree, booted_deployment.as_ref())?; host }; // 3. Filter to booted deployment if requested if opts.booted { host.filter_to_slot(Slot::Booted); } // 4. Determine output format let out = std::io::stdout(); let mut out = out.lock(); let legacy_opt = if opts.json { OutputFormat::Json } else if std::io::stdout().is_terminal() { OutputFormat::HumanReadable } else { OutputFormat::Yaml }; let format = opts.format.unwrap_or(legacy_opt); // 5. Output in requested format match format { OutputFormat::Json => host.to_canon_json_writer(&mut out), OutputFormat::Yaml => serde_yaml::to_writer(&mut out, &host), OutputFormat::HumanReadable => { human_readable_output(&mut out, &host, opts.verbose) } } } ``` ### 3. Core Status Gathering ```rust pub(crate) fn get_status( sysroot: &SysrootLock, booted_deployment: Option<&ostree::Deployment>, ) -> Result<(Deployments, Host)> { // 1. Get stateroot name let stateroot = booted_deployment.as_ref().map(|d| d.osname()); // 2. Partition deployments let (mut related_deployments, other_deployments) = sysroot .deployments() .into_iter() .partition::, _>(|d| Some(d.osname()) == stateroot); // 3. Find staged deployment let staged = related_deployments .iter() .position(|d| d.is_staged()) .map(|i| related_deployments.remove(i).unwrap()); // 4. Filter out booted deployment if let Some(booted) = booted_deployment.as_ref() { related_deployments.retain(|f| !f.equal(booted)); } // 5. Get rollback deployment let rollback = related_deployments.pop_front(); // 6. Determine rollback queued status let rollback_queued = match (booted_deployment.as_ref(), rollback.as_ref()) { (Some(booted), Some(rollback)) => rollback.index() < booted.index(), _ => false, }; // 7. Determine boot order let boot_order = if rollback_queued { BootOrder::Rollback } else { BootOrder::Default }; // 8. Create deployments structure let deployments = Deployments { staged, rollback, other: related_deployments, }; // 9. Create boot entries let staged = deployments.staged .as_ref() .map(|d| boot_entry_from_deployment(sysroot, d)) .transpose() .context("Staged deployment")?; let booted = booted_deployment .as_ref() .map(|d| boot_entry_from_deployment(sysroot, d)) .transpose() .context("Booted deployment")?; let rollback = deployments.rollback .as_ref() .map(|d| boot_entry_from_deployment(sysroot, d)) .transpose() .context("Rollback deployment")?; // 10. Create host specification let spec = staged .as_ref() .or(booted.as_ref()) .and_then(|entry| entry.image.as_ref()) .map(|img| HostSpec { image: Some(img.image.clone()), boot_order, }) .unwrap_or_default(); // 11. Determine host type let ty = if booted .as_ref() .map(|b| b.image.is_some()) .unwrap_or_default() { Some(HostType::BootcHost) } else { None }; // 12. Create host status let mut host = Host::new(spec); host.status = HostStatus { staged, booted, rollback, other_deployments: other_deployments, rollback_queued, ty, }; Ok((deployments, host)) } ``` ## Data Structures ### 1. Host Structure ```rust pub struct Host { pub resource: k8sapitypes::Resource, pub spec: HostSpec, pub status: HostStatus, } ``` ### 2. Host Specification ```rust pub struct HostSpec { pub image: Option, pub boot_order: BootOrder, } ``` ### 3. Host Status ```rust pub struct HostStatus { pub staged: Option, pub booted: Option, pub rollback: Option, pub other_deployments: Vec, pub rollback_queued: bool, pub ty: Option, } ``` ### 4. Boot Entry ```rust pub struct BootEntry { pub deployment: DeploymentInfo, pub image: Option, } ``` ### 5. Image Status ```rust pub struct ImageStatus { pub image: ImageReference, pub version: Option, pub timestamp: Option>, pub image_digest: String, pub architecture: String, } ``` ## Output Formats ### 1. Human Readable Format **Default for terminal output** ``` System is deployed via bootc. Image: quay.io/myorg/debian-bootc:v2.0 Version: 2.0.0 Digest: sha256:abc123def456... Architecture: x86_64 Boot Order: Default Rollback Queued: false Deployments: Staged: None Booted: quay.io/myorg/debian-bootc:v2.0 Rollback: quay.io/myorg/debian-bootc:v1.0 ``` ### 2. YAML Format **Default for non-terminal output** ```yaml apiVersion: v1 kind: Host metadata: name: localhost spec: image: image: quay.io/myorg/debian-bootc:v2.0 transport: registry bootOrder: Default status: staged: null booted: deployment: id: abc123def456... osname: debian-bootc checksum: def456ghi789... image: image: image: quay.io/myorg/debian-bootc:v2.0 transport: registry version: "2.0.0" timestamp: "2024-01-15T10:30:00Z" imageDigest: sha256:abc123def456... architecture: x86_64 rollback: deployment: id: def456ghi789... osname: debian-bootc checksum: ghi789jkl012... image: image: image: quay.io/myorg/debian-bootc:v1.0 transport: registry version: "1.0.0" timestamp: "2024-01-10T15:45:00Z" imageDigest: sha256:def456ghi789... architecture: x86_64 otherDeployments: [] rollbackQueued: false ty: BootcHost ``` ### 3. JSON Format **For programmatic access** ```json { "apiVersion": "v1", "kind": "Host", "metadata": { "name": "localhost" }, "spec": { "image": { "image": "quay.io/myorg/debian-bootc:v2.0", "transport": "registry" }, "bootOrder": "Default" }, "status": { "staged": null, "booted": { "deployment": { "id": "abc123def456...", "osname": "debian-bootc", "checksum": "def456ghi789..." }, "image": { "image": { "image": "quay.io/myorg/debian-bootc:v2.0", "transport": "registry" }, "version": "2.0.0", "timestamp": "2024-01-15T10:30:00Z", "imageDigest": "sha256:abc123def456...", "architecture": "x86_64" } }, "rollback": { "deployment": { "id": "def456ghi789...", "osname": "debian-bootc", "checksum": "ghi789jkl012..." }, "image": { "image": { "image": "quay.io/myorg/debian-bootc:v1.0", "transport": "registry" }, "version": "1.0.0", "timestamp": "2024-01-10T15:45:00Z", "imageDigest": "sha256:def456ghi789...", "architecture": "x86_64" } }, "otherDeployments": [], "rollbackQueued": false, "ty": "BootcHost" } } ``` ## Deployment Detection ### 1. OSTree Boot Detection ```rust if !ostree_booted()? { Default::default() } else { // Get system status } ``` **Purpose**: Check if system is booted via OSTree **Process**: Verify OSTree boot environment ### 2. Deployment Partitioning ```rust let (mut related_deployments, other_deployments) = sysroot .deployments() .into_iter() .partition::, _>(|d| Some(d.osname()) == stateroot); ``` **Purpose**: Separate related deployments from others **Process**: Filter deployments by stateroot name ### 3. Staged Deployment Detection ```rust let staged = related_deployments .iter() .position(|d| d.is_staged()) .map(|i| related_deployments.remove(i).unwrap()); ``` **Purpose**: Find staged deployment for next boot **Process**: Look for deployment marked as staged ### 4. Rollback Detection ```rust let rollback = related_deployments.pop_front(); let rollback_queued = match (booted_deployment.as_ref(), rollback.as_ref()) { (Some(booted), Some(rollback)) => rollback.index() < booted.index(), _ => false, }; ``` **Purpose**: Determine rollback deployment and queued status **Process**: Check deployment order and indices ## Boot Order Management ### 1. Boot Order States ```rust let boot_order = if rollback_queued { BootOrder::Rollback } else { BootOrder::Default }; ``` **States**: - **Default**: Current deployment first, rollback second - **Rollback**: Rollback deployment first, current second ### 2. Rollback Queued Detection ```rust let rollback_queued = match (booted_deployment.as_ref(), rollback.as_ref()) { (Some(booted), Some(rollback)) => rollback.index() < booted.index(), _ => false, }; ``` **Purpose**: Determine if rollback is queued for next boot **Process**: Compare deployment indices ## Image Information Extraction ### 1. Image Status Creation ```rust fn create_imagestatus( image: ImageReference, manifest_digest: &Digest, config: &ImageConfiguration, ) -> ImageStatus { let labels = labels_of_config(config); let timestamp = labels .and_then(|l| { l.get(oci_spec::image::ANNOTATION_CREATED) .map(|s| s.as_str()) }) .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok()) .map(|dt| dt.with_timezone(&chrono::Utc)); let architecture = config.architecture().unwrap_or("unknown").to_string(); ImageStatus { image, version: labels.and_then(|l| l.get("version").cloned()), timestamp, image_digest: manifest_digest.to_string(), architecture, } } ``` **Purpose**: Extract image metadata and configuration **Process**: Parse OCI image configuration and labels ### 2. Boot Entry Creation ```rust fn boot_entry_from_deployment( sysroot: &SysrootLock, deployment: &ostree::Deployment, ) -> Result { let deployment_info = DeploymentInfo { id: deployment.csum().to_string(), osname: deployment.osname().to_string(), checksum: deployment.csum().to_string(), }; let image = if let Ok(origin) = deployment.origin() { if let Some(refspec) = origin.optional_string("origin", "refspec")? { if let Ok(ostree_ref) = ostree::parse_refspec(&refspec) { if let Ok(image_ref) = ostree_container::OstreeImageReference::try_from(ostree_ref) { let image_ref = ImageReference::from(image_ref); let repo = &sysroot.repo(); let imgstate = ostree_container::store::query_image_commit(repo, &deployment.csum())?; let cached = imgstate.cached_update .map(|cached| create_imagestatus(image_ref, &cached.manifest_digest, &cached.config)); cached } else { None } } else { None } } else { None } } else { None }; Ok(BootEntry { deployment: deployment_info, image, }) } ``` **Purpose**: Create boot entry from OSTree deployment **Process**: Extract deployment info and image metadata ## Format Detection ### 1. Automatic Format Selection ```rust let legacy_opt = if opts.json { OutputFormat::Json } else if std::io::stdout().is_terminal() { OutputFormat::HumanReadable } else { OutputFormat::Yaml }; ``` **Logic**: - **JSON**: If `--json` flag specified - **Human Readable**: If output is a terminal - **YAML**: If output is not a terminal ### 2. Format Version Support ```rust match opts.format_version.unwrap_or_default() { 0 | 1 => {} // Both 0 and 1 mean "v1" o => anyhow::bail!("Unsupported format version: {o}"), }; ``` **Purpose**: Support multiple format versions **Current**: Version 1 (exposed as both 0 and 1) ## Filtering Options ### 1. Booted Deployment Filter ```rust if opts.booted { host.filter_to_slot(Slot::Booted); } ``` **Purpose**: Show only booted deployment information **Use Case**: Focus on current deployment ### 2. Verbose Output ```rust human_readable_output(&mut out, &host, opts.verbose) ``` **Purpose**: Include additional fields in human readable format **Use Case**: Detailed troubleshooting information ## Error Handling ### 1. OSTree Boot Detection Errors ```rust if !ostree_booted()? { Default::default() } ``` **Error**: System not booted via OSTree **Response**: Return default empty status ### 2. Deployment Access Errors ```rust let (_deployments, host) = get_status(&ostree, booted_deployment.as_ref())?; ``` **Error**: Cannot access deployments **Response**: Propagate error up the call stack ### 3. Format Version Errors ```rust match opts.format_version.unwrap_or_default() { 0 | 1 => {} o => anyhow::bail!("Unsupported format version: {o}"), }; ``` **Error**: Unsupported format version **Response**: Return error with message ## Usage Patterns ### 1. Interactive Use ```bash # Check system status bootc status # Check with verbose output bootc status --verbose # Check only booted deployment bootc status --booted ``` ### 2. Programmatic Use ```bash # Get JSON output for parsing bootc status --format=json # Get YAML output for parsing bootc status --format=yaml # Check if system is bootc compatible bootc status --format=json | jq '.status.booted != null' ``` ### 3. Automation Scripts ```bash #!/bin/bash # Check if rollback is queued if bootc status --format=json | jq -r '.status.rollbackQueued' | grep -q true; then echo "Rollback is queued for next boot" fi # Get current image version CURRENT_VERSION=$(bootc status --format=json | jq -r '.status.booted.image.version // "unknown"') echo "Current version: $CURRENT_VERSION" ``` ## Integration with Other Commands ### 1. Relationship to bootc upgrade **Status Before Upgrade**: ```bash bootc status bootc upgrade --apply bootc status ``` **Status After Upgrade**: - Shows new staged deployment - Shows updated booted deployment - Shows previous deployment as rollback ### 2. Relationship to bootc switch **Status Before Switch**: ```bash bootc status bootc switch quay.io/myorg/debian-bootc:v2.0 bootc status ``` **Status After Switch**: - Shows new image reference - Shows staged deployment - Shows updated boot order ### 3. Relationship to bootc rollback **Status Before Rollback**: ```bash bootc status bootc rollback bootc status ``` **Status After Rollback**: - Shows rollback queued status - Shows updated boot order - Shows deployment reordering ## Troubleshooting ### 1. Common Issues #### System Not Bootc Compatible ```bash # Check if system is bootc compatible bootc status --format=json | jq '.status.booted != null' # Check OSTree status ostree admin status ``` #### No Deployments Found ```bash # Check deployment status ostree admin status # Check system logs journalctl -u bootc-fetch-apply-updates.service ``` #### Format Parsing Errors ```bash # Use specific format bootc status --format=json # Check format version bootc status --format-version=1 ``` ### 2. Debug Commands ```bash # Enable debug logging RUST_LOG=debug bootc status # Check system logs journalctl -u bootc-fetch-apply-updates.service # Check OSTree status ostree admin status --verbose ``` ## Best Practices ### 1. Programmatic Usage - **Use JSON/YAML**: For programmatic parsing - **Check Format Version**: Specify format version explicitly - **Handle Errors**: Check for null values and errors - **Validate Output**: Verify expected fields exist ### 2. Interactive Usage - **Use Human Readable**: For interactive use - **Use Verbose**: For detailed information - **Check Booted**: Focus on current deployment - **Monitor Changes**: Track status over time ### 3. Automation - **Parse JSON**: Use `jq` for JSON parsing - **Check Compatibility**: Verify bootc compatibility - **Monitor Status**: Track deployment changes - **Handle Errors**: Implement proper error handling ## Future Enhancements ### 1. Planned Features - **Additional Formats**: Support for more output formats - **Filtering Options**: More granular filtering - **Status History**: Track status changes over time - **Health Checks**: Include system health information ### 2. Integration Improvements - **API Support**: REST API for status queries - **Web Interface**: Web-based status display - **Monitoring Integration**: Integration with monitoring systems - **Alerting**: Status-based alerting This technical guide provides comprehensive understanding of the bootc status system's architecture, implementation, and usage patterns.