Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a76e520e7 | |||
| d9e1fc17f8 | |||
| 3b179075a8 |
@@ -3,6 +3,14 @@
|
|||||||
## Pending
|
## Pending
|
||||||
|
|
||||||
|
|
||||||
|
## 2026-05-25 - 2.1.2
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- keep self-upgrades alive after stopping the service (upgrade)
|
||||||
|
- Launch dashboard-triggered upgrades as transient systemd units outside the service cgroup.
|
||||||
|
- Download and validate installer binaries before stopping the running service.
|
||||||
|
- Restart the previous service if installation fails after it was stopped.
|
||||||
|
|
||||||
## 2026-05-25 - 2.1.1
|
## 2026-05-25 - 2.1.1
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@serve.zone/onebox",
|
"name": "@serve.zone/onebox",
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"exports": "./mod.ts",
|
"exports": "./mod.ts",
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"test": "deno test --allow-all test/",
|
"test": "deno test --allow-all test/",
|
||||||
|
|||||||
+51
-41
@@ -170,14 +170,55 @@ DOWNLOAD_URL="${GITEA_BASE_URL}/${GITEA_REPO}/releases/download/${VERSION}/${BIN
|
|||||||
echo "Download URL: $DOWNLOAD_URL"
|
echo "Download URL: $DOWNLOAD_URL"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Check if service is running and stop it
|
# Check whether the service should be restarted after a successful install.
|
||||||
SERVICE_WAS_RUNNING=0
|
SERVICE_WAS_RUNNING=0
|
||||||
if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null || systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null || systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||||
SERVICE_WAS_RUNNING=1
|
SERVICE_WAS_RUNNING=1
|
||||||
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
fi
|
||||||
echo "Stopping Onebox service..."
|
|
||||||
systemctl stop "$SERVICE_NAME"
|
# Download and validate the new binary before touching the running service.
|
||||||
|
echo "Downloading Onebox binary..."
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
TEMP_FILE="$TEMP_DIR/$BINARY_NAME"
|
||||||
|
cleanup_temp() {
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup_temp EXIT
|
||||||
|
|
||||||
|
if ! curl -fSL "$DOWNLOAD_URL" -o "$TEMP_FILE"; then
|
||||||
|
echo "Error: Failed to download binary from $DOWNLOAD_URL"
|
||||||
|
echo ""
|
||||||
|
echo "Please check:"
|
||||||
|
echo " 1. Your internet connection"
|
||||||
|
echo " 2. The specified version exists: ${GITEA_BASE_URL}/${GITEA_REPO}/releases"
|
||||||
|
echo " 3. The platform binary is available for this release"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -s "$TEMP_FILE" ]; then
|
||||||
|
echo "Error: Downloaded file is empty or does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "$TEMP_FILE"
|
||||||
|
if ! "$TEMP_FILE" --version >/dev/null 2>&1; then
|
||||||
|
echo "Error: Downloaded file is not an executable Onebox binary"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SERVICE_STOPPED=0
|
||||||
|
restart_previous_service_on_error() {
|
||||||
|
if [ $SERVICE_STOPPED -eq 1 ]; then
|
||||||
|
echo "Installation failed after stopping Onebox; restarting previous service..."
|
||||||
|
systemctl start "$SERVICE_NAME" || true
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
trap 'restart_previous_service_on_error; cleanup_temp' ERR
|
||||||
|
|
||||||
|
if [ $SERVICE_WAS_RUNNING -eq 1 ] && systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||||
|
echo "Stopping Onebox service..."
|
||||||
|
systemctl stop "$SERVICE_NAME"
|
||||||
|
SERVICE_STOPPED=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clean installation directory - ensure only binary exists
|
# Clean installation directory - ensure only binary exists
|
||||||
@@ -190,44 +231,10 @@ fi
|
|||||||
echo "Creating installation directory: $INSTALL_DIR"
|
echo "Creating installation directory: $INSTALL_DIR"
|
||||||
mkdir -p "$INSTALL_DIR"
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
|
||||||
# Download binary
|
# Install binary
|
||||||
echo "Downloading Onebox binary..."
|
|
||||||
TEMP_FILE="$INSTALL_DIR/onebox.download"
|
|
||||||
curl -sSL "$DOWNLOAD_URL" -o "$TEMP_FILE"
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Error: Failed to download binary from $DOWNLOAD_URL"
|
|
||||||
echo ""
|
|
||||||
echo "Please check:"
|
|
||||||
echo " 1. Your internet connection"
|
|
||||||
echo " 2. The specified version exists: ${GITEA_BASE_URL}/${GITEA_REPO}/releases"
|
|
||||||
echo " 3. The platform binary is available for this release"
|
|
||||||
rm -f "$TEMP_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if download was successful (file exists and not empty)
|
|
||||||
if [ ! -s "$TEMP_FILE" ]; then
|
|
||||||
echo "Error: Downloaded file is empty or does not exist"
|
|
||||||
rm -f "$TEMP_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Move to final location
|
|
||||||
BINARY_PATH="$INSTALL_DIR/onebox"
|
BINARY_PATH="$INSTALL_DIR/onebox"
|
||||||
mv "$TEMP_FILE" "$BINARY_PATH"
|
if ! install -m 0755 "$TEMP_FILE" "$BINARY_PATH" || [ ! -f "$BINARY_PATH" ]; then
|
||||||
|
echo "Error: Failed to install binary to $BINARY_PATH"
|
||||||
if [ $? -ne 0 ] || [ ! -f "$BINARY_PATH" ]; then
|
|
||||||
echo "Error: Failed to move binary to $BINARY_PATH"
|
|
||||||
rm -f "$TEMP_FILE" 2>/dev/null
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make executable
|
|
||||||
chmod +x "$BINARY_PATH"
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Error: Failed to make binary executable"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -256,10 +263,13 @@ if [ $SERVICE_WAS_RUNNING -eq 1 ]; then
|
|||||||
onebox systemd enable
|
onebox systemd enable
|
||||||
echo "Restarting Onebox service..."
|
echo "Restarting Onebox service..."
|
||||||
systemctl restart "$SERVICE_NAME"
|
systemctl restart "$SERVICE_NAME"
|
||||||
|
SERVICE_STOPPED=0
|
||||||
echo "Service restarted successfully."
|
echo "Service restarted successfully."
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
trap - ERR
|
||||||
|
|
||||||
echo "================================================"
|
echo "================================================"
|
||||||
echo " Onebox Installation Complete!"
|
echo " Onebox Installation Complete!"
|
||||||
echo "================================================"
|
echo "================================================"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@serve.zone/onebox",
|
"name": "@serve.zone/onebox",
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"description": "Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers",
|
"description": "Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers",
|
||||||
"main": "mod.ts",
|
"main": "mod.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/onebox',
|
name: '@serve.zone/onebox',
|
||||||
version: '2.1.1',
|
version: '2.1.2',
|
||||||
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,24 +66,43 @@ export class OneboxUpdateManager {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const command = new Deno.Command('bash', {
|
const unitName = `onebox-upgrade-${Date.now()}`;
|
||||||
args: ['-c', this.createDetachedUpgradeScript()],
|
const command = new Deno.Command('systemd-run', {
|
||||||
|
args: [
|
||||||
|
'--unit',
|
||||||
|
unitName,
|
||||||
|
'--description',
|
||||||
|
`Onebox upgrade to ${targetVersion}`,
|
||||||
|
'--collect',
|
||||||
|
'--property=Type=oneshot',
|
||||||
|
'--setenv=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
|
||||||
|
'bash',
|
||||||
|
'-lc',
|
||||||
|
this.createDetachedUpgradeScript(),
|
||||||
|
],
|
||||||
stdin: 'null',
|
stdin: 'null',
|
||||||
stdout: 'null',
|
stdout: 'piped',
|
||||||
stderr: 'null',
|
stderr: 'piped',
|
||||||
detached: true,
|
|
||||||
});
|
});
|
||||||
const child = command.spawn();
|
const result = await command.output();
|
||||||
child.unref();
|
if (!result.success) {
|
||||||
|
const stderr = new TextDecoder().decode(result.stderr).trim();
|
||||||
|
const stdout = new TextDecoder().decode(result.stdout).trim();
|
||||||
|
throw new Error(
|
||||||
|
`Failed to start Onebox upgrade systemd unit: ${
|
||||||
|
stderr || stdout || `exit code ${result.code}`
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
this.upgradeStartedAt = Date.now();
|
this.upgradeStartedAt = Date.now();
|
||||||
|
|
||||||
logger.info(`Started detached Onebox upgrade process ${child.pid}`);
|
logger.info(`Started Onebox upgrade systemd unit ${unitName}`);
|
||||||
return {
|
return {
|
||||||
accepted: true,
|
accepted: true,
|
||||||
currentVersion: status.currentVersion,
|
currentVersion: status.currentVersion,
|
||||||
targetVersion,
|
targetVersion,
|
||||||
message: 'Onebox upgrade started. The service will restart automatically.',
|
message: 'Onebox upgrade started. The service will restart automatically.',
|
||||||
pid: child.pid,
|
unitName,
|
||||||
logPath: UPGRADE_LOG_PATH,
|
logPath: UPGRADE_LOG_PATH,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -107,7 +126,7 @@ export class OneboxUpdateManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const installCommand = new Deno.Command('bash', {
|
const installCommand = new Deno.Command('bash', {
|
||||||
args: ['-c', `curl -sSL ${ONEBOX_INSTALL_SCRIPT_URL} | bash`],
|
args: ['-c', `set -o pipefail; curl -fsSL ${ONEBOX_INSTALL_SCRIPT_URL} | bash`],
|
||||||
stdin: 'inherit',
|
stdin: 'inherit',
|
||||||
stdout: 'inherit',
|
stdout: 'inherit',
|
||||||
stderr: 'inherit',
|
stderr: 'inherit',
|
||||||
@@ -202,11 +221,12 @@ export class OneboxUpdateManager {
|
|||||||
private createDetachedUpgradeScript(): string {
|
private createDetachedUpgradeScript(): string {
|
||||||
return `
|
return `
|
||||||
set -e
|
set -e
|
||||||
|
set -o pipefail
|
||||||
mkdir -p /var/log
|
mkdir -p /var/log
|
||||||
{
|
{
|
||||||
echo "==== Onebox upgrade started $(date -Is) ===="
|
echo "==== Onebox upgrade started $(date -Is) ===="
|
||||||
sleep 2
|
sleep 2
|
||||||
curl -sSL ${ONEBOX_INSTALL_SCRIPT_URL} | bash
|
curl -fsSL ${ONEBOX_INSTALL_SCRIPT_URL} | bash
|
||||||
echo "==== Onebox upgrade finished $(date -Is) ===="
|
echo "==== Onebox upgrade finished $(date -Is) ===="
|
||||||
} >> ${UPGRADE_LOG_PATH} 2>&1
|
} >> ${UPGRADE_LOG_PATH} 2>&1
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* System status data shapes for Onebox
|
* System status data shapes for Onebox
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { TPlatformServiceType, TPlatformServiceStatus } from './platform.ts';
|
import type { TPlatformServiceStatus, TPlatformServiceType } from './platform.ts';
|
||||||
|
|
||||||
export interface IOneboxUpdateStatus {
|
export interface IOneboxUpdateStatus {
|
||||||
currentVersion: string;
|
currentVersion: string;
|
||||||
@@ -20,6 +20,7 @@ export interface IOneboxUpgradeStartResult {
|
|||||||
targetVersion: string;
|
targetVersion: string;
|
||||||
message: string;
|
message: string;
|
||||||
pid?: number;
|
pid?: number;
|
||||||
|
unitName?: string;
|
||||||
logPath?: string;
|
logPath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@serve.zone/onebox',
|
name: '@serve.zone/onebox',
|
||||||
version: '2.1.1',
|
version: '2.1.2',
|
||||||
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user