| 1 | #!/bin/bash |
| 2 | # Sets up EdenFS on the hub server. |
| 3 | # EdenFS runs on the HOST (not in Docker) because it needs FUSE access. |
| 4 | # |
| 5 | # Prerequisites: |
| 6 | # - grove/edenfs:latest Docker image must be built |
| 7 | # - Mononoke SLAPI must be running (grove.host:8443) |
| 8 | # - TLS client certs at /data/grove/tls/ |
| 9 | # |
| 10 | # What this does: |
| 11 | # 1. Extracts edenfs + edenfs_privhelper binaries from Docker image |
| 12 | # 2. Creates EdenFS config pointing at Mononoke SLAPI |
| 13 | # 3. Creates a backing repo (metadata-only sl clone) |
| 14 | # 4. Installs a systemd service for the edenfs daemon |
| 15 | # 5. Creates an EdenFS mount at /mnt/sapling |
| 16 | # |
| 17 | # Usage: sudo bash setup-edenfs.sh |
| 18 | |
| 19 | set -euo pipefail |
| 20 | |
| 21 | EDEN_DIR="/data/eden" |
| 22 | EDEN_CONFIG_DIR="/etc/eden" |
| 23 | EDEN_BIN_DIR="/usr/local/bin" |
| 24 | MOUNT_POINT="/mnt/sapling" |
| 25 | BACKING_REPO="/data/eden/backing/sapling" |
| 26 | TLS_DIR="/data/grove/tls" |
| 27 | SLAPI_URL="https://localhost:8443" |
| 28 | REPO_NAME="sapling" |
| 29 | |
| 30 | # ── Extract binaries from Docker image ──────────────────────────── |
| 31 | |
| 32 | echo "Extracting EdenFS binaries from Docker image..." |
| 33 | CONTAINER_ID=$(docker create grove/edenfs:latest) |
| 34 | docker cp "$CONTAINER_ID:/usr/local/bin/edenfs" "$EDEN_BIN_DIR/edenfs" || true |
| 35 | docker cp "$CONTAINER_ID:/usr/local/bin/edenfs_privhelper" "$EDEN_BIN_DIR/edenfs_privhelper" || true |
| 36 | docker cp "$CONTAINER_ID:/usr/local/bin/edenfsctl" "$EDEN_BIN_DIR/edenfsctl" || true |
| 37 | docker rm "$CONTAINER_ID" |
| 38 | |
| 39 | chmod +x "$EDEN_BIN_DIR/edenfs" "$EDEN_BIN_DIR/edenfs_privhelper" "$EDEN_BIN_DIR/edenfsctl" 2>/dev/null || true |
| 40 | |
| 41 | echo "Extracted binaries:" |
| 42 | ls -la "$EDEN_BIN_DIR/edenfs" "$EDEN_BIN_DIR/edenfs_privhelper" "$EDEN_BIN_DIR/edenfsctl" 2>/dev/null || echo "(some binaries not found — build may have produced different names)" |
| 43 | |
| 44 | # ── Create directories ──────────────────────────────────────────── |
| 45 | |
| 46 | mkdir -p "$EDEN_DIR" |
| 47 | mkdir -p "$EDEN_CONFIG_DIR" |
| 48 | mkdir -p "$MOUNT_POINT" |
| 49 | mkdir -p "$BACKING_REPO" |
| 50 | |
| 51 | # ── Create EdenFS system config ─────────────────────────────────── |
| 52 | |
| 53 | cat > "$EDEN_CONFIG_DIR/edenfs.toml" <<TOML |
| 54 | [core] |
| 55 | edenDirectory = "$EDEN_DIR" |
| 56 | |
| 57 | [clone] |
| 58 | default-revision = "main" |
| 59 | TOML |
| 60 | |
| 61 | # ── Create backing repo config ──────────────────────────────────── |
| 62 | # EdenFS needs a Sapling backing repo with edenapi config pointing |
| 63 | # at Mononoke. This is like a metadata-only clone — EdenFS fetches |
| 64 | # actual file contents lazily via SLAPI. |
| 65 | |
| 66 | mkdir -p "$BACKING_REPO/.sl" |
| 67 | |
| 68 | cat > "$BACKING_REPO/.sl/config" <<TOML |
| 69 | [remotefilelog] |
| 70 | reponame = $REPO_NAME |
| 71 | |
| 72 | [edenapi] |
| 73 | url = $SLAPI_URL |
| 74 | |
| 75 | [auth] |
| 76 | grove.cert = $TLS_DIR/client.crt |
| 77 | grove.key = $TLS_DIR/client.key |
| 78 | grove.cacerts = $TLS_DIR/ca.crt |
| 79 | grove.prefix = * |
| 80 | |
| 81 | [remotenames] |
| 82 | selectivepulldefault = main |
| 83 | |
| 84 | [push] |
| 85 | edenapi = true |
| 86 | TOML |
| 87 | |
| 88 | # ── Install systemd service ─────────────────────────────────────── |
| 89 | |
| 90 | cat > /etc/systemd/system/edenfs.service <<SERVICE |
| 91 | [Unit] |
| 92 | Description=EdenFS Virtual Filesystem Daemon |
| 93 | After=network.target docker.service |
| 94 | Wants=network.target |
| 95 | |
| 96 | [Service] |
| 97 | Type=simple |
| 98 | ExecStart=$EDEN_BIN_DIR/edenfs \ |
| 99 | --edenDir $EDEN_DIR \ |
| 100 | --etcEdenDir $EDEN_CONFIG_DIR \ |
| 101 | --configPath $EDEN_CONFIG_DIR/edenfs.toml \ |
| 102 | --foreground |
| 103 | Restart=on-failure |
| 104 | RestartSec=5 |
| 105 | |
| 106 | # FUSE requires these capabilities |
| 107 | AmbientCapabilities=CAP_SYS_ADMIN |
| 108 | NoNewPrivileges=false |
| 109 | |
| 110 | [Install] |
| 111 | WantedBy=multi-user.target |
| 112 | SERVICE |
| 113 | |
| 114 | systemctl daemon-reload |
| 115 | |
| 116 | echo "" |
| 117 | echo "=== EdenFS Setup Complete ===" |
| 118 | echo "" |
| 119 | echo "Next steps:" |
| 120 | echo " 1. Start the daemon: systemctl start edenfs" |
| 121 | echo " 2. Check status: systemctl status edenfs" |
| 122 | echo " 3. Mount the sapling repo:" |
| 123 | echo " edenfsctl clone $BACKING_REPO $MOUNT_POINT" |
| 124 | echo " 4. Verify the mount: ls $MOUNT_POINT" |
| 125 | echo " 5. Enable on boot: systemctl enable edenfs" |
| 126 | echo "" |
| 127 | echo "The sapling repo will be lazily mounted at $MOUNT_POINT" |
| 128 | echo "Files are fetched on-demand from Mononoke SLAPI ($SLAPI_URL)" |
| 129 | |