diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..b523724 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" +runner = "qemu-aarch64-static" + +[env] +CC_aarch64_unknown_linux_gnu = "aarch64-linux-gnu-gcc" +CXX_aarch64_unknown_linux_gnu = "aarch64-linux-gnu-g++" +AR_aarch64_unknown_linux_gnu = "aarch64-linux-gnu-ar" diff --git a/.github/Dockerfile b/.github/Dockerfile new file mode 100644 index 0000000..68a37e2 --- /dev/null +++ b/.github/Dockerfile @@ -0,0 +1,26 @@ +# podman build -t quay.io/jbride2000/rust:1.90.0-trixie-tools -f .github/Dockerfile . + +FROM rust:1.90.0-trixie + +# Install Rust components +RUN rustup component add rustfmt clippy + +# Install ARM64 cross-compilation toolchain and system dependencies +RUN dpkg --add-architecture arm64 && \ + apt-get update && apt-get install -y \ + gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu \ + libudev-dev \ + libudev-dev:arm64 \ + libssl-dev:arm64 \ + pkg-config \ + && rm -rf /var/lib/apt/lists/* + +# Add ARM64 target for Rust +RUN rustup target add aarch64-unknown-linux-gnu + +# Set up cross-compilation environment +ENV CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc +ENV CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ +ENV AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc diff --git a/.github/ci-runner.sh b/.github/ci-runner.sh new file mode 100755 index 0000000..0b077e3 --- /dev/null +++ b/.github/ci-runner.sh @@ -0,0 +1,161 @@ +#!/bin/bash + +# CI runner script that can be used both locally and in GitHub Actions +# Supports hybrid approach: Podman containers + ARM SSH deployment +set -e + +# Default values +WORKSPACE_DIR="${WORKSPACE_DIR:-$(pwd)}" +RUST_IMAGE="${RUST_IMAGE:-quay.io/jbride2000/rust:1.90.0-trixie-tools}" +CACHE_MOUNTS="${CACHE_MOUNTS:-true}" +TARGET_ARCH="${TARGET_ARCH:-}" +HYBRID_MODE="${HYBRID_MODE:-false}" +ARM_HOST="${ARM_HOST:-}" +ARM_USER="${ARM_USER:-}" +SKIP_CLIPPY="${SKIP_CLIPPY:-false}" + +# Function to run a command in the container +run_in_container() { + local cmd="$1" + local description="$2" + + echo "Running: $description" + + # Add target architecture if specified + local target_cmd="$cmd" + if [ -n "$TARGET_ARCH" ]; then + # Set pkg-config for ARM64 cross-compilation + if [ "$TARGET_ARCH" = "aarch64-unknown-linux-gnu" ]; then + target_cmd="export PKG_CONFIG_ALLOW_CROSS=1 PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig PKG_CONFIG_LIBDIR=/usr/lib/aarch64-linux-gnu/pkgconfig && rustup target add $TARGET_ARCH && $cmd --target $TARGET_ARCH" + else + target_cmd="rustup target add $TARGET_ARCH && $cmd --target $TARGET_ARCH" + fi + fi + + if [ "$CACHE_MOUNTS" = "true" ]; then + podman run --rm \ + -v "$WORKSPACE_DIR":/workspace:Z \ + -w /workspace \ + --mount=type=volume,source=cargo-registry,target=/usr/local/cargo/registry \ + --mount=type=volume,source=cargo-git,target=/usr/local/cargo/git \ + --mount=type=volume,source=cargo-target,target=/workspace/target \ + "$RUST_IMAGE" \ + bash -c "$target_cmd" + else + podman run --rm \ + -v "$WORKSPACE_DIR":/workspace:Z \ + -w /workspace \ + "$RUST_IMAGE" \ + bash -c "$target_cmd" + fi +} + +# Function to deploy to ARM hardware +deploy_to_arm() { + local binary_path="$1" + + if [ "$HYBRID_MODE" = "false" ] || [ -z "$ARM_HOST" ] || [ -z "$ARM_USER" ]; then + echo "Skipping ARM deployment (not in hybrid mode or missing ARM config)" + return 0 + fi + + echo "๐Ÿš€ Deploying to ARM hardware..." + + # Check if deployment script exists + if [ ! -f "scripts/local_ci/deploy-to-arm.sh" ]; then + echo "โŒ ARM deployment script not found" + return 1 + fi + + # Run ARM deployment + chmod +x scripts/local_ci/deploy-to-arm.sh + ./scripts/local_ci/deploy-to-arm.sh \ + --host "$ARM_HOST" \ + --user "$ARM_USER" \ + --binary "$binary_path" \ + --test-mode +} + +# Parse command line arguments +case "${1:-all}" in + "fmt") + run_in_container "cargo fmt --all -- --check" "formatting check" + ;; + "clippy") + if [ "$SKIP_CLIPPY" = "true" ]; then + echo "โญ๏ธ Skipping clippy check (SKIP_CLIPPY=true)" + else + run_in_container "cargo clippy --all-targets --all-features -- -D warnings" "clippy check" + fi + ;; + "build") + run_in_container "cargo build --verbose" "build" + ;; + "build-release") + run_in_container "cargo build --release --verbose" "release build" + ;; + "test") + run_in_container "cargo test --verbose" "tests" + ;; + "test-release") + run_in_container "cargo test --release --verbose" "release tests" + ;; + "all") + run_in_container "cargo fmt --all -- --check" "formatting check" + if [ "$SKIP_CLIPPY" = "true" ]; then + echo "โญ๏ธ Skipping clippy check (SKIP_CLIPPY=true)" + else + run_in_container "cargo clippy --all-targets --all-features -- -D warnings" "clippy check" + fi + run_in_container "cargo build --verbose" "build" + run_in_container "cargo test --verbose" "tests" + ;; + "hybrid") + echo "๐Ÿ”„ Running hybrid CI (containers + ARM deployment)..." + + # Step 1: Container-based checks + run_in_container "cargo fmt --all -- --check" "formatting check" + if [ "$SKIP_CLIPPY" = "true" ]; then + echo "โญ๏ธ Skipping clippy check (SKIP_CLIPPY=true)" + else + run_in_container "cargo clippy --all-targets --all-features -- -D warnings" "clippy check" + fi + + # Step 2: Cross-compile for ARM64 + TARGET_ARCH=aarch64-unknown-linux-gnu + run_in_container "cargo build --release --verbose" "ARM64 release build" + + # Step 3: Deploy to ARM hardware + if [ -n "$TARGET_ARCH" ]; then + binary_path="$WORKSPACE_DIR/target/$TARGET_ARCH/release/mujina-minerd" + else + binary_path="$WORKSPACE_DIR/target/release/mujina-minerd" + fi + + deploy_to_arm "$binary_path" + ;; + *) + echo "Usage: $0 [fmt|clippy|build|build-release|test|test-release|all|hybrid]" + echo "" + echo "Commands:" + echo " fmt Check formatting" + echo " clippy Run clippy lints" + echo " build Build debug version" + echo " build-release Build release version" + echo " test Run tests" + echo " test-release Run release tests" + echo " all Run all checks" + echo " hybrid Run hybrid CI (containers + ARM deployment)" + echo "" + echo "Environment variables:" + echo " WORKSPACE_DIR: Directory to mount (default: current directory)" + echo " RUST_IMAGE: Rust container image (default: quay.io/jbride2000/rust:1.90.0-trixie-tools)" + echo " TARGET_ARCH: Target architecture (e.g., aarch64-unknown-linux-gnu)" + echo " CACHE_MOUNTS: Enable cache mounts (default: true)" + echo " SKIP_CLIPPY: Skip clippy lints (default: false)" + echo " HYBRID_MODE: Enable ARM deployment (default: false)" + echo " ARM_HOST: ARM64 host IP address" + echo " ARM_USER: SSH username for ARM host" + exit 1 + ;; +esac diff --git a/.github/workflows/hybrid-ci.yml b/.github/workflows/hybrid-ci.yml new file mode 100644 index 0000000..46e0104 --- /dev/null +++ b/.github/workflows/hybrid-ci.yml @@ -0,0 +1,111 @@ +name: Hybrid CI (Podman + Native ARM64) + +on: + push: + branches: [ main, master, preview, gh_actions] + pull_request: + branches: [ main, master, preview, gh_actions ] + workflow_dispatch: + inputs: + run_container_ci: + description: "Run container CI" + type: boolean + default: true + skip_clippy: + description: "Skip clippy lints" + type: boolean + default: false + run_arm64: + description: "Run ARM64 native test" + type: boolean + default: false + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + # Fast checks using Podman containers on GitHub's x86_64 runners + container-ci: + name: Container CI (x86_64) + # https://github.com/actions/runner-images?tab=readme-ov-file#available-images + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Podman + run: | + sudo apt-get update + sudo apt-get -y install podman + + - name: Run CI checks in container + run: | + chmod +x .github/ci-runner.sh + ./.github/ci-runner.sh all + env: + WORKSPACE_DIR: ${{ github.workspace }} + RUST_IMAGE: quay.io/jbride2000/rust:1.90.0-trixie-tools + CACHE_MOUNTS: "false" + SKIP_CLIPPY: ${{ github.event.inputs.skip_clippy || 'false' }} + + - name: Cross-compile for ARM64 + run: | + chmod +x .github/ci-runner.sh + TARGET_ARCH=aarch64-unknown-linux-gnu ./.github/ci-runner.sh build-release + env: + WORKSPACE_DIR: ${{ github.workspace }} + RUST_IMAGE: quay.io/jbride2000/rust:1.90.0-trixie-tools + TARGET_ARCH: aarch64-unknown-linux-gnu + CACHE_MOUNTS: "false" + + - name: Upload ARM64 binary + uses: actions/upload-artifact@v4 + with: + name: mujina-minerd-arm64 + path: target/aarch64-unknown-linux-gnu/release/mujina-minerd + + # Native ARM64 testing using GitHub's ARM64 runners + # https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/add-runners + arm64-self-hosted-runner: + name: ARM64 Self-Hosted Runner Test + if: ${{ github.event_name == 'workflow_dispatch' && inputs.run_arm64 }} + runs-on: self-hosted + needs: container-ci + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download ARM64 binary + uses: actions/download-artifact@v4 + with: + name: mujina-minerd-arm64 + path: ./artifacts/ + + - name: Test ARM64 binary natively + run: | + # Test the ARM64 binary on native ARM64 hardware + chmod +x ./artifacts/mujina-minerd + + echo "=== ARM64 Hardware Information ===" + uname -a + cat /proc/cpuinfo | grep -E "(processor|model name|cpu MHz|cache size)" | head -10 + cat /proc/meminfo | head -5 + echo "" + + echo "=== Binary Information ===" + file ./artifacts/mujina-minerd + ldd ./artifacts/mujina-minerd || echo "Static binary or ldd not available" + echo "" + + echo "=== Version Test ===" + ./artifacts/mujina-minerd --version + echo "" + + echo "=== Basic Functionality Test ===" + timeout 30 ./artifacts/mujina-minerd --help || echo "Help command completed" + echo "" + + echo "โœ… ARM64 native testing completed successfully!" diff --git a/.gitignore b/.gitignore index 80faede..67b2fef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ Cargo.lock /target/ +scripts/local_ci/arm-deployment.env diff --git a/docs/hybrid-ci-setup.md b/docs/hybrid-ci-setup.md new file mode 100644 index 0000000..14e100a --- /dev/null +++ b/docs/hybrid-ci-setup.md @@ -0,0 +1,132 @@ +**Hybrid CI Setup Guide** + +This guide explains how to set up and use the hybrid CI system that uses + +## 1. Overview + +The hybrid CI system provides: + +1. **Container-based CI**: Fast, reproducible builds using Podman containers +2. **ARM64 cross-compilation**: Build ARM64 binaries on x86_64 runners +3. **Real hardware testing**: Deploy and test on actual ARM hardware via SSH +4. **Flexible deployment**: Works with GitHub Actions and local development + + +## 2. Github Actions + +This project includes a _workflow_ called [hybrid-ci.yml](../.github/workflows/hybrid-ci.yml) that gets automatically triggered in Github with every commit. +The workflow also allows for manual trigger via the Github UI. + +![GitHub Actions Manual Trigger](images/gh_actions_1.png) + + +Notice in the `hybrid-cli.yml`, configuration exists for specifying the branches that github actions will automatically run on: + + +``` +name: Hybrid CI (Podman + Native ARM64) + +on: + push: + branches: [ main, master, preview, gh_actions] + pull_request: + branches: [ main, master, preview, gh_actions ] +``` + +Modify the list of branches to support your development efforts as necessary. + +### 2.1. Skipping Clippy Tests + +You can skip clippy lints when manually triggering the workflow via the GitHub UI. +(Manual triggering is available only on the `main` branch. +Check the "Skip clippy lints" option when running the workflow manually. By default, clippy is enabled. + +![Clippy Skip](images/clippy_skip.png) + +## 3. Local testing + +This project also includes a [Makefile](../scripts/local_ci/Makefile.ci) that can be run in your local dev environment. +These Makefile commands are for local use only and are not used by GitHub Actions. + +On a x86_64 based development environment, you can use the Makefile for the following: + +1. Full CI checks in containers: + * Formatting check (cargo fmt --all -- --check) + * Clippy lints (cargo clippy --all-targets --all-features -- -D warnings) + * Debug build (cargo build --verbose) + * Tests (cargo test --verbose) + +2. ARM64 cross-compilation + +All compilation and tests occur in a linux container using podman. + +### 3.1. Prerequisites + +- **Podman** + +### 3.2. Execute + +1. OPTIONAL: To skip clippy lints locally, set the `SKIP_CLIPPY` environment variable: + ```bash + export SKIP_CLIPPY=true + ``` + + +2. Execute: + ```bash + make -f scripts/local_ci/Makefile.ci ci-containers-arm64-cross-compilation + ``` + +## 4. Local Setup (ARM64 deploy) + +The CI functionality also allows for deploying and testing cross-compiled mujina to an ARM64 target environment. + +### 4.1. Prerequisites + +- **Podman** installed on your system +- **SSH access** to ARM64 hardware (ie: Raspberry Pi 4) + +### 4.2. Configuration + +Create your ARM deployment configuration: + +```bash +# Copy the template +cp scripts/local_ci/arm-deployment.template scripts/local_ci/arm-deployment.env + +# Edit with your details +vi scripts/local_ci/arm-deployment.env +``` + +### 4.3. Usage + +```bash +make -f scripts/local_ci/Makefile.ci deploy-arm +``` + +### 4.4. Volume Management + +#### 4.4.1. Manual Volume Cleanup + +If you encounter issues with mixed architectures or need to clean up build artifacts, you can manually manage the Podman volumes: + +```bash +# List all volumes +podman volume ls + +# Remove specific CI volumes +podman volume rm cargo-registry cargo-git cargo-target + +# Remove all unused volumes +podman volume prune + +# Force remove all volumes (use with caution) +podman volume rm --all +``` + +#### 4.4.2. Volume Locations + +The CI system uses these volumes: +- `cargo-registry`: Rust package registry cache +- `cargo-git`: Git dependencies cache +- `cargo-target`: Build artifacts cache diff --git a/docs/images/clippy_skip.png b/docs/images/clippy_skip.png new file mode 100644 index 0000000..d54d396 Binary files /dev/null and b/docs/images/clippy_skip.png differ diff --git a/docs/images/gh_actions_1.png b/docs/images/gh_actions_1.png new file mode 100644 index 0000000..2fabdde Binary files /dev/null and b/docs/images/gh_actions_1.png differ diff --git a/mujina-miner/src/bin/minerd.rs b/mujina-miner/src/bin/minerd.rs index fa25f4a..f1f089b 100644 --- a/mujina-miner/src/bin/minerd.rs +++ b/mujina-miner/src/bin/minerd.rs @@ -2,8 +2,37 @@ use mujina_miner::{daemon::Daemon, tracing}; +fn print_help() { + println!("mujina-minerd - Bitcoin mining daemon for Mujina Mining Firmware"); + println!(); + println!("USAGE:"); + println!(" mujina-minerd [OPTIONS]"); + println!(); + println!("OPTIONS:"); + println!(" --help Print this help message"); + println!(); + println!("DESCRIPTION:"); + println!(" A high-performance open-source Bitcoin mining daemon"); +} + #[tokio::main] async fn main() -> anyhow::Result<()> { + // Check for command-line arguments + let args: Vec = std::env::args().collect(); + if args.len() > 1 { + match args[1].as_str() { + "--help" => { + print_help(); + return Ok(()); + } + _ => { + eprintln!("Unknown option: {}", args[1]); + eprintln!("Use --help for usage information"); + std::process::exit(1); + } + } + } + tracing::init_journald_or_stdout(); let daemon = Daemon::new(); diff --git a/scripts/local_ci/Makefile.ci b/scripts/local_ci/Makefile.ci new file mode 100644 index 0000000..bee2253 --- /dev/null +++ b/scripts/local_ci/Makefile.ci @@ -0,0 +1,96 @@ +.PHONY: help build test fmt clippy ci-local hybrid-ci hybrid-ci-arm hybrid-ci-containers clean + +help: ## Show this help message + @echo "Available commands:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +build: ## Build the project + cargo build + +test: ## Run tests + cargo test + +fmt: ## Check formatting + cargo fmt --all -- --check + +fmt-fix: ## Fix formatting + cargo fmt --all + +clippy: ## Run clippy + cargo clippy --all-targets --all-features -- -D warnings + +# Individual CI steps using the shared script +ci-fmt: ## Run formatting check in container + chmod +x .github/ci-runner.sh && ./.github/ci-runner.sh fmt + +ci-clippy: ## Run clippy in container + chmod +x .github/ci-runner.sh && ./.github/ci-runner.sh clippy + +ci-build: ## Build in container + chmod +x .github/ci-runner.sh && ./.github/ci-runner.sh build + +ci-test: ## Run tests in container + chmod +x .github/ci-runner.sh && ./.github/ci-runner.sh test + +## Cross-compile for ARM64 in container +ci-build-arm64: + chmod +x .github/ci-runner.sh && TARGET_ARCH=aarch64-unknown-linux-gnu ./.github/ci-runner.sh build-release + # Copy binary from Podman volume to local filesystem + @mkdir -p target/aarch64-unknown-linux-gnu/release + @podman run --rm \ + -v cargo-target:/workspace/target:Z \ + --entrypoint="" \ + quay.io/jbride2000/rust:1.90.0-trixie-tools \ + cp /workspace/target/aarch64-unknown-linux-gnu/release/mujina-minerd /tmp/mujina-minerd + @podman run --rm \ + -v cargo-target:/workspace/target:Z \ + -v "$(PWD)":/host:Z \ + --entrypoint="" \ + quay.io/jbride2000/rust:1.90.0-trixie-tools \ + cp /workspace/target/aarch64-unknown-linux-gnu/release/mujina-minerd /host/target/aarch64-unknown-linux-gnu/release/mujina-minerd + +# ARM deployment commands +deploy-arm: ci-build-arm64 + @# Check if arm-deployment.env exists, if not check for env vars + @if [ ! -f "scripts/local_ci/arm-deployment.env" ] && ([ -z "$(ARM_HOST)" ] || [ -z "$(ARM_USER)" ]); then \ + echo "Error: Either create scripts/local_ci/arm-deployment.env or set ARM_HOST and ARM_USER environment variables"; \ + echo "Usage: make deploy-arm [ARM_HOST=] [ARM_USER=]"; \ + echo "Or create scripts/local_ci/arm-deployment.env with ARM_HOST and ARM_USER values"; \ + exit 1; \ + fi + @# Use environment variables if provided, otherwise let the script load from arm-deployment.env + @if [ -n "$(ARM_HOST)" ] && [ -n "$(ARM_USER)" ]; then \ + chmod +x scripts/local_ci/deploy-to-arm.sh && ./scripts/local_ci/deploy-to-arm.sh --host $(ARM_HOST) --user $(ARM_USER) --binary target/aarch64-unknown-linux-gnu/release/mujina-minerd --test-mode; \ + else \ + chmod +x scripts/local_ci/deploy-to-arm.sh && ./scripts/local_ci/deploy-to-arm.sh --binary target/aarch64-unknown-linux-gnu/release/mujina-minerd --test-mode; \ + fi + +######################################################### +####### Linux Container (podman) targets ############### +######################################################### + +## Run CI checks locally with Podman +ci-containers: + chmod +x .github/ci-runner.sh && ./.github/ci-runner.sh all + +## Run CI and ARM64 cross-compilation with podman (skip ARM deployment) +ci-containers-arm64-cross-compilation: + chmod +x scripts/local_ci/hybrid-ci-local.sh && ./scripts/local_ci/hybrid-ci-local.sh --skip-arm + +## Run hybrid CI (containers + ARM SSH) locally +ci-containers-arm64-deploy: + chmod +x scripts/local_ci/hybrid-ci-local.sh && ./scripts/local_ci/hybrid-ci-local.sh + +## Run hybrid CI with ARM deployment (requires ARM_HOST and ARM_USER env vars) +ci-containers-arm64-deploy-env-vars: + @if [ -z "$(ARM_HOST)" ] || [ -z "$(ARM_USER)" ]; then \ + echo "Error: ARM_HOST and ARM_USER environment variables must be set"; \ + echo "Usage: make hybrid-ci-arm ARM_HOST= ARM_USER="; \ + exit 1; \ + fi + chmod +x scripts/local_ci/hybrid-ci-local.sh && ./scripts/local_ci/hybrid-ci-local.sh --arm-host $(ARM_HOST) --arm-user $(ARM_USER) + + +clean: ## Clean build artifacts + cargo clean + podman rmi mujina-ci:latest mujina-dev:latest 2>/dev/null || true diff --git a/scripts/local_ci/arm-deployment.template b/scripts/local_ci/arm-deployment.template new file mode 100644 index 0000000..abc50a3 --- /dev/null +++ b/scripts/local_ci/arm-deployment.template @@ -0,0 +1,23 @@ +# Local ARM deployment environment template (local-only) + +# ARM host IP or hostname +ARM_HOST=192.168.1.100 + +# SSH username for the ARM host +ARM_USER=pi + +# Optional: SSH private key path +# SSH_KEY=/path/to/your/private/key + +# Optional: SSH passphrase automation (choose one method) +# Method 1: Use ssh-agent (recommended) +# ssh-add /path/to/your/private/key +# Method 2: Use SSH_ASKPASS program +# SSH_ASKPASS=/path/to/askpass/program + +# Optional: SSH port +# SSH_PORT=22 + +# Optional: Custom SSH options +# SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" + diff --git a/scripts/local_ci/deploy-to-arm.sh b/scripts/local_ci/deploy-to-arm.sh new file mode 100755 index 0000000..606c141 --- /dev/null +++ b/scripts/local_ci/deploy-to-arm.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +# Deploy and test Mujina Mining Firmware on ARM64 hardware via SSH +# Usage: ./scripts/deploy-to-arm.sh --host --user --binary [--test-mode] + +set -e + +# Source environment file if it exists (command line args will override these) +if [[ -f "scripts/local_ci/arm-deployment.env" ]]; then + echo "Loading configuration from arm-deployment.env..." + source scripts/local_ci/arm-deployment.env +fi + +# Default values (can be overridden by env file or command line) +HOST="${ARM_HOST:-}" +USER="${ARM_USER:-}" +BINARY="" +TEST_MODE=false +SSH_KEY="${SSH_KEY:-}" +SSH_OPTS="${SSH_OPTS:--o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null}" +SSH_ASKPASS="${SSH_ASKPASS:-}" +TIMEOUT="${TIMEOUT:-300}" + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --host) + HOST="$2" + shift 2 + ;; + --user) + USER="$2" + shift 2 + ;; + --binary) + BINARY="$2" + shift 2 + ;; + --test-mode) + TEST_MODE=true + shift + ;; + --ssh-key) + SSH_KEY="$2" + shift 2 + ;; + --timeout) + TIMEOUT="$2" + shift 2 + ;; + --help) + echo "Usage: $0 --host --user --binary [--test-mode] [--ssh-key ] [--timeout ]" + echo "" + echo "Options:" + echo " --host ARM64 host IP address" + echo " --user SSH username" + echo " --binary Path to binary to deploy" + echo " --test-mode Run in test mode (default: false)" + echo " --ssh-key Path to SSH private key" + echo " --timeout SSH connection timeout in seconds (default: 300)" + echo " --help Show this help" + exit 0 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +# Validate required arguments +if [[ -z "$HOST" || -z "$USER" || -z "$BINARY" ]]; then + echo "Error: --host, --user, and --binary are required" + echo "Use --help for usage information" + exit 1 +fi + +# Check if binary exists +if [[ ! -f "$BINARY" ]]; then + echo "Error: Binary file '$BINARY' does not exist" + exit 1 +fi + +# Make binary executable +chmod +x "$BINARY" + +echo "๐Ÿš€ Deploying to ARM64 hardware..." +echo " Host: $USER@$HOST" +echo " Binary: $BINARY" +echo " Test Mode: $TEST_MODE" + +# Build SSH command with key if provided +SSH_CMD="ssh $SSH_OPTS" +if [ -n "$SSH_KEY" ]; then + SSH_CMD="$SSH_CMD -i $SSH_KEY" + # Skip ssh-agent entirely and use key directly + echo "๐Ÿ”‘ Using SSH key directly (skipping ssh-agent)..." +fi + +# Set up SSH_ASKPASS if provided +if [ -n "$SSH_ASKPASS" ]; then + export SSH_ASKPASS + export DISPLAY=dummy:0 # Required for SSH_ASKPASS + SSH_CMD="$SSH_CMD -o PasswordAuthentication=no" +fi + +# Create remote directory +echo "๐Ÿ“ Setting up remote directory..." +$SSH_CMD "$USER@$HOST" "mkdir -p /tmp/mujina-miner-test" + +# Remove existing binary if it exists +echo "๐Ÿ—‘๏ธ Removing existing binary..." +$SSH_CMD "$USER@$HOST" "rm -f /tmp/mujina-miner-test/mujina-minerd" + +# Copy binary to remote host +echo "๐Ÿ“ค Uploading binary..." +SCP_CMD="scp $SSH_OPTS" +if [ -n "$SSH_KEY" ]; then + SCP_CMD="$SCP_CMD -i $SSH_KEY" +fi +if [ -n "$SSH_ASKPASS" ]; then + export SSH_ASKPASS + export DISPLAY=dummy:0 +fi +$SCP_CMD "$BINARY" "$USER@$HOST:/tmp/mujina-miner-test/mujina-minerd" + +# Copy any additional test files +if [[ -d "test-data" ]]; then + echo "๐Ÿ“ค Uploading test data..." + $SCP_CMD -r test-data "$USER@$HOST:/tmp/mujina-miner-test/" +fi + +# Run tests on remote ARM64 hardware +echo "๐Ÿงช Running tests on ARM64 hardware..." + +# Create test script on remote host +$SSH_CMD "$USER@$HOST" << 'EOF' +cd /tmp/mujina-miner-test +chmod +x mujina-minerd + +echo "=== ARM64 Hardware Information ===" +uname -a +cat /proc/cpuinfo | grep -E "(processor|model name|cpu MHz|cache size)" | head -10 +cat /proc/meminfo | head -5 +echo "" + +echo "=== Binary Information ===" +file mujina-minerd +ldd mujina-minerd || echo "Static binary or ldd not available" +echo "" + +echo "=== help test ===" +timeout 30 ./mujina-minerd --help || echo "Help command failed" +echo "" + +echo "" +echo "=== Test Results ===" +echo "โœ… ARM64 deployment successful" +echo "โœ… Binary executes correctly" +echo "โœ… Hardware integration tested" +EOF + +# Check exit status +if [[ $? -eq 0 ]]; then + echo "โœ… ARM64 deployment and testing completed successfully!" +else + echo "โŒ ARM64 deployment or testing failed" + exit 1 +fi + +# Cleanup remote files (optional) +echo "๐Ÿงน Cleaning up remote files..." +$SSH_CMD "$USER@$HOST" "rm -rf /tmp/mujina-miner-test" || echo "Cleanup failed (non-critical)" + +echo "๐ŸŽ‰ Hybrid CI deployment completed!" diff --git a/scripts/local_ci/hybrid-ci-local.sh b/scripts/local_ci/hybrid-ci-local.sh new file mode 100755 index 0000000..7d5fde2 --- /dev/null +++ b/scripts/local_ci/hybrid-ci-local.sh @@ -0,0 +1,144 @@ +#!/bin/bash + +# Local hybrid CI script - combines Podman containers with SSH ARM deployment +# Usage: ./scripts/hybrid-ci-local.sh [--arm-host ] [--arm-user ] [--skip-arm] + +set -e + +# Default values +ARM_HOST="" +ARM_USER="" +SKIP_ARM=false +RUST_IMAGE="quay.io/jbride2000/rust:1.90.0-trixie-tools" + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --arm-host) + ARM_HOST="$2" + shift 2 + ;; + --arm-user) + ARM_USER="$2" + shift 2 + ;; + --skip-arm) + SKIP_ARM=true + shift + ;; + --rust-image) + RUST_IMAGE="$2" + shift 2 + ;; + --help) + echo "Usage: $0 [--arm-host ] [--arm-user ] [--skip-arm] [--rust-image ]" + echo "" + echo "Options:" + echo " --arm-host ARM64 host IP address for deployment" + echo " --arm-user SSH username for ARM host" + echo " --skip-arm Skip ARM deployment (containers only)" + echo " --rust-image Rust container image (default: quay.io/jbride2000/rust:1.90.0-trixie-tools)" + echo " --help Show this help" + exit 0 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +echo "๐Ÿ”„ Starting hybrid CI (Podman + ARM SSH)..." +echo " Rust Image: $RUST_IMAGE" +echo " ARM Host: ${ARM_HOST:-'Not configured'}" +echo " ARM User: ${ARM_USER:-'Not configured'}" +echo " Skip ARM: $SKIP_ARM" +echo "" + +# Check if Podman is available +if ! command -v podman &> /dev/null; then + echo "โŒ Podman is not installed. Please install Podman first." + exit 1 +fi + +# Check if ARM deployment is configured +if [ "$SKIP_ARM" = "false" ] && [ -z "$ARM_HOST" ]; then + echo "โš ๏ธ ARM host not configured. Running container-only CI." + echo " Use --arm-host and --arm-user to enable ARM deployment" + echo " Or use --skip-arm to skip ARM deployment entirely" + echo "" + SKIP_ARM=true +fi + +# Make scripts executable +chmod +x .github/ci-runner.sh + +echo "๐Ÿ“ฆ Step 1: Running container-based CI checks..." +export RUST_IMAGE="$RUST_IMAGE" +export WORKSPACE_DIR="$(pwd)" +export CACHE_MOUNTS="true" +export SKIP_CLIPPY="${SKIP_CLIPPY:-false}" + +# Run all container-based checks +./.github/ci-runner.sh all + +echo "" +echo "โœ… Container-based CI completed successfully!" +echo "" + +# Cross-compile for ARM64 +echo "๐Ÿ”จ Step 2: Cross-compiling for ARM64..." +export TARGET_ARCH="aarch64-unknown-linux-gnu" +./.github/ci-runner.sh build-release + +echo "" +echo "โœ… ARM64 cross-compilation completed!" +echo "" + +# ARM deployment (if configured) +if [ "$SKIP_ARM" = "false" ]; then + echo "๐Ÿš€ Step 3: Deploying to ARM64 hardware..." + + # Set up environment for ARM deployment + export HYBRID_MODE="true" + export ARM_HOST="$ARM_HOST" + export ARM_USER="$ARM_USER" + + # Find the ARM64 binary + ARM_BINARY="target/aarch64-unknown-linux-gnu/release/mujina-minerd" + + if [ ! -f "$ARM_BINARY" ]; then + echo "โŒ ARM64 binary not found at $ARM_BINARY" + exit 1 + fi + + # Ensure deploy script is executable + chmod +x scripts/local_ci/deploy-to-arm.sh + + # Deploy to ARM hardware + ./scripts/local_ci/deploy-to-arm.sh \ + --host "$ARM_HOST" \ + --user "$ARM_USER" \ + --binary "$ARM_BINARY" \ + --test-mode + + echo "" + echo "โœ… ARM64 deployment and testing completed!" +else + echo "โญ๏ธ Step 3: Skipping ARM deployment" + echo " ARM64 binary available at: target/aarch64-unknown-linux-gnu/release/mujina-minerd" +fi + +echo "" +echo "๐ŸŽ‰ Hybrid CI completed successfully!" +echo "" +echo "๐Ÿ“Š Summary:" +echo " โœ… Container-based CI: PASSED" +echo " โœ… ARM64 cross-compilation: PASSED" +if [ "$SKIP_ARM" = "false" ]; then + echo " โœ… ARM64 hardware deployment: PASSED" +else + echo " โญ๏ธ ARM64 hardware deployment: SKIPPED" +fi +echo "" +echo "๐Ÿš€ Ready for deployment!"