Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/pack-build-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,11 @@ jobs:
- name: Check compilation
working-directory: pack
run: cargo check --all-targets --all-features

- name: Run tests
working-directory: pack
run: cargo test --all-features

- name: Run tests
working-directory: pack
run: cargo test --all-features
42 changes: 42 additions & 0 deletions .github/workflows/pack-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,45 @@ jobs:
name: "PACK v${{ inputs.version }}"
generate_release_notes: true
make_latest: true

build-and-push:
needs: [ release ]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4

- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0

- name: Log in to GitHub Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: ghcr.io/${{ github.repository_owner }}/pack
tags: |
type=raw,value=${{ inputs.version }}
type=raw,value=latest

- name: Build and push Docker image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: ./pack
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
21 changes: 21 additions & 0 deletions pack/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM registry.suse.com/bci/rust:latest AS builder

WORKDIR /app

# Copy manifests first — dependencies built separately for layer caching
COPY Cargo.toml Cargo.lock* ./
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release
RUN rm src/main.rs

# Build with real source
COPY src ./src
RUN touch src/main.rs && cargo build --release

FROM registry.suse.com/bci/bci-micro:latest

COPY --from=builder /app/target/release/pack /usr/local/bin/pack

RUN chmod 1777 /tmp

ENTRYPOINT ["/usr/local/bin/pack"]
69 changes: 23 additions & 46 deletions pack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A blazingly fast 🦀 Rust-powered tool that collects arbitrary host paths and a
🔒 **Read-Only by Design** - Input paths are always mounted read-only in container mode
🐳 **Container Ready** - Runs as a privileged container with explicit host path mounts and SELinux support
⚙️ **Env Var Support** - Every flag has a `PACK_*` env var equivalent for Ansible-driven automation
🔌 **stack-validation Native** - Output naming and archive format designed to plug directly into existing Ansible upload pipelines
📤 **Upload Ready** - Produces a single self-contained archive ready for sharing with support engineers
🦀 **Fast & Safe** - Built with Rust for reliable, predictable behaviour under privileged execution

## 🚀 Quick Start
Expand Down Expand Up @@ -45,21 +45,6 @@ podman run --rm --privileged \

**Note:** Each input path must be explicitly bind-mounted into the container with `:ro`. The output directory must be mounted with write access. The `:Z` flag may be required on SELinux systems — see the [SELinux note](#-troubleshooting) below.

### Building Custom Container Image

```bash
# Build the container image
podman build -t pack:custom .

# Run your custom image
podman run --rm --privileged \
-v /var/lib/rancher/rke2/server/db/etcd:/var/lib/rancher/rke2/server/db/etcd:ro \
-v /tmp:/tmp \
pack:custom \
--paths /var/lib/rancher/rke2/server/db/etcd \
--output /tmp
```

### Installation from Source

**Prerequisites:**
Expand Down Expand Up @@ -126,8 +111,6 @@ pack_logs_2025-11-12_14-30-00/
└── collection-summary.yaml
```

The `_logs_` infix in the archive name is intentional — it allows the existing `nessie_upload_logs.yaml` Ansible playbook in stack-validation to pick up PACK archives with its `*logs*.tar.gz` glob without any changes.

## 🏗️ Architecture

```
Expand Down Expand Up @@ -164,30 +147,6 @@ The `_logs_` infix in the archive name is intentional — it allows the existing
pack_logs_<timestamp>.tar.gz
┌─────────────────────────────┼───────────────────────────────────┐
│ ANSIBLE / stack-validation │
│ │ │
│ ┌───────────────────────────▼───────────────────────────────┐ │
│ │ pack_collect.yaml │ │
│ │ podman run --privileged │ │
│ │ -v /host/path:/host/path:ro (per input path) │ │
│ │ -v /tmp:/tmp (output, rw) │ │
│ │ │ │
│ │ sed rename → │ │
│ │ pack_<CLUSTER><CLUSTER_SUFFIX>_logs_<timestamp> │ │
│ └───────────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼───────────────────────────────┐ │
│ │ nessie_upload_logs.yaml (reused as-is) │ │
│ │ glob: *logs*.tar.gz · WebDAV PUT │ │
│ └───────────────────────────┬───────────────────────────────┘ │
│ │ │
└─────────────────────────────┼───────────────────────────────────┘
WebDAV server
/pipelines/<id>/logs/
```

## 💡 Common Use Cases
Expand Down Expand Up @@ -269,9 +228,28 @@ src/
-v /tmp:/tmp:Z
```

**📦 Archive not picked up by upload playbook**
- Verify the archive name contains `_logs_` — this is required by the `nessie_upload_logs.yaml` glob
- Check the output directory matches `log_source_dir` passed to the upload playbook
## 🚢 Releasing

PACK uses a manual release workflow via GitHub Actions.

To create a new release:

1. Go to **Actions** → **PACK: Release** → **Run workflow**
2. Enter the version number in semver format (e.g., `1.0.0`)
3. The workflow will:
* Run build checks (formatting, clippy, compilation, tests)
* Validate the version format and ensure the tag doesn't already exist
* Create a GitHub Release with tag `pack-v<version>` and auto-generated release notes
* Build and push a multi-arch container image to `ghcr.io/<org>/pack:<version>` and `:latest`

### Container Image Tags

| When | Image Tags |
|------|------------|
| Release `1.0.0` triggered | `ghcr.io/<org>/pack:1.0.0`, `ghcr.io/<org>/pack:latest` |
| Release `1.1.0` triggered | `ghcr.io/<org>/pack:1.1.0`, `ghcr.io/<org>/pack:latest` |

The `:latest` tag always points to the most recent release.

## 📄 License

Expand All @@ -282,7 +260,6 @@ This project is part of the SUSE Edge Support Tools collection.
## 🙏 Acknowledgments

- 🦀 Built with **Rust** for performance and safety
- 🔌 Designed to integrate natively with **stack-validation** Ansible pipelines
- 📦 Keeping it simple, one archive at a time

---
Expand Down
14 changes: 8 additions & 6 deletions pack/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ mod archive;
mod collector;

#[derive(Parser, Debug)]
#[command(
name = "pack",
about = "Path Archiver Collection Kit",
version
)]
#[command(name = "pack", about = "Path Archiver Collection Kit", version)]
struct Args {
/// Comma-separated list of host paths to collect
#[arg(short, long, env = "PACK_PATHS", value_delimiter = ',', required = true)]
#[arg(
short,
long,
env = "PACK_PATHS",
value_delimiter = ',',
required = true
)]
paths: Vec<String>,

/// Output directory for the archive
Expand Down
Loading