setup CI and a more complete installation script
Use woodpecker-ci to deploy binaries to the R2 object storage. Use multi-target builds to deploy multiple binaries for one or more CPU architectures. Now the installation script lives on the root of the repo, and it is more complete checking the machine's requirements, operating system and cpu architecture.
This commit is contained in:
parent
749780a1d5
commit
7fe45ca94b
11 changed files with 564 additions and 394 deletions
32
.woodpecker/release_agent.yml
Normal file
32
.woodpecker/release_agent.yml
Normal file
|
@ -0,0 +1,32 @@
|
|||
branches: [main]
|
||||
|
||||
matrix:
|
||||
BUILD_TARGET:
|
||||
- aarch64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-gnu
|
||||
|
||||
steps:
|
||||
build:
|
||||
image: git.nikos.gg/prymn/rust/aarch64:latest
|
||||
# when:
|
||||
# - path: "agent/src/*"
|
||||
commands:
|
||||
- protoc --version
|
||||
- cd agent
|
||||
- cargo build --release --target "${BUILD_TARGET}"
|
||||
- mkdir -p "dist/${BUILD_TARGET}"
|
||||
- cp "target/${BUILD_TARGET}/release/prymn_agent" "dist/${BUILD_TARGET}"
|
||||
|
||||
release-binaries:
|
||||
image: woodpeckerci/plugin-s3
|
||||
# when:
|
||||
# - path: "agent/src/*"
|
||||
settings:
|
||||
bucket: prymn-static
|
||||
endpoint: https://75178f9eca227dea51b3db4db2c15a5a.r2.cloudflarestorage.com
|
||||
access_key:
|
||||
from_secret: r2_access_key
|
||||
secret_key:
|
||||
from_secret: r2_secret_key
|
||||
source: agent/dist/**/*
|
||||
target: /
|
17
.woodpecker/release_install_script.yml
Normal file
17
.woodpecker/release_install_script.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
branches: [main]
|
||||
|
||||
when:
|
||||
- path: "get_prymn.sh"
|
||||
|
||||
steps:
|
||||
upload:
|
||||
image: woodpeckerci/plugin-s3
|
||||
settings:
|
||||
bucket: prymn-static
|
||||
endpoint: https://75178f9eca227dea51b3db4db2c15a5a.r2.cloudflarestorage.com
|
||||
access_key:
|
||||
from_secret: r2_access_key
|
||||
secret_key:
|
||||
from_secret: r2_secret_key
|
||||
source: "get_prymn.sh"
|
||||
target: "/agent/dist"
|
656
agent/Cargo.lock
generated
656
agent/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -8,12 +8,12 @@ anyhow = "1.0.71"
|
|||
clap = { version = "4.3.9" }
|
||||
nix = "0.26.2"
|
||||
prost = "0.11.9"
|
||||
reqwest = { version = "0.11.18", features = ["blocking"] }
|
||||
reqwest = { version = "0.11.18", features = ["blocking", "rustls-tls"], default-features = false }
|
||||
serde_json = "1.0.99"
|
||||
sysinfo = { version = "0.29.2", default-features = false }
|
||||
tokio = { version = "1.28.2", features = ["rt-multi-thread", "io-util", "process", "macros", "signal"] }
|
||||
tokio-stream = { version = "0.1.14", features = ["net"] }
|
||||
tonic = "0.9.2"
|
||||
tonic = { version = "0.9.2", features = ["tls"] }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = "0.3.17"
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
#!/bin/sh
|
||||
# shellcheck shell=dash
|
||||
|
||||
# A simple script that is run on a remote host to download and install the
|
||||
# agent binary.
|
||||
|
||||
set -u
|
||||
|
||||
# For Dev: file:///home/nikos/Projects/prymn/agent/target/debug/prymn_agent
|
||||
GET_PRYMN_ROOT="${GET_PRYMN_ROOT:?You need to set GET_PRYMN_ROOT to the prymn_agent path for now}"
|
||||
|
||||
main() {
|
||||
# Check for dependencies
|
||||
check_for_command curl
|
||||
check_for_command mktemp
|
||||
|
||||
local dir
|
||||
if ! dir="$(mktemp -d)"; then
|
||||
error "mktemp was not executed successfully"
|
||||
fi
|
||||
|
||||
local file="${dir}/prymn_agent"
|
||||
local url="${GET_PRYMN_ROOT}"
|
||||
|
||||
printf "downloading prymn agent...\n" 1>&2
|
||||
|
||||
ensure download "${url}" "${file}"
|
||||
ensure chmod u+x "$file"
|
||||
|
||||
# Run the installer
|
||||
"$file" --install "$@"
|
||||
local ret=$?
|
||||
|
||||
rm "${file}"
|
||||
rmdir "${dir}"
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
download() {
|
||||
local err
|
||||
err=$(curl -sSfL "$1" -o "$2" 2>&1)
|
||||
if [ -n "$err" ]; then
|
||||
error "$err"
|
||||
fi
|
||||
}
|
||||
|
||||
error() {
|
||||
printf "Error: %s\n" "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_for_command() {
|
||||
if ! command -v "$1" > /dev/null 2>&1; then
|
||||
error "get_prymn.sh requires the program '$1' but it was not found in your system."
|
||||
fi
|
||||
}
|
||||
|
||||
ensure() {
|
||||
"$@" || error "failed to execute: $*"
|
||||
}
|
||||
|
||||
main "$@" || exit 1
|
|
@ -3,10 +3,6 @@ use clap::arg;
|
|||
use prymn_agent::{self_update, server};
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
if std::env::consts::OS != "linux" {
|
||||
return Err(anyhow!("platform is not linux!"));
|
||||
}
|
||||
|
||||
tracing_subscriber::fmt().init();
|
||||
|
||||
let command = clap::Command::new(env!("CARGO_BIN_NAME"))
|
||||
|
@ -18,10 +14,10 @@ fn main() -> anyhow::Result<()> {
|
|||
.unwrap_or_else(|e| e.exit());
|
||||
|
||||
if command.get_flag("daemon") {
|
||||
tracing::info!("running as daemon");
|
||||
tracing::info!("starting agent");
|
||||
server::main()
|
||||
} else if let Some(token) = command.get_one::<String>("install") {
|
||||
tracing::info!("running install mode");
|
||||
tracing::info!("starting installation...");
|
||||
self_update::install(token)
|
||||
} else {
|
||||
unreachable!()
|
||||
|
|
|
@ -5,7 +5,9 @@ import Config
|
|||
# manifest is generated by the `mix assets.deploy` task,
|
||||
# which you should run after static files are built and
|
||||
# before starting your production server.
|
||||
config :prymn, PrymnWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
|
||||
config :prymn, PrymnWeb.Endpoint,
|
||||
cache_static_manifest: "priv/static/cache_manifest.json",
|
||||
http: [host: "prymn.net"]
|
||||
|
||||
# Configures Swoosh API Client
|
||||
config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: Prymn.Finch
|
||||
|
|
|
@ -127,19 +127,10 @@ defmodule Prymn.Servers do
|
|||
"""
|
||||
@spec create_setup_command(%Server{}) :: String.t()
|
||||
def create_setup_command(%Server{registration_token: token}) do
|
||||
build_command = fn token ->
|
||||
if Application.get_env(:prymn, :environment) == :prod do
|
||||
"curl -sSf https://static.prymn.net/get_prymn.sh | sh -s " <> token
|
||||
else
|
||||
# On a dev environment we want to download the local version of the agent
|
||||
agent_path = Path.expand("../agent/target/debug/prymn_agent")
|
||||
get_prymn_path = Path.expand("../agent/get_prymn.sh")
|
||||
"GET_PRYMN_ROOT=file://#{agent_path} #{get_prymn_path} #{token}"
|
||||
end
|
||||
end
|
||||
|
||||
token
|
||||
|> Base.encode64()
|
||||
|> then(build_command)
|
||||
|> then(fn token ->
|
||||
"curl -sSfL " <> PrymnWeb.Endpoint.url() <> "/install | sh -s " <> token
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,4 +6,9 @@ defmodule PrymnWeb.PageController do
|
|||
# so skip the default app layout.
|
||||
render(conn, :home, layout: false)
|
||||
end
|
||||
|
||||
def install(conn, _params) do
|
||||
# TODO: Check for Production vs Development download
|
||||
redirect(conn, external: "https://static.prymn.net/agent/dist/get_prymn.sh")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,6 +18,7 @@ defmodule PrymnWeb.Router do
|
|||
pipe_through :browser
|
||||
|
||||
get "/", PageController, :home
|
||||
get "/install", PageController, :install
|
||||
|
||||
live "/servers", ServerLive.Index, :index
|
||||
live "/servers/new", ServerLive.Index, :new
|
||||
|
|
153
get_prymn.sh
Executable file
153
get_prymn.sh
Executable file
|
@ -0,0 +1,153 @@
|
|||
#!/bin/sh
|
||||
# shellcheck shell=dash
|
||||
|
||||
# A simple script that is run on a remote host to download and install the
|
||||
# agent binary.
|
||||
|
||||
set -u
|
||||
|
||||
ROOT_URL=${ROOT_URL:-"https://static.prymn.net/agent/dist"}
|
||||
|
||||
main() {
|
||||
if [ $# -eq 0 ]; then
|
||||
exit_error "missing command parameters. please make sure you copied the installation command correctly."
|
||||
fi
|
||||
|
||||
check_user_is_root
|
||||
|
||||
check_os
|
||||
local arch=${RETURN_VALUE}
|
||||
|
||||
check_for_command curl
|
||||
check_for_command mktemp
|
||||
|
||||
local dir
|
||||
dir="$(mktemp -d)"
|
||||
local file="${dir}/prymn_agent"
|
||||
local url="${ROOT_URL}/${arch}/prymn_agent"
|
||||
|
||||
printf "info: downloading prymn agent...\n" 1>&2
|
||||
|
||||
ensure download "${url}" "${file}"
|
||||
ensure chmod u+x "${file}"
|
||||
|
||||
# Run the installer
|
||||
"${file}" --install "$@"
|
||||
local ret=$?
|
||||
|
||||
rm "${file}"
|
||||
rmdir "${dir}"
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
check_user_is_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
exit_error "this script must be run as the root user."
|
||||
fi
|
||||
}
|
||||
|
||||
check_os() {
|
||||
local os_release os_id os_version_id os_pretty os_old_flag
|
||||
if test -e /etc/os-release; then
|
||||
os_release="/etc/os-release"
|
||||
elif test -e /usr/lib/os-release; then
|
||||
os_release="/usr/lib/os-release"
|
||||
else
|
||||
exit_error "could not determine your operating system; it might not be supported."
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
. "${os_release}"
|
||||
|
||||
local os_id=${ID:-0}
|
||||
local os_version_id=${VERSION_ID:-0}
|
||||
local os_pretty=${PRETTY_NAME:-Linux}
|
||||
|
||||
if [ "${os_id}" = 0 ] || [ "${os_version_id}" = 0 ]; then
|
||||
exit_error "could not detect your operating system type or version."
|
||||
fi
|
||||
|
||||
case "${os_id}" in
|
||||
debian)
|
||||
local min_version=10
|
||||
if [ "${os_version_id}" -lt ${min_version} ]; then
|
||||
warning "detected Debian version ${os_version_id} which may be too old."
|
||||
fi
|
||||
;;
|
||||
|
||||
ubuntu)
|
||||
local min_version="20.09"
|
||||
os_old_flag="$(echo "${os_version_id}" | awk -v n=${min_version} '{print $1 < n}')"
|
||||
if [ "${os_old_flag}" -eq 1 ]; then
|
||||
warning "detected Ubuntu version ${os_version_id} which may be too old."
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
exit_error "your operating system ${os_pretty} is not be supported."
|
||||
;;
|
||||
esac
|
||||
|
||||
local arch clib kernel cputype
|
||||
# TODO: check for musl (probably not be needed because we support distros
|
||||
# that don't use it)
|
||||
clib="gnu"
|
||||
kernel="$(uname -s)"
|
||||
cputype="$(uname -m)"
|
||||
|
||||
case "${kernel}" in
|
||||
Linux)
|
||||
arch=unknown-linux-${clib}
|
||||
;;
|
||||
|
||||
*)
|
||||
exit_error "your operating system type ${kernel} is not supported."
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${cputype}" in
|
||||
x86_64 | x64)
|
||||
arch="x86_64-${arch}"
|
||||
;;
|
||||
|
||||
aarch64 | arm64)
|
||||
arch="aarch64-${arch}"
|
||||
;;
|
||||
|
||||
*)
|
||||
exit_error "your CPU architecture ${cputype} is not supported."
|
||||
;;
|
||||
esac
|
||||
|
||||
RETURN_VALUE="${arch}"
|
||||
}
|
||||
|
||||
download() {
|
||||
local err
|
||||
err=$(curl -sSfL "$1" -o "$2" 2>&1)
|
||||
if [ -n "$err" ]; then
|
||||
exit_error "$err"
|
||||
fi
|
||||
}
|
||||
|
||||
warning() {
|
||||
printf "warning: %s\n" "$1" >&2
|
||||
}
|
||||
|
||||
exit_error() {
|
||||
printf "error: %s\n" "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_for_command() {
|
||||
if ! command -v "$1" > /dev/null 2>&1; then
|
||||
exit_error "the program '$1' is required, but it was not found in your system."
|
||||
fi
|
||||
}
|
||||
|
||||
ensure() {
|
||||
"$@" || exit_error "failed to execute: $*"
|
||||
}
|
||||
|
||||
main "$@" || exit 1
|
Loading…
Reference in a new issue