opn
This commit is contained in:
1 parent
cce1081f75
commit
2b8f11ef8c
36 files changed
+1868
-309
No files matched your search
Executable
+143
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
source /opt/rust-package-builder/scripts/lib.sh
|
||||
|
||||
SOURCE_DIR=${1:?source path required}
|
||||
BINARY=${2:?FreeBSD binary required}
|
||||
PACKAGE_FILE=${3:?output package file required}
|
||||
PACKAGE_VERSION=${4:?OPNsense package version required}
|
||||
|
||||
PLUGIN_ROOT=/opt/rust-package-builder/opnsense/plugin
|
||||
FREEBSD_ABI=${FREEBSD_ABI:-FreeBSD:15:amd64}
|
||||
FREEBSD_ARCH=${FREEBSD_ARCH:-freebsd:15:x86:64}
|
||||
|
||||
for tool in python3 sha256sum tar zstd file; do
|
||||
require_cmd "$tool"
|
||||
done
|
||||
|
||||
[[ -f "$SOURCE_DIR/Cargo.toml" ]] || fatal "missing Cargo.toml in $SOURCE_DIR"
|
||||
[[ -f "$BINARY" ]] || fatal "missing cross-built binary: $BINARY"
|
||||
[[ -d "$PLUGIN_ROOT/src" ]] || fatal "missing embedded OPNsense plugin source: $PLUGIN_ROOT/src"
|
||||
|
||||
binary_desc=$(file -b "$BINARY")
|
||||
[[ "$binary_desc" == *FreeBSD* ]] || fatal "refusing to package a non-FreeBSD binary: $binary_desc"
|
||||
|
||||
WORK=$(mktemp -d "${PACKAGE_FILE}.work.XXXXXX")
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
STAGE="$WORK/stage"
|
||||
META="$WORK/meta"
|
||||
ARCHIVE="$WORK/os-rustproxy.tar"
|
||||
PAYLOAD_LIST="$WORK/payload.list"
|
||||
mkdir -p "$STAGE/usr/local" "$META" "$(dirname "$PACKAGE_FILE")"
|
||||
|
||||
cp -a "$PLUGIN_ROOT/src/." "$STAGE/usr/local/"
|
||||
mkdir -p "$STAGE/usr/local/sbin"
|
||||
install -m 0555 "$BINARY" "$STAGE/usr/local/sbin/rust-proxy"
|
||||
|
||||
chmod 0555 "$STAGE/usr/local/etc/rc.d/rustproxy"
|
||||
chmod 0555 "$STAGE/usr/local/etc/rc.syshook.d/10-rustproxy.start"
|
||||
chmod 0555 "$STAGE/usr/local/opnsense/scripts/rustproxy/service.sh"
|
||||
|
||||
POST_INSTALL_FILE="$PLUGIN_ROOT/+POST_INSTALL.pre"
|
||||
PRE_DEINSTALL_FILE="$PLUGIN_ROOT/+PRE_DEINSTALL.pre"
|
||||
|
||||
python3 - "$STAGE" "$META" "$PACKAGE_VERSION" "$FREEBSD_ABI" "$FREEBSD_ARCH" \
|
||||
"$POST_INSTALL_FILE" "$PRE_DEINSTALL_FILE" <<'PY'
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
stage = Path(sys.argv[1])
|
||||
meta_dir = Path(sys.argv[2])
|
||||
version = sys.argv[3]
|
||||
abi = sys.argv[4]
|
||||
arch = sys.argv[5]
|
||||
post_install = Path(sys.argv[6]).read_text(encoding="utf-8")
|
||||
pre_deinstall = Path(sys.argv[7]).read_text(encoding="utf-8")
|
||||
|
||||
files = {}
|
||||
flatsize = 0
|
||||
for p in sorted(stage.rglob("*")):
|
||||
if p.is_symlink():
|
||||
files["/" + p.relative_to(stage).as_posix()] = "-"
|
||||
elif p.is_file():
|
||||
files["/" + p.relative_to(stage).as_posix()] = hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
flatsize += p.stat().st_size
|
||||
|
||||
common = {
|
||||
"name": "os-rustproxy",
|
||||
"version": version,
|
||||
"origin": "opnsense/os-rustproxy",
|
||||
"comment": "RustProxy reverse proxy service",
|
||||
"desc": "RustProxy packaged as an OPNsense plugin with configurable HTTP, HTTPS/TLS and administration listeners.",
|
||||
"maintainer": "local@localhost",
|
||||
"www": "https://git.linuxiarz.pl/gru/RustProxy",
|
||||
"prefix": "/usr/local",
|
||||
"abi": abi,
|
||||
"arch": arch,
|
||||
"flatsize": flatsize,
|
||||
"licenselogic": "single",
|
||||
"licenses": ["UNKNOWN"],
|
||||
"categories": ["www"],
|
||||
"deps": {},
|
||||
"options": {},
|
||||
}
|
||||
manifest = dict(common)
|
||||
manifest["files"] = files
|
||||
manifest["scripts"] = {
|
||||
"post-install": post_install,
|
||||
"pre-deinstall": pre_deinstall,
|
||||
}
|
||||
|
||||
(meta_dir / "+COMPACT_MANIFEST").write_text(
|
||||
json.dumps(common, separators=(",", ":"), ensure_ascii=False) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(meta_dir / "+MANIFEST").write_text(
|
||||
json.dumps(manifest, separators=(",", ":"), ensure_ascii=False) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
PY
|
||||
|
||||
(
|
||||
cd "$STAGE"
|
||||
find . \( -type f -o -type l \) -print | LC_ALL=C sort | sed 's#^\./##' > "$PAYLOAD_LIST"
|
||||
)
|
||||
[[ -s "$PAYLOAD_LIST" ]] || fatal "OPNsense package payload is empty"
|
||||
|
||||
tar --format=ustar --owner=0 --group=0 --numeric-owner \
|
||||
-cf "$ARCHIVE" -C "$META" +COMPACT_MANIFEST +MANIFEST
|
||||
tar -P --format=ustar --owner=0 --group=0 --numeric-owner --no-recursion \
|
||||
--transform='s,^,/,S' \
|
||||
-rf "$ARCHIVE" -C "$STAGE" -T "$PAYLOAD_LIST"
|
||||
|
||||
python3 - "$ARCHIVE" "$META/+MANIFEST" <<'PY'
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
archive = Path(sys.argv[1])
|
||||
manifest = json.loads(Path(sys.argv[2]).read_text(encoding="utf-8"))
|
||||
expected = set(manifest.get("files", {}))
|
||||
with tarfile.open(archive, "r:") as tf:
|
||||
members = tf.getmembers()
|
||||
if [m.name for m in members[:2]] != ["+COMPACT_MANIFEST", "+MANIFEST"]:
|
||||
raise SystemExit("package metadata must be the first two tar members")
|
||||
payload = members[2:]
|
||||
if any(m.isdir() for m in payload):
|
||||
raise SystemExit("directory entries are not allowed in OPNsense package payload")
|
||||
actual = {m.name for m in payload if m.isfile() or m.issym() or m.islnk()}
|
||||
relative = sorted(name for name in actual if not name.startswith("/"))
|
||||
if relative:
|
||||
raise SystemExit(f"payload contains non-absolute paths: {relative[:5]}")
|
||||
missing = sorted(expected - actual)
|
||||
extra = sorted(actual - expected)
|
||||
if missing or extra:
|
||||
raise SystemExit(f"package payload does not match +MANIFEST; missing={missing[:5]} extra={extra[:5]}")
|
||||
PY
|
||||
|
||||
zstd -q -f -19 -T0 "$ARCHIVE" -o "$PACKAGE_FILE"
|
||||
zstd -dc "$PACKAGE_FILE" | tar -tf - >/dev/null
|
||||
log "created OPNsense package: $PACKAGE_FILE"
|
||||
Reference in new issue
Block a user