From f28c9616c2bf3cdaa474ddaae039263aa4db6154 Mon Sep 17 00:00:00 2001 From: Dongju Park Date: Thu, 21 Aug 2025 00:28:05 +0900 Subject: [PATCH 1/4] feat(install): Add arch-specific install scripts with systemd unit --- scripts/install_amd64.sh | 59 ++++++++++++++++++++++++++++++++++++++++ scripts/install_arm64.sh | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 scripts/install_amd64.sh create mode 100644 scripts/install_arm64.sh diff --git a/scripts/install_amd64.sh b/scripts/install_amd64.sh new file mode 100644 index 0000000..5e3e39e --- /dev/null +++ b/scripts/install_amd64.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${MORPHER_CONTROLLER_IP:?set MORPHER_CONTROLLER_IP (e.g. 192.168.54.3)}" + +REPO="${REPO:-morpher-vm/morpher-agent}" +VERSION="${VERSION:-v0.0.1}" # e.g. v0.1.0 or latest +SERVICE_NAME="${SERVICE_NAME:-morpher-agent}" +INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}" +CONFIG_DIR="/etc/${SERVICE_NAME}" + +ASSET_FILE="${ASSET_FILE:-${SERVICE_NAME}_Linux_x86_64.tar.gz}" +BASE_URL="https://github.com/${REPO}/releases" +DL_URL="${BASE_URL}/download/${VERSION}/${ASSET_FILE}" +[[ "${VERSION}" == "latest" ]] && DL_URL="https://github.com/${REPO}/releases/latest/download/${ASSET_FILE}" + +tmpdir="$(mktemp -d)"; trap 'rm -rf "$tmpdir"' EXIT +echo "[*] Download ${DL_URL}" +curl -fsSL -o "${tmpdir}/asset.tgz" "${DL_URL}" + +echo "[*] Extract" +tar -xzf "${tmpdir}/asset.tgz" -C "${tmpdir}" + +bin_path="$(find "${tmpdir}" -type f -perm -u+x -name "${SERVICE_NAME}" | head -n1)" +[[ -z "${bin_path}" ]] && { echo "binary not found: ${SERVICE_NAME}"; exit 1; } + +echo "[*] Install -> ${INSTALL_DIR}" +install -d "${INSTALL_DIR}" +install -m 0755 "${bin_path}" "${INSTALL_DIR}/${SERVICE_NAME}" + +echo "[*] Config -> ${CONFIG_DIR}" +install -d "${CONFIG_DIR}" +cat > "${CONFIG_DIR}/${SERVICE_NAME}.env" < ${unit}" +cat > "${unit}" < ${INSTALL_DIR}" +install -d "${INSTALL_DIR}" +install -m 0755 "${bin_path}" "${INSTALL_DIR}/${SERVICE_NAME}" + +echo "[*] Config -> ${CONFIG_DIR}" +install -d "${CONFIG_DIR}" +cat > "${CONFIG_DIR}/${SERVICE_NAME}.env" < ${unit}" +cat > "${unit}" < Date: Thu, 21 Aug 2025 00:43:51 +0900 Subject: [PATCH 2/4] docs(install): Document install and env --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index b93897d..75361ab 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,47 @@ **morpher-agent** is a lightweight agent that collects VM information for migration. +# Installation + +You can install the agent using the provided arch-specific install scripts. +These scripts will download the release tarball, extract the binary, create a +systemd service, and start it automatically. + +> **Note:** Requires `sudo` privileges. + +--- + +## Quick Start + +### x86_64 +```bash +wget -O install_amd64.sh https://raw.githubusercontent.com/morpher-vm/morpher-agent/main/scripts/install_amd64.sh +chmod +x install_amd64.sh +sudo MORPHER_CONTROLLER_IP= ./install_amd64.sh +``` + +### ARM64 +```bash +wget -O install_arm64.sh https://raw.githubusercontent.com/morpher-vm/morpher-agent/main/scripts/install_arm64.sh +chmod +x install_arm64.sh +sudo MORPHER_CONTROLLER_IP= ./install_arm64.sh +``` + +## Environment Variables + +- `MORPHER_CONTROLLER_IP`: The IP address of the Morpher controller to connect to. + +## Service Management + +After installation, the morpher-agent service is managed via systemd: + +```bash +sudo systemctl start morpher-agent +sudo systemctl enable morpher-agent +sudo systemctl status morpher-agent +sudo journalctl -u morpher-agent -f +``` + ## License Licensed under the [MIT License](LICENSE). From 3bf5757bcfdd2ece890a3e5689821af77d4e6f99 Mon Sep 17 00:00:00 2001 From: Dongju Park Date: Thu, 21 Aug 2025 00:54:28 +0900 Subject: [PATCH 3/4] docs(readme): Add verify, delete agent --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 75361ab..7e6d569 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,12 @@ chmod +x install_arm64.sh sudo MORPHER_CONTROLLER_IP= ./install_arm64.sh ``` +### Verify +```bash +systemctl status morpher-agent --no-pager +journalctl -u morpher-agent -e --no-pager +``` + ## Environment Variables - `MORPHER_CONTROLLER_IP`: The IP address of the Morpher controller to connect to. @@ -47,6 +53,15 @@ sudo systemctl status morpher-agent sudo journalctl -u morpher-agent -f ``` +## Delete agent +```bash +sudo systemctl disable --now morpher-agent +sudo rm -f /etc/systemd/system/morpher-agent.service +sudo rm -rf /etc/morpher-agent +sudo rm -f /usr/local/bin/morpher-agent +sudo systemctl daemon-reload +``` + ## License Licensed under the [MIT License](LICENSE). From 2bd571e65f290cbf4c42226f8f8c981c5f2e9812 Mon Sep 17 00:00:00 2001 From: Dongju Park Date: Thu, 21 Aug 2025 14:03:32 +0900 Subject: [PATCH 4/4] feat(install): Verify release checksum and secure env file permissions --- scripts/install_amd64.sh | 19 ++++++++++++++++++- scripts/install_arm64.sh | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/scripts/install_amd64.sh b/scripts/install_amd64.sh index 5e3e39e..e056c80 100644 --- a/scripts/install_amd64.sh +++ b/scripts/install_amd64.sh @@ -18,10 +18,26 @@ tmpdir="$(mktemp -d)"; trap 'rm -rf "$tmpdir"' EXIT echo "[*] Download ${DL_URL}" curl -fsSL -o "${tmpdir}/asset.tgz" "${DL_URL}" +# Download and verify checksum +cs_url="${BASE_URL}/download/${VERSION}/checksums.txt" +[[ "${VERSION}" == "latest" ]] && cs_url="https://github.com/${REPO}/releases/latest/download/checksums.txt" + +curl -fsSL -o "${tmpdir}/checksums.txt" "${cs_url}" + +line="$(grep -E " ${ASSET_FILE}\$" "${tmpdir}/checksums.txt" || true)" +if [[ -z "${line}" ]]; then + echo "[X] ${ASSET_FILE} entry not found in checksums.txt (${cs_url})" + exit 1 +fi + +hash="$(echo "${line}" | awk '{print $1}')" +echo "[*] Verifying checksum for ${ASSET_FILE}" +echo "${hash} asset.tgz" | (cd "${tmpdir}" && sha256sum -c -) + echo "[*] Extract" tar -xzf "${tmpdir}/asset.tgz" -C "${tmpdir}" -bin_path="$(find "${tmpdir}" -type f -perm -u+x -name "${SERVICE_NAME}" | head -n1)" +bin_path="$(find "${tmpdir}" -type f -executable -name "${SERVICE_NAME}" | head -n1)" [[ -z "${bin_path}" ]] && { echo "binary not found: ${SERVICE_NAME}"; exit 1; } echo "[*] Install -> ${INSTALL_DIR}" @@ -33,6 +49,7 @@ install -d "${CONFIG_DIR}" cat > "${CONFIG_DIR}/${SERVICE_NAME}.env" < ${unit}" diff --git a/scripts/install_arm64.sh b/scripts/install_arm64.sh index 0df13af..cd1c10b 100644 --- a/scripts/install_arm64.sh +++ b/scripts/install_arm64.sh @@ -18,10 +18,26 @@ tmpdir="$(mktemp -d)"; trap 'rm -rf "$tmpdir"' EXIT echo "[*] Download ${DL_URL}" curl -fsSL -o "${tmpdir}/asset.tgz" "${DL_URL}" +# Download and verify checksum +cs_url="${BASE_URL}/download/${VERSION}/checksums.txt" +[[ "${VERSION}" == "latest" ]] && cs_url="https://github.com/${REPO}/releases/latest/download/checksums.txt" + +curl -fsSL -o "${tmpdir}/checksums.txt" "${cs_url}" + +line="$(grep -E " ${ASSET_FILE}\$" "${tmpdir}/checksums.txt" || true)" +if [[ -z "${line}" ]]; then + echo "[X] ${ASSET_FILE} entry not found in checksums.txt (${cs_url})" + exit 1 +fi + +hash="$(echo "${line}" | awk '{print $1}')" +echo "[*] Verifying checksum for ${ASSET_FILE}" +echo "${hash} asset.tgz" | (cd "${tmpdir}" && sha256sum -c -) + echo "[*] Extract" tar -xzf "${tmpdir}/asset.tgz" -C "${tmpdir}" -bin_path="$(find "${tmpdir}" -type f -perm -u+x -name "${SERVICE_NAME}" | head -n1)" +bin_path="$(find "${tmpdir}" -type f -executable -name "${SERVICE_NAME}" | head -n1)" [[ -z "${bin_path}" ]] && { echo "binary not found: ${SERVICE_NAME}"; exit 1; } echo "[*] Install -> ${INSTALL_DIR}" @@ -33,6 +49,7 @@ install -d "${CONFIG_DIR}" cat > "${CONFIG_DIR}/${SERVICE_NAME}.env" < ${unit}"