@fastybird/smart-panel-backend 0.2.0-alpha.1 → 0.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/platform/platforms/abstract.platform.d.ts +21 -0
- package/dist/modules/platform/platforms/abstract.platform.js +178 -0
- package/dist/modules/platform/platforms/abstract.platform.js.map +1 -1
- package/dist/modules/platform/platforms/docker.platform.d.ts +2 -0
- package/dist/modules/platform/platforms/docker.platform.js +3 -0
- package/dist/modules/platform/platforms/docker.platform.js.map +1 -1
- package/dist/modules/platform/platforms/home-assistant.platform.d.ts +2 -0
- package/dist/modules/platform/platforms/home-assistant.platform.js +3 -0
- package/dist/modules/platform/platforms/home-assistant.platform.js.map +1 -1
- package/dist/modules/system/scripts/update-worker.sh +294 -0
- package/dist/modules/system/services/update-executor.service.js +21 -1
- package/dist/modules/system/services/update-executor.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -29,5 +29,26 @@ export declare abstract class Platform {
|
|
|
29
29
|
softTempLimit: boolean;
|
|
30
30
|
};
|
|
31
31
|
protected readThrottleFromSysfs(): Promise<ThrottleStatusDto | null>;
|
|
32
|
+
protected readContainerMemory(): Promise<{
|
|
33
|
+
total: number;
|
|
34
|
+
used: number;
|
|
35
|
+
free: number;
|
|
36
|
+
} | null>;
|
|
37
|
+
protected readContainerCpuCount(): Promise<number>;
|
|
38
|
+
protected readContainerCpuLoad(): Promise<number | null>;
|
|
39
|
+
protected filterContainerStorage(fsList: Array<{
|
|
40
|
+
fs: string;
|
|
41
|
+
type: string;
|
|
42
|
+
mount: string;
|
|
43
|
+
size: number;
|
|
44
|
+
used: number;
|
|
45
|
+
available: number;
|
|
46
|
+
}>): Array<{
|
|
47
|
+
fs: string;
|
|
48
|
+
used: number;
|
|
49
|
+
size: number;
|
|
50
|
+
available: number;
|
|
51
|
+
}>;
|
|
52
|
+
protected getContainerSystemInfo(): Promise<SystemInfoDto>;
|
|
32
53
|
protected validateDto<T extends object>(dtoClass: new () => T, rawData: unknown): Promise<T>;
|
|
33
54
|
}
|
|
@@ -6,8 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.Platform = void 0;
|
|
7
7
|
const class_validator_1 = require("class-validator");
|
|
8
8
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const systeminformation_1 = __importDefault(require("systeminformation"));
|
|
9
11
|
const logger_1 = require("../../../common/logger");
|
|
10
12
|
const transform_utils_1 = require("../../../common/utils/transform.utils");
|
|
13
|
+
const system_info_dto_1 = require("../dto/system-info.dto");
|
|
11
14
|
const throttle_status_dto_1 = require("../dto/throttle-status.dto");
|
|
12
15
|
const platform_constants_1 = require("../platform.constants");
|
|
13
16
|
const platform_exceptions_1 = require("../platform.exceptions");
|
|
@@ -35,6 +38,181 @@ class Platform {
|
|
|
35
38
|
}
|
|
36
39
|
return null;
|
|
37
40
|
}
|
|
41
|
+
async readContainerMemory() {
|
|
42
|
+
try {
|
|
43
|
+
const [maxRaw, currentRaw] = await Promise.all([
|
|
44
|
+
promises_1.default.readFile('/sys/fs/cgroup/memory.max', 'utf-8'),
|
|
45
|
+
promises_1.default.readFile('/sys/fs/cgroup/memory.current', 'utf-8'),
|
|
46
|
+
]);
|
|
47
|
+
const max = maxRaw.trim();
|
|
48
|
+
const current = parseInt(currentRaw.trim(), 10);
|
|
49
|
+
if (max !== 'max' && !isNaN(current)) {
|
|
50
|
+
const total = parseInt(max, 10);
|
|
51
|
+
if (!isNaN(total) && total > 0) {
|
|
52
|
+
return { total, used: current, free: Math.max(0, total - current) };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const [limitRaw, usageRaw] = await Promise.all([
|
|
60
|
+
promises_1.default.readFile('/sys/fs/cgroup/memory/memory.limit_in_bytes', 'utf-8'),
|
|
61
|
+
promises_1.default.readFile('/sys/fs/cgroup/memory/memory.usage_in_bytes', 'utf-8'),
|
|
62
|
+
]);
|
|
63
|
+
const limit = parseInt(limitRaw.trim(), 10);
|
|
64
|
+
const usage = parseInt(usageRaw.trim(), 10);
|
|
65
|
+
if (!isNaN(limit) && !isNaN(usage) && limit < 2 ** 62) {
|
|
66
|
+
return { total: limit, used: usage, free: Math.max(0, limit - usage) };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
async readContainerCpuCount() {
|
|
74
|
+
try {
|
|
75
|
+
const raw = await promises_1.default.readFile('/sys/fs/cgroup/cpu.max', 'utf-8');
|
|
76
|
+
const [quotaStr, periodStr] = raw.trim().split(/\s+/);
|
|
77
|
+
if (quotaStr !== 'max') {
|
|
78
|
+
const quota = parseInt(quotaStr, 10);
|
|
79
|
+
const period = parseInt(periodStr, 10);
|
|
80
|
+
if (!isNaN(quota) && quota > 0 && !isNaN(period) && period > 0) {
|
|
81
|
+
return quota / period;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const [quotaRaw, periodRaw] = await Promise.all([
|
|
89
|
+
promises_1.default.readFile('/sys/fs/cgroup/cpu/cpu.cfs_quota_us', 'utf-8'),
|
|
90
|
+
promises_1.default.readFile('/sys/fs/cgroup/cpu/cpu.cfs_period_us', 'utf-8'),
|
|
91
|
+
]);
|
|
92
|
+
const quota = parseInt(quotaRaw.trim(), 10);
|
|
93
|
+
const period = parseInt(periodRaw.trim(), 10);
|
|
94
|
+
if (!isNaN(quota) && quota > 0 && !isNaN(period) && period > 0) {
|
|
95
|
+
return quota / period;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
}
|
|
100
|
+
return os_1.default.cpus().length || 1;
|
|
101
|
+
}
|
|
102
|
+
async readContainerCpuLoad() {
|
|
103
|
+
const cpuCount = await this.readContainerCpuCount();
|
|
104
|
+
try {
|
|
105
|
+
const readV2 = async () => {
|
|
106
|
+
const stat = await promises_1.default.readFile('/sys/fs/cgroup/cpu.stat', 'utf-8');
|
|
107
|
+
const match = stat.match(/usage_usec\s+(\d+)/);
|
|
108
|
+
if (!match) {
|
|
109
|
+
throw new Error('usage_usec not found');
|
|
110
|
+
}
|
|
111
|
+
return parseInt(match[1], 10);
|
|
112
|
+
};
|
|
113
|
+
const t1 = Date.now();
|
|
114
|
+
const u1 = await readV2();
|
|
115
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
116
|
+
const t2 = Date.now();
|
|
117
|
+
const u2 = await readV2();
|
|
118
|
+
const elapsedUs = (t2 - t1) * 1000;
|
|
119
|
+
const cpuUs = u2 - u1;
|
|
120
|
+
if (elapsedUs > 0) {
|
|
121
|
+
return Math.min(100, (cpuUs / (elapsedUs * cpuCount)) * 100);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const readV1 = async () => {
|
|
128
|
+
const raw = await promises_1.default.readFile('/sys/fs/cgroup/cpuacct/cpuacct.usage', 'utf-8');
|
|
129
|
+
return parseInt(raw.trim(), 10);
|
|
130
|
+
};
|
|
131
|
+
const t1 = Date.now();
|
|
132
|
+
const u1 = await readV1();
|
|
133
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
134
|
+
const t2 = Date.now();
|
|
135
|
+
const u2 = await readV1();
|
|
136
|
+
const elapsedNs = (t2 - t1) * 1_000_000;
|
|
137
|
+
const cpuNs = u2 - u1;
|
|
138
|
+
if (elapsedNs > 0) {
|
|
139
|
+
return Math.min(100, (cpuNs / (elapsedNs * cpuCount)) * 100);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
filterContainerStorage(fsList) {
|
|
147
|
+
const PSEUDO_FS = new Set(['tmpfs', 'devtmpfs', 'squashfs', 'proc', 'sysfs', 'ramfs']);
|
|
148
|
+
return fsList
|
|
149
|
+
.filter((d) => d.size > 0 && !PSEUDO_FS.has(d.type) && !d.type.startsWith('cgroup'))
|
|
150
|
+
.map((d) => ({ fs: d.fs, used: d.used, size: d.size, available: d.available }));
|
|
151
|
+
}
|
|
152
|
+
async getContainerSystemInfo() {
|
|
153
|
+
const [hostCpu, hostMemory, storage, osInfo, temp, network, graphics, networkInterface, containerMemory, containerCpu,] = await Promise.all([
|
|
154
|
+
systeminformation_1.default.currentLoad(),
|
|
155
|
+
systeminformation_1.default.mem(),
|
|
156
|
+
systeminformation_1.default.fsSize(),
|
|
157
|
+
systeminformation_1.default.osInfo(),
|
|
158
|
+
systeminformation_1.default.cpuTemperature(),
|
|
159
|
+
systeminformation_1.default.networkStats(),
|
|
160
|
+
systeminformation_1.default.graphics(),
|
|
161
|
+
systeminformation_1.default.networkInterfaces('default'),
|
|
162
|
+
this.readContainerMemory(),
|
|
163
|
+
this.readContainerCpuLoad(),
|
|
164
|
+
]);
|
|
165
|
+
const time = systeminformation_1.default.time();
|
|
166
|
+
const memory = containerMemory ?? {
|
|
167
|
+
total: hostMemory.total,
|
|
168
|
+
used: hostMemory.used,
|
|
169
|
+
free: hostMemory.free,
|
|
170
|
+
};
|
|
171
|
+
const cpuLoad = containerCpu ?? hostCpu.currentLoad;
|
|
172
|
+
const containerStorage = this.filterContainerStorage(storage);
|
|
173
|
+
const defaultNetworkInterface = Array.isArray(networkInterface) ? networkInterface[0] : networkInterface;
|
|
174
|
+
const rawData = {
|
|
175
|
+
cpuLoad,
|
|
176
|
+
memory,
|
|
177
|
+
storage: containerStorage,
|
|
178
|
+
primaryStorage: containerStorage[0] ?? { fs: '', used: 0, size: 0, available: 0 },
|
|
179
|
+
os: {
|
|
180
|
+
platform: osInfo.platform,
|
|
181
|
+
distro: osInfo.distro,
|
|
182
|
+
release: osInfo.release,
|
|
183
|
+
uptime: Math.floor(process.uptime()),
|
|
184
|
+
node: process.version.replace(/^v/, ''),
|
|
185
|
+
npm: null,
|
|
186
|
+
timezone: time.timezone,
|
|
187
|
+
},
|
|
188
|
+
temperature: {
|
|
189
|
+
cpu: temp.main,
|
|
190
|
+
},
|
|
191
|
+
network: network.map((row) => ({
|
|
192
|
+
interface: row.iface,
|
|
193
|
+
rxBytes: row.rx_bytes,
|
|
194
|
+
txBytes: row.tx_bytes,
|
|
195
|
+
})),
|
|
196
|
+
defaultNetwork: {
|
|
197
|
+
interface: defaultNetworkInterface?.iface ?? '',
|
|
198
|
+
ip4: defaultNetworkInterface?.ip4 ?? '',
|
|
199
|
+
ip6: defaultNetworkInterface?.ip6 ?? '',
|
|
200
|
+
mac: defaultNetworkInterface?.mac ?? '',
|
|
201
|
+
hostname: osInfo.hostname,
|
|
202
|
+
},
|
|
203
|
+
display: {
|
|
204
|
+
resolutionX: graphics.displays[0]?.resolutionX || 0,
|
|
205
|
+
resolutionY: graphics.displays[0]?.resolutionY || 0,
|
|
206
|
+
currentResX: graphics.displays[0]?.currentResX || 0,
|
|
207
|
+
currentResY: graphics.displays[0]?.currentResY || 0,
|
|
208
|
+
},
|
|
209
|
+
process: {
|
|
210
|
+
pid: process.pid,
|
|
211
|
+
uptime: Math.floor(process.uptime()),
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
return this.validateDto(system_info_dto_1.SystemInfoDto, rawData);
|
|
215
|
+
}
|
|
38
216
|
async validateDto(dtoClass, rawData) {
|
|
39
217
|
const instance = (0, transform_utils_1.toInstance)(dtoClass, rawData);
|
|
40
218
|
const errors = await (0, class_validator_1.validate)(instance, { whitelist: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"abstract.platform.js","sourceRoot":"","sources":["../../../../src/modules/platform/platforms/abstract.platform.ts"],"names":[],"mappings":";;;;;;AAAA,qDAA2C;AAC3C,2DAA6B;
|
|
1
|
+
{"version":3,"file":"abstract.platform.js","sourceRoot":"","sources":["../../../../src/modules/platform/platforms/abstract.platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { SystemInfoDto } from '../dto/system-info.dto';
|
|
1
2
|
import { GenericPlatform } from './generic.platform';
|
|
2
3
|
export declare class DockerPlatform extends GenericPlatform {
|
|
4
|
+
getSystemInfo(): Promise<SystemInfoDto>;
|
|
3
5
|
rebootDevice(): Promise<void>;
|
|
4
6
|
powerOffDevice(): Promise<void>;
|
|
5
7
|
private getContainerId;
|
|
@@ -11,6 +11,9 @@ const util_1 = require("util");
|
|
|
11
11
|
const generic_platform_1 = require("./generic.platform");
|
|
12
12
|
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
13
13
|
class DockerPlatform extends generic_platform_1.GenericPlatform {
|
|
14
|
+
async getSystemInfo() {
|
|
15
|
+
return this.getContainerSystemInfo();
|
|
16
|
+
}
|
|
14
17
|
async rebootDevice() {
|
|
15
18
|
this.logger.log('[SYSTEM] Restarting container via Docker API...');
|
|
16
19
|
const containerId = await this.getContainerId();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker.platform.js","sourceRoot":"","sources":["../../../../src/modules/platform/platforms/docker.platform.ts"],"names":[],"mappings":";;;;;;AAAA,iDAAyC;AACzC,0CAAuC;AACvC,4CAAoB;AACpB,+BAAiC;
|
|
1
|
+
{"version":3,"file":"docker.platform.js","sourceRoot":"","sources":["../../../../src/modules/platform/platforms/docker.platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { SystemInfoDto } from '../dto/system-info.dto';
|
|
1
2
|
import { ThrottleStatusDto } from '../dto/throttle-status.dto';
|
|
2
3
|
import { GenericPlatform } from './generic.platform';
|
|
3
4
|
export declare class HomeAssistantPlatform extends GenericPlatform {
|
|
4
5
|
private readonly supervisorToken;
|
|
5
6
|
private readonly supervisorUrl;
|
|
6
7
|
constructor();
|
|
8
|
+
getSystemInfo(): Promise<SystemInfoDto>;
|
|
7
9
|
getThrottleStatus(): Promise<ThrottleStatusDto>;
|
|
8
10
|
rebootDevice(): Promise<void>;
|
|
9
11
|
powerOffDevice(): Promise<void>;
|
|
@@ -10,6 +10,9 @@ class HomeAssistantPlatform extends generic_platform_1.GenericPlatform {
|
|
|
10
10
|
this.supervisorToken = process.env.SUPERVISOR_TOKEN ?? null;
|
|
11
11
|
this.supervisorUrl = process.env.SUPERVISOR_URL ?? 'http://supervisor';
|
|
12
12
|
}
|
|
13
|
+
async getSystemInfo() {
|
|
14
|
+
return this.getContainerSystemInfo();
|
|
15
|
+
}
|
|
13
16
|
async getThrottleStatus() {
|
|
14
17
|
const result = await this.readThrottleFromSysfs();
|
|
15
18
|
if (result) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home-assistant.platform.js","sourceRoot":"","sources":["../../../../src/modules/platform/platforms/home-assistant.platform.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"home-assistant.platform.js","sourceRoot":"","sources":["../../../../src/modules/platform/platforms/home-assistant.platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
VERSION="${1:-${UPDATE_VERSION:-latest}}"
|
|
5
|
+
STATUS_FILE="${STATUS_FILE:-/var/lib/smart-panel/update-status.json}"
|
|
6
|
+
INSTALL_TYPE="${INSTALL_TYPE:-npm}"
|
|
7
|
+
IMAGE_BASE_DIR="${IMAGE_BASE_DIR:-/opt/smart-panel}"
|
|
8
|
+
DOWNLOAD_URL="${DOWNLOAD_URL:-}"
|
|
9
|
+
|
|
10
|
+
# Capture once — used for all status writes so timeout detection works correctly
|
|
11
|
+
STARTED_AT="$(date -Iseconds)"
|
|
12
|
+
|
|
13
|
+
update_status() {
|
|
14
|
+
local status="$1"
|
|
15
|
+
local phase="$2"
|
|
16
|
+
local error="${3:-}"
|
|
17
|
+
local completed_at=""
|
|
18
|
+
|
|
19
|
+
if [ "$status" = "complete" ] || [ "$status" = "failed" ]; then
|
|
20
|
+
completed_at=$(date -Iseconds)
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
local tmp_file="${STATUS_FILE}.tmp"
|
|
24
|
+
|
|
25
|
+
# Use printf with %s to prevent injection in JSON values.
|
|
26
|
+
# Escape double-quotes and backslashes in the error message.
|
|
27
|
+
local safe_error=""
|
|
28
|
+
if [ -n "$error" ]; then
|
|
29
|
+
safe_error=$(printf '%s' "$error" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
printf '{\n\t"status": "%s",\n\t"phase": "%s",\n\t"targetVersion": "%s",\n\t"startedAt": "%s"' \
|
|
33
|
+
"$status" "$phase" "$VERSION" "$STARTED_AT" > "$tmp_file"
|
|
34
|
+
|
|
35
|
+
if [ -n "$completed_at" ]; then
|
|
36
|
+
printf ',\n\t"completedAt": "%s"' "$completed_at" >> "$tmp_file"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
printf ',\n\t"error": "%s"' "$safe_error" >> "$tmp_file"
|
|
40
|
+
printf '\n}\n' >> "$tmp_file"
|
|
41
|
+
|
|
42
|
+
mv "$tmp_file" "$STATUS_FILE"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
cleanup() {
|
|
46
|
+
local exit_code=$?
|
|
47
|
+
|
|
48
|
+
if [ $exit_code -ne 0 ]; then
|
|
49
|
+
# Only write a generic failure if a specific error wasn't already recorded
|
|
50
|
+
if [ -f "$STATUS_FILE" ] && grep -q '"status": "failed"' "$STATUS_FILE" 2>/dev/null; then
|
|
51
|
+
return
|
|
52
|
+
fi
|
|
53
|
+
update_status "failed" "failed" "Update process exited with code $exit_code"
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
trap cleanup EXIT
|
|
58
|
+
|
|
59
|
+
# ──────────────────────────────────────────────────────────────
|
|
60
|
+
# Image-based update (Raspbian image installs)
|
|
61
|
+
# ──────────────────────────────────────────────────────────────
|
|
62
|
+
if [ "$INSTALL_TYPE" = "image" ]; then
|
|
63
|
+
# Verify passwordless sudo is available (required for systemctl, chown, ln)
|
|
64
|
+
if ! sudo -n true 2>/dev/null; then
|
|
65
|
+
update_status "failed" "failed" "Passwordless sudo is not available for this user"
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
68
|
+
# Strip leading 'v' prefix if present to avoid double-prefixed dirs like vv1.0.0
|
|
69
|
+
CLEAN_VERSION="${VERSION#v}"
|
|
70
|
+
NEW_VERSION_DIR="${IMAGE_BASE_DIR}/v${CLEAN_VERSION}"
|
|
71
|
+
CURRENT_LINK="${IMAGE_BASE_DIR}/current"
|
|
72
|
+
PREVIOUS_TARGET=""
|
|
73
|
+
|
|
74
|
+
# Save the current version for rollback
|
|
75
|
+
if [ -L "$CURRENT_LINK" ]; then
|
|
76
|
+
PREVIOUS_TARGET=$(readlink "$CURRENT_LINK")
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Guard: refuse to overwrite the currently running version
|
|
80
|
+
# Resolve relative to IMAGE_BASE_DIR since PREVIOUS_TARGET may be relative
|
|
81
|
+
RESOLVED_PREV=$(cd "$IMAGE_BASE_DIR" && realpath "$PREVIOUS_TARGET" 2>/dev/null || true)
|
|
82
|
+
RESOLVED_NEW=$(cd "$IMAGE_BASE_DIR" && realpath "$NEW_VERSION_DIR" 2>/dev/null || true)
|
|
83
|
+
|
|
84
|
+
if [ -n "$PREVIOUS_TARGET" ] && [ -n "$RESOLVED_PREV" ] && [ -n "$RESOLVED_NEW" ] && [ "$RESOLVED_PREV" = "$RESOLVED_NEW" ]; then
|
|
85
|
+
update_status "failed" "failed" "Target version v${CLEAN_VERSION} is already the active version"
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# ── Download ──
|
|
90
|
+
update_status "downloading" "downloading"
|
|
91
|
+
|
|
92
|
+
if [ -z "$DOWNLOAD_URL" ]; then
|
|
93
|
+
update_status "failed" "failed" "No download URL provided for image update"
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
TMP_TARBALL="/tmp/smart-panel-backend-v${CLEAN_VERSION}.tar.gz"
|
|
98
|
+
|
|
99
|
+
curl -fSL -o "$TMP_TARBALL" "$DOWNLOAD_URL" 2>&1 || {
|
|
100
|
+
update_status "failed" "failed" "Download failed from ${DOWNLOAD_URL}"
|
|
101
|
+
exit 1
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# ── Extract ──
|
|
105
|
+
update_status "installing" "installing"
|
|
106
|
+
|
|
107
|
+
mkdir -p "$NEW_VERSION_DIR"
|
|
108
|
+
|
|
109
|
+
tar -xzf "$TMP_TARBALL" -C "$NEW_VERSION_DIR" 2>&1 || {
|
|
110
|
+
rm -rf "$NEW_VERSION_DIR"
|
|
111
|
+
rm -f "$TMP_TARBALL"
|
|
112
|
+
update_status "failed" "failed" "Failed to extract update archive"
|
|
113
|
+
exit 1
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
rm -f "$TMP_TARBALL"
|
|
117
|
+
|
|
118
|
+
# Create the image-install marker in the new version
|
|
119
|
+
touch "${NEW_VERSION_DIR}/.image-install" || {
|
|
120
|
+
rm -rf "$NEW_VERSION_DIR"
|
|
121
|
+
update_status "failed" "failed" "Failed to create image-install marker"
|
|
122
|
+
exit 1
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# ── Install dependencies ──
|
|
126
|
+
cd "$NEW_VERSION_DIR"
|
|
127
|
+
|
|
128
|
+
pnpm install --prod --ignore-scripts 2>&1 || {
|
|
129
|
+
rm -rf "$NEW_VERSION_DIR"
|
|
130
|
+
update_status "failed" "failed" "pnpm install failed"
|
|
131
|
+
exit 1
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# ── Rebuild native modules ──
|
|
135
|
+
if [ -x "${IMAGE_BASE_DIR}/rebuild-native.sh" ]; then
|
|
136
|
+
"${IMAGE_BASE_DIR}/rebuild-native.sh" "${NEW_VERSION_DIR}" 2>&1 || {
|
|
137
|
+
rm -rf "$NEW_VERSION_DIR"
|
|
138
|
+
update_status "failed" "failed" "Native module rebuild failed"
|
|
139
|
+
exit 1
|
|
140
|
+
}
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Set ownership
|
|
144
|
+
sudo chown -R smart-panel:smart-panel "$NEW_VERSION_DIR" || {
|
|
145
|
+
rm -rf "$NEW_VERSION_DIR"
|
|
146
|
+
update_status "failed" "failed" "Failed to set ownership on ${NEW_VERSION_DIR}"
|
|
147
|
+
exit 1
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# ── Stop service ──
|
|
151
|
+
update_status "stopping" "stopping"
|
|
152
|
+
sudo systemctl stop smart-panel 2>/dev/null || true
|
|
153
|
+
|
|
154
|
+
# ── Switch symlink (atomic on same filesystem) ──
|
|
155
|
+
sudo ln -sfn "$NEW_VERSION_DIR" "$CURRENT_LINK" || {
|
|
156
|
+
# Revert on failure
|
|
157
|
+
if [ -n "$PREVIOUS_TARGET" ]; then
|
|
158
|
+
sudo ln -sfn "$PREVIOUS_TARGET" "$CURRENT_LINK"
|
|
159
|
+
fi
|
|
160
|
+
sudo systemctl start smart-panel 2>/dev/null || true
|
|
161
|
+
update_status "failed" "failed" "Failed to switch version symlink"
|
|
162
|
+
exit 1
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# ── Run database migrations ──
|
|
166
|
+
update_status "migrating" "migrating"
|
|
167
|
+
|
|
168
|
+
ENV_FILE="/etc/smart-panel/environment"
|
|
169
|
+
|
|
170
|
+
if [ -f "${NEW_VERSION_DIR}/dist/dataSource.js" ]; then
|
|
171
|
+
(
|
|
172
|
+
set -a
|
|
173
|
+
# shellcheck source=/dev/null
|
|
174
|
+
[ -f "$ENV_FILE" ] && . "$ENV_FILE"
|
|
175
|
+
set +a
|
|
176
|
+
cd "$NEW_VERSION_DIR"
|
|
177
|
+
node node_modules/typeorm/cli.js migration:run -d dist/dataSource.js
|
|
178
|
+
) 2>&1 || {
|
|
179
|
+
# Migration failed — revert symlink if possible
|
|
180
|
+
update_status "stopping" "stopping"
|
|
181
|
+
sudo systemctl stop smart-panel 2>/dev/null || true
|
|
182
|
+
|
|
183
|
+
if [ -n "$PREVIOUS_TARGET" ]; then
|
|
184
|
+
if sudo ln -sfn "$PREVIOUS_TARGET" "$CURRENT_LINK"; then
|
|
185
|
+
rm -rf "$NEW_VERSION_DIR"
|
|
186
|
+
update_status "failed" "failed" "Database migration failed — reverted to previous version"
|
|
187
|
+
else
|
|
188
|
+
# Symlink revert failed — keep new version so system stays bootable
|
|
189
|
+
update_status "failed" "failed" "Database migration failed — symlink revert also failed"
|
|
190
|
+
fi
|
|
191
|
+
else
|
|
192
|
+
# No previous version — keep current in place so system stays bootable
|
|
193
|
+
update_status "failed" "failed" "Database migration failed — no previous version to revert to"
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
sudo systemctl start smart-panel 2>/dev/null || true
|
|
197
|
+
exit 1
|
|
198
|
+
}
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# ── Start service ──
|
|
202
|
+
update_status "starting" "starting"
|
|
203
|
+
sudo systemctl start smart-panel 2>&1 || {
|
|
204
|
+
# Try to revert if start fails
|
|
205
|
+
if [ -n "$PREVIOUS_TARGET" ]; then
|
|
206
|
+
sudo ln -sfn "$PREVIOUS_TARGET" "$CURRENT_LINK"
|
|
207
|
+
sudo systemctl start smart-panel 2>/dev/null || true
|
|
208
|
+
fi
|
|
209
|
+
update_status "failed" "failed" "Failed to start service after update"
|
|
210
|
+
exit 1
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# ── Cleanup old versions (keep max 2 previous) ──
|
|
214
|
+
cd "$IMAGE_BASE_DIR"
|
|
215
|
+
|
|
216
|
+
# Use the known current version rather than re-reading the symlink,
|
|
217
|
+
# so cleanup is safe even if readlink fails unexpectedly
|
|
218
|
+
CURRENT_BASENAME="v${CLEAN_VERSION}"
|
|
219
|
+
|
|
220
|
+
if [ -n "$CURRENT_BASENAME" ]; then
|
|
221
|
+
# Only match semver-versioned directories (v<digits>.<digits>.<digits>*)
|
|
222
|
+
# to avoid accidentally deleting unrelated v-prefixed directories
|
|
223
|
+
# shellcheck disable=SC2010
|
|
224
|
+
OLD_VERSIONS=$(ls -d v[0-9]*.[0-9]*.[0-9]*/ 2>/dev/null | grep -v "^${CURRENT_BASENAME}/" | sort -V | head -n -2 || true)
|
|
225
|
+
|
|
226
|
+
for old_dir in $OLD_VERSIONS; do
|
|
227
|
+
rm -rf "${IMAGE_BASE_DIR}/${old_dir}"
|
|
228
|
+
done
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
# ── Mark complete ──
|
|
232
|
+
update_status "complete" "complete"
|
|
233
|
+
trap - EXIT
|
|
234
|
+
exit 0
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
# ──────────────────────────────────────────────────────────────
|
|
238
|
+
# NPM-based update (global npm installs)
|
|
239
|
+
# ──────────────────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
# Downloading / preparing
|
|
242
|
+
update_status "downloading" "downloading"
|
|
243
|
+
|
|
244
|
+
# Stop the service
|
|
245
|
+
update_status "stopping" "stopping"
|
|
246
|
+
sudo systemctl stop smart-panel 2>/dev/null || true
|
|
247
|
+
|
|
248
|
+
# Install the update
|
|
249
|
+
update_status "installing" "installing"
|
|
250
|
+
|
|
251
|
+
if [ "$VERSION" = "latest" ]; then
|
|
252
|
+
npm update -g @fastybird/smart-panel 2>&1 || {
|
|
253
|
+
update_status "failed" "failed" "npm update failed"
|
|
254
|
+
sudo systemctl start smart-panel 2>/dev/null || true
|
|
255
|
+
exit 1
|
|
256
|
+
}
|
|
257
|
+
else
|
|
258
|
+
npm install -g "@fastybird/smart-panel@$VERSION" 2>&1 || {
|
|
259
|
+
update_status "failed" "failed" "npm install failed for version $VERSION"
|
|
260
|
+
sudo systemctl start smart-panel 2>/dev/null || true
|
|
261
|
+
exit 1
|
|
262
|
+
}
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
# Run database migrations
|
|
266
|
+
update_status "migrating" "migrating"
|
|
267
|
+
|
|
268
|
+
DATA_DIR="${FB_DATA_DIR:-/var/lib/smart-panel}"
|
|
269
|
+
DB_PATH="${FB_DB_PATH:-${DATA_DIR}/data}"
|
|
270
|
+
|
|
271
|
+
if [ -f "$(npm root -g)/@fastybird/smart-panel/dataSource.js" ]; then
|
|
272
|
+
node "$(npm root -g)/@fastybird/smart-panel/node_modules/typeorm/cli.js" \
|
|
273
|
+
migration:run \
|
|
274
|
+
-d "$(npm root -g)/@fastybird/smart-panel/dataSource.js" 2>&1 || {
|
|
275
|
+
update_status "failed" "failed" "Database migration failed"
|
|
276
|
+
sudo systemctl start smart-panel 2>/dev/null || true
|
|
277
|
+
exit 1
|
|
278
|
+
}
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
# Start the service
|
|
282
|
+
update_status "starting" "starting"
|
|
283
|
+
sudo systemctl start smart-panel 2>&1 || {
|
|
284
|
+
update_status "failed" "failed" "Failed to start service after update"
|
|
285
|
+
exit 1
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
# Mark as complete
|
|
289
|
+
update_status "complete" "complete"
|
|
290
|
+
|
|
291
|
+
# Remove the exit trap since we completed successfully
|
|
292
|
+
trap - EXIT
|
|
293
|
+
|
|
294
|
+
exit 0
|
|
@@ -158,7 +158,27 @@ let UpdateExecutorService = class UpdateExecutorService {
|
|
|
158
158
|
error: null,
|
|
159
159
|
startedAt: new Date(),
|
|
160
160
|
});
|
|
161
|
-
const updateScript = (0, path_1.join)(__dirname, '..', '
|
|
161
|
+
const updateScript = (0, path_1.join)(__dirname, '..', 'scripts', 'update-worker.sh');
|
|
162
|
+
if (!(0, fs_1.existsSync)(updateScript)) {
|
|
163
|
+
this.updateService.releaseUpdateLock();
|
|
164
|
+
const errorMsg = `Update worker script not found at ${updateScript}`;
|
|
165
|
+
this.logger.error(errorMsg);
|
|
166
|
+
this.updateService.setStatus({
|
|
167
|
+
status: system_constants_1.UpdateStatusType.FAILED,
|
|
168
|
+
phase: system_constants_1.UpdatePhase.FAILED,
|
|
169
|
+
progressPercent: null,
|
|
170
|
+
message: null,
|
|
171
|
+
error: errorMsg,
|
|
172
|
+
});
|
|
173
|
+
this.writeStatusFile({
|
|
174
|
+
status: system_constants_1.UpdateStatusType.FAILED,
|
|
175
|
+
phase: system_constants_1.UpdatePhase.FAILED,
|
|
176
|
+
targetVersion,
|
|
177
|
+
startedAt: new Date().toISOString(),
|
|
178
|
+
error: errorMsg,
|
|
179
|
+
});
|
|
180
|
+
throw new Error(errorMsg);
|
|
181
|
+
}
|
|
162
182
|
try {
|
|
163
183
|
const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
164
184
|
const child = spawn('bash', [updateScript, targetVersion], {
|