- ✅ Real package installation (replaced mock installation) - ✅ Real OSTree commit creation from installed packages - ✅ OCI image creation from both commits and rootfs - ✅ Full bootc compatibility with proper labels - ✅ Comprehensive test suite (test-bootc-apt-ostree.sh) - ✅ Container tool validation (skopeo, podman) - ✅ Updated compatibility reports for Ubuntu Questing - ✅ Fixed OCI schema version and field naming issues - ✅ Temporary directory lifecycle fixes - ✅ Serde rename attributes for OCI JSON compliance Ready for Aurora-style workflow deployment!
541 lines
No EOL
16 KiB
Markdown
541 lines
No EOL
16 KiB
Markdown
# apt-ostree OSTree Implementation
|
|
|
|
## Overview
|
|
|
|
apt-ostree implements OSTree as its core filesystem management system, providing atomic, immutable deployments with APT/DEB package layering capabilities. This document explains how apt-ostree implements and extends OSTree functionality for Debian/Ubuntu systems.
|
|
|
|
## Core OSTree Integration
|
|
|
|
### Repository Management
|
|
|
|
apt-ostree maintains an OSTree repository at `/ostree/repo` that stores:
|
|
- **Content-addressable objects**: Files and metadata stored by SHA256 hash
|
|
- **Commits**: Immutable snapshots of filesystem trees
|
|
- **Refs**: Symbolic pointers to specific commits (e.g., `ubuntu/24.04/x86_64/desktop`)
|
|
- **Static deltas**: Pre-calculated differences between commits for efficient updates
|
|
|
|
### Deployment Structure
|
|
|
|
```
|
|
/ostree/
|
|
├── repo/ # OSTree repository (content-addressable storage)
|
|
├── deploy/ # Active deployments
|
|
│ └── ubuntu-desktop/ # State root for Ubuntu Desktop
|
|
│ ├── var/ # Shared mutable data across deployments
|
|
│ └── <checksum>/ # Individual deployment directories
|
|
└── boot/ # Bootloader configuration
|
|
```
|
|
|
|
### Filesystem Assembly
|
|
|
|
apt-ostree assembles the live filesystem using:
|
|
- **Hardlinks**: Deployments use hardlinks to objects in `/ostree/repo`
|
|
- **Bind mounts**: Read-only `/usr` mounted from deployment
|
|
- **Symlinks**: User directories redirected to `/var`
|
|
- **3-way merge**: `/etc` merged from old deployment, new deployment, and local changes
|
|
|
|
## APT-OSTree Specific Extensions
|
|
|
|
### Package Layering
|
|
|
|
apt-ostree extends OSTree with APT/DEB package layering:
|
|
|
|
```rust
|
|
// Core layering implementation in src/ostree.rs
|
|
pub struct OstreeManager {
|
|
repo: OstreeRepo,
|
|
sysroot: OstreeSysroot,
|
|
}
|
|
|
|
impl OstreeManager {
|
|
// Create new deployment with layered packages
|
|
pub fn create_deployment_with_layers(
|
|
&self,
|
|
base_commit: &str,
|
|
new_commit: &str,
|
|
layered_packages: &[String],
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// 1. Extract base filesystem from OSTree commit
|
|
let base_tree = self.repo.read_commit(base_commit, None)?;
|
|
|
|
// 2. Apply DEB package layers
|
|
let layered_tree = self.apply_deb_layers(&base_tree, layered_packages)?;
|
|
|
|
// 3. Create new OSTree commit
|
|
let new_commit_checksum = self.repo.write_commit(
|
|
&layered_tree,
|
|
"Package layer update",
|
|
None,
|
|
None,
|
|
)?;
|
|
|
|
// 4. Update ref to point to new commit
|
|
self.repo.set_ref(None, "ubuntu/24.04/x86_64/desktop", &new_commit_checksum)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Apply DEB package layers to deployment
|
|
pub fn apply_deb_layers(
|
|
&self,
|
|
base_tree: &OstreeRepoFile,
|
|
packages: &[String],
|
|
) -> Result<OstreeRepoFile, Box<dyn std::error::Error>> {
|
|
// Extract DEB packages and apply to filesystem tree
|
|
for package in packages {
|
|
let extracted_package = self.extract_deb_package(package)?;
|
|
self.merge_package_into_tree(&base_tree, &extracted_package)?;
|
|
}
|
|
|
|
Ok(base_tree.clone())
|
|
}
|
|
}
|
|
```
|
|
|
|
### Transaction Management
|
|
|
|
apt-ostree implements atomic transactions for all OSTree operations:
|
|
|
|
```rust
|
|
// Transaction types for OSTree operations
|
|
#[derive(Debug, Clone)]
|
|
pub enum TransactionType {
|
|
Deploy,
|
|
Rollback,
|
|
PkgChange,
|
|
Rebase,
|
|
Upgrade,
|
|
}
|
|
|
|
// Transaction execution with OSTree integration
|
|
pub struct OstreeTransaction {
|
|
transaction_type: TransactionType,
|
|
sysroot: OstreeSysroot,
|
|
}
|
|
|
|
impl OstreeTransaction {
|
|
// Execute transaction with OSTree commit creation
|
|
pub fn execute_with_ostree_commit(
|
|
&self,
|
|
base_commit: &str,
|
|
new_commit: &str,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
match self.transaction_type {
|
|
TransactionType::Deploy => {
|
|
self.create_deployment(base_commit, new_commit)?;
|
|
}
|
|
TransactionType::Rollback => {
|
|
self.rollback_to_previous_deployment()?;
|
|
}
|
|
TransactionType::PkgChange => {
|
|
self.apply_package_changes(base_commit, new_commit)?;
|
|
}
|
|
_ => {
|
|
return Err("Unsupported transaction type".into());
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// Rollback to previous OSTree deployment
|
|
pub fn rollback_to_previous_deployment(&self) -> Result<(), Box<dyn std::error::Error>> {
|
|
let deployments = self.sysroot.get_deployments()?;
|
|
if deployments.len() < 2 {
|
|
return Err("No previous deployment available for rollback".into());
|
|
}
|
|
|
|
// Switch to previous deployment
|
|
let previous_deployment = &deployments[1];
|
|
self.sysroot.set_default_deployment(previous_deployment)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
```
|
|
|
|
### OSTree Commit Creation
|
|
|
|
apt-ostree creates OSTree commits for all system changes:
|
|
|
|
```rust
|
|
// Commit creation workflow in src/ostree.rs
|
|
impl OstreeManager {
|
|
pub fn create_commit(
|
|
&self,
|
|
base_commit: &str,
|
|
new_commit: &str,
|
|
subject: &str,
|
|
layered_packages: &[String],
|
|
) -> Result<String, Box<dyn std::error::Error>> {
|
|
// 1. Extract base filesystem from OSTree commit
|
|
let base_tree = self.repo.read_commit(base_commit, None)?;
|
|
|
|
// 2. Apply DEB package layers
|
|
let layered_tree = self.apply_deb_layers(&base_tree, layered_packages)?;
|
|
|
|
// 3. Create new OSTree commit
|
|
let new_commit_checksum = self.repo.write_commit(
|
|
&layered_tree,
|
|
subject,
|
|
None,
|
|
None,
|
|
)?;
|
|
|
|
// 4. Update ref to point to new commit
|
|
self.repo.set_ref(None, "ubuntu/24.04/x86_64/desktop", &new_commit_checksum)?;
|
|
|
|
Ok(new_commit_checksum)
|
|
}
|
|
}
|
|
```
|
|
|
|
## OSTree Environment Detection
|
|
|
|
apt-ostree detects OSTree environments using multiple methods:
|
|
|
|
```rust
|
|
// Environment detection in src/ostree_detection.rs
|
|
pub struct OstreeDetection;
|
|
|
|
impl OstreeDetection {
|
|
pub fn is_ostree_environment() -> bool {
|
|
// Method 1: Check for /ostree directory
|
|
if !std::path::Path::new("/ostree").is_dir() {
|
|
return false;
|
|
}
|
|
|
|
// Method 2: Check for /run/ostree-booted file
|
|
if !std::path::Path::new("/run/ostree-booted").exists() {
|
|
return false;
|
|
}
|
|
|
|
// Method 3: Check kernel command line for ostree parameter
|
|
if let Ok(cmdline) = std::fs::read_to_string("/proc/cmdline") {
|
|
if !cmdline.contains("ostree") {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Method 4: Try to load OSTree sysroot
|
|
if let Ok(sysroot) = OstreeSysroot::new_default() {
|
|
if sysroot.load().is_ok() {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
pub fn get_detection_methods() -> Vec<String> {
|
|
vec![
|
|
"Filesystem detection (/ostree directory)".to_string(),
|
|
"Boot detection (/run/ostree-booted file)".to_string(),
|
|
"Kernel parameter detection (ostree in /proc/cmdline)".to_string(),
|
|
"Library detection (OSTree sysroot loading)".to_string(),
|
|
"Service detection (daemon availability)".to_string(),
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
## OSTree Integration Points
|
|
|
|
### Daemon Integration
|
|
|
|
The apt-ostree daemon integrates with OSTree for privileged operations:
|
|
|
|
```rust
|
|
// Daemon OSTree operations in src/bin/apt-ostreed.rs
|
|
pub struct AptOstreedDaemon {
|
|
ostree_manager: OstreeManager,
|
|
}
|
|
|
|
impl AptOstreedDaemon {
|
|
// OSTree deployment management
|
|
pub fn deploy_ostree_commit(
|
|
&self,
|
|
commit_checksum: &str,
|
|
osname: &str,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
self.ostree_manager.create_deployment(commit_checksum, osname)
|
|
}
|
|
|
|
// OSTree rollback operations
|
|
pub fn rollback_ostree_deployment(
|
|
&self,
|
|
osname: &str,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
self.ostree_manager.rollback_deployment(osname)
|
|
}
|
|
|
|
// OSTree status reporting
|
|
pub fn get_ostree_status(&self) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
|
|
let deployments = self.ostree_manager.get_deployments()?;
|
|
let current_deployment = self.ostree_manager.get_current_deployment()?;
|
|
|
|
Ok(json!({
|
|
"deployments": deployments,
|
|
"current": current_deployment,
|
|
"booted": self.ostree_manager.is_booted_deployment(¤t_deployment)?,
|
|
}))
|
|
}
|
|
}
|
|
```
|
|
|
|
### CLI Integration
|
|
|
|
apt-ostree CLI commands integrate with OSTree operations:
|
|
|
|
```rust
|
|
// CLI command integration in src/main.rs
|
|
pub fn deploy_command(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
|
|
let commit = matches.get_one::<String>("COMMIT")
|
|
.ok_or("No commit specified")?;
|
|
|
|
// Create deployment via D-Bus daemon
|
|
let client = AptOstreeClient::new()?;
|
|
client.deploy(commit)?;
|
|
|
|
println!("Deployment created successfully");
|
|
Ok(())
|
|
}
|
|
|
|
pub fn rollback_command(_matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Rollback via D-Bus daemon
|
|
let client = AptOstreeClient::new()?;
|
|
client.rollback()?;
|
|
|
|
println!("Rollback completed successfully");
|
|
Ok(())
|
|
}
|
|
```
|
|
|
|
## OSTree Performance Optimizations
|
|
|
|
### Static Delta Support
|
|
|
|
apt-ostree leverages OSTree static deltas for efficient updates:
|
|
|
|
```rust
|
|
// Static delta usage in src/ostree.rs
|
|
impl OstreeManager {
|
|
pub fn pull_with_static_deltas(
|
|
&self,
|
|
remote_name: &str,
|
|
refspec: &str,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Configure static delta usage
|
|
self.repo.set_enable_static_deltas(true);
|
|
|
|
// Pull with static delta optimization
|
|
self.repo.pull(remote_name, refspec, None)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Content Deduplication
|
|
|
|
apt-ostree benefits from OSTree's content-addressable storage:
|
|
|
|
```rust
|
|
// Content deduplication example
|
|
impl OstreeManager {
|
|
pub fn commit_with_deduplication(
|
|
&self,
|
|
base_commit: &str,
|
|
new_commit: &str,
|
|
) -> Result<String, Box<dyn std::error::Error>> {
|
|
// OSTree automatically deduplicates identical files
|
|
// Only unique content is stored in the repository
|
|
let base_tree = self.repo.read_commit(base_commit, None)?;
|
|
|
|
// Create commit with automatic deduplication
|
|
self.repo.write_commit(&base_tree, "Update", None, None)
|
|
}
|
|
}
|
|
```
|
|
|
|
## OSTree Security Features
|
|
|
|
### GPG Signature Verification
|
|
|
|
apt-ostree verifies OSTree commits using GPG signatures:
|
|
|
|
```rust
|
|
// GPG verification in src/ostree.rs
|
|
impl OstreeManager {
|
|
pub fn verify_commit_signature(
|
|
&self,
|
|
commit_checksum: &str,
|
|
) -> Result<bool, Box<dyn std::error::Error>> {
|
|
// Verify commit signature
|
|
let sign = OstreeSign::new()?;
|
|
self.repo.verify_commit(commit_checksum, &sign)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Read-Only Filesystem Enforcement
|
|
|
|
apt-ostree enforces OSTree's read-only filesystem model:
|
|
|
|
```rust
|
|
// Read-only enforcement in src/system.rs
|
|
impl SystemManager {
|
|
pub fn enforce_readonly_filesystem(
|
|
&self,
|
|
deployment_path: &str,
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// Mount /usr as read-only
|
|
let mount_cmd = format!("mount --bind -o ro {} /usr", deployment_path);
|
|
self.run_command(&mount_cmd)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
```
|
|
|
|
## OSTree Integration Testing
|
|
|
|
### Deployment Testing
|
|
|
|
```bash
|
|
# Test OSTree deployment creation
|
|
apt-ostree deploy $(apt-ostree status --json | jq -r '.deployments[0].checksum')
|
|
|
|
# Test OSTree rollback
|
|
apt-ostree rollback
|
|
|
|
# Test OSTree status
|
|
apt-ostree status --json
|
|
```
|
|
|
|
### Performance Testing
|
|
|
|
```bash
|
|
# Test OSTree pull performance
|
|
time ostree pull ubuntu ubuntu/24.04/x86_64/desktop
|
|
|
|
# Test static delta usage
|
|
ostree pull --enable-static-deltas ubuntu ubuntu/24.04/x86_64/desktop
|
|
|
|
# Test commit creation performance
|
|
time apt-ostree install package-name
|
|
```
|
|
|
|
## OSTree Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
1. **OSTree repository corruption**: Use `ostree fsck` to verify repository integrity
|
|
2. **Deployment failures**: Check `/var/log/ostree.log` for detailed error messages
|
|
3. **Bootloader issues**: Verify GRUB configuration with `ostree admin boot`
|
|
4. **Space issues**: Use `ostree admin cleanup` to remove old deployments
|
|
|
|
### Debug Commands
|
|
|
|
```bash
|
|
# Check OSTree repository status
|
|
ostree fsck --repo=/ostree/repo
|
|
|
|
# List available deployments
|
|
ostree admin status
|
|
|
|
# Check bootloader configuration
|
|
ostree admin boot
|
|
|
|
# Verify commit signatures
|
|
ostree verify --repo=/ostree/repo ubuntu/24.04/x86_64/desktop
|
|
```
|
|
|
|
## OSTree Future Enhancements
|
|
|
|
### Planned Features
|
|
|
|
1. **Composefs Integration**: Enhanced filesystem layering with composefs
|
|
2. **OCI Container Support**: Direct OSTree to OCI container conversion
|
|
3. **Bootc Compatibility**: Integration with bootc for container-native deployments
|
|
4. **Enhanced Static Deltas**: Improved delta generation and application
|
|
|
|
### Integration Roadmap
|
|
|
|
- **Phase 1**: Core OSTree integration (✅ Complete)
|
|
- **Phase 2**: Performance optimizations (✅ Complete)
|
|
- **Phase 3**: Security enhancements (✅ Complete)
|
|
- **Phase 4**: OCI container support (🔄 In Progress)
|
|
- **Phase 5**: Bootc compatibility (📋 Planned)
|
|
|
|
## Ubuntu/Debian Specific Considerations
|
|
|
|
### Filesystem Layout
|
|
|
|
apt-ostree adapts OSTree for Ubuntu/Debian filesystem conventions:
|
|
|
|
```
|
|
/
|
|
├── ostree/ # OSTree repository and deployments
|
|
│ ├── repo/ # OSTree repository
|
|
│ ├── deploy/ # Deployed systems
|
|
│ └── boot/ # Boot configurations
|
|
├── var/ # Writable data (shared across deployments)
|
|
│ ├── home/ # User home directories
|
|
│ ├── opt/ # Optional application software
|
|
│ ├── usrlocal/ # Locally installed software
|
|
│ ├── etc/ # System configuration (merged on upgrade)
|
|
│ └── tmp/ # Temporary files
|
|
├── etc/ # System configuration (writable)
|
|
└── usr/ # Read-only system software
|
|
```
|
|
|
|
### Package Management Integration
|
|
|
|
apt-ostree integrates APT package management with OSTree:
|
|
|
|
```rust
|
|
// APT-OSTree integration in src/apt.rs
|
|
impl AptManager {
|
|
pub fn install_packages_with_ostree(
|
|
&self,
|
|
packages: &[String],
|
|
) -> Result<(), Box<dyn std::error::Error>> {
|
|
// 1. Download and extract DEB packages
|
|
let extracted_packages = self.download_and_extract_packages(packages)?;
|
|
|
|
// 2. Create OSTree commit with package layers
|
|
let ostree_manager = OstreeManager::new()?;
|
|
ostree_manager.create_commit_with_layers(
|
|
&self.get_current_commit()?,
|
|
"Package installation",
|
|
&extracted_packages,
|
|
)?;
|
|
|
|
// 3. Deploy new commit
|
|
ostree_manager.deploy_latest_commit()?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
```
|
|
|
|
### mmdebstrap Integration
|
|
|
|
apt-ostree uses mmdebstrap for efficient base system creation:
|
|
|
|
```bash
|
|
# Create base system with mmdebstrap
|
|
sudo mmdebstrap --arch=amd64 --variant=minbase \
|
|
--include=systemd,systemd-sysv,ostree \
|
|
noble /tmp/ubuntu-base
|
|
|
|
# Create package layer
|
|
sudo mmdebstrap --arch=amd64 \
|
|
--include=ubuntu-desktop-minimal,gnome-shell \
|
|
noble /tmp/ubuntu-desktop /tmp/ubuntu-base
|
|
|
|
# Create OSTree commit
|
|
sudo ostree commit --repo=/ostree/repo \
|
|
--branch=ubuntu/24.04/x86_64/desktop \
|
|
--parent=ubuntu/24.04/x86_64/base \
|
|
/tmp/ubuntu-desktop
|
|
``` |