Compare commits
3 Commits
cf05e0ca5b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 947d156921 | |||
| 721e26a855 | |||
| 334821dacf |
@@ -7,6 +7,7 @@ RUN apk add --no-cache \
|
||||
rustup \
|
||||
upx \
|
||||
git \
|
||||
openssh-client \
|
||||
wget \
|
||||
curl \
|
||||
tar \
|
||||
@@ -19,6 +20,7 @@ RUN apk add --no-cache \
|
||||
musl-utils \
|
||||
pkgconfig \
|
||||
openssl openssl-dev \
|
||||
libseccomp libseccomp-dev \
|
||||
perl \
|
||||
shadow \
|
||||
bash \
|
||||
@@ -54,4 +56,4 @@ RUN chown builder:builder /workspace
|
||||
# Set environment variables - rustup handles everything
|
||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
CMD ["/bin/bash"]
|
||||
|
||||
121
README.md
121
README.md
@@ -7,7 +7,7 @@ A comprehensive build system for creating custom Alpine Linux 3.22 x86_64 initra
|
||||
- **Alpine Linux 3.22** miniroot as base system
|
||||
- **zinit** process manager (complete OpenRC replacement)
|
||||
- **Rootless containers** (Docker/Podman compatible)
|
||||
- **Rust components** with musl targeting (zinit, rfs, mycelium)
|
||||
- **Rust components** with musl targeting (zinit, rfs, mycelium, zosstorage)
|
||||
- **Aggressive optimization** (strip + UPX compression)
|
||||
- **2-stage module loading** for hardware support
|
||||
- **GitHub Actions** compatible build pipeline
|
||||
@@ -103,8 +103,7 @@ zosbuilder/
|
||||
│ │ ├── alpine.sh # Alpine operations
|
||||
│ │ ├── components.sh # source building
|
||||
│ │ ├── initramfs.sh # assembly & optimization
|
||||
│ │ ├── kernel.sh # kernel building
|
||||
│ │ └── testing.sh # QEMU/cloud-hypervisor
|
||||
│ │ └── kernel.sh # kernel building
|
||||
│ ├── build.sh # main orchestrator
|
||||
│ └── clean.sh # cleanup script
|
||||
├── initramfs/ # build output (generated)
|
||||
@@ -222,6 +221,7 @@ Services are migrated from existing `configs/zinit/` directory with proper initi
|
||||
- **zinit**: Standard cargo build
|
||||
- **rfs**: Standard cargo build
|
||||
- **mycelium**: Build in `myceliumd/` subdirectory
|
||||
- **zosstorage**: Build from the storage orchestration component for Zero-OS
|
||||
4. Install binaries to initramfs
|
||||
|
||||
### Phase 4: System Configuration
|
||||
@@ -243,34 +243,40 @@ Services are migrated from existing `configs/zinit/` directory with proper initi
|
||||
### Phase 6: Packaging
|
||||
1. Create `initramfs.cpio.xz` with XZ compression
|
||||
2. Build kernel with embedded initramfs
|
||||
3. Generate `vmlinuz.efi`
|
||||
3. Generate `vmlinuz.efi` (default kernel)
|
||||
4. Generate versioned kernel: `vmlinuz-{VERSION}-{ZINIT_HASH}.efi`
|
||||
5. Optionally upload versioned kernel to S3 (set `UPLOAD_KERNEL=true`)
|
||||
|
||||
## Testing
|
||||
|
||||
### QEMU Testing
|
||||
```bash
|
||||
# Boot test with QEMU
|
||||
./scripts/test.sh --qemu
|
||||
# Boot test with QEMU (default)
|
||||
./runit.sh
|
||||
|
||||
# With serial console
|
||||
./scripts/test.sh --qemu --serial
|
||||
# With custom parameters
|
||||
./runit.sh --hypervisor qemu --memory 2048 --disks 3
|
||||
```
|
||||
|
||||
### cloud-hypervisor Testing
|
||||
```bash
|
||||
# Boot test with cloud-hypervisor
|
||||
./scripts/test.sh --cloud-hypervisor
|
||||
./runit.sh --hypervisor ch
|
||||
|
||||
# With disk reset
|
||||
./runit.sh --hypervisor ch --reset --disks 5
|
||||
```
|
||||
|
||||
### Custom Testing
|
||||
### Advanced Options
|
||||
```bash
|
||||
# Manual QEMU command
|
||||
qemu-system-x86_64 \
|
||||
-kernel dist/vmlinuz.efi \
|
||||
-m 512M \
|
||||
-nographic \
|
||||
-serial mon:stdio \
|
||||
-append "console=ttyS0,115200 console=tty1 loglevel=7"
|
||||
# See all options
|
||||
./runit.sh --help
|
||||
|
||||
# Custom disk size and bridge
|
||||
./runit.sh --disk-size 20G --bridge zosbr --disks 4
|
||||
|
||||
# Environment variables
|
||||
HYPERVISOR=ch NUM_DISKS=5 ./runit.sh
|
||||
```
|
||||
|
||||
## Size Optimization
|
||||
@@ -320,7 +326,7 @@ jobs:
|
||||
- name: Build
|
||||
run: ./scripts/build.sh
|
||||
- name: Test
|
||||
run: ./scripts/test.sh --qemu
|
||||
run: ./runit.sh --hypervisor qemu
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
@@ -353,6 +359,72 @@ function build_myapp() {
|
||||
}
|
||||
```
|
||||
|
||||
### S3 Uploads (Kernel & RFS Flists)
|
||||
|
||||
Automatically upload build artifacts to S3-compatible storage:
|
||||
|
||||
#### Configuration
|
||||
|
||||
Create `config/rfs.conf`:
|
||||
|
||||
```bash
|
||||
S3_ENDPOINT="https://s3.example.com:9000"
|
||||
S3_REGION="us-east-1"
|
||||
S3_BUCKET="zos"
|
||||
S3_PREFIX="flists/zosbuilder"
|
||||
S3_ACCESS_KEY="YOUR_ACCESS_KEY"
|
||||
S3_SECRET_KEY="YOUR_SECRET_KEY"
|
||||
```
|
||||
|
||||
#### Upload Kernel
|
||||
|
||||
```bash
|
||||
# Enable kernel upload
|
||||
UPLOAD_KERNEL=true ./scripts/build.sh
|
||||
|
||||
# Custom kernel subpath (default: kernel)
|
||||
KERNEL_SUBPATH=kernels UPLOAD_KERNEL=true ./scripts/build.sh
|
||||
```
|
||||
|
||||
**Uploaded files:**
|
||||
- `s3://{bucket}/{prefix}/kernel/vmlinuz-{VERSION}-{ZINIT_HASH}.efi` - Versioned kernel
|
||||
- `s3://{bucket}/{prefix}/kernel/kernels.txt` - Text index (one kernel per line)
|
||||
- `s3://{bucket}/{prefix}/kernel/kernels.json` - JSON index with metadata
|
||||
|
||||
**Index files:**
|
||||
The build automatically generates and uploads index files listing all available kernels in the S3 bucket. This enables:
|
||||
- Easy kernel selection in web UIs (dropdown menus)
|
||||
- Programmatic access without S3 API listing
|
||||
- Metadata like upload timestamp and kernel count (JSON format)
|
||||
|
||||
**JSON index format:**
|
||||
```json
|
||||
{
|
||||
"kernels": [
|
||||
"vmlinuz-6.12.44-Zero-OS-abc1234.efi",
|
||||
"vmlinuz-6.12.44-Zero-OS-def5678.efi"
|
||||
],
|
||||
"updated": "2025-01-04T12:00:00Z",
|
||||
"count": 2
|
||||
}
|
||||
```
|
||||
|
||||
#### Upload RFS Flists
|
||||
|
||||
```bash
|
||||
# Enable flist uploads
|
||||
UPLOAD_MANIFESTS=true ./scripts/build.sh
|
||||
```
|
||||
|
||||
Uploaded as:
|
||||
- `s3://{bucket}/{prefix}/manifests/modules-{VERSION}.fl`
|
||||
- `s3://{bucket}/{prefix}/manifests/firmware-{TAG}.fl`
|
||||
|
||||
#### Requirements
|
||||
|
||||
- MinIO Client (`mcli` or `mc`) must be installed
|
||||
- Valid S3 credentials in `config/rfs.conf`
|
||||
|
||||
### Container Builds
|
||||
|
||||
Build in isolated container:
|
||||
@@ -431,13 +503,16 @@ export DEBUG=1
|
||||
|
||||
```bash
|
||||
# Setup development environment
|
||||
./scripts/setup-dev.sh
|
||||
./scripts/dev-container.sh start
|
||||
|
||||
# Run tests
|
||||
./scripts/test.sh --all
|
||||
# Run incremental build
|
||||
./scripts/build.sh
|
||||
|
||||
# Check size impact
|
||||
./scripts/analyze-size.sh --compare
|
||||
# Test with QEMU
|
||||
./runit.sh --hypervisor qemu
|
||||
|
||||
# Test with cloud-hypervisor
|
||||
./runit.sh --hypervisor ch
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
523
claude.md
Normal file
523
claude.md
Normal file
@@ -0,0 +1,523 @@
|
||||
# Claude Code Reference for Zero-OS Builder
|
||||
|
||||
This document provides essential context for Claude Code (or any AI assistant) working with this Zero-OS Alpine Initramfs Builder repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
**What is this?**
|
||||
A sophisticated build system for creating custom Alpine Linux 3.22 x86_64 initramfs images with zinit process management, designed for Zero-OS deployment on ThreeFold Grid.
|
||||
|
||||
**Key Features:**
|
||||
- Container-based reproducible builds (rootless podman/docker)
|
||||
- Incremental staged build pipeline with completion markers
|
||||
- zinit process manager (complete OpenRC replacement)
|
||||
- RFS (Remote File System) for lazy-loading modules/firmware from S3
|
||||
- Rust components built with musl static linking
|
||||
- Aggressive size optimization (strip + UPX)
|
||||
- Embedded initramfs in kernel (single vmlinuz.efi output)
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
zosbuilder/
|
||||
├── config/ # All configuration files
|
||||
│ ├── build.conf # Build settings (versions, paths, flags)
|
||||
│ ├── packages.list # Alpine packages to install
|
||||
│ ├── sources.conf # ThreeFold components to build
|
||||
│ ├── modules.conf # 2-stage kernel module loading
|
||||
│ ├── firmware.conf # Firmware to include in initramfs
|
||||
│ ├── kernel.config # Linux kernel configuration
|
||||
│ ├── init # /init script for initramfs
|
||||
│ └── zinit/ # zinit service definitions (YAML)
|
||||
│
|
||||
├── scripts/
|
||||
│ ├── build.sh # Main orchestrator (DO NOT EDIT LIGHTLY)
|
||||
│ ├── clean.sh # Clean all artifacts
|
||||
│ ├── dev-container.sh # Persistent dev container manager
|
||||
│ ├── rebuild-after-zinit.sh # Quick rebuild helper
|
||||
│ ├── lib/ # Modular build libraries
|
||||
│ │ ├── common.sh # Logging, path normalization, utilities
|
||||
│ │ ├── stages.sh # Incremental stage tracking
|
||||
│ │ ├── docker.sh # Container lifecycle
|
||||
│ │ ├── alpine.sh # Alpine extraction, packages, cleanup
|
||||
│ │ ├── components.sh # Build Rust components from sources.conf
|
||||
│ │ ├── initramfs.sh # Assembly, optimization, CPIO creation
|
||||
│ │ └── kernel.sh # Kernel download, config, build, embed
|
||||
│ └── rfs/ # RFS flist generation scripts
|
||||
│ ├── common.sh # S3 config, version computation
|
||||
│ ├── pack-modules.sh # Create modules flist
|
||||
│ ├── pack-firmware.sh # Create firmware flist
|
||||
│ └── verify-flist.sh # Inspect/test flists
|
||||
│
|
||||
├── docs/ # Detailed documentation
|
||||
│ ├── NOTES.md # Operational knowledge & troubleshooting
|
||||
│ ├── PROMPT.md # Agent guidance (strict debugger mode)
|
||||
│ ├── TODO.md # Persistent checklist with code refs
|
||||
│ ├── AGENTS.md # Quick reference for agents
|
||||
│ ├── rfs-flists.md # RFS design and runtime flow
|
||||
│ ├── review-rfs-integration.md # Integration points
|
||||
│ └── depmod-behavior.md # Module dependency details
|
||||
│
|
||||
├── runit.sh # Test runner (QEMU/cloud-hypervisor)
|
||||
├── initramfs/ # Generated initramfs tree
|
||||
├── components/ # Generated component sources
|
||||
├── kernel/ # Generated kernel source
|
||||
├── dist/ # Final outputs
|
||||
│ ├── vmlinuz.efi # Kernel with embedded initramfs
|
||||
│ └── initramfs.cpio.xz # Standalone initramfs archive
|
||||
└── .build-stages/ # Incremental build markers (*.done files)
|
||||
```
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### 1. Incremental Staged Builds
|
||||
|
||||
**How it works:**
|
||||
- Each stage creates a `.build-stages/<stage_name>.done` marker on success
|
||||
- Subsequent builds skip completed stages unless forced
|
||||
- Use `./scripts/build.sh --show-stages` to see status
|
||||
- Use `./scripts/build.sh --rebuild-from=<stage>` to restart from a specific stage
|
||||
- Manually remove `.done` files to re-run specific stages
|
||||
|
||||
**Build stages (in order):**
|
||||
```
|
||||
alpine_extract → alpine_configure → alpine_packages → alpine_firmware
|
||||
→ components_build → components_verify → kernel_modules
|
||||
→ init_script → components_copy → zinit_setup
|
||||
→ modules_setup → modules_copy → cleanup → rfs_flists
|
||||
→ validation → initramfs_create → initramfs_test → kernel_build
|
||||
```
|
||||
|
||||
**Key insight:** The build ALWAYS runs inside a container. Host invocations auto-spawn containers.
|
||||
|
||||
### 2. Container-First Architecture
|
||||
|
||||
**Why containers?**
|
||||
- Reproducible toolchain (Alpine 3.22 base with exact dependencies)
|
||||
- Rootless execution (no privileged access needed)
|
||||
- Isolation from host environment
|
||||
- GitHub Actions compatible
|
||||
|
||||
**Container modes:**
|
||||
- **Transient:** `./scripts/build.sh` spawns, builds, exits
|
||||
- **Persistent:** `./scripts/dev-container.sh start/shell/build`
|
||||
|
||||
**Important:** Directory paths are normalized to absolute PROJECT_ROOT to avoid CWD issues when stages change directories (especially kernel builds).
|
||||
|
||||
### 3. Component Build System
|
||||
|
||||
**sources.conf format:**
|
||||
```
|
||||
TYPE:NAME:URL:VERSION:BUILD_FUNCTION[:EXTRA]
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
git:zinit:https://github.com/threefoldtech/zinit:master:build_zinit
|
||||
git:rfs:https://github.com/threefoldtech/rfs:development:build_rfs
|
||||
git:mycelium:https://github.com/threefoldtech/mycelium:0.6.1:build_mycelium
|
||||
release:corex:https://github.com/threefoldtech/corex/releases/download/2.1.4/corex-2.1.4-amd64-linux-static:2.1.4:install_corex:rename=corex
|
||||
```
|
||||
|
||||
**Build functions** are defined in `scripts/lib/components.sh` and handle:
|
||||
- Rust builds with `x86_64-unknown-linux-musl` target
|
||||
- Static linking via `RUSTFLAGS="-C target-feature=+crt-static"`
|
||||
- Special cases (e.g., mycelium builds in `myceliumd/` subdirectory)
|
||||
|
||||
### 4. RFS Flists (Remote File System)
|
||||
|
||||
**Purpose:** Lazy-load kernel modules and firmware from S3 at runtime
|
||||
|
||||
**Flow:**
|
||||
1. Build stage creates flists: `modules-<KERNEL_VERSION>.fl` and `firmware-<TAG>.fl`
|
||||
2. Flists are SQLite databases containing:
|
||||
- Content-addressed blob references
|
||||
- S3 store URIs (patched for read-only access)
|
||||
- Directory tree metadata
|
||||
3. Flists embedded in initramfs at `/etc/rfs/`
|
||||
4. Runtime: zinit units mount flists over `/lib/modules/` and `/lib/firmware/`
|
||||
5. Dual udev coldplug: early (before RFS) for networking, post-RFS for new hardware
|
||||
|
||||
**Key files:**
|
||||
- `scripts/rfs/pack-modules.sh` - Creates modules flist from container `/lib/modules/`
|
||||
- `scripts/rfs/pack-firmware.sh` - Creates firmware flist from Alpine packages
|
||||
- `config/zinit/init/modules.sh` - Runtime mount script
|
||||
- `config/zinit/init/firmware.sh` - Runtime mount script
|
||||
|
||||
### 5. zinit Service Management
|
||||
|
||||
**No OpenRC:** This system uses zinit exclusively for process management.
|
||||
|
||||
**Service graph:**
|
||||
```
|
||||
/init → zinit → [stage1-modules, udevd, depmod]
|
||||
→ udev-trigger (early coldplug)
|
||||
→ network
|
||||
→ rfs-modules + rfs-firmware (mount flists)
|
||||
→ udev-rfs (post-RFS coldplug)
|
||||
→ services
|
||||
```
|
||||
|
||||
**Service definitions:** YAML files in `config/zinit/` with `after:`, `needs:`, `wants:` dependencies
|
||||
|
||||
### 6. Kernel Versioning and S3 Upload
|
||||
|
||||
**Versioned Kernel Output:**
|
||||
- Standard kernel: `dist/vmlinuz.efi` (for compatibility)
|
||||
- Versioned kernel: `dist/vmlinuz-{VERSION}-{ZINIT_HASH}.efi`
|
||||
- Example: `vmlinuz-6.12.44-Zero-OS-a1b2c3d.efi`
|
||||
|
||||
**Version components:**
|
||||
- `{VERSION}`: Full kernel version from `KERNEL_VERSION` + `CONFIG_LOCALVERSION`
|
||||
- `{ZINIT_HASH}`: Short git commit hash from `components/zinit/.git`
|
||||
|
||||
**S3 Upload (optional):**
|
||||
- Controlled by `UPLOAD_KERNEL=true` environment variable
|
||||
- Uses MinIO client (`mcli` or `mc`) to upload to S3-compatible storage
|
||||
- Uploads versioned kernel to: `s3://{bucket}/{prefix}/kernel/{versioned_filename}`
|
||||
|
||||
**Kernel Index Generation:**
|
||||
After uploading, automatically generates and uploads index files:
|
||||
- `kernels.txt` - Plain text, one kernel per line, sorted reverse chronologically
|
||||
- `kernels.json` - JSON format with metadata (timestamp, count)
|
||||
|
||||
**Why index files?**
|
||||
- S3 web interfaces often don't support directory listings
|
||||
- Enables dropdown menus in web UIs without S3 API access
|
||||
- Provides kernel discovery for deployment tools
|
||||
|
||||
**JSON index structure:**
|
||||
```json
|
||||
{
|
||||
"kernels": ["vmlinuz-6.12.44-Zero-OS-abc1234.efi", ...],
|
||||
"updated": "2025-01-04T12:00:00Z",
|
||||
"count": 2
|
||||
}
|
||||
```
|
||||
|
||||
**Key functions:**
|
||||
- `get_git_commit_hash()` in `scripts/lib/common.sh` - Extracts git hash
|
||||
- `kernel_build_with_initramfs()` in `scripts/lib/kernel.sh` - Creates versioned kernel
|
||||
- `kernel_upload_to_s3()` in `scripts/lib/kernel.sh` - Uploads to S3
|
||||
- `kernel_generate_index()` in `scripts/lib/kernel.sh` - Generates and uploads index
|
||||
|
||||
## Critical Conventions
|
||||
|
||||
### Path Normalization
|
||||
**Problem:** Stages can change CWD (kernel build uses `/workspace/kernel/current`)
|
||||
**Solution:** All paths normalized to absolute at startup in `scripts/lib/common.sh:244`
|
||||
|
||||
**Variables affected:**
|
||||
- `INSTALL_DIR` (initramfs/)
|
||||
- `COMPONENTS_DIR` (components/)
|
||||
- `KERNEL_DIR` (kernel/)
|
||||
- `DIST_DIR` (dist/)
|
||||
|
||||
**Never use relative paths** when calling functions that might be in different CWDs.
|
||||
|
||||
### Branding and Security
|
||||
**Passwordless root enforcement:**
|
||||
- Applied in `scripts/lib/initramfs.sh:575` via `passwd -d -R "${initramfs_dir}" root`
|
||||
- Creates `root::` in `/etc/shadow` (empty password field)
|
||||
- Controlled by `ZEROOS_BRANDING` and `ZEROOS_PASSWORDLESS_ROOT` flags
|
||||
|
||||
**Never edit /etc/shadow manually** - always use `passwd` or `chpasswd` with chroot.
|
||||
|
||||
### Module Loading Strategy
|
||||
**2-stage approach:**
|
||||
- **Stage 1:** Critical boot modules (virtio, e1000, scsi) - loaded by zinit early
|
||||
- **Stage 2:** Extended hardware (igb, ixgbe, i40e) - loaded after network
|
||||
|
||||
**Config:** `config/modules.conf` with `stage1:` and `stage2:` prefixes
|
||||
|
||||
**Dependency resolution:**
|
||||
- Uses `modinfo` to build dependency tree
|
||||
- Resolves from container `/lib/modules/<FULL_VERSION>/`
|
||||
- Must run after `kernel_modules` stage
|
||||
|
||||
### Firmware Policy
|
||||
**For initramfs:** `config/firmware.conf` is the SINGLE source of truth
|
||||
- Any firmware hints in `modules.conf` are IGNORED
|
||||
- Prevents duplication/version mismatches
|
||||
|
||||
**For RFS:** Full Alpine `linux-firmware*` packages installed in container
|
||||
- Packed from container `/lib/firmware/`
|
||||
- Overmounts at runtime for extended hardware
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Full Build from Scratch
|
||||
```bash
|
||||
# Clean everything and rebuild
|
||||
./scripts/build.sh --clean
|
||||
|
||||
# Or just rebuild all stages
|
||||
./scripts/build.sh --force-rebuild
|
||||
```
|
||||
|
||||
### Quick Iteration After Config Changes
|
||||
```bash
|
||||
# After editing zinit configs, init script, or modules.conf
|
||||
./scripts/rebuild-after-zinit.sh
|
||||
|
||||
# With kernel rebuild
|
||||
./scripts/rebuild-after-zinit.sh --with-kernel
|
||||
|
||||
# Dry-run to see what changed
|
||||
./scripts/rebuild-after-zinit.sh --verify-only
|
||||
```
|
||||
|
||||
### Minimal Manual Rebuild
|
||||
```bash
|
||||
# Remove specific stages
|
||||
rm -f .build-stages/initramfs_create.done
|
||||
rm -f .build-stages/validation.done
|
||||
|
||||
# Rebuild only those stages
|
||||
DEBUG=1 ./scripts/build.sh
|
||||
```
|
||||
|
||||
### Testing the Built Kernel
|
||||
```bash
|
||||
# QEMU (default)
|
||||
./runit.sh
|
||||
|
||||
# cloud-hypervisor with 5 disks
|
||||
./runit.sh --hypervisor ch --disks 5 --reset
|
||||
|
||||
# Custom memory and bridge
|
||||
./runit.sh --memory 4096 --bridge zosbr
|
||||
```
|
||||
|
||||
### Persistent Dev Container
|
||||
```bash
|
||||
# Start persistent container
|
||||
./scripts/dev-container.sh start
|
||||
|
||||
# Enter shell
|
||||
./scripts/dev-container.sh shell
|
||||
|
||||
# Run build inside
|
||||
./scripts/dev-container.sh build
|
||||
|
||||
# Stop container
|
||||
./scripts/dev-container.sh stop
|
||||
```
|
||||
|
||||
## Debugging Guidelines
|
||||
|
||||
### Diagnostics-First Approach
|
||||
**ALWAYS add diagnostics before fixes:**
|
||||
1. Enable `DEBUG=1` for verbose safe_execute logs
|
||||
2. Add strategic `log_debug` statements
|
||||
3. Confirm hypothesis in logs
|
||||
4. Then apply minimal fix
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
# Bad: Guess and fix
|
||||
Edit file to fix suspected issue
|
||||
|
||||
# Good: Diagnose first
|
||||
1. Add log_debug "Variable X=${X}, resolved=${resolved_path}"
|
||||
2. DEBUG=1 ./scripts/build.sh
|
||||
3. Confirm in output
|
||||
4. Apply fix with evidence
|
||||
```
|
||||
|
||||
### Key Diagnostic Functions
|
||||
- `scripts/lib/common.sh`: `log_info`, `log_warn`, `log_error`, `log_debug`
|
||||
- `scripts/lib/initramfs.sh:820`: Validation debug prints (input, PWD, PROJECT_ROOT, resolved paths)
|
||||
- `scripts/lib/initramfs.sh:691`: Pre-CPIO sanity checks with file listings
|
||||
|
||||
### Common Issues and Solutions
|
||||
|
||||
**"Initramfs directory not found"**
|
||||
- **Cause:** INSTALL_DIR interpreted as relative in different CWD
|
||||
- **Fix:** Already patched - paths normalized at startup
|
||||
- **Check:** Look for "Validation debug:" logs showing resolved paths
|
||||
|
||||
**"INITRAMFS_ARCHIVE unbound"**
|
||||
- **Cause:** Incremental build skipped initramfs_create stage
|
||||
- **Fix:** Already patched - stages default INITRAMFS_ARCHIVE if unset
|
||||
- **Check:** `scripts/build.sh:401` logs "defaulting INITRAMFS_ARCHIVE"
|
||||
|
||||
**"Module dependency resolution fails"**
|
||||
- **Cause:** Container `/lib/modules/<FULL_VERSION>` missing or stale
|
||||
- **Fix:** `./scripts/rebuild-after-zinit.sh --refresh-container-mods`
|
||||
- **Check:** Ensure `kernel_modules` stage completed successfully
|
||||
|
||||
**"Passwordless root not working"**
|
||||
- **Cause:** Branding disabled or shadow file not updated
|
||||
- **Fix:** Check ZEROOS_BRANDING=true in logs, verify /etc/shadow has `root::`
|
||||
- **Verify:** Extract initramfs and `grep '^root:' etc/shadow`
|
||||
|
||||
## Important Files Quick Reference
|
||||
|
||||
### Must-Read Before Editing
|
||||
- `scripts/build.sh` - Orchestrator with precise stage order
|
||||
- `scripts/lib/common.sh` - Path normalization, logging, utilities
|
||||
- `scripts/lib/stages.sh` - Stage tracking logic
|
||||
- `config/build.conf` - Version pins, directory settings, flags
|
||||
|
||||
### Safe to Edit
|
||||
- `config/zinit/*.yaml` - Service definitions
|
||||
- `config/zinit/init/*.sh` - Runtime initialization scripts
|
||||
- `config/modules.conf` - Module lists (stage1/stage2)
|
||||
- `config/firmware.conf` - Initramfs firmware selection
|
||||
- `config/packages.list` - Alpine packages
|
||||
|
||||
### Generated (Never Edit)
|
||||
- `initramfs/` - Assembled initramfs tree
|
||||
- `components/` - Downloaded component sources
|
||||
- `kernel/` - Kernel source tree
|
||||
- `dist/` - Build outputs
|
||||
- `.build-stages/` - Completion markers
|
||||
|
||||
## Testing Architecture
|
||||
|
||||
**No built-in tests during build** - Tests run separately via `runit.sh`
|
||||
|
||||
**Why?**
|
||||
- Build is for assembly, not validation
|
||||
- Tests require hypervisor (QEMU/cloud-hypervisor)
|
||||
- Separation allows faster iteration
|
||||
|
||||
**runit.sh features:**
|
||||
- Multi-disk support (qcow2 for QEMU, raw for cloud-hypervisor)
|
||||
- Network bridge/TAP configuration
|
||||
- Persistent volumes (reset with `--reset`)
|
||||
- Serial console logging
|
||||
|
||||
## Quick Command Reference
|
||||
|
||||
```bash
|
||||
# Build
|
||||
./scripts/build.sh # Incremental build
|
||||
./scripts/build.sh --clean # Clean build
|
||||
./scripts/build.sh --show-stages # Show completion status
|
||||
./scripts/build.sh --rebuild-from=zinit_setup # Rebuild from stage
|
||||
DEBUG=1 ./scripts/build.sh # Verbose output
|
||||
|
||||
# Rebuild helpers
|
||||
./scripts/rebuild-after-zinit.sh # After zinit/init/modules changes
|
||||
./scripts/rebuild-after-zinit.sh --with-kernel # Also rebuild kernel
|
||||
./scripts/rebuild-after-zinit.sh --verify-only # Dry-run
|
||||
|
||||
# Testing
|
||||
./runit.sh # QEMU test
|
||||
./runit.sh --hypervisor ch # cloud-hypervisor test
|
||||
./runit.sh --help # All options
|
||||
|
||||
# Dev container
|
||||
./scripts/dev-container.sh start # Start persistent container
|
||||
./scripts/dev-container.sh shell # Enter shell
|
||||
./scripts/dev-container.sh build # Build inside container
|
||||
./scripts/dev-container.sh stop # Stop container
|
||||
|
||||
# Cleanup
|
||||
./scripts/clean.sh # Remove all generated files
|
||||
rm -rf .build-stages/ # Reset stage markers
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
**Build control:**
|
||||
- `DEBUG=1` - Enable verbose logging
|
||||
- `FORCE_REBUILD=true` - Force rebuild all stages
|
||||
- `REBUILD_FROM_STAGE=<name>` - Rebuild from specific stage
|
||||
|
||||
**Version overrides:**
|
||||
- `ALPINE_VERSION=3.22` - Alpine Linux version
|
||||
- `KERNEL_VERSION=6.12.44` - Linux kernel version
|
||||
- `RUST_TARGET=x86_64-unknown-linux-musl` - Rust compilation target
|
||||
|
||||
**Firmware tagging:**
|
||||
- `FIRMWARE_TAG=20250908` - Firmware flist version tag
|
||||
|
||||
**S3 upload control:**
|
||||
- `UPLOAD_KERNEL=true` - Upload versioned kernel to S3 (default: false)
|
||||
- `UPLOAD_MANIFESTS=true` - Upload RFS flists to S3 (default: false)
|
||||
- `KERNEL_SUBPATH=kernel` - S3 subpath for kernel uploads (default: kernel)
|
||||
|
||||
**S3 configuration:**
|
||||
- See `config/rfs.conf` for S3 endpoint, credentials, paths
|
||||
- Used by both RFS flist uploads and kernel uploads
|
||||
|
||||
## Documentation Hierarchy
|
||||
|
||||
**Start here:**
|
||||
1. `README.md` - User-facing guide with features and setup
|
||||
2. This file (`claude.md`) - AI assistant context
|
||||
|
||||
**For development:**
|
||||
3. `docs/NOTES.md` - Operational knowledge, troubleshooting
|
||||
4. `docs/AGENTS.md` - Quick agent reference
|
||||
5. `docs/TODO.md` - Current work checklist with code links
|
||||
|
||||
**For deep dives:**
|
||||
6. `docs/PROMPT.md` - Strict debugger agent mode (diagnostics-first)
|
||||
7. `docs/rfs-flists.md` - RFS design and implementation
|
||||
8. `docs/review-rfs-integration.md` - Integration points analysis
|
||||
9. `docs/depmod-behavior.md` - Module dependency deep dive
|
||||
|
||||
**Historical:**
|
||||
10. `IMPLEMENTATION_PLAN.md` - Original design document
|
||||
11. `GITHUB_ACTIONS.md` - CI/CD setup guide
|
||||
|
||||
## Project Philosophy
|
||||
|
||||
1. **Reproducibility:** Container-based builds ensure identical results
|
||||
2. **Incrementality:** Stage markers minimize rebuild time
|
||||
3. **Diagnostics-first:** Log before fixing, validate assumptions
|
||||
4. **Minimal intervention:** Alpine + zinit only, no systemd/OpenRC
|
||||
5. **Size-optimized:** Aggressive cleanup, strip, UPX compression
|
||||
6. **Remote-ready:** RFS enables lazy-loading for extended hardware support
|
||||
|
||||
## Commit Message Guidelines
|
||||
|
||||
**DO NOT add Claude Code or AI assistant references to commit messages.**
|
||||
|
||||
Keep commits clean and professional:
|
||||
- Focus on what changed and why
|
||||
- Use conventional commit prefixes: `build:`, `docs:`, `fix:`, `feat:`, `refactor:`
|
||||
- Be concise but descriptive
|
||||
- No emoji unless project convention
|
||||
- No "Generated with Claude Code" or "Co-Authored-By: Claude" footers
|
||||
|
||||
**Good example:**
|
||||
```
|
||||
build: remove testing.sh in favor of runit.sh
|
||||
|
||||
Replace inline boot testing with standalone runit.sh runner.
|
||||
Tests now run separately from build pipeline for faster iteration.
|
||||
```
|
||||
|
||||
**Bad example:**
|
||||
```
|
||||
build: remove testing.sh 🤖
|
||||
|
||||
Made some changes to testing.
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
## Keywords for Quick Search
|
||||
|
||||
- **Build fails:** Check `DEBUG=1` logs, stage completion markers, container state
|
||||
- **Module issues:** `kernel_modules` stage, `CONTAINER_MODULES_PATH`, depmod logs
|
||||
- **Firmware missing:** `config/firmware.conf` for initramfs, RFS flist for runtime
|
||||
- **zinit problems:** Service YAML syntax, dependency order, init script errors
|
||||
- **Path errors:** Absolute path normalization in `common.sh:244`
|
||||
- **Size too large:** Check cleanup stage, strip/UPX execution, package list
|
||||
- **Container issues:** Rootless setup, subuid/subgid, podman vs docker
|
||||
- **RFS mount fails:** S3 credentials, network readiness, flist manifest paths
|
||||
- **Kernel upload:** `UPLOAD_KERNEL=true`, requires `config/rfs.conf`, MinIO client (`mcli`/`mc`)
|
||||
- **Kernel index:** Auto-generated `kernels.txt`/`kernels.json` for dropdown UIs, updated on upload
|
||||
|
||||
---
|
||||
|
||||
**Last updated:** 2025-01-04
|
||||
|
||||
**Maintainer notes:** This file is the entry point for AI assistants. Keep it updated when architecture changes. Cross-reference with `docs/NOTES.md` for operational details.
|
||||
@@ -61,6 +61,7 @@ ENABLE_STRIP="true"
|
||||
ENABLE_UPX="true"
|
||||
ENABLE_AGGRESSIVE_CLEANUP="true"
|
||||
ENABLE_2STAGE_MODULES="true"
|
||||
UPLOAD_KERNEL=true
|
||||
|
||||
# Debug and development
|
||||
DEBUG_DEFAULT="0"
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/x86 6.12.44 Kernel Configuration
|
||||
# Linux/x86 6.12.49 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Alpine 14.2.0) 14.2.0"
|
||||
CONFIG_CC_VERSION_TEXT="gcc (GCC) 15.2.1 20250813"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=140200
|
||||
CONFIG_GCC_VERSION=150201
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_AS_IS_GNU=y
|
||||
CONFIG_AS_VERSION=24400
|
||||
CONFIG_AS_VERSION=24500
|
||||
CONFIG_LD_IS_BFD=y
|
||||
CONFIG_LD_VERSION=24400
|
||||
CONFIG_LD_VERSION=24500
|
||||
CONFIG_LLD_VERSION=0
|
||||
CONFIG_RUSTC_VERSION=109000
|
||||
CONFIG_RUSTC_LLVM_VERSION=200108
|
||||
CONFIG_RUSTC_VERSION=108900
|
||||
CONFIG_RUSTC_LLVM_VERSION=200107
|
||||
CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||
@@ -20,6 +20,7 @@ CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
|
||||
CONFIG_TOOLS_SUPPORT_RELR=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||
CONFIG_CC_HAS_COUNTED_BY=y
|
||||
CONFIG_LD_CAN_USE_KEEP_IN_OVERLAY=y
|
||||
CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES=y
|
||||
CONFIG_PAHOLE_VERSION=130
|
||||
@@ -368,23 +369,10 @@ CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
|
||||
CONFIG_SCHED_OMIT_FRAME_POINTER=y
|
||||
CONFIG_HYPERVISOR_GUEST=y
|
||||
CONFIG_PARAVIRT=y
|
||||
CONFIG_PARAVIRT_XXL=y
|
||||
# CONFIG_PARAVIRT_DEBUG is not set
|
||||
CONFIG_PARAVIRT_SPINLOCKS=y
|
||||
CONFIG_X86_HV_CALLBACK_VECTOR=y
|
||||
CONFIG_XEN=y
|
||||
CONFIG_XEN_PV=y
|
||||
CONFIG_XEN_512GB=y
|
||||
CONFIG_XEN_PV_SMP=y
|
||||
CONFIG_XEN_PV_DOM0=y
|
||||
CONFIG_XEN_PVHVM=y
|
||||
CONFIG_XEN_PVHVM_SMP=y
|
||||
CONFIG_XEN_PVHVM_GUEST=y
|
||||
CONFIG_XEN_SAVE_RESTORE=y
|
||||
# CONFIG_XEN_DEBUG_FS is not set
|
||||
CONFIG_XEN_PVH=y
|
||||
CONFIG_XEN_DOM0=y
|
||||
CONFIG_XEN_PV_MSR_SAFE=y
|
||||
# CONFIG_XEN is not set
|
||||
CONFIG_KVM_GUEST=y
|
||||
CONFIG_ARCH_CPUIDLE_HALTPOLL=y
|
||||
CONFIG_PVH=y
|
||||
@@ -528,7 +516,7 @@ CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_LEGACY_VSYSCALL_XONLY=y
|
||||
# CONFIG_LEGACY_VSYSCALL_NONE is not set
|
||||
CONFIG_CMDLINE_BOOL=y
|
||||
CONFIG_CMDLINE="intel_iommu=on kvm-intel.nested=1 console=ttyS1,115200n8 console=tty1 consoleblank=0 earlyprintk=serial,ttyS1,115200n8 loglevel=7"
|
||||
CONFIG_CMDLINE="consoleblank=0 earlyprintk=serial loglevel=7"
|
||||
# CONFIG_CMDLINE_OVERRIDE is not set
|
||||
CONFIG_MODIFY_LDT_SYSCALL=y
|
||||
# CONFIG_STRICT_SIGALTSTACK_SIZE is not set
|
||||
@@ -573,6 +561,7 @@ CONFIG_MITIGATION_SRBDS=y
|
||||
CONFIG_MITIGATION_SSB=y
|
||||
CONFIG_MITIGATION_ITS=y
|
||||
CONFIG_MITIGATION_TSA=y
|
||||
CONFIG_MITIGATION_VMSCAPE=y
|
||||
CONFIG_ARCH_HAS_ADD_PAGES=y
|
||||
|
||||
#
|
||||
@@ -737,7 +726,6 @@ CONFIG_INTEL_IDLE=y
|
||||
#
|
||||
CONFIG_PCI_DIRECT=y
|
||||
CONFIG_PCI_MMCONFIG=y
|
||||
CONFIG_PCI_XEN=y
|
||||
CONFIG_MMCONF_FAM10H=y
|
||||
# CONFIG_PCI_CNB20LE_QUIRK is not set
|
||||
# CONFIG_ISA_BUS is not set
|
||||
@@ -1959,7 +1947,6 @@ CONFIG_FIB_RULES=y
|
||||
CONFIG_NET_9P=m
|
||||
CONFIG_NET_9P_FD=m
|
||||
CONFIG_NET_9P_VIRTIO=m
|
||||
CONFIG_NET_9P_XEN=m
|
||||
# CONFIG_NET_9P_RDMA is not set
|
||||
# CONFIG_NET_9P_DEBUG is not set
|
||||
# CONFIG_CAIF is not set
|
||||
@@ -2009,7 +1996,6 @@ CONFIG_PCI_QUIRKS=y
|
||||
CONFIG_PCI_REALLOC_ENABLE_AUTO=y
|
||||
CONFIG_PCI_STUB=m
|
||||
# CONFIG_PCI_PF_STUB is not set
|
||||
CONFIG_XEN_PCIDEV_FRONTEND=m
|
||||
CONFIG_PCI_ATS=y
|
||||
CONFIG_PCI_LOCKLESS_CONFIG=y
|
||||
CONFIG_PCI_IOV=y
|
||||
@@ -2127,7 +2113,6 @@ CONFIG_ALLOW_DEV_COREDUMP=y
|
||||
# CONFIG_DEBUG_DEVRES is not set
|
||||
# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
|
||||
# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
|
||||
CONFIG_SYS_HYPERVISOR=y
|
||||
CONFIG_GENERIC_CPU_DEVICES=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_CPU_VULNERABILITIES=y
|
||||
@@ -2397,8 +2382,6 @@ CONFIG_CDROM_PKTCDVD=m
|
||||
CONFIG_CDROM_PKTCDVD_BUFFERS=8
|
||||
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
|
||||
CONFIG_ATA_OVER_ETH=m
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=m
|
||||
CONFIG_XEN_BLKDEV_BACKEND=m
|
||||
CONFIG_VIRTIO_BLK=m
|
||||
CONFIG_BLK_DEV_RBD=m
|
||||
# CONFIG_BLK_DEV_UBLK is not set
|
||||
@@ -2602,7 +2585,6 @@ CONFIG_SCSI_FLASHPOINT=y
|
||||
# CONFIG_SCSI_MYRB is not set
|
||||
# CONFIG_SCSI_MYRS is not set
|
||||
CONFIG_VMWARE_PVSCSI=m
|
||||
CONFIG_XEN_SCSI_FRONTEND=m
|
||||
CONFIG_HYPERV_STORAGE=m
|
||||
CONFIG_LIBFC=m
|
||||
CONFIG_LIBFCOE=m
|
||||
@@ -3408,8 +3390,6 @@ CONFIG_IEEE802154_ATUSB=m
|
||||
# CONFIG_WWAN is not set
|
||||
# end of Wireless WAN
|
||||
|
||||
CONFIG_XEN_NETDEV_FRONTEND=m
|
||||
CONFIG_XEN_NETDEV_BACKEND=m
|
||||
CONFIG_VMXNET3=m
|
||||
CONFIG_FUJITSU_ES=m
|
||||
CONFIG_HYPERV_NET=m
|
||||
@@ -3583,9 +3563,6 @@ CONFIG_N_GSM=m
|
||||
CONFIG_NOZOMI=m
|
||||
# CONFIG_NULL_TTY is not set
|
||||
CONFIG_HVC_DRIVER=y
|
||||
CONFIG_HVC_IRQ=y
|
||||
CONFIG_HVC_XEN=y
|
||||
CONFIG_HVC_XEN_FRONTEND=y
|
||||
CONFIG_SERIAL_DEV_BUS=y
|
||||
CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
|
||||
# CONFIG_TTY_PRINTK is not set
|
||||
@@ -3636,7 +3613,6 @@ CONFIG_TCG_TIS_I2C_NUVOTON=m
|
||||
CONFIG_TCG_NSC=m
|
||||
CONFIG_TCG_ATMEL=m
|
||||
CONFIG_TCG_INFINEON=m
|
||||
CONFIG_TCG_XEN=m
|
||||
CONFIG_TCG_CRB=m
|
||||
# CONFIG_TCG_VTPM_PROXY is not set
|
||||
# CONFIG_TCG_TIS_ST33ZP24_I2C is not set
|
||||
@@ -4412,7 +4388,6 @@ CONFIG_INTEL_MEI_WDT=m
|
||||
CONFIG_NI903X_WDT=m
|
||||
CONFIG_NIC7018_WDT=m
|
||||
CONFIG_MEN_A21_WDT=m
|
||||
CONFIG_XEN_WDT=m
|
||||
|
||||
#
|
||||
# PCI-based Watchdog Cards
|
||||
@@ -4868,7 +4843,6 @@ CONFIG_DRM_CIRRUS_QEMU=m
|
||||
# CONFIG_TINYDRM_REPAPER is not set
|
||||
# CONFIG_TINYDRM_ST7586 is not set
|
||||
# CONFIG_TINYDRM_ST7735R is not set
|
||||
# CONFIG_DRM_XEN_FRONTEND is not set
|
||||
CONFIG_DRM_VBOXVIDEO=m
|
||||
# CONFIG_DRM_GUD is not set
|
||||
# CONFIG_DRM_SSD130X is not set
|
||||
@@ -4920,7 +4894,6 @@ CONFIG_FB_EFI=y
|
||||
# CONFIG_FB_UDL is not set
|
||||
# CONFIG_FB_IBM_GXT4500 is not set
|
||||
# CONFIG_FB_VIRTUAL is not set
|
||||
CONFIG_XEN_FBDEV_FRONTEND=m
|
||||
# CONFIG_FB_METRONOME is not set
|
||||
# CONFIG_FB_MB862XX is not set
|
||||
CONFIG_FB_HYPERV=m
|
||||
@@ -5132,7 +5105,6 @@ CONFIG_SND_PCMCIA=y
|
||||
# CONFIG_SND_SOC is not set
|
||||
CONFIG_SND_X86=y
|
||||
# CONFIG_HDMI_LPE_AUDIO is not set
|
||||
# CONFIG_SND_XEN_FRONTEND is not set
|
||||
CONFIG_SND_VIRTIO=m
|
||||
CONFIG_HID_SUPPORT=y
|
||||
CONFIG_HID=m
|
||||
@@ -5349,7 +5321,6 @@ CONFIG_USB_R8A66597_HCD=m
|
||||
# CONFIG_USB_HCD_BCMA is not set
|
||||
# CONFIG_USB_HCD_SSB is not set
|
||||
# CONFIG_USB_HCD_TEST_MODE is not set
|
||||
# CONFIG_USB_XEN_HCD is not set
|
||||
|
||||
#
|
||||
# USB Device Class drivers
|
||||
@@ -6024,41 +5995,6 @@ CONFIG_HYPERV_UTILS=m
|
||||
CONFIG_HYPERV_BALLOON=m
|
||||
# end of Microsoft Hyper-V guest support
|
||||
|
||||
#
|
||||
# Xen driver support
|
||||
#
|
||||
CONFIG_XEN_BALLOON=y
|
||||
CONFIG_XEN_BALLOON_MEMORY_HOTPLUG=y
|
||||
CONFIG_XEN_MEMORY_HOTPLUG_LIMIT=512
|
||||
CONFIG_XEN_SCRUB_PAGES_DEFAULT=y
|
||||
CONFIG_XEN_DEV_EVTCHN=m
|
||||
CONFIG_XEN_BACKEND=y
|
||||
CONFIG_XENFS=m
|
||||
CONFIG_XEN_COMPAT_XENFS=y
|
||||
CONFIG_XEN_SYS_HYPERVISOR=y
|
||||
CONFIG_XEN_XENBUS_FRONTEND=y
|
||||
CONFIG_XEN_GNTDEV=m
|
||||
CONFIG_XEN_GRANT_DEV_ALLOC=m
|
||||
# CONFIG_XEN_GRANT_DMA_ALLOC is not set
|
||||
CONFIG_SWIOTLB_XEN=y
|
||||
CONFIG_XEN_PCI_STUB=y
|
||||
CONFIG_XEN_PCIDEV_BACKEND=m
|
||||
# CONFIG_XEN_PVCALLS_FRONTEND is not set
|
||||
# CONFIG_XEN_PVCALLS_BACKEND is not set
|
||||
CONFIG_XEN_SCSI_BACKEND=m
|
||||
CONFIG_XEN_PRIVCMD=m
|
||||
CONFIG_XEN_ACPI_PROCESSOR=m
|
||||
CONFIG_XEN_MCE_LOG=y
|
||||
CONFIG_XEN_HAVE_PVMMU=y
|
||||
CONFIG_XEN_EFI=y
|
||||
CONFIG_XEN_AUTO_XLATE=y
|
||||
CONFIG_XEN_ACPI=y
|
||||
CONFIG_XEN_SYMS=y
|
||||
CONFIG_XEN_HAVE_VPMU=y
|
||||
CONFIG_XEN_UNPOPULATED_ALLOC=y
|
||||
# CONFIG_XEN_VIRTIO is not set
|
||||
# end of Xen driver support
|
||||
|
||||
# CONFIG_GREYBUS is not set
|
||||
# CONFIG_COMEDI is not set
|
||||
CONFIG_STAGING=y
|
||||
|
||||
@@ -70,5 +70,8 @@ stage1:evdev
|
||||
stage1:serio_raw
|
||||
stage1:serio
|
||||
|
||||
# zos core networking is with openvswitch vxlan over mycelium
|
||||
openvswitch
|
||||
|
||||
# Keep stage2 empty; we only use stage1 in this build
|
||||
# stage2: (intentionally unused)
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
# Git repositories to clone and build
|
||||
git zinit https://github.com/threefoldtech/zinit master build_zinit
|
||||
git mycelium https://github.com/threefoldtech/mycelium v0.6.1 build_mycelium
|
||||
|
||||
git zosstorage https://git.ourworld.tf/delandtj/zosstorage main build_zosstorage
|
||||
git youki git@github.com:youki-dev/youki.git v0.5.7 build_youki
|
||||
git rfs https://github.com/threefoldtech/rfs development build_rfs
|
||||
# Pre-built releases to download
|
||||
release rfs https://github.com/threefoldtech/rfs/releases/download/v2.0.6/rfs v2.0.6 install_rfs
|
||||
release corex https://github.com/threefoldtech/corex/releases/download/2.1.4/corex-2.1.4-amd64-linux-static 2.1.4 install_corex rename=corex
|
||||
# release rfs https://github.com/threefoldtech/rfs/releases/download/v2.0.6/rfs v2.0.6 install_rfs
|
||||
release corex https://github.com/threefoldtech/corex/releases/download/2.1.4/corex-2.1.4-amd64-linux-static 2.1.4 install_corex rename=corex
|
||||
|
||||
32
config/zinit/init/ovs-dbserver.sh
Normal file
32
config/zinit/init/ovs-dbserver.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
# Simple script to create OVS database and start ovsdb-server
|
||||
|
||||
# Configuration
|
||||
DATABASE=${DATABASE:-"/etc/openvswitch/conf.db"}
|
||||
DBSCHEMA="/usr/share/openvswitch/vswitch.ovsschema"
|
||||
DB_SOCKET=${DB_SOCKET:-"/var/run/openvswitch/db.sock"}
|
||||
RUNDIR="/var/run/openvswitch"
|
||||
|
||||
# Create run directory
|
||||
mkdir -p "$RUNDIR"
|
||||
|
||||
# Create database if it doesn't exist
|
||||
if [ ! -e "$DATABASE" ]; then
|
||||
echo "Creating database: $DATABASE"
|
||||
ovsdb-tool create "$DATABASE" "$DBSCHEMA"
|
||||
fi
|
||||
|
||||
# Check if database needs conversion
|
||||
if [ "$(ovsdb-tool needs-conversion "$DATABASE" "$DBSCHEMA")" = "yes" ]; then
|
||||
echo "Converting database: $DATABASE"
|
||||
ovsdb-tool convert "$DATABASE" "$DBSCHEMA"
|
||||
fi
|
||||
|
||||
# Start ovsdb-server
|
||||
echo "Starting ovsdb-server..."
|
||||
exec ovsdb-server \
|
||||
--remote=punix:"$DB_SOCKET" \
|
||||
--remote=db:Open_vSwitch,Open_vSwitch,manager_options \
|
||||
--pidfile \
|
||||
--detach \
|
||||
"$DATABASE"
|
||||
@@ -1,7 +1,8 @@
|
||||
exec: /usr/bin/mycelium --key-file /tmp/mycelium_priv_key.bin
|
||||
exec: /usr/bin/mycelium --key-file /var/cache/etc/mycelium_priv_key.bin
|
||||
--tun-name my0 --silent --peers tcp://188.40.132.242:9651 tcp://136.243.47.186:9651
|
||||
tcp://185.69.166.7:9651 tcp://185.69.166.8:9651 tcp://65.21.231.58:9651 tcp://65.109.18.113:9651
|
||||
tcp://209.159.146.190:9651 tcp://5.78.122.16:9651 tcp://5.223.43.251:9651 tcp://142.93.217.194:9651
|
||||
after:
|
||||
- network
|
||||
- udev-rfs
|
||||
- udev-rfs
|
||||
- zosstorage
|
||||
@@ -3,4 +3,4 @@ after:
|
||||
- depmod
|
||||
- udevd
|
||||
- udev-trigger
|
||||
test: ping www.google.com
|
||||
test: ping -c1 www.google.com
|
||||
|
||||
4
config/zinit/ovs-dbserver.yaml
Normal file
4
config/zinit/ovs-dbserver.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
exec: /etc/zinit/init/ovsdb-server.sh
|
||||
oneshot: true
|
||||
after:
|
||||
- zossstorage
|
||||
4
config/zinit/zosstorage.yaml
Normal file
4
config/zinit/zosstorage.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
exec: /usr/bin/zosstorage -l debug
|
||||
oneshot: true
|
||||
after:
|
||||
- rfs-modules
|
||||
@@ -84,7 +84,7 @@ Initramfs Assembly – Key Functions
|
||||
- Install init script: [bash.initramfs_install_init_script()](scripts/lib/initramfs.sh:74)
|
||||
- Installs [config/init](config/init) as /init in initramfs root.
|
||||
- Components copy: [bash.initramfs_copy_components()](scripts/lib/initramfs.sh:101)
|
||||
- Installs built components (zinit/rfs/mycelium/corex) into proper locations, strips/UPX where applicable.
|
||||
- Installs built components (zinit/rfs/mycelium/corex/zosstorage) into proper locations, strips/UPX where applicable.
|
||||
- Modules setup: [bash.initramfs_setup_modules()](scripts/lib/initramfs.sh:229)
|
||||
- Reads [config/modules.conf](config/modules.conf), resolves deps via [bash.initramfs_resolve_module_dependencies()](scripts/lib/initramfs.sh:318), generates stage1 list (firmware hints in modules.conf are ignored; firmware.conf is authoritative).
|
||||
- Create module scripts: [bash.initramfs_create_module_scripts()](scripts/lib/initramfs.sh:427)
|
||||
@@ -176,9 +176,12 @@ Stage System and Incremental Rebuilds
|
||||
- Shows stage status before/after marker removal; no --rebuild-from is passed by default (relies on markers only).
|
||||
- Manual minimal rebuild:
|
||||
- Remove relevant .done files, e.g.: initramfs_create.done initramfs_test.done validation.done
|
||||
- Rerun: DEBUG=1 ./scripts/build.sh --skip-tests
|
||||
- Rerun: DEBUG=1 ./scripts/build.sh
|
||||
- Show status:
|
||||
- ./scripts/build.sh --show-stages
|
||||
- Test built kernel:
|
||||
- ./runit.sh --hypervisor qemu
|
||||
- ./runit.sh --hypervisor ch --disks 5 --reset
|
||||
|
||||
Key Decisions (current)
|
||||
- Firmware selection for initramfs comes exclusively from [config/firmware.conf](config/firmware.conf); firmware hints in modules.conf are ignored to avoid duplication/mismatch.
|
||||
@@ -204,6 +207,8 @@ Change Log
|
||||
- Normalize INSTALL_DIR/COMPONENTS_DIR/KERNEL_DIR/DIST_DIR to absolute paths post-config load.
|
||||
- Add validation diagnostics prints (input/PWD/PROJECT_ROOT/INSTALL_DIR/resolved).
|
||||
- Ensure shadow package in container for passwd/chpasswd; keep openssl and openssl-dev; remove perl earlier.
|
||||
- 2025-10-10:
|
||||
- Record zosstorage as a standard component installed during [bash.initramfs_copy_components()](scripts/lib/initramfs.sh:101) and sync component documentation references.
|
||||
Updates 2025-10-01
|
||||
|
||||
- Function index regenerated: see [scripts/functionlist.md](scripts/functionlist.md) for an authoritative map of all functions with current line numbers. Use it alongside the quick links below to jump into code fast.
|
||||
|
||||
@@ -107,7 +107,7 @@ Diagnostics-first workflow (strict)
|
||||
- For any failure, first collect specific logs:
|
||||
- Enable DEBUG=1 for verbose logs.
|
||||
- Re-run only the impacted stage if possible:
|
||||
- Example: rm -f .build-stages/validation.done && DEBUG=1 ./scripts/build.sh --skip-tests
|
||||
- Example: rm -f .build-stages/validation.done && DEBUG=1 ./scripts/build.sh
|
||||
- Use existing diagnostics:
|
||||
- Branding debug lines: [bash.initramfs_finalize_customization()](scripts/lib/initramfs.sh:575)
|
||||
- Validation debug lines (input, PWD, PROJECT_ROOT, INSTALL_DIR, resolved): [bash.initramfs_validate()](scripts/lib/initramfs.sh:799)
|
||||
@@ -119,12 +119,15 @@ Common tasks and commands
|
||||
- DEBUG=1 ./scripts/build.sh
|
||||
- Minimal rebuild of last steps:
|
||||
- rm -f .build-stages/initramfs_create.done .build-stages/initramfs_test.done .build-stages/validation.done
|
||||
- DEBUG=1 ./scripts/build.sh --skip-tests
|
||||
- DEBUG=1 ./scripts/build.sh
|
||||
- Validation only:
|
||||
- rm -f .build-stages/validation.done
|
||||
- DEBUG=1 ./scripts/build.sh --skip-tests
|
||||
- DEBUG=1 ./scripts/build.sh
|
||||
- Show stage status:
|
||||
- ./scripts/build.sh --show-stages
|
||||
- Test built kernel:
|
||||
- ./runit.sh --hypervisor qemu
|
||||
- ./runit.sh --hypervisor ch --disks 5
|
||||
|
||||
Checklists and helpers
|
||||
|
||||
@@ -154,7 +157,7 @@ C) Minimal rebuild after zinit/init/modules.conf changes
|
||||
- Stage status is printed before/after marker removal; the helper avoids --rebuild-from by default to prevent running early stages.
|
||||
- Manual fallback:
|
||||
- rm -f .build-stages/initramfs_create.done .build-stages/initramfs_test.done .build-stages/validation.done
|
||||
- DEBUG=1 ./scripts/build.sh --skip-tests
|
||||
- DEBUG=1 ./scripts/build.sh
|
||||
|
||||
D) INITRAMFS_ARCHIVE unbound during kernel build stage
|
||||
- stage_kernel_build now defaults INITRAMFS_ARCHIVE if unset:
|
||||
|
||||
@@ -57,7 +57,7 @@ This canonical checklist is the single source of truth for ongoing work. It mirr
|
||||
- Create: [bash.initramfs_create_cpio()](../scripts/lib/initramfs.sh:691)
|
||||
- Validate: [bash.initramfs_validate()](../scripts/lib/initramfs.sh:820)
|
||||
- [ ] QEMU / cloud-hypervisor smoke tests
|
||||
- Test suite: [bash.testing_run_all()](../scripts/lib/testing.sh:299)
|
||||
- Test runner: [runit.sh](../runit.sh)
|
||||
- [ ] Kernel embed path and versioning sanity
|
||||
- Embed config: [bash.kernel_modify_config_for_initramfs()](../scripts/lib/kernel.sh:130)
|
||||
- Full version logic: [bash.kernel_get_full_version()](../scripts/lib/kernel.sh:14)
|
||||
|
||||
@@ -13,7 +13,6 @@ Key sourced libraries:
|
||||
- [initramfs.sh](scripts/lib/initramfs.sh)
|
||||
- [stages.sh](scripts/lib/stages.sh)
|
||||
- [docker.sh](scripts/lib/docker.sh)
|
||||
- [testing.sh](scripts/lib/testing.sh)
|
||||
|
||||
Main stages executed (incremental via [stage_run()](scripts/lib/stages.sh:99)):
|
||||
1) alpine_extract, alpine_configure, alpine_packages
|
||||
|
||||
263
runit.sh
Executable file
263
runit.sh
Executable file
@@ -0,0 +1,263 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Default configuration
|
||||
HYPERVISOR="${HYPERVISOR:-qemu}" # qemu or ch (cloud-hypervisor)
|
||||
NUM_DISKS="${NUM_DISKS:-3}"
|
||||
DISK_SIZE="${DISK_SIZE:-10G}"
|
||||
DISK_PREFIX="zosvol"
|
||||
KERNEL="dist/vmlinuz.efi"
|
||||
MEMORY="2048"
|
||||
BRIDGE="${BRIDGE:-zosbr}"
|
||||
TAP_INTERFACE="${TAP_INTERFACE:-zos-tap0}"
|
||||
|
||||
# Parse command line arguments
|
||||
RESET_VOLUMES=false
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTIONS]
|
||||
|
||||
Options:
|
||||
-H, --hypervisor <qemu|ch> Choose hypervisor (default: qemu)
|
||||
-d, --disks <N> Number of disks to create (default: 3)
|
||||
-s, --disk-size <SIZE> Size of each disk (default: 10G)
|
||||
-r, --reset Delete and recreate all volumes
|
||||
-m, --memory <MB> Memory in MB (default: 2048)
|
||||
-b, --bridge <NAME> Network bridge name (default: zosbr)
|
||||
-h, --help Show this help message
|
||||
|
||||
Environment variables:
|
||||
HYPERVISOR Same as --hypervisor
|
||||
NUM_DISKS Same as --disks
|
||||
DISK_SIZE Same as --disk-size
|
||||
BRIDGE Same as --bridge
|
||||
|
||||
Examples:
|
||||
$0 -H qemu -d 5
|
||||
$0 --hypervisor ch --reset
|
||||
$0 -d 4 -r
|
||||
HYPERVISOR=ch NUM_DISKS=4 $0
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Parse arguments using getopt
|
||||
TEMP=$(getopt -o 'H:d:s:rm:b:h' --long 'hypervisor:,disks:,disk-size:,reset,memory:,bridge:,help' -n "$0" -- "$@")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error parsing arguments. Try '$0 --help' for more information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eval set -- "$TEMP"
|
||||
unset TEMP
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
'-H' | '--hypervisor')
|
||||
HYPERVISOR="$2"
|
||||
shift 2
|
||||
;;
|
||||
'-d' | '--disks')
|
||||
NUM_DISKS="$2"
|
||||
shift 2
|
||||
;;
|
||||
'-s' | '--disk-size')
|
||||
DISK_SIZE="$2"
|
||||
shift 2
|
||||
;;
|
||||
'-r' | '--reset')
|
||||
RESET_VOLUMES=true
|
||||
shift
|
||||
;;
|
||||
'-m' | '--memory')
|
||||
MEMORY="$2"
|
||||
shift 2
|
||||
;;
|
||||
'-b' | '--bridge')
|
||||
BRIDGE="$2"
|
||||
shift 2
|
||||
;;
|
||||
'-h' | '--help')
|
||||
usage
|
||||
;;
|
||||
'--')
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "Internal error!"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate hypervisor choice
|
||||
if [[ "$HYPERVISOR" != "qemu" && "$HYPERVISOR" != "ch" ]]; then
|
||||
echo "Error: Invalid hypervisor '$HYPERVISOR'. Must be 'qemu' or 'ch'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$HYPERVISOR" == "qemu" ]]; then
|
||||
DISK_SUFFIX="qcow"
|
||||
DISK_FORMAT="qcow2"
|
||||
else
|
||||
DISK_SUFFIX="raw"
|
||||
DISK_FORMAT="raw"
|
||||
fi
|
||||
|
||||
# Validate kernel exists
|
||||
if [[ ! -f "$KERNEL" ]]; then
|
||||
echo "Error: Kernel not found at $KERNEL"
|
||||
echo "Run the build first: ./scripts/build.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setup TAP interface for cloud-hypervisor
|
||||
setup_tap_interface() {
|
||||
local tap="$1"
|
||||
local bridge="$2"
|
||||
|
||||
echo "Setting up TAP interface $tap for cloud-hypervisor..."
|
||||
if [[ -z "${CH_TAP_IP:-}" && -z "${CH_TAP_MASK:-}" ]]; then
|
||||
echo " Reminder: set CH_TAP_IP and CH_TAP_MASK to configure $tap and silence cloud-hypervisor IP warnings."
|
||||
fi
|
||||
|
||||
# Check if bridge exists
|
||||
if ! ip link show "$bridge" &>/dev/null; then
|
||||
echo "Warning: Bridge $bridge does not exist. Create it with:"
|
||||
echo " sudo ip link add name $bridge type bridge"
|
||||
echo " sudo ip link set $bridge up"
|
||||
echo ""
|
||||
read -p "Continue anyway? (y/N) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if TAP already exists
|
||||
if ip link show "$tap" &>/dev/null; then
|
||||
echo " TAP interface $tap already exists"
|
||||
# Check if it's already attached to bridge
|
||||
if bridge link show | grep -q "$tap"; then
|
||||
echo " $tap is already attached to bridge"
|
||||
return 0
|
||||
else
|
||||
echo " Attaching $tap to bridge $bridge"
|
||||
sudo ip link set dev "$tap" master "$bridge" 2>/dev/null || true
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create new TAP interface
|
||||
echo " Creating TAP interface $tap"
|
||||
sudo ip tuntap add "$tap" mode tap user "$(whoami)"
|
||||
|
||||
# Bring it up
|
||||
echo " Bringing up $tap"
|
||||
sudo ip link set "$tap" up
|
||||
|
||||
# Attach to bridge
|
||||
echo " Attaching $tap to bridge $bridge"
|
||||
sudo ip link set dev "$tap" master "$bridge"
|
||||
|
||||
echo " TAP interface setup complete"
|
||||
}
|
||||
|
||||
# Cleanup TAP interface on exit (for cloud-hypervisor)
|
||||
cleanup_tap_interface() {
|
||||
local tap="$1"
|
||||
if [[ -n "$tap" ]] && ip link show "$tap" &>/dev/null; then
|
||||
echo "Cleaning up TAP interface $tap"
|
||||
sudo ip link delete "$tap" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Reset volumes if requested
|
||||
if [[ "$RESET_VOLUMES" == "true" ]]; then
|
||||
echo "Resetting volumes..."
|
||||
for i in $(seq 0 $((NUM_DISKS - 1))); do
|
||||
for suffix in qcow raw; do
|
||||
vol="${DISK_PREFIX}${i}.${suffix}"
|
||||
if [[ -f "$vol" ]]; then
|
||||
echo " Removing $vol"
|
||||
rm -f "$vol"
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
# Create disk volumes if they don't exist
|
||||
echo "Ensuring $NUM_DISKS disk volume(s) exist..."
|
||||
for i in $(seq 0 $((NUM_DISKS - 1))); do
|
||||
vol="${DISK_PREFIX}${i}.${DISK_SUFFIX}"
|
||||
if [[ ! -f "$vol" ]]; then
|
||||
echo " Creating $vol (size: $DISK_SIZE, format: $DISK_FORMAT)"
|
||||
qemu-img create -f "$DISK_FORMAT" "$vol" "$DISK_SIZE" >/dev/null
|
||||
else
|
||||
echo " $vol already exists"
|
||||
fi
|
||||
done
|
||||
|
||||
# Build disk arguments based on hypervisor
|
||||
DISK_ARGS=()
|
||||
if [[ "$HYPERVISOR" == "qemu" ]]; then
|
||||
for i in $(seq 0 $((NUM_DISKS - 1))); do
|
||||
vol="${DISK_PREFIX}${i}.${DISK_SUFFIX}"
|
||||
DISK_ARGS+=("-drive" "file=$vol,format=$DISK_FORMAT,if=virtio")
|
||||
done
|
||||
elif [[ "$HYPERVISOR" == "ch" ]]; then
|
||||
# cloud-hypervisor requires comma-separated disk list in single --disk argument
|
||||
# Use raw format (no compression)
|
||||
CH_DISKS=""
|
||||
for i in $(seq 0 $((NUM_DISKS - 1))); do
|
||||
vol="${DISK_PREFIX}${i}.${DISK_SUFFIX}"
|
||||
if [[ -z "$CH_DISKS" ]]; then
|
||||
CH_DISKS="path=$vol,iommu=on"
|
||||
else
|
||||
CH_DISKS="${CH_DISKS},path=$vol,iommu=on"
|
||||
fi
|
||||
done
|
||||
if [[ -n "$CH_DISKS" ]]; then
|
||||
DISK_ARGS+=("--disk" "$CH_DISKS")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Launch the appropriate hypervisor
|
||||
echo "Launching with $HYPERVISOR hypervisor..."
|
||||
echo ""
|
||||
|
||||
if [[ "$HYPERVISOR" == "qemu" ]]; then
|
||||
exec qemu-system-x86_64 \
|
||||
-kernel "$KERNEL" \
|
||||
-m "$MEMORY" \
|
||||
-enable-kvm \
|
||||
-cpu host \
|
||||
-net nic,model=virtio \
|
||||
-net bridge,br="$BRIDGE" \
|
||||
"${DISK_ARGS[@]}" \
|
||||
-chardev stdio,id=char0,mux=on,logfile=serial.log \
|
||||
-serial chardev:char0 \
|
||||
-mon chardev=char0 \
|
||||
-append "console=ttyS0,115200n8 console=tty"
|
||||
|
||||
elif [[ "$HYPERVISOR" == "ch" ]]; then
|
||||
# Setup TAP interface for cloud-hypervisor
|
||||
setup_tap_interface "$TAP_INTERFACE" "$BRIDGE"
|
||||
|
||||
# Cleanup on exit
|
||||
trap "cleanup_tap_interface '$TAP_INTERFACE'" EXIT
|
||||
|
||||
exec cloud-hypervisor \
|
||||
--kernel "$KERNEL" \
|
||||
--memory size="${MEMORY}M" \
|
||||
--cpus boot=2 \
|
||||
--net "tap=$TAP_INTERFACE" \
|
||||
"${DISK_ARGS[@]}" \
|
||||
--console off \
|
||||
--serial tty \
|
||||
--cmdline "console=ttyS0,115200n8"
|
||||
fi
|
||||
@@ -15,7 +15,6 @@ source "${SCRIPT_DIR}/lib/alpine.sh"
|
||||
source "${SCRIPT_DIR}/lib/components.sh"
|
||||
source "${SCRIPT_DIR}/lib/initramfs.sh"
|
||||
source "${SCRIPT_DIR}/lib/kernel.sh"
|
||||
source "${SCRIPT_DIR}/lib/testing.sh"
|
||||
|
||||
# Build configuration loaded from config/build.conf via common.sh
|
||||
# Environment variables can override config file values
|
||||
@@ -42,7 +41,6 @@ ZINIT_CONFIG_DIR="${CONFIG_DIR}/zinit"
|
||||
# Build options
|
||||
USE_CONTAINER="${USE_CONTAINER:-auto}"
|
||||
CLEAN_BUILD="${CLEAN_BUILD:-false}"
|
||||
SKIP_TESTS="${SKIP_TESTS:-false}"
|
||||
KEEP_ARTIFACTS="${KEEP_ARTIFACTS:-false}"
|
||||
|
||||
# Display usage information
|
||||
@@ -54,7 +52,6 @@ Usage: $0 [OPTIONS]
|
||||
|
||||
Options:
|
||||
--clean Clean build (remove all artifacts first)
|
||||
--skip-tests Skip boot tests
|
||||
--keep-artifacts Keep build artifacts after completion
|
||||
--force-rebuild Force rebuild all stages (ignore completion markers)
|
||||
--rebuild-from=STAGE Force rebuild from specific stage onward
|
||||
@@ -92,10 +89,6 @@ function parse_arguments() {
|
||||
CLEAN_BUILD="true"
|
||||
shift
|
||||
;;
|
||||
--skip-tests)
|
||||
SKIP_TESTS="true"
|
||||
shift
|
||||
;;
|
||||
--keep-artifacts)
|
||||
KEEP_ARTIFACTS="true"
|
||||
shift
|
||||
@@ -408,21 +401,19 @@ function main_build_process() {
|
||||
log_debug "stage_kernel_build: defaulting INITRAMFS_ARCHIVE=${INITRAMFS_ARCHIVE}"
|
||||
fi
|
||||
|
||||
# Ensure FULL_KERNEL_VERSION is set for versioned output filename
|
||||
if [[ -z "${FULL_KERNEL_VERSION:-}" ]]; then
|
||||
FULL_KERNEL_VERSION=$(kernel_get_full_version "$KERNEL_VERSION" "$KERNEL_CONFIG")
|
||||
export FULL_KERNEL_VERSION
|
||||
log_debug "stage_kernel_build: resolved FULL_KERNEL_VERSION=${FULL_KERNEL_VERSION}"
|
||||
fi
|
||||
|
||||
kernel_build_with_initramfs "$KERNEL_CONFIG" "$INITRAMFS_ARCHIVE" "$kernel_output"
|
||||
export KERNEL_OUTPUT="$kernel_output"
|
||||
}
|
||||
|
||||
function stage_boot_tests() {
|
||||
if [[ "$SKIP_TESTS" != "true" ]]; then
|
||||
# Ensure KERNEL_OUTPUT is set (for incremental builds)
|
||||
if [[ -z "${KERNEL_OUTPUT:-}" ]]; then
|
||||
KERNEL_OUTPUT="${DIST_DIR}/vmlinuz.efi"
|
||||
export KERNEL_OUTPUT
|
||||
fi
|
||||
testing_run_all "$KERNEL_OUTPUT"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Boot tests removed - use runit.sh for testing instead
|
||||
|
||||
# Run all stages with incremental tracking
|
||||
stage_run "alpine_extract" stage_alpine_extract
|
||||
stage_run "alpine_configure" stage_alpine_configure
|
||||
@@ -442,8 +433,7 @@ function main_build_process() {
|
||||
stage_run "initramfs_create" stage_initramfs_create
|
||||
stage_run "initramfs_test" stage_initramfs_test
|
||||
stage_run "kernel_build" stage_kernel_build
|
||||
stage_run "boot_tests" stage_boot_tests
|
||||
|
||||
|
||||
# Calculate build time
|
||||
local end_time=$(date +%s)
|
||||
local build_time=$((end_time - start_time))
|
||||
@@ -501,16 +491,13 @@ function main() {
|
||||
log_info "Starting container build"
|
||||
docker_detect_runtime
|
||||
docker_build_container
|
||||
|
||||
|
||||
# Pass through relevant arguments to container
|
||||
local container_args=""
|
||||
if [[ "$SKIP_TESTS" == "true" ]]; then
|
||||
container_args="$container_args --skip-tests"
|
||||
fi
|
||||
if [[ "$KEEP_ARTIFACTS" == "true" ]]; then
|
||||
container_args="$container_args --keep-artifacts"
|
||||
fi
|
||||
|
||||
|
||||
docker_run_build "./scripts/build.sh${container_args}"
|
||||
else
|
||||
log_error "Container runtime required (podman or docker)"
|
||||
|
||||
@@ -9,6 +9,7 @@ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
# Container configuration
|
||||
CONTAINER_NAME="zero-os-dev"
|
||||
BUILDER_IMAGE="zero-os-builder:latest"
|
||||
HOST_SSH_DIR="${SSH_MOUNT_DIR:-${HOME}/.ssh}"
|
||||
|
||||
# Default to verbose, streaming logs for dev flows unless explicitly disabled
|
||||
export DEBUG="${DEBUG:-1}"
|
||||
@@ -17,7 +18,7 @@ export DEBUG="${DEBUG:-1}"
|
||||
source "${SCRIPT_DIR}/lib/common.sh"
|
||||
|
||||
function show_usage() {
|
||||
cat << EOF
|
||||
cat <<EOF
|
||||
Zero OS Development Container Manager
|
||||
|
||||
Usage: $0 [COMMAND]
|
||||
@@ -69,10 +70,10 @@ function ensure_builder_image() {
|
||||
|
||||
function dev_container_start() {
|
||||
section_header "Starting Development Container"
|
||||
|
||||
|
||||
# Ensure builder image exists (handles clean --all case and short-name policy)
|
||||
ensure_builder_image
|
||||
|
||||
|
||||
# Check if container already exists
|
||||
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
if podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}' | grep -q "running"; then
|
||||
@@ -84,23 +85,38 @@ function dev_container_start() {
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
log_info "Creating new development container: ${CONTAINER_NAME}"
|
||||
|
||||
|
||||
# Create persistent container with all necessary mounts and environment
|
||||
safe_execute podman run -d \
|
||||
--name "$CONTAINER_NAME" \
|
||||
--privileged \
|
||||
-v "${PROJECT_ROOT}:/workspace" \
|
||||
-w /workspace \
|
||||
-e DEBUG=1 \
|
||||
-e ALPINE_VERSION=3.22 \
|
||||
-e KERNEL_VERSION=6.12.44 \
|
||||
-e RUST_TARGET=x86_64-unknown-linux-musl \
|
||||
-e OPTIMIZATION_LEVEL=max \
|
||||
"$BUILDER_IMAGE" \
|
||||
local podman_args=(
|
||||
run -d
|
||||
--name "$CONTAINER_NAME"
|
||||
--privileged
|
||||
-v "${PROJECT_ROOT}:/workspace"
|
||||
-v "$HOME/.ssh:root/.ssh"
|
||||
-w /workspace
|
||||
-e DEBUG=1
|
||||
-e ALPINE_VERSION=3.22
|
||||
-e KERNEL_VERSION=6.12.44
|
||||
-e RUST_TARGET=x86_64-unknown-linux-musl
|
||||
-e OPTIMIZATION_LEVEL=max
|
||||
)
|
||||
|
||||
if [[ -d "$HOST_SSH_DIR" ]]; then
|
||||
log_info "Mounting SSH directory: ${HOST_SSH_DIR} -> /root/.ssh (read-only)"
|
||||
podman_args+=(-v "${HOST_SSH_DIR}:/root/.ssh:ro")
|
||||
else
|
||||
log_warn "SSH directory not found at ${HOST_SSH_DIR}; skipping SSH mount"
|
||||
fi
|
||||
|
||||
podman_args+=(
|
||||
"$BUILDER_IMAGE"
|
||||
sleep infinity
|
||||
|
||||
)
|
||||
|
||||
safe_execute podman "${podman_args[@]}"
|
||||
|
||||
log_info "Development container started successfully"
|
||||
log_info "Container name: ${CONTAINER_NAME}"
|
||||
log_info "Access with: $0 shell"
|
||||
@@ -108,7 +124,7 @@ function dev_container_start() {
|
||||
|
||||
function dev_container_stop() {
|
||||
section_header "Stopping Development Container"
|
||||
|
||||
|
||||
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
log_info "Stopping development container: ${CONTAINER_NAME}"
|
||||
safe_execute podman stop "$CONTAINER_NAME"
|
||||
@@ -120,17 +136,17 @@ function dev_container_stop() {
|
||||
|
||||
function dev_container_shell() {
|
||||
section_header "Entering Development Container Shell"
|
||||
|
||||
|
||||
if ! podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
log_info "Development container not found, starting..."
|
||||
dev_container_start
|
||||
fi
|
||||
|
||||
|
||||
if ! podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}' | grep -q "running"; then
|
||||
log_info "Starting stopped development container"
|
||||
safe_execute podman start "$CONTAINER_NAME"
|
||||
fi
|
||||
|
||||
|
||||
log_info "Entering container shell (exit with 'exit' or Ctrl+D)"
|
||||
# Use direct execution for interactive shell (don't use safe_execute)
|
||||
exec podman exec -it "$CONTAINER_NAME" /bin/bash
|
||||
@@ -138,56 +154,56 @@ function dev_container_shell() {
|
||||
|
||||
function dev_container_build() {
|
||||
section_header "Running Build in Development Container"
|
||||
|
||||
|
||||
if ! podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
log_info "Development container not found, starting..."
|
||||
dev_container_start
|
||||
fi
|
||||
|
||||
|
||||
if ! podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}' | grep -q "running"; then
|
||||
log_info "Starting stopped development container"
|
||||
safe_execute podman start "$CONTAINER_NAME"
|
||||
fi
|
||||
|
||||
|
||||
log_info "Running build in persistent container (real-time output)"
|
||||
log_info "Command: podman exec $CONTAINER_NAME ./scripts/build.sh $*"
|
||||
|
||||
|
||||
# Use direct execution to show real-time output (bypass safe_execute)
|
||||
podman exec "$CONTAINER_NAME" ./scripts/build.sh "$@"
|
||||
local exit_code=$?
|
||||
|
||||
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
log_info "Build completed successfully in container"
|
||||
else
|
||||
log_error "Build failed in container with exit code: $exit_code"
|
||||
fi
|
||||
|
||||
|
||||
return $exit_code
|
||||
}
|
||||
|
||||
function dev_container_clean() {
|
||||
section_header "Cleaning Development Container"
|
||||
|
||||
|
||||
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
log_info "Removing existing development container"
|
||||
safe_execute podman rm -f "$CONTAINER_NAME"
|
||||
fi
|
||||
|
||||
|
||||
log_info "Starting fresh development container"
|
||||
dev_container_start
|
||||
}
|
||||
|
||||
function dev_container_status() {
|
||||
section_header "Development Container Status"
|
||||
|
||||
|
||||
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
local status=$(podman container inspect "$CONTAINER_NAME" --format '{{.State.Status}}')
|
||||
local created=$(podman container inspect "$CONTAINER_NAME" --format '{{.Created}}')
|
||||
|
||||
|
||||
log_info "Container: ${CONTAINER_NAME}"
|
||||
log_info "Status: ${status}"
|
||||
log_info "Created: ${created}"
|
||||
|
||||
|
||||
if [[ "$status" == "running" ]]; then
|
||||
log_info "✓ Ready for development"
|
||||
else
|
||||
@@ -201,7 +217,7 @@ function dev_container_status() {
|
||||
|
||||
function dev_container_logs() {
|
||||
section_header "Development Container Logs"
|
||||
|
||||
|
||||
if podman container exists "$CONTAINER_NAME" 2>/dev/null; then
|
||||
safe_execute podman logs "$CONTAINER_NAME"
|
||||
else
|
||||
@@ -213,39 +229,39 @@ function dev_container_logs() {
|
||||
# Main function
|
||||
function main() {
|
||||
local command="${1:-help}"
|
||||
|
||||
|
||||
case "$command" in
|
||||
start)
|
||||
dev_container_start
|
||||
;;
|
||||
stop)
|
||||
dev_container_stop
|
||||
;;
|
||||
shell)
|
||||
dev_container_shell
|
||||
;;
|
||||
build)
|
||||
shift
|
||||
dev_container_build "$@"
|
||||
;;
|
||||
clean)
|
||||
dev_container_clean
|
||||
;;
|
||||
status)
|
||||
dev_container_status
|
||||
;;
|
||||
logs)
|
||||
dev_container_logs
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_usage
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown command: $command"
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
start)
|
||||
dev_container_start
|
||||
;;
|
||||
stop)
|
||||
dev_container_stop
|
||||
;;
|
||||
shell)
|
||||
dev_container_shell
|
||||
;;
|
||||
build)
|
||||
shift
|
||||
dev_container_build "$@"
|
||||
;;
|
||||
clean)
|
||||
dev_container_clean
|
||||
;;
|
||||
status)
|
||||
dev_container_status
|
||||
;;
|
||||
logs)
|
||||
dev_container_logs
|
||||
;;
|
||||
help | --help | -h)
|
||||
show_usage
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown command: $command"
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
main "$@"
|
||||
|
||||
@@ -195,6 +195,26 @@ function get_file_size() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Get short git commit hash from a git repository directory
|
||||
function get_git_commit_hash() {
|
||||
local repo_dir="$1"
|
||||
local short="${2:-true}" # Default to short hash
|
||||
|
||||
if [[ ! -d "$repo_dir/.git" ]]; then
|
||||
echo "unknown"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local hash
|
||||
if [[ "$short" == "true" ]]; then
|
||||
hash=$(cd "$repo_dir" && git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
||||
else
|
||||
hash=$(cd "$repo_dir" && git rev-parse HEAD 2>/dev/null || echo "unknown")
|
||||
fi
|
||||
|
||||
echo "$hash"
|
||||
}
|
||||
|
||||
# Wait for file to exist with timeout
|
||||
function wait_for_file() {
|
||||
local file="$1"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -186,6 +186,34 @@ function initramfs_copy_components() {
|
||||
log_error "✗ mycelium binary not found: ${mycelium_binary}"
|
||||
((missing_count++))
|
||||
fi
|
||||
|
||||
# Copy zosstorage to /usr/bin
|
||||
local zosstorage_binary="${components_dir}/zosstorage/target/x86_64-unknown-linux-musl/release/zosstorage"
|
||||
if [[ -f "$zosstorage_binary" ]]; then
|
||||
safe_mkdir "${initramfs_dir}/usr/bin"
|
||||
safe_execute cp "$zosstorage_binary" "${initramfs_dir}/usr/bin/zosstorage"
|
||||
safe_execute chmod +x "${initramfs_dir}/usr/bin/zosstorage"
|
||||
|
||||
local original_size=$(get_file_size "${initramfs_dir}/usr/bin/zosstorage")
|
||||
if strip "${initramfs_dir}/usr/bin/zosstorage" 2>/dev/null || true; then
|
||||
log_debug "Stripped zosstorage"
|
||||
else
|
||||
log_debug "zosstorage already stripped or strip failed"
|
||||
fi
|
||||
|
||||
if command_exists "upx" && upx --best --force "${initramfs_dir}/usr/bin/zosstorage" >/dev/null 2>&1 || true; then
|
||||
log_debug "UPX compressed zosstorage"
|
||||
else
|
||||
log_debug "UPX failed or already compressed"
|
||||
fi
|
||||
|
||||
local final_size=$(get_file_size "${initramfs_dir}/usr/bin/zosstorage")
|
||||
log_info "✓ Copied zosstorage ${original_size} → ${final_size} to /usr/bin/zosstorage"
|
||||
((copied_count++))
|
||||
else
|
||||
log_error "✗ zosstorage binary not found: ${zosstorage_binary}"
|
||||
((missing_count++))
|
||||
fi
|
||||
|
||||
# Copy corex to /usr/bin
|
||||
local corex_binary="${components_dir}/corex/corex"
|
||||
@@ -929,6 +957,7 @@ function initramfs_validate() {
|
||||
local component_binaries=(
|
||||
"usr/bin/rfs"
|
||||
"usr/bin/mycelium"
|
||||
"usr/bin/zosstorage"
|
||||
"usr/bin/corex"
|
||||
)
|
||||
|
||||
|
||||
@@ -223,20 +223,219 @@ function kernel_build_with_initramfs() {
|
||||
output_dir=$(dirname "$output_abs")
|
||||
safe_mkdir "$output_dir"
|
||||
safe_copy "$kernel_image" "$output_abs"
|
||||
|
||||
|
||||
# Also copy with versioned filename including kernel version and zinit hash
|
||||
local full_kernel_version="${FULL_KERNEL_VERSION:-unknown}"
|
||||
local zinit_hash="unknown"
|
||||
local zinit_dir="${COMPONENTS_DIR:-${PROJECT_ROOT}/components}/zinit"
|
||||
|
||||
if [[ -d "$zinit_dir/.git" ]]; then
|
||||
zinit_hash=$(get_git_commit_hash "$zinit_dir")
|
||||
else
|
||||
log_warn "zinit git directory not found at ${zinit_dir}, using 'unknown' for hash"
|
||||
fi
|
||||
|
||||
# Create versioned filename: vmlinuz-{VERSION}-{ZINIT_HASH}.efi
|
||||
local versioned_name="vmlinuz-${full_kernel_version}-${zinit_hash}.efi"
|
||||
local versioned_output="${output_dir}/${versioned_name}"
|
||||
safe_copy "$kernel_image" "$versioned_output"
|
||||
|
||||
# Verify final kernel
|
||||
local kernel_size
|
||||
kernel_size=$(get_file_size "$output_abs")
|
||||
local versioned_size
|
||||
versioned_size=$(get_file_size "$versioned_output")
|
||||
log_info "Kernel build complete:"
|
||||
log_info " Output file: ${output_abs}"
|
||||
log_info " Versioned: ${versioned_output}"
|
||||
log_info " Kernel size: ${kernel_size}"
|
||||
|
||||
log_info " Version: ${full_kernel_version}"
|
||||
log_info " zinit hash: ${zinit_hash}"
|
||||
|
||||
# Verify initramfs is embedded
|
||||
if strings "$output_file" | grep -q "initramfs"; then
|
||||
log_info "✓ Initramfs appears to be embedded in kernel"
|
||||
else
|
||||
log_warn "Initramfs embedding verification inconclusive"
|
||||
fi
|
||||
|
||||
# Upload versioned kernel to S3 if enabled
|
||||
kernel_upload_to_s3 "$versioned_output" "$full_kernel_version" "$zinit_hash"
|
||||
}
|
||||
|
||||
# Upload versioned kernel to S3 using MinIO client (mcli/mc)
|
||||
function kernel_upload_to_s3() {
|
||||
local kernel_file="$1"
|
||||
local kernel_version="$2"
|
||||
local zinit_hash="$3"
|
||||
|
||||
section_header "Uploading Kernel to S3"
|
||||
|
||||
# Check if upload is enabled
|
||||
if [[ "${UPLOAD_KERNEL:-false}" != "true" ]]; then
|
||||
log_info "UPLOAD_KERNEL not enabled; skipping kernel upload"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Verify kernel file exists
|
||||
if [[ ! -f "$kernel_file" ]]; then
|
||||
log_error "Kernel file not found: ${kernel_file}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Load S3 configuration from rfs.conf
|
||||
local rfs_conf="${PROJECT_ROOT}/config/rfs.conf"
|
||||
local rfs_conf_example="${PROJECT_ROOT}/config/rfs.conf.example"
|
||||
|
||||
if [[ -f "$rfs_conf" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "$rfs_conf"
|
||||
log_info "Loaded S3 config from: ${rfs_conf}"
|
||||
elif [[ -f "$rfs_conf_example" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "$rfs_conf_example"
|
||||
log_warn "Using example S3 config: ${rfs_conf_example}"
|
||||
else
|
||||
log_error "No S3 config found (config/rfs.conf or config/rfs.conf.example)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate required S3 variables
|
||||
for var in S3_ENDPOINT S3_BUCKET S3_PREFIX S3_ACCESS_KEY S3_SECRET_KEY; do
|
||||
if [[ -z "${!var}" ]]; then
|
||||
log_error "Missing required S3 variable: ${var}"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Detect MinIO client binary (mcli or mc)
|
||||
local mcli_bin=""
|
||||
if command -v mcli >/dev/null 2>&1; then
|
||||
mcli_bin="mcli"
|
||||
elif command -v mc >/dev/null 2>&1; then
|
||||
mcli_bin="mc"
|
||||
else
|
||||
log_warn "MinIO Client not found (expected mcli or mc); skipping kernel upload"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Using MinIO client: ${mcli_bin}"
|
||||
|
||||
# Setup S3 alias
|
||||
log_info "Configuring S3 alias..."
|
||||
safe_execute "${mcli_bin}" alias set rfs "${S3_ENDPOINT}" "${S3_ACCESS_KEY}" "${S3_SECRET_KEY}"
|
||||
|
||||
# Construct destination path: rfs/{bucket}/{prefix}/kernel/{versioned_filename}
|
||||
local kernel_filename
|
||||
kernel_filename=$(basename "$kernel_file")
|
||||
local kernel_subpath="${KERNEL_SUBPATH:-kernel}"
|
||||
local mcli_dst="rfs/${S3_BUCKET}/${S3_PREFIX%/}/${kernel_subpath%/}/${kernel_filename}"
|
||||
|
||||
# Upload kernel
|
||||
log_info "Uploading: ${kernel_file} -> ${mcli_dst}"
|
||||
safe_execute "${mcli_bin}" cp "${kernel_file}" "${mcli_dst}"
|
||||
|
||||
log_info "✓ Kernel uploaded successfully"
|
||||
log_info " Version: ${kernel_version}"
|
||||
log_info " zinit: ${zinit_hash}"
|
||||
log_info " S3 path: ${mcli_dst}"
|
||||
|
||||
# Generate and upload kernel index
|
||||
kernel_generate_index "${mcli_bin}" "${S3_BUCKET}" "${S3_PREFIX}" "${kernel_subpath}"
|
||||
}
|
||||
|
||||
# Generate kernel index file from S3 listing and upload it
|
||||
function kernel_generate_index() {
|
||||
local mcli_bin="$1"
|
||||
local bucket="$2"
|
||||
local prefix="$3"
|
||||
local kernel_subpath="$4"
|
||||
|
||||
section_header "Generating Kernel Index"
|
||||
|
||||
# Construct S3 path for listing
|
||||
local s3_path="rfs/${bucket}/${prefix%/}/${kernel_subpath%/}/"
|
||||
|
||||
log_info "Listing kernels from: ${s3_path}"
|
||||
|
||||
# List all files in the kernel directory
|
||||
local ls_output
|
||||
if ! ls_output=$("${mcli_bin}" ls "${s3_path}" 2>&1); then
|
||||
log_warn "Failed to list S3 kernel directory, index not generated"
|
||||
log_debug "mcli ls output: ${ls_output}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Parse output and extract kernel filenames matching vmlinuz-*
|
||||
local kernels=()
|
||||
while IFS= read -r line; do
|
||||
# mcli ls output format: [DATE TIME TZ] SIZE FILENAME
|
||||
# Extract filename (last field)
|
||||
local filename
|
||||
filename=$(echo "$line" | awk '{print $NF}')
|
||||
|
||||
# Filter for vmlinuz files (both .efi and without extension)
|
||||
if [[ "$filename" =~ ^vmlinuz-.* ]]; then
|
||||
kernels+=("$filename")
|
||||
fi
|
||||
done <<< "$ls_output"
|
||||
|
||||
if [[ ${#kernels[@]} -eq 0 ]]; then
|
||||
log_warn "No kernels found in S3 path: ${s3_path}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Found ${#kernels[@]} kernel(s)"
|
||||
|
||||
# Create index files in dist directory
|
||||
local index_dir="${DIST_DIR:-${PROJECT_ROOT}/dist}"
|
||||
local text_index="${index_dir}/kernels.txt"
|
||||
local json_index="${index_dir}/kernels.json"
|
||||
|
||||
# Generate text index (one kernel per line, sorted)
|
||||
printf "%s\n" "${kernels[@]}" | sort -r > "$text_index"
|
||||
log_info "Created text index: ${text_index}"
|
||||
|
||||
# Generate JSON index (array of kernel filenames)
|
||||
{
|
||||
echo "{"
|
||||
echo " \"kernels\": ["
|
||||
local first=true
|
||||
for kernel in $(printf "%s\n" "${kernels[@]}" | sort -r); do
|
||||
if [[ "$first" == "true" ]]; then
|
||||
first=false
|
||||
else
|
||||
echo ","
|
||||
fi
|
||||
printf " \"%s\"" "$kernel"
|
||||
done
|
||||
echo ""
|
||||
echo " ],"
|
||||
echo " \"updated\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\","
|
||||
echo " \"count\": ${#kernels[@]}"
|
||||
echo "}"
|
||||
} > "$json_index"
|
||||
log_info "Created JSON index: ${json_index}"
|
||||
|
||||
# Upload both index files to S3
|
||||
log_info "Uploading kernel index files to S3..."
|
||||
|
||||
local text_dst="${s3_path}kernels.txt"
|
||||
local json_dst="${s3_path}kernels.json"
|
||||
|
||||
if safe_execute "${mcli_bin}" cp "$text_index" "$text_dst"; then
|
||||
log_info "✓ Uploaded text index: ${text_dst}"
|
||||
else
|
||||
log_warn "Failed to upload text index"
|
||||
fi
|
||||
|
||||
if safe_execute "${mcli_bin}" cp "$json_index" "$json_dst"; then
|
||||
log_info "✓ Uploaded JSON index: ${json_dst}"
|
||||
else
|
||||
log_warn "Failed to upload JSON index"
|
||||
fi
|
||||
|
||||
log_info "Kernel index generation complete"
|
||||
}
|
||||
|
||||
# Build and install modules in container for proper dependency resolution
|
||||
|
||||
@@ -218,13 +218,9 @@ build_from_args=()
|
||||
|
||||
if in_container; then
|
||||
# Run directly when already inside the dev/build container
|
||||
if [[ "$run_tests" -eq 1 ]]; then
|
||||
log "Including boot tests (in-container)"
|
||||
DEBUG=1 "${PROJECT_ROOT}/scripts/build.sh" "${build_from_args[@]}" "${extra_args[@]}"
|
||||
else
|
||||
log "Skipping boot tests (in-container)"
|
||||
DEBUG=1 "${PROJECT_ROOT}/scripts/build.sh" --skip-tests "${build_from_args[@]}" "${extra_args[@]}"
|
||||
fi
|
||||
# Note: Tests are run separately using runit.sh, not during build
|
||||
log "Running rebuild (in-container) - use runit.sh for testing"
|
||||
DEBUG=1 "${PROJECT_ROOT}/scripts/build.sh" "${build_from_args[@]}" "${extra_args[@]}"
|
||||
else
|
||||
# Not in container: delegate to dev-container manager which ensures container exists and is running
|
||||
devctl="${PROJECT_ROOT}/scripts/dev-container.sh"
|
||||
@@ -234,11 +230,7 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$run_tests" -eq 1 ]]; then
|
||||
log "Including boot tests via dev-container"
|
||||
"$devctl" build "${build_from_args[@]}" "${extra_args[@]}"
|
||||
else
|
||||
log "Skipping boot tests via dev-container"
|
||||
"$devctl" build --skip-tests "${build_from_args[@]}" "${extra_args[@]}"
|
||||
fi
|
||||
# Note: Tests are run separately using runit.sh, not during build
|
||||
log "Running rebuild via dev-container - use runit.sh for testing"
|
||||
"$devctl" build "${build_from_args[@]}" "${extra_args[@]}"
|
||||
fi
|
||||
@@ -109,7 +109,7 @@ section "Packing directory to flist"
|
||||
log_info "Source path: ${SRC_PATH}"
|
||||
log_info "Manifest: ${MANIFEST_PATH}"
|
||||
log_info "Store: ${RFS_S3_STORE_URI}"
|
||||
safe_execute "${RFS_BIN}" pack --debug -m "${MANIFEST_PATH}" -s "${RFS_S3_STORE_URI}" "${SRC_PATH}"
|
||||
safe_execute "${RFS_BIN}" --debug pack -m "${MANIFEST_PATH}" -s "${RFS_S3_STORE_URI}" "${SRC_PATH}"
|
||||
|
||||
section "Patching route.url in manifest to S3 read-only endpoint"
|
||||
rfs_common_build_route_url
|
||||
|
||||
Reference in New Issue
Block a user