Add Debian packaging support with cargo-deb
- Add cargo-deb metadata to socktop and socktop_agent Cargo.toml - Create systemd service file for socktop_agent - Add postinst/postrm maintainer scripts for user/group management - Create GitHub Actions workflow to build .deb packages for AMD64 and ARM64 - Add comprehensive documentation in docs/DEBIAN_PACKAGING.md - Packages will be available as artifacts on every push - Automatic GitHub releases for version tags
This commit is contained in:
parent
518ae8c2bf
commit
350611b3b1
180
.github/workflows/build-deb.yml
vendored
Normal file
180
.github/workflows/build-deb.yml
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
name: Build Debian Packages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- feature/debian-packaging
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build-deb:
|
||||
name: Build .deb for ${{ matrix.target }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
arch: amd64
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
arch: arm64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: Install cargo-deb
|
||||
run: cargo install cargo-deb
|
||||
|
||||
- name: Install cross-compilation tools (ARM64)
|
||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
|
||||
- name: Configure cross-compilation (ARM64)
|
||||
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
||||
run: |
|
||||
mkdir -p .cargo
|
||||
cat >> .cargo/config.toml << EOF
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
EOF
|
||||
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo index
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache target directory
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: target
|
||||
key: ${{ runner.os }}-target-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Build socktop .deb package
|
||||
run: |
|
||||
cargo deb --package socktop --target ${{ matrix.target }} --no-strip
|
||||
|
||||
- name: Build socktop_agent .deb package
|
||||
run: |
|
||||
cargo deb --package socktop_agent --target ${{ matrix.target }} --no-strip
|
||||
|
||||
- name: Rename packages with architecture
|
||||
run: |
|
||||
mkdir -p debs
|
||||
cp target/${{ matrix.target }}/debian/*.deb debs/
|
||||
cd debs
|
||||
for deb in *.deb; do
|
||||
# Extract package info
|
||||
pkg_name=$(echo $deb | cut -d_ -f1)
|
||||
version=$(echo $deb | cut -d_ -f2)
|
||||
# Rename to include arch
|
||||
mv "$deb" "${pkg_name}_${version}_${{ matrix.arch }}.deb"
|
||||
done
|
||||
|
||||
- name: List generated packages
|
||||
run: ls -lh debs/
|
||||
|
||||
- name: Upload .deb packages as artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debian-packages-${{ matrix.arch }}
|
||||
path: debs/*.deb
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
|
||||
# Combine all artifacts into a single downloadable archive
|
||||
combine-artifacts:
|
||||
name: Combine all .deb packages
|
||||
needs: build-deb
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download AMD64 packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: debian-packages-amd64
|
||||
path: all-debs
|
||||
|
||||
- name: Download ARM64 packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: debian-packages-arm64
|
||||
path: all-debs
|
||||
|
||||
- name: List all packages
|
||||
run: |
|
||||
echo "All generated .deb packages:"
|
||||
ls -lh all-debs/
|
||||
|
||||
- name: Upload combined artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: all-debian-packages
|
||||
path: all-debs/*.deb
|
||||
if-no-files-found: error
|
||||
retention-days: 90
|
||||
|
||||
- name: Generate checksums
|
||||
run: |
|
||||
cd all-debs
|
||||
sha256sum *.deb > SHA256SUMS
|
||||
cat SHA256SUMS
|
||||
|
||||
- name: Upload checksums
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: checksums
|
||||
path: all-debs/SHA256SUMS
|
||||
retention-days: 90
|
||||
|
||||
# Optional: Create a release with the .deb files if this is a tag
|
||||
create-release:
|
||||
name: Create GitHub Release
|
||||
needs: combine-artifacts
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download all packages
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: all-debian-packages
|
||||
path: release-debs
|
||||
|
||||
- name: Download checksums
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: checksums
|
||||
path: release-debs
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: release-debs/*
|
||||
draft: false
|
||||
prerelease: false
|
||||
generate_release_notes: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
274
docs/DEBIAN_PACKAGING.md
Normal file
274
docs/DEBIAN_PACKAGING.md
Normal file
@ -0,0 +1,274 @@
|
||||
# Debian Packaging for socktop
|
||||
|
||||
This document describes how to build and use Debian packages for socktop and socktop_agent.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Install `cargo-deb`:
|
||||
|
||||
```bash
|
||||
cargo install cargo-deb
|
||||
```
|
||||
|
||||
## Building Packages Locally
|
||||
|
||||
### Build for your current architecture (x86_64)
|
||||
|
||||
```bash
|
||||
# Build socktop TUI client
|
||||
cargo deb --package socktop
|
||||
|
||||
# Build socktop_agent daemon
|
||||
cargo deb --package socktop_agent
|
||||
```
|
||||
|
||||
The `.deb` files will be created in `target/debian/`.
|
||||
|
||||
### Cross-compile for ARM64 (Raspberry Pi, etc.)
|
||||
|
||||
First, install cross-compilation tools:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
```
|
||||
|
||||
Add the ARM64 target:
|
||||
|
||||
```bash
|
||||
rustup target add aarch64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
Configure the linker by creating `.cargo/config.toml`:
|
||||
|
||||
```toml
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
```
|
||||
|
||||
Build the packages:
|
||||
|
||||
```bash
|
||||
# Build for ARM64
|
||||
cargo deb --package socktop --target aarch64-unknown-linux-gnu
|
||||
cargo deb --package socktop_agent --target aarch64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
## Installing Packages
|
||||
|
||||
### Install socktop TUI client
|
||||
|
||||
```bash
|
||||
sudo dpkg -i socktop_*.deb
|
||||
```
|
||||
|
||||
### Install socktop_agent daemon
|
||||
|
||||
```bash
|
||||
sudo dpkg -i socktop_agent_*.deb
|
||||
```
|
||||
|
||||
The agent package will:
|
||||
- Create a `socktop` system user and group
|
||||
- Install the binary to `/usr/bin/socktop_agent`
|
||||
- Install a systemd service file (disabled by default)
|
||||
- Create `/var/lib/socktop` for state files
|
||||
|
||||
### Enable and start the agent service
|
||||
|
||||
```bash
|
||||
# Enable to start on boot
|
||||
sudo systemctl enable socktop-agent
|
||||
|
||||
# Start the service
|
||||
sudo systemctl start socktop-agent
|
||||
|
||||
# Check status
|
||||
sudo systemctl status socktop-agent
|
||||
```
|
||||
|
||||
### Configure the agent
|
||||
|
||||
Edit the systemd service to customize settings:
|
||||
|
||||
```bash
|
||||
sudo systemctl edit socktop-agent
|
||||
```
|
||||
|
||||
Add configuration in the override section:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
Environment=SOCKTOP_PORT=8080
|
||||
Environment=SOCKTOP_TOKEN=your-secret-token
|
||||
Environment=RUST_LOG=info
|
||||
```
|
||||
|
||||
Then restart:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart socktop-agent
|
||||
```
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
The project includes a GitHub Actions workflow (`.github/workflows/build-deb.yml`) that automatically builds `.deb` packages for both x86_64 and ARM64 architectures on every push to master or when tags are created.
|
||||
|
||||
### Downloading pre-built packages
|
||||
|
||||
1. Go to the [Actions tab](https://github.com/jasonwitty/socktop/actions)
|
||||
2. Click on the latest "Build Debian Packages" workflow run
|
||||
3. Download the artifacts:
|
||||
- `debian-packages-amd64` - x86_64 packages
|
||||
- `debian-packages-arm64` - ARM64 packages
|
||||
- `all-debian-packages` - All packages combined
|
||||
- `checksums` - SHA256 checksums
|
||||
|
||||
### Release packages
|
||||
|
||||
When you create a git tag starting with `v` (e.g., `v1.50.0`), the workflow will automatically create a GitHub Release with all `.deb` packages attached.
|
||||
|
||||
```bash
|
||||
git tag v1.50.0
|
||||
git push origin v1.50.0
|
||||
```
|
||||
|
||||
## Package Details
|
||||
|
||||
### socktop package
|
||||
|
||||
- **Binary**: `/usr/bin/socktop`
|
||||
- **Documentation**: `/usr/share/doc/socktop/`
|
||||
- **Size**: ~5-8 MB (depends on architecture)
|
||||
|
||||
### socktop_agent package
|
||||
|
||||
- **Binary**: `/usr/bin/socktop_agent`
|
||||
- **Service**: `socktop-agent.service`
|
||||
- **User/Group**: `socktop`
|
||||
- **State directory**: `/var/lib/socktop`
|
||||
- **Config directory**: `/etc/socktop` (created but empty by default)
|
||||
- **Documentation**: `/usr/share/doc/socktop_agent/`
|
||||
- **Size**: ~5-8 MB (depends on architecture)
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
# Remove packages but keep configuration
|
||||
sudo apt remove socktop socktop_agent
|
||||
|
||||
# Remove packages and all configuration (purge)
|
||||
sudo apt purge socktop socktop_agent
|
||||
```
|
||||
|
||||
When purging `socktop_agent`, the following are removed:
|
||||
- The `socktop` user and group
|
||||
- `/var/lib/socktop` directory
|
||||
- Empty `/etc/socktop` directory (if empty)
|
||||
|
||||
## Verifying Packages
|
||||
|
||||
Check package contents:
|
||||
|
||||
```bash
|
||||
dpkg -c socktop_*.deb
|
||||
dpkg -c socktop_agent_*.deb
|
||||
```
|
||||
|
||||
Check package information:
|
||||
|
||||
```bash
|
||||
dpkg -I socktop_*.deb
|
||||
dpkg -I socktop_agent_*.deb
|
||||
```
|
||||
|
||||
After installation, verify files:
|
||||
|
||||
```bash
|
||||
dpkg -L socktop
|
||||
dpkg -L socktop-agent
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Service fails to start
|
||||
|
||||
Check logs:
|
||||
|
||||
```bash
|
||||
sudo journalctl -u socktop-agent -f
|
||||
```
|
||||
|
||||
Verify the socktop user exists:
|
||||
|
||||
```bash
|
||||
id socktop
|
||||
```
|
||||
|
||||
### Permission issues
|
||||
|
||||
Ensure the state directory has correct permissions:
|
||||
|
||||
```bash
|
||||
sudo chown -R socktop:socktop /var/lib/socktop
|
||||
sudo chmod 755 /var/lib/socktop
|
||||
```
|
||||
|
||||
### Missing dependencies
|
||||
|
||||
If installation fails due to missing dependencies:
|
||||
|
||||
```bash
|
||||
sudo apt --fix-broken install
|
||||
```
|
||||
|
||||
## Creating a Local APT Repository (Advanced)
|
||||
|
||||
To create your own APT repository for easy installation:
|
||||
|
||||
1. Install required tools:
|
||||
```bash
|
||||
sudo apt install dpkg-dev
|
||||
```
|
||||
|
||||
2. Create repository structure:
|
||||
```bash
|
||||
mkdir -p ~/socktop-repo/pool/main
|
||||
cp *.deb ~/socktop-repo/pool/main/
|
||||
```
|
||||
|
||||
3. Generate package index:
|
||||
```bash
|
||||
cd ~/socktop-repo
|
||||
dpkg-scanpackages pool/main /dev/null | gzip -9c > pool/main/Packages.gz
|
||||
```
|
||||
|
||||
4. Serve via HTTP (for testing):
|
||||
```bash
|
||||
cd ~/socktop-repo
|
||||
python3 -m http.server 8000
|
||||
```
|
||||
|
||||
5. Add to sources on client machines:
|
||||
```bash
|
||||
echo "deb [trusted=yes] http://your-server:8000 pool/main/" | \
|
||||
sudo tee /etc/apt/sources.list.d/socktop.list
|
||||
sudo apt update
|
||||
sudo apt install socktop socktop-agent
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
When adding new features that affect packaging:
|
||||
|
||||
1. Update `Cargo.toml` metadata in the `[package.metadata.deb]` section
|
||||
2. Add new assets to the `assets` array if needed
|
||||
3. Update maintainer scripts in `socktop_agent/debian/` if needed
|
||||
4. Test package building locally before committing
|
||||
5. Update this documentation
|
||||
|
||||
## References
|
||||
|
||||
- [cargo-deb documentation](https://github.com/kornelski/cargo-deb)
|
||||
- [Debian Policy Manual](https://www.debian.org/doc/debian-policy/)
|
||||
- [systemd service files](https://www.freedesktop.org/software/systemd/man/systemd.service.html)
|
||||
@ -6,6 +6,8 @@ description = "Remote system monitor over WebSocket, TUI like top"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
homepage = "https://github.com/jasonwitty/socktop"
|
||||
repository = "https://github.com/jasonwitty/socktop"
|
||||
|
||||
[dependencies]
|
||||
# socktop connector for agent communication
|
||||
@ -25,3 +27,20 @@ sysinfo = { workspace = true }
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2.0"
|
||||
tempfile = "3"
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "Jason Witty <jasonpwitty+socktop@proton.me>"
|
||||
copyright = "2024, Jason Witty <jasonpwitty+socktop@proton.me>"
|
||||
license-file = ["../LICENSE", "4"]
|
||||
extended-description = """\
|
||||
socktop is a remote system monitor with a rich terminal user interface (TUI) \
|
||||
that connects to remote hosts running the socktop_agent over WebSocket. \
|
||||
It provides real-time monitoring of CPU, memory, processes, and more with \
|
||||
an interface similar to the traditional 'top' command."""
|
||||
depends = "$auto"
|
||||
section = "admin"
|
||||
priority = "optional"
|
||||
assets = [
|
||||
["target/release/socktop", "usr/bin/", "755"],
|
||||
["../README.md", "usr/share/doc/socktop/", "644"],
|
||||
]
|
||||
|
||||
@ -6,6 +6,8 @@ description = "Socktop agent daemon. Serves host metrics over WebSocket."
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
homepage = "https://github.com/jasonwitty/socktop"
|
||||
repository = "https://github.com/jasonwitty/socktop"
|
||||
|
||||
[dependencies]
|
||||
# Tokio: Use minimal features instead of "full" to reduce binary size
|
||||
@ -45,3 +47,21 @@ protoc-bin-vendored = "3"
|
||||
assert_cmd = "2.0"
|
||||
tempfile = "3.10"
|
||||
tokio-tungstenite = "0.21"
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "Jason Witty <jasonpwitty+socktop@proton.me>"
|
||||
copyright = "2024, Jason Witty <jasonpwitty+socktop@proton.me>"
|
||||
license-file = ["../LICENSE", "4"]
|
||||
extended-description = """\
|
||||
socktop_agent is the daemon component that runs on remote hosts to collect \
|
||||
and serve system metrics over WebSocket. It gathers CPU, memory, disk, network, \
|
||||
GPU, and process information that can be monitored remotely by the socktop TUI client."""
|
||||
depends = "$auto"
|
||||
section = "admin"
|
||||
priority = "optional"
|
||||
assets = [
|
||||
["target/release/socktop_agent", "usr/bin/", "755"],
|
||||
["../README.md", "usr/share/doc/socktop_agent/", "644"],
|
||||
]
|
||||
maintainer-scripts = "debian/"
|
||||
systemd-units = { unit-name = "socktop-agent", unit-scripts = ".", enable = false }
|
||||
|
||||
26
socktop_agent/debian/postinst
Executable file
26
socktop_agent/debian/postinst
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Create socktop user and group if they don't exist
|
||||
if ! getent group socktop >/dev/null; then
|
||||
addgroup --system socktop
|
||||
fi
|
||||
|
||||
if ! getent passwd socktop >/dev/null; then
|
||||
adduser --system --ingroup socktop --home /var/lib/socktop \
|
||||
--no-create-home --disabled-password --disabled-login \
|
||||
--gecos "Socktop Agent" socktop
|
||||
fi
|
||||
|
||||
# Create state directory
|
||||
mkdir -p /var/lib/socktop
|
||||
chown socktop:socktop /var/lib/socktop
|
||||
chmod 755 /var/lib/socktop
|
||||
|
||||
# Create config directory if it doesn't exist
|
||||
mkdir -p /etc/socktop
|
||||
chmod 755 /etc/socktop
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
34
socktop_agent/debian/postrm
Executable file
34
socktop_agent/debian/postrm
Executable file
@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
purge)
|
||||
# Remove user and group on purge
|
||||
if getent passwd socktop >/dev/null; then
|
||||
deluser --quiet socktop || true
|
||||
fi
|
||||
|
||||
if getent group socktop >/dev/null; then
|
||||
delgroup --quiet socktop || true
|
||||
fi
|
||||
|
||||
# Remove state directory on purge
|
||||
rm -rf /var/lib/socktop
|
||||
|
||||
# Remove config directory if empty
|
||||
rmdir --ignore-fail-on-non-empty /etc/socktop 2>/dev/null || true
|
||||
;;
|
||||
|
||||
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
# Do nothing on remove/upgrade
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
27
socktop_agent/socktop-agent.service
Normal file
27
socktop_agent/socktop-agent.service
Normal file
@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=Socktop Agent - Remote System Monitor
|
||||
Documentation=https://github.com/jasonwitty/socktop
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/socktop_agent --port 3000
|
||||
Environment=RUST_LOG=info
|
||||
# Optional authentication token:
|
||||
# Environment=SOCKTOP_TOKEN=changeme
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=socktop
|
||||
Group=socktop
|
||||
NoNewPrivileges=true
|
||||
|
||||
# Security hardening
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/var/lib/socktop
|
||||
StateDirectory=socktop
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Loading…
Reference in New Issue
Block a user