node-install.sh: remember which repository a core came from

A core is now the release of one repository: .managed lists "repo tag",
the plan says where the core comes from, and a script following another
repository (a fork's, say) moves the server to that repository's core
instead of keeping a release whose number only happens to be higher. The
updater's script copy is replaced by a script from another repository in
the same way. CORE_BASE now follows RELEASE_REPO.
This commit is contained in:
meepo161
2026-09-28 10:08:09 +03:00
parent 1394680027
commit 122ab88bae
2 changed files with 47 additions and 20 deletions
+33 -20
View File
@@ -47,16 +47,17 @@ set -u
umask 077
CORE_VERSION="node-v1.0.1"
CORE_BASE="https://github.com/p1neappleXpress/OpenFlux/releases/download/$CORE_VERSION"
SHA_amd64="9fa157550d2c20c0bc03c12823b4ad0140ba070199b5548eacf98c5a2cca6cb8"
SHA_arm64="325335fa416d2f87cba84c5a85d865c596169cd79c7f4cfc916cd67a88612886"
SHA_arm="7f280b01a53bee33e84a7525e035f1e09f51e9070b612b903e492c45c6edf300"
# Where the updater looks for newer node-v* releases. UPDATE_CONF may
# override it with a "repo=owner/name" line.
# The repository this script and its core come from: the core is one of its
# node-v* releases, and the updater follows them (UPDATE_CONF may override
# that with a "repo=owner/name" line).
RELEASE_REPO="p1neappleXpress/OpenFlux"
GITHUB_API="https://api.github.com"
GITHUB_RAW="https://raw.githubusercontent.com"
GITHUB_WEB="https://github.com"
CORE_BASE="$GITHUB_WEB/$RELEASE_REPO/releases/download/$CORE_VERSION"
BIN_DIR="/opt/openflux-node/bin"
CONF_ROOT="/etc/openflux-node"
@@ -175,27 +176,29 @@ installed_core() {
esac
}
# managed_core: installed_core, if this script or the updater put it there
# (BIN_DIR/.managed lists those). A core from anywhere else, such as an old
# fork's node-v1.4.0 whose number says nothing about this repository's
# releases, counts as none.
# managed_core REPO: installed_core, if this script or the updater put it
# there from REPO's releases (BIN_DIR/.managed lists "repo tag" lines).
# A core from anywhere else counts as none: another repository's release
# numbers, like an old fork's node-v1.4.0, say nothing about REPO's.
managed_core() {
cur=$(installed_core)
[ -n "$cur" ] && grep -qsxF "$cur" "$BIN_DIR/.managed" && printf '%s' "$cur"
[ -n "$cur" ] && grep -qsxF "$1 $cur" "$BIN_DIR/.managed" && printf '%s' "$cur"
return 0
}
# mark_managed REPO TAG: BIN_DIR/openflux-TAG is REPO's release now.
mark_managed() {
grep -qsxF "$1" "$BIN_DIR/.managed" || printf '%s\n' "$1" >> "$BIN_DIR/.managed"
{ grep -sv " $2\$" "$BIN_DIR/.managed"; printf '%s %s\n' "$1" "$2"; } > "$BIN_DIR/.managed.new" \
&& mv -f "$BIN_DIR/.managed.new" "$BIN_DIR/.managed"
# A plain user's plan reads it too.
chmod 0644 "$BIN_DIR/.managed"
}
# core_to_use: this script's core, or the installed one when the updater has
# already moved the server to a newer release (an older app must not
# downgrade every channel).
# already moved the server to a newer release of the same repository (an
# older app must not downgrade every channel).
core_to_use() {
cur=$(managed_core)
cur=$(managed_core "$RELEASE_REPO")
if [ -n "$cur" ] && version_gt "$cur" "$CORE_VERSION"; then printf '%s' "$cur"; else printf '%s' "$CORE_VERSION"; fi
}
@@ -367,10 +370,12 @@ cmd_plan() {
core=$(core_to_use)
set --
id "$NODE_USER" >/dev/null 2>&1 || set -- "$@" "Создать системного пользователя $NODE_USER (без входа и домашней папки)"
if [ -x "$BIN_DIR/openflux-$core" ]; then
set -- "$@" "Использовать уже установленное ядро OpenFlux $core"
# The installed file counts only if it is this release of RELEASE_REPO
# (another repository may have a release with the same number).
if [ "$core" != "$CORE_VERSION" ] || { [ -x "$BIN_DIR/openflux-$core" ] && [ "$(sha256_of "$BIN_DIR/openflux-$core")" = "$(core_sha "$arch")" ]; }; then
set -- "$@" "Использовать уже установленное ядро OpenFlux $core ($RELEASE_REPO)"
else
set -- "$@" "Скачать ядро OpenFlux $core (linux-$arch) с GitHub и сверить SHA-256 в $BIN_DIR"
set -- "$@" "Скачать ядро OpenFlux $core (linux-$arch) из релизов $RELEASE_REPO на GitHub и сверить SHA-256 в $BIN_DIR"
fi
set -- "$@" "Создать $CONF_ROOT/$CHANNEL: node.conf и ключ шифрования канала (права 0640)"
[ -n "$COOKIES" ] && set -- "$@" "Сохранить вход в Яндекс для этого канала в $STATE_ROOT/$CHANNEL/cookies.json (права 0600, только для ноды)"
@@ -447,7 +452,7 @@ install_core() {
CREATED_BIN=1
fi
ln -sfn "openflux-$CORE_VERSION" "$BIN_DIR/openflux"
mark_managed "$CORE_VERSION"
mark_managed "$RELEASE_REPO" "$CORE_VERSION"
}
write_unit() {
@@ -485,10 +490,18 @@ EOF
# script_core FILE: the CORE_VERSION a copy of this script pins.
script_core() { sed -n 's/^CORE_VERSION="\(node-v[0-9.]*\)"$/\1/p' "$1" 2>/dev/null | head -n 1; }
# script_repo FILE: the RELEASE_REPO a copy of this script follows.
script_repo() { sed -n 's/^RELEASE_REPO="\([^"]*\)"$/\1/p' "$1" 2>/dev/null | head -n 1; }
# install_self FILE: makes FILE the script the updater runs, unless the copy
# there already pins a newer core (the updater put a newer release's script).
# there follows the same repository and already pins a newer core (the
# updater put a newer release's script). A script from another repository
# always replaces it: the server now runs that repository's core.
install_self() {
if [ -f "$SELF_COPY" ] && version_gt "$(script_core "$SELF_COPY")" "$(script_core "$1")"; then return 0; fi
if [ -f "$SELF_COPY" ] && [ "$(script_repo "$SELF_COPY")" = "$(script_repo "$1")" ] &&
version_gt "$(script_core "$SELF_COPY")" "$(script_core "$1")"; then
return 0
fi
mkdir -p /opt/openflux-node && chmod 0755 /opt/openflux-node || return 1
tmp=$(mktemp /opt/openflux-node/.node-install.XXXXXX) || return 1
if cat "$1" > "$tmp" && chmod 0755 "$tmp" && mv -f "$tmp" "$SELF_COPY"; then return 0; fi
@@ -757,7 +770,7 @@ cmd_update() {
arch=$(detect_arch)
[ -n "$arch" ] || fail update "архитектура $(uname -m) не поддерживается"
repo=$(release_repo)
current=$(managed_core)
current=$(managed_core "$repo")
work=$(mktemp -d /tmp/openflux-node-update.XXXXXX) || fail update "не удалось создать временную папку"
trap 'rm -rf "$work"' EXIT
fetch "$GITHUB_API/repos/$repo/releases?per_page=30" "$work/releases.json" \
@@ -804,7 +817,7 @@ cmd_update() {
printf '%s\n' "$latest" >> "$skip"
fail update "на ядре $latest каналы не поднялись, вернул ${prev#openflux-}; этот релиз больше не ставлю"
fi
mark_managed "$latest"
mark_managed "$repo" "$latest"
install_self "$work/node-install.sh" || true
# Keep the previous core for a manual rollback, drop the older ones.
for old in "$BIN_DIR"/openflux-node-v*; do
+14
View File
@@ -61,6 +61,9 @@ func TestInstallOnVDS(t *testing.T) {
gh.add("node-v1.0.1", gh.good)
mux := http.NewServeMux()
mux.HandleFunc("/node-install.sh", func(w http.ResponseWriter, _ *http.Request) { w.Write(script) })
// The same script following another repository, like a fork's.
otherRepo := regexp.MustCompile(`(?m)^RELEASE_REPO=.*$`).ReplaceAll(script, []byte(`RELEASE_REPO="someone/OpenFlux"`))
mux.HandleFunc("/other-install.sh", func(w http.ResponseWriter, _ *http.Request) { w.Write(otherRepo) })
mux.Handle("/", gh)
srv := &http.Server{Handler: mux}
go srv.Serve(ln)
@@ -266,6 +269,17 @@ func TestInstallOnVDS(t *testing.T) {
if err != nil || older.Core != "node-v1.1.0" {
t.Fatalf("plan after an update: %+v %v", older, err)
}
// A script from another repository does not keep this one's release,
// however new: the server moves to that repository's core.
pinned := c.script
if err := c.FetchScript(Script{URL: base + "/other-install.sh", SHA256: ScriptHash(otherRepo)}); err != nil {
t.Fatal(err)
}
switched, err := c.Plan(Channel{ID: "other"}, false)
if err != nil || switched.Core != "node-v1.0.1" || !strings.Contains(strings.Join(switched.Actions, "\n"), "someone/OpenFlux") {
t.Fatalf("plan from another repository: %+v %v", switched, err)
}
c.script = pinned
if err := c.Remove(id, userPass); err != nil {
t.Fatal(err)