Compare commits

...
678 Commits
Author SHA1 Message Date
KroeseandGitHub 51d6f3aeca fix: Reserve internal ports for user-mode forwarding (#1348) 2026-08-02 23:01:52 +02:00
KroeseandGitHub 4544620d48 feat: Increase indentation of printed QEMU arguments (#1347) 2026-08-01 05:49:50 +02:00
KroeseandGitHub de8468161f feat: Refactor negated command conditions (#1346) 2026-07-30 21:22:21 +02:00
renovate[bot]andGitHub 18d6be8210 chore(deps): update hadolint/hadolint-action action to v3.4.0 (#1345) 2026-07-30 21:06:27 +02:00
KroeseandGitHub e5b8cf3bf8 build: Update Passt to v2026_07_28 (#1344) 2026-07-30 10:10:41 +02:00
KroeseandGitHub ec12039f43 feat: Use deadline-based process timeouts (#1343) 2026-07-28 15:22:47 +02:00
KroeseandGitHub 3c7c3ca1b1 fix: Prevent race when reading PID files (#1342) 2026-07-28 14:22:08 +02:00
KroeseandGitHub 2b27f32cd4 fix: Disk options were applied to the controller (#1341) 2026-07-28 03:30:55 +02:00
KroeseandGitHub 55d1d50284 fix: Retry transient gateway errors in web status (#1340) 2026-07-27 23:49:22 +02:00
KroeseandGitHub 784b73b5b5 feat: Add DISK_OPTIONS support to disk devices (#1339) 2026-07-27 23:48:21 +02:00
KroeseandGitHub 85f00bb9cc docs: Added new DISK_OPTIONS variable (#1338) 2026-07-27 12:04:25 +02:00
KroeseandGitHub efe8732e47 fix: Avoid shadowing PID output variables (#1337) 2026-07-27 12:03:24 +02:00
KroeseandGitHub f6871dd61b fix: Clear invalid PID values in shared reader (#1336) 2026-07-26 17:52:14 +02:00
KroeseandGitHub a713b728ff fix: Use shared PID reader for helper processes (#1335) 2026-07-26 17:41:46 +02:00
KroeseandGitHub 0d74c6ac80 build: Update dependabot config (#1334) 2026-07-26 00:58:36 +02:00
KroeseandGitHub 63e4529eff fix: Add cleanup for failed web server startup (#1333) 2026-07-25 13:47:20 +02:00
KroeseandGitHub afd848cebb fix: Make healthcheck succeed during download (#1332) 2026-07-25 12:16:41 +02:00
KroeseandGitHub 695b075130 feat: Provide host access through system.lan (#1331) 2026-07-25 03:38:36 +02:00
KroeseandGitHub 7eff53e722 feat: Improve disk error handling (#1328) 2026-07-24 13:51:59 +02:00
KroeseandGitHub bcaf0e5980 fix: Improve network error handling (#1327) 2026-07-24 13:27:09 +02:00
KroeseandGitHub faa820c2cc feat: Inline local variable declarations (#1326) 2026-07-24 13:11:40 +02:00
KroeseandGitHub 81e477fcc4 feat: Warn when DSM and container share an IP address (#1325) 2026-07-24 12:45:54 +02:00
KroeseandGitHub abd3a1c3df fix: Network mode shown for DHCP mode (#1324) 2026-07-24 12:03:57 +02:00
KroeseandGitHub 3b59bcd284 fix: Ensure progress reaches 100% (#1322) 2026-07-23 23:03:54 +02:00
KroeseandGitHub f1b56f394a build: Create a detailed .gitignore file (#1321) 2026-07-23 15:42:59 +02:00
KroeseandGitHub 1a983ebcd1 feat: Improve error handling for webserver config (#1320) 2026-07-23 04:17:26 +02:00
KroeseandGitHub 41c76198fa feat: Use atomic writes for progress updates (#1319) 2026-07-23 04:10:09 +02:00
KroeseandGitHub 222b5649b0 fix: Prevent stale polling responses for web status (#1318) 2026-07-23 04:00:12 +02:00
KroeseandGitHub e14fd4b711 docs: Environment variables (#1317) 2026-07-21 13:14:32 +02:00
KroeseandGitHub 6fe19a8af4 feat: Improve download progress reporting (#1316) 2026-07-21 06:00:58 +02:00
KroeseandGitHub 072b5c3070 build: Update workflow (#1315) 2026-07-21 01:31:29 +02:00
KroeseandGitHub 89dbaeb2a4 feat: Improve download progress reporting (#1314) 2026-07-21 00:13:53 +02:00
KroeseandGitHub 02f76b44cd fix: Resolve shellcheck error (#1313) 2026-07-20 17:00:32 +02:00
KroeseandGitHub 99d6b8f830 feat: Preserve graceful shutdown for interactive console (#1312) 2026-07-20 16:31:21 +02:00
KroeseandGitHub e6b68b2f08 fix: Avoid shellcheck warning (#1311) 2026-07-20 14:32:03 +02:00
KroeseandGitHub 7a8f0041e7 build: Update workflow (#1310) 2026-07-20 12:31:13 +02:00
KroeseandGitHub 64809bb4d4 feat: Support progress tracking for segmented downloads (#1309) 2026-07-20 05:48:16 +02:00
KroeseandGitHub f08b2cbd99 fix: Decrease default timeout (#1307) 2026-07-19 09:17:51 +02:00
KroeseandGitHub 18d9ecd434 fix: Decrease default timeout (#1308) 2026-07-19 08:57:09 +02:00
KroeseandGitHub 6944293a32 fix: Add Recreate strategy to Kubernetes deployment (#1306) 2026-07-19 03:15:10 +02:00
KroeseandGitHub d807a365ff feat: Added optional lossy VNC compression (#1305) 2026-07-19 03:09:35 +02:00
KroeseandGitHub 066af83d07 fix: Decrease default timeout (#1304) 2026-07-19 01:03:21 +02:00
KroeseandGitHub 81536818df feat: Add escapeHTML function (#1303) 2026-07-18 22:00:45 +02:00
KroeseandGitHub 949c288565 fix: Set correct MTU option for dnsmasq (#1302) 2026-07-18 20:40:52 +02:00
KroeseandGitHub 5d5bbbcf4d feat: Improve NAT networking (#1300) 2026-07-18 15:34:46 +02:00
KroeseandGitHub 82a62c0240 build: Update workflow (#1301) 2026-07-18 15:32:07 +02:00
KroeseandGitHub 5399e1d463 feat: Use Unix sockets for qemu-host communication (#1299) 2026-07-18 11:31:20 +02:00
KroeseandGitHub c7e7b60f01 fix: Improve IP tables cleanup verification (#1298) 2026-07-18 10:54:20 +02:00
KroeseandGitHub f1defa6890 docs: Environment variables (#1297) 2026-07-18 00:28:24 +02:00
KroeseandGitHub a7fb161974 feat: Improve download progress readability (#1296) 2026-07-17 22:59:07 +02:00
KroeseandGitHub dcdf5e5293 fix: Improve interactive terminal detection (#1295) 2026-07-17 22:45:07 +02:00
KroeseandGitHub 1eb0db66ba feat: Improve download progress in container logs (#1294) 2026-07-17 22:29:10 +02:00
KroeseandGitHub 3eec8e03ed feat: Improve AMD detection (#1293) 2026-07-17 20:54:41 +02:00
KroeseandGitHub 5483981ed4 feat: Refactor config code (#1292) 2026-07-17 20:37:54 +02:00
KroeseandGitHub 62330a5bf4 fix: Cleanup stale pipe files (#1291) 2026-07-17 20:01:53 +02:00
KroeseandGitHub 2b0b59dfba feat: Preserve graceful shutdown for interactive console (#1290) 2026-07-17 19:56:05 +02:00
KroeseandGitHub b680ff9dd8 feat: Preserve graceful shutdown for interactive console (#1289) 2026-07-17 19:16:30 +02:00
KroeseandGitHub 5c889b272d fix: Store pid for serial debugging (#1288) 2026-07-17 14:44:49 +02:00
KroeseandGitHub 585ebb3f53 build: Update Passt to v2026_07_16 (#1287) 2026-07-17 13:49:26 +02:00
KroeseandGitHub 401307b981 build: Update QEMU host to v2.06 (#1286) 2026-07-17 13:24:34 +02:00
KroeseandGitHub 46820fe6eb build: Set dependabot cooldown period (#1284) 2026-07-17 13:20:19 +02:00
KroeseandGitHub 9452d48694 feat: Make machine type configurable (#1283) 2026-07-17 11:33:05 +02:00
KroeseandGitHub 5c3fed1387 fix: Clear service logs on startup (#1281) 2026-07-17 06:26:25 +02:00
KroeseandGitHub 797411ae7f fix: Show QEMU errors on unexpected exit (#1280) 2026-07-17 05:54:04 +02:00
KroeseandGitHub e81c509208 feat: Check RENDERNODE permissions (#1279) 2026-07-17 02:11:38 +02:00
KroeseandGitHub ace8614a50 feat: Refactor disk code (#1278) 2026-07-17 01:52:47 +02:00
KroeseandGitHub 8263b3a737 feat: Improve iptable backend selection (#1277) 2026-07-17 01:51:39 +02:00
KroeseandGitHub 61c6142988 feat: Remove unused functions (#1276) 2026-07-17 00:10:59 +02:00
KroeseandGitHub 5d26338bb3 feat: Improve detection of valid data disk (#1275) 2026-07-16 21:41:29 +02:00
KroeseandGitHub 084d475cde build: Add diffutils package (#1274) 2026-07-16 20:55:47 +02:00
KroeseandGitHub c36b0dcb00 docs: Environment variables (#1273) 2026-07-16 20:50:17 +02:00
KroeseandGitHub 6e9993742b feat: Limit wget progress output (#1272) 2026-07-15 23:01:39 +02:00
KroeseandGitHub 6946af0212 build: Update workflow (#1271) 2026-07-15 21:55:07 +02:00
KroeseandGitHub 0a9361d62f fix: Localize available memory formatting (#1270) 2026-07-15 21:13:51 +02:00
KroeseandGitHub 7cbfcd44a6 fix: Remove unnecessary guards (#1269) 2026-07-15 21:00:50 +02:00
KroeseandGitHub 6bcacf5e59 feat: Improve boolean helpers (#1268) 2026-07-15 19:35:16 +02:00
KroeseandGitHub 3bea87f087 feat: Suppress empty iptables debug sections (#1267) 2026-07-15 19:21:43 +02:00
KroeseandGitHub f01e1564f7 fix: Make setting owner non-fatal (#1266) 2026-07-15 18:00:24 +02:00
KroeseandGitHub cf8cdbf0c1 fix: Make failed chown non-fatal (#1265) 2026-07-15 17:39:05 +02:00
KroeseandGitHub 0813494ee0 feat: Use cgroup when calculating RAM (#1264) 2026-07-15 15:40:51 +02:00
KroeseandGitHub 0d71e30f50 feat: Add state helpers to utils (#1263) 2026-07-15 15:28:42 +02:00
KroeseandGitHub c203deab9a feat: Improve webserver configuration (#1262) 2026-07-15 15:27:24 +02:00
KroeseandGitHub 9cf31df266 fix: Validate subnet mask (#1261) 2026-07-15 14:17:01 +02:00
KroeseandGitHub 0cd08f2ee1 fix: Improve NAT port forwarding (#1260) 2026-07-15 12:24:25 +02:00
KroeseandGitHub a32d215e90 feat: Improve wget error reporting (#1259) 2026-07-15 11:34:55 +02:00
KroeseandGitHub c1f9a690f9 fix: Remove dots from info line (#1258) 2026-07-15 09:00:14 +02:00
KroeseandGitHub 5de504deb3 feat: Improve rootless container detection (#1256) 2026-07-15 06:02:12 +02:00
KroeseandGitHub 250eb18238 docs: Readme (#1255) 2026-07-14 12:50:07 +02:00
KroeseandGitHub ca80da59bd docs: Environment variables (#1254) 2026-07-14 11:29:10 +02:00
KroeseandGitHub 9cd86dfe82 fix: Use exec form for health check (#1253) 2026-07-13 19:40:30 +02:00
KroeseandGitHub 5bb93651f7 docs: Readme (#1252) 2026-07-13 00:38:58 +02:00
KroeseandGitHub 0c268308a4 feat: Preserve source image until conversion completes (#1251) 2026-07-12 23:33:10 +02:00
KroeseandGitHub 7b741d3e4b feat: Warn about UDP host ports (#1250) 2026-07-12 22:14:11 +02:00
KroeseandGitHub f1d29212ae feat: Improve iptables rule cleanup (#1249) 2026-07-12 21:58:49 +02:00
KroeseandGitHub fdee9f89a3 feat: Improve iptables backend selection (#1248) 2026-07-12 21:36:52 +02:00
KroeseandGitHub 210a360797 fix: Restore compatible NAT forwarding rules (#1247) 2026-07-12 13:18:52 +03:00
KroeseandGitHub 991bb2627a fix: Prefer legacy iptables backend for NAT (#1246) 2026-07-12 12:44:00 +03:00
KroeseandGitHub 764a186836 feat: Allow all forwarded NAT traffic (#1245) 2026-07-11 11:58:35 +03:00
KroeseandGitHub 726786a98a feat: Default host and user ports to TCP only (#1244) 2026-07-09 11:06:01 +02:00
KroeseandGitHub 2caf97d407 docs: Network modes (#1243) 2026-07-09 00:39:52 +02:00
KroeseandGitHub 0e67286599 fix: Improve file handling (#1242) 2026-07-08 23:55:02 +02:00
KroeseandGitHub 2b9fc80275 feat: Validate MAC file writes (#1241) 2026-07-08 23:28:56 +02:00
KroeseandGitHub 0d88774bd3 feat: Display base directory in warnings (#1240) 2026-07-08 23:16:20 +02:00
KroeseandGitHub fa23052ed4 fix: Set default DHCP lease time to 1 hour (#1239) 2026-07-08 22:46:47 +02:00
KroeseandGitHub cc3267f258 docs: Correct hostname (#1238) 2026-07-08 18:57:55 +02:00
KroeseandGitHub fd002564a6 feat: Validate custom QEMU CPU arguments (#1237) 2026-07-08 18:50:31 +02:00
KroeseandGitHub 2703a97cfa docs: Refer to environment documentation (#1236) 2026-07-08 18:44:04 +02:00
KroeseandGitHub 29e2d034bf docs: Document all environment variables (#1235) 2026-07-08 17:11:10 +02:00
KroeseandGitHub cbe3644335 fix: Add extra line after boot (#1234) 2026-07-08 16:50:21 +02:00
KroeseandGitHub c9a2a6966b feat: Always show network info (#1233) 2026-07-07 19:37:59 +02:00
KroeseandGitHub 498248f43e feat: Display guest info before mode warning (#1232) 2026-07-07 12:21:25 +02:00
KroeseandGitHub 8963228b1c fix: Set returnvalue for waitForPort (#1231) 2026-07-07 12:13:13 +02:00
KroeseandGitHub 827d6d9e10 fix: Status monitor exited early (#1230) 2026-07-07 12:03:58 +02:00
KroeseandGitHub 1c577abef4 fix: Guest IP was not retrieved correctly (#1229) 2026-07-07 11:16:22 +02:00
KroeseandGitHub 20fd1a975c fix: Read QEMU pid correctly (#1228) 2026-07-07 10:53:53 +02:00
KroeseandGitHub 770774680c feat: Improve shutdown logic (#1226) 2026-07-07 03:16:35 +02:00
KroeseandGitHub 0c75aa81fe fix: Detect guest IP without assuming eth0 (#1225) 2026-07-06 23:54:24 +02:00
KroeseandGitHub 36ec57ac15 fix: Initialize indexdb path before extraction (#1224) 2026-07-06 23:50:26 +02:00
KroeseandGitHub 9c488c52b9 feat: Normalize disk image format (#1223)
*
2026-07-06 23:44:14 +02:00
KroeseandGitHub 2ba756260f fix: Sanitize guest hostname (#1222) 2026-07-06 23:33:34 +02:00
KroeseandGitHub b306012743 feat: Normalize discard mode for qemu drives (#1221) 2026-07-06 23:21:25 +02:00
KroeseandGitHub 61b3ee7e01 feat: Read qcow2 virtual size from qemu-img json (#1220) 2026-07-06 23:15:27 +02:00
KroeseandGitHub 245036f844 fix: Preserve port protocols in passt mode (#1219) 2026-07-06 23:11:34 +02:00
KroeseandGitHub 68cadfe035 fix: Tolerate missing sector-size output (#1218) 2026-07-06 22:56:00 +02:00
KroeseandGitHub 96102832b1 fix: Tolerate missing sector-size output (#1217) 2026-07-06 22:38:58 +02:00
KroeseandGitHub 211a56bf73 feat: Show additional guest info in debug mode (#1216) 2026-07-06 22:11:03 +02:00
KroeseandGitHub 506fb7b114 fix: Parse Debian ipcalc output correctly (#1215) 2026-07-06 21:58:11 +02:00
KroeseandGitHub bcc3393b7f fix: Shutdown Passt after DNS failure (#1214) 2026-07-06 19:21:48 +02:00
KroeseandGitHub 45c0f91d6e feat: Refactor networking code (#1213) 2026-07-06 17:47:29 +02:00
KroeseandGitHub a1910546a6 feat: Check file operation results (#1212) 2026-07-06 07:44:41 +02:00
KroeseandGitHub 637ed0e3a6 fix: Do not match multiple files (#1211) 2026-07-06 05:09:29 +02:00
KroeseandGitHub 954a6076ad feat: Add returnvalues to functions (#1210) 2026-07-06 03:48:39 +02:00
KroeseandGitHub 415aaa3038 feat: Refactor server code (#1209) 2026-07-05 23:35:56 +02:00
KroeseandGitHub c87e45719b feat: Refactor serial code (#1208) 2026-07-05 23:24:43 +02:00
KroeseandGitHub 102945ab48 feat: Refactor memory check (#1207) 2026-07-05 23:17:53 +02:00
KroeseandGitHub 1c3d490303 feat: Refactor status monitor (#1206) 2026-07-05 23:02:51 +02:00
KroeseandGitHub 73fa70f52f feat: Refactor CPU logic (#1205) 2026-07-05 22:46:39 +02:00
KroeseandGitHub 7b095702fc feat: Refactor shutdown logic (#1204) 2026-07-05 22:09:49 +02:00
KroeseandGitHub f82b2769d3 feat: Refactor entrypoint (#1203) 2026-07-05 21:43:10 +02:00
Peng LiuandGitHub cafe619028 fix: Parse quoted values consistently (#1202) 2026-07-05 21:25:33 +02:00
KroeseandGitHub e94a0c4a52 feat: Refactor disk code (#1201) 2026-07-05 20:09:47 +02:00
KroeseandGitHub d6a353df0e feat: Refactor network code (#1200) 2026-07-05 19:58:36 +02:00
KroeseandGitHub 050812e996 fix: Filter IPv6 DNS records when disabled (#1199) 2026-07-05 19:30:41 +02:00
KroeseandGitHub 75280e9aa9 feat: Improve bus detection (#1198) 2026-07-05 18:51:56 +02:00
KroeseandGitHub 8dcc8ccee1 fix: Move MTU check to finish (#1197) 2026-07-05 18:34:55 +02:00
KroeseandGitHub ba866e9e75 feat: Improve support for non-standard MTU sizes (#1196) 2026-07-05 17:10:59 +02:00
KroeseandGitHub 06e7a8edb9 docs: Readme (#1195) 2026-07-05 14:49:47 +02:00
KroeseandGitHub 495c67734a fix: Check adapter before setting MTU (#1194) 2026-07-05 03:13:14 +02:00
KroeseandGitHub 1557735331 build: Use heredoc for Dockerfile commands (#1193) 2026-07-04 20:34:32 +02:00
KroeseandGitHub f45b308c78 feat: Sanitize environment variables (#1192) 2026-07-03 17:14:59 +02:00
CopilotandGitHub d5821cd782 feat: Normalize boolean option handling (#1191) 2026-07-03 15:17:14 +02:00
KroeseandGitHub 312816b18e feat: Implement strip() function (#1190)
Added strip function to remove whitespace and quotes.
2026-07-03 14:48:58 +02:00
KroeseandGitHub f42a3f1662 feat: Add enabled() function (#1189) 2026-07-03 14:06:42 +02:00
KroeseandGitHub 558e5022ca docs: Readme (#1188) 2026-07-02 20:26:15 +02:00
KroeseandGitHub e03822f26e feat: Improve shutdown logic (#1187) 2026-07-02 20:14:05 +02:00
KroeseandGitHub 7b90ca30ba feat: Improve socket cleanup (#1186) 2026-07-02 18:51:40 +02:00
KroeseandGitHub 22c01bf2f1 docs: Readme (#1185) 2026-07-02 12:28:35 +02:00
KroeseandGitHub 1f601db8b0 build: Update Passt to v2026_06_11 (#1183) 2026-06-28 12:43:44 +02:00
KroeseandGitHub e7e2c35cb7 build: Run review steps in parallel (#1182) 2026-06-25 22:31:34 +02:00
KroeseandGitHub 50089112c0 docs: Update stargazers chart (#1181) 2026-06-25 14:21:53 +02:00
KroeseandGitHub f9538ce53b feat: Improve IPv6 check (#1180) 2026-06-19 13:24:54 +02:00
renovate[bot]andGitHub 49d25a13d0 chore(deps): update actions/checkout action to v7 (#1179) 2026-06-19 11:48:11 +02:00
KroeseandGitHub 7c9d2b1fd5 feat: Improved start and stop logic (#1178) 2026-06-05 02:37:20 +02:00
KroeseandGitHub b68d243b6a fix: Add fail_level to reviewdog actions (#1177) 2026-06-04 23:45:01 +02:00
KroeseandGitHub 79e85f9fd1 fix: Provide exitcode on shutdown (#1176) 2026-05-31 00:32:49 +02:00
KroeseandGitHub 476048a4ee fix: Update paths for QEMU files (#1175) 2026-05-30 23:50:39 +02:00
KroeseandGitHub f983dc3e46 fix: Remove stale QEMU files (#1174) 2026-05-30 23:05:16 +02:00
KroeseandGitHub 38f9c49200 feat: Added finishDisks function (#1173) 2026-05-30 20:51:58 +02:00
KroeseandGitHub 7157717a85 feat: Added option to disable data disks (#1171) 2026-05-30 19:52:54 +02:00
KroeseandGitHub 031674424d fix: Handle iptables-save errors better (#1170) 2026-05-30 18:58:12 +02:00
KroeseandGitHub 28e6f8da78 fix: IP address parsing (#1168) 2026-05-29 17:13:47 +02:00
KroeseandGitHub d5802607b5 fix: Throw object for XMLHttpRequest (#1166) 2026-05-29 16:54:45 +02:00
KroeseandGitHub 7168f2f843 feat: Update version file path (#1165) 2026-05-29 16:08:23 +02:00
KroeseandGitHub 819dd29025 fix: Network interface detection (#1164) 2026-05-29 14:34:34 +02:00
KroeseandGitHub 48ef47b85b fix: Previous XHR not aborted (#1163) 2026-05-29 14:33:23 +02:00
KroeseandGitHub 10c902bc9b build: Update Passt to v2026_05_26 (#1162) 2026-05-29 12:52:20 +02:00
KroeseandGitHub d6de10efe1 feat: Flush iptables on container restarts (#1161) 2026-05-29 05:00:56 +02:00
KroeseandGitHub 6d1d9d92b4 feat: Improve iptable rules (#1160) 2026-05-28 23:00:17 +02:00
KroeseandGitHub 799649e78c docs: Improve low diskspace warning (#1158) 2026-05-24 14:29:17 +02:00
KroeseandGitHub 12060c72b2 feat: Update warning message (#1157) 2026-05-23 20:31:37 +02:00
KroeseandGitHub 6eadd1b953 fix: Timeout comparison operator (#1155) 2026-05-17 13:01:57 +02:00
KroeseandGitHub 342ca4da03 fix: Wrong IP was passed to getSlirp (#1154) 2026-05-17 12:27:58 +02:00
KroeseandGitHub b0b6190560 feat: Add warning when macvlan parent is a bridge (#1153)
Fixes #1152
2026-05-17 06:56:55 +02:00
KroeseandGitHub 075410e4cf fix: CPU cores validation logic (#1151) 2026-05-16 20:59:57 +02:00
KroeseandGitHub 2a388b434b feat: Improve Dnsmasq error handling (#1149) 2026-05-16 11:35:04 +02:00
KroeseandGitHub 280c4037f3 fix: CPU cores validation logic (#1150) 2026-05-16 11:33:23 +02:00
KroeseandGitHub 007bdc735d fix: Warning message for missing clock source (#1148) 2026-05-16 10:58:37 +02:00
KroeseandGitHub 41fc0a6a10 fix: Undeclared variable in ConvertDisk (#1147) 2026-05-16 10:11:37 +02:00
KroeseandGitHub 7753e4ac74 fix: Slirp portmapping was missing last port (#1146) 2026-05-16 02:22:44 +02:00
KroeseandGitHub f74bf35202 fix: Socket detection logic (#1145) 2026-05-16 02:17:55 +02:00
KroeseandGitHub aa472c96c6 feat: Use iptables multiport extension (#1144) 2026-05-15 23:28:01 +02:00
KroeseandGitHub 0dcb880800 fix: Do not remove QEMU files (#1143) 2026-05-15 22:43:44 +02:00
KroeseandGitHub 8daa6973b7 feat: Do not require NET_RAW for dnsmasq (#1142) 2026-05-15 21:30:16 +02:00
KroeseandGitHub 3884befa56 feat: Improve memory allocation logic (#1141) 2026-05-15 17:58:41 +02:00
KroeseandGitHub 85b83f8eb1 feat: Remove reliability on iptables multiport extension (#1140) 2026-05-15 17:44:35 +02:00
KroeseandGitHub f395dfaa66 feat: Removed legacy code (#1139) 2026-05-14 20:59:36 +02:00
KroeseandGitHub b3124075ea feat: Refactor QEMU PID variables (#1138) 2026-05-10 17:34:22 +02:00
KroeseandGitHub aed909bdee fix: NFT tables detection (#1137) 2026-05-10 17:24:02 +02:00
KroeseandGitHub d4cf5778e2 build: Update Passt to v2026_05_07 (#1136) 2026-05-10 17:20:26 +02:00
KroeseandGitHub 48de7dd00b fix: Size comparison variables (#1135) 2026-05-10 17:16:20 +02:00
dependabot[bot]andGitHub 686e64da3f build(deps): Bump docker/setup-buildx-action from 3 to 4 (#1130) 2026-05-10 17:15:02 +02:00
dependabot[bot]andGitHub 7517dc8b3e build(deps): Bump docker/metadata-action from 5 to 6 (#1131) 2026-05-10 17:13:41 +02:00
renovate[bot]andGitHub 660fe715e4 chore(deps): update grantbirki/json-yaml-validate action to v5 (#1134) 2026-05-10 17:06:56 +02:00
dependabot[bot]andGitHub 04ea29ec77 build(deps): Bump docker/build-push-action from 6 to 7 (#1132) 2026-05-10 17:05:14 +02:00
dependabot[bot]andGitHub 02c891cb16 build(deps): Bump docker/login-action from 3 to 4 (#1129) 2026-05-10 17:04:00 +02:00
Quang-Linh LEandGitHub 0b5d21357e fiz: Ignore sector size for whole disk passthrough (#1121) 2026-01-13 11:40:35 +01:00
KroeseandGitHub e0545b37d7 fix: Avoid duplicating dnsmasq arguments (#1113) 2025-11-22 04:28:11 +01:00
renovate[bot]andGitHub 4161c21082 chore(deps): update actions/checkout action to v6 (#1112) 2025-11-21 12:39:39 +01:00
KroeseandGitHub 48d9a1771d fix: Update Codespaces configuration (#1110) 2025-11-14 06:05:19 +01:00
KroeseandGitHub 471cdbb338 fix: Workaround AppArmor profile for passt (#1108) 2025-11-12 07:03:22 +01:00
KroeseandGitHub e77bca202b fix: Spelling mistake (#1105) 2025-11-06 03:46:35 +01:00
KroeseandGitHub 2e6c01e934 feat: Detect if container is running in privileged mode (#1104) 2025-11-06 03:39:46 +01:00
KroeseandGitHub 302c991c0c fix: Change condition for OverlayFS warning (#1103) 2025-11-06 03:22:47 +01:00
KroeseandGitHub a89007ee03 build: Use Github token (#1100) 2025-10-29 14:05:53 +01:00
KroeseandGitHub 8a89149d58 feat: Check for SSE4 instruction set (#1099) 2025-10-29 08:32:42 +01:00
KroeseandGitHub 5e8bbc2868 fix: Remove unnecessary operation (#1097) 2025-10-24 04:30:21 +02:00
KroeseandGitHub 4e48920309 fix: Do not assume Podman never has privileges (#1096) 2025-10-24 01:19:38 +02:00
KroeseandGitHub 8b145924b9 fix: Reduce spare disk space threshold (#1093) 2025-10-22 02:47:50 +02:00
KroeseandGitHub a0328e1e9c fix: Inherit owner from parent folder (#1092) 2025-10-22 02:38:57 +02:00
KroeseandGitHub b7f5214a7b build: Add code quality checks (#1091) 2025-10-22 00:59:35 +02:00
KroeseandGitHub b0e4c4ac5f docs: Update docker run command (#1090) 2025-10-21 23:15:31 +02:00
KroeseandGitHub bbb67aac93 build: Add review workflow for shell formatting (#1089) 2025-10-21 22:39:50 +02:00
KroeseandGitHub 433c83b393 fix: Kill QEMU after 5 seconds if it hangs (#1088) 2025-10-19 17:56:44 +02:00
KroeseandGitHub 5577178eeb fix: Only display non-zero percentage (#1087) 2025-10-19 17:32:25 +02:00
KroeseandGitHub 221b0242fa fix: Kill QEMU after 5 seconds when it hangs (#1086) 2025-10-19 16:57:51 +02:00
KroeseandGitHub c05623f8af fix: Round filesize up to nearest cluster (#1085) 2025-10-19 14:38:36 +02:00
KroeseandGitHub eb9884cc96 feat: Improve Github Codespaces configuration (#1084) 2025-10-19 12:48:40 +02:00
KroeseandGitHub 8e2490e6bc feat: Improve Github Codespaces configuration (#1082) 2025-10-19 10:40:03 +02:00
KroeseandGitHub 399243886e feat: Show directory size (#1083) 2025-10-19 09:40:45 +02:00
KroeseandGitHub b0dbfcb805 feat: Improve Github Codespaces configuration (#1081) 2025-10-19 01:14:11 +02:00
KroeseandGitHub dec2dc9230 feat: Check free diskspace during startup (#1080) 2025-10-17 16:47:43 +02:00
KroeseandGitHub 2c44669d91 feat: Improve Codespaces configuration (#1079) 2025-10-17 13:25:02 +02:00
KroeseandGitHub 175d90aad7 fix: Move order in entry file (#1078) 2025-10-17 13:04:03 +02:00
KroeseandGitHub e1e5f8f91d fix: Validate status messages (#1077) 2025-10-17 12:07:13 +02:00
KroeseandGitHub dff8abbe1e build: Validate JSON and YML files (#1076) 2025-10-17 10:05:52 +02:00
KroeseandGitHub 0f97091e61 fix: Set network flag (#1075) 2025-10-17 01:39:49 +02:00
KroeseandGitHub ea0d7ee6cd feat: Implement extra disksize preset (#1074) 2025-10-17 00:17:30 +02:00
KroeseandGitHub 75daa31d36 feat: Implement extra CPU_CORES preset (#1073) 2025-10-17 00:15:56 +02:00
KroeseandGitHub 8c44319c45 feat: Move memory check to own module (#1072) 2025-10-16 23:49:16 +02:00
KroeseandGitHub dac574d933 feat: Automatically adjust RAM size when too high (#1071) 2025-10-16 12:36:49 +02:00
KroeseandGitHub fd4c5001e8 feat: Update Github Codespaces configuration (#1070) 2025-10-16 09:43:19 +02:00
KroeseandGitHub dfe0b23995 feat: Improve Github Codespaces configuration (#1069) 2025-10-15 23:58:01 +02:00
KroeseandGitHub 6158372eaa fix: Remove nat option (#1068) 2025-10-15 14:39:28 +02:00
KroeseandGitHub b1a778d7b2 docs: Readme (#1067) 2025-10-15 12:43:07 +02:00
KroeseandGitHub bc0defd813 feat: Add custom .yml for Github Codespaces (#1066) 2025-10-15 11:39:36 +02:00
KroeseandGitHub 48e7a9fff0 fix: Round down minimum disk size (#1065) 2025-10-15 11:37:05 +02:00
KroeseandGitHub c2fa58ef27 feat: Fall back to slirp when passt fails (#1064) 2025-10-15 10:31:42 +02:00
KroeseandGitHub ea49cb144b feat: Validate user port configuration (#1063) 2025-10-14 16:44:11 +02:00
KroeseandGitHub b8e778a79d fix: Configure ports for Slirp networking (#1062) 2025-10-14 14:16:20 +02:00
KroeseandGitHub c70e12f0a2 fix: Lower spare disk space (#1061)
Reduced spare disk space threshold from 2GB to 512MB.
2025-10-14 03:33:25 +02:00
KroeseandGitHub 6281205912 feat: Add "max" setting for DISK_SIZE (#1060) 2025-10-14 01:22:44 +02:00
KroeseandGitHub 1ffc5c55b2 fix: Show Passt output on error (#1059) 2025-10-13 14:11:54 +02:00
KroeseandGitHub c3302e1720 fix: Rename physical to logical (#1058) 2025-10-13 09:28:25 +02:00
KroeseandGitHub 25227944b5 fix: Do not reset loading animation (#1056) 2025-10-12 01:51:17 +02:00
KroeseandGitHub 06650e916a build: Run check for all files (#1057)
Removed specific paths from pull request triggers.
2025-10-12 01:48:25 +02:00
KroeseandGitHub 2e34dffed5 feat: Expose only selected ports with Passt (#1055) 2025-10-12 01:44:24 +02:00
KroeseandGitHub 3db91f077f fix: Relay last status message (#1054) 2025-10-11 17:56:44 +02:00
KroeseandGitHub fae14f4dd9 feat: Set listening interface for Passt (#1052) 2025-10-09 11:48:08 +02:00
KroeseandGitHub d190b3ba87 feat: Use websocket for status messages (#1051) 2025-10-08 21:28:26 +02:00
KroeseandGitHub 554f3295cb fix: Terminate tail on exit (#1049) 2025-10-08 08:13:27 +02:00
KroeseandGitHub cdc4689d6a feat: Use the engine variable (#1048) 2025-10-07 12:41:42 +02:00
KroeseandGitHub 21d18fd439 feat: Improve healthcheck (#1047) 2025-10-07 05:53:06 +02:00
KroeseandGitHub fd5ec52226 fix: Check if logfile exists (#1046) 2025-10-07 02:21:49 +02:00
KroeseandGitHub fc7ab22741 fix: Use gateway MAC for passt (#1045) 2025-10-07 02:15:26 +02:00
KroeseandGitHub 59cf59faa4 feat: Improved networking implementation (#1044) 2025-10-07 00:58:34 +02:00
KroeseandGitHub 705c6ce7f1 fix: Exclude 'tap' from bus check (#1043) 2025-10-05 17:06:57 +02:00
KroeseandGitHub f2937ab507 feat: Allow large MTU sizes (#1042) 2025-10-04 10:35:20 +02:00
KroeseandGitHub 399829cf3c feat: Make monitor port configurable (#1041) 2025-10-04 09:39:20 +02:00
xrh0905andGitHub b694d6faf8 feat: Support 8k sector sizes (#1040) 2025-10-03 12:57:08 +02:00
KroeseandGitHub 7acd1f6cdb feat: Enhanced Dnsmasq logging (#1039) 2025-10-03 01:54:44 +02:00
KroeseandGitHub 09ca3bf118 feat: Add debug trace option (#1038) 2025-10-02 17:18:53 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6cac45c397 chore(deps): update peter-evans/dockerhub-description action to v5 (#1037)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-01 23:39:30 +02:00
KroeseandGitHub f18663d840 feat: Network mode detection (#1036) 2025-10-01 13:05:13 +02:00
KroeseandGitHub fefe1af9e6 fix: CPU detection (#1035)
Refactor CPU string processing to remove 'th Gen' suffix.
2025-09-30 17:18:43 +02:00
KroeseandGitHub 87a8cf7513 feat: Support 32k sector sizes (#1034) 2025-09-30 10:49:07 +02:00
KroeseandGitHub 7f31cb6023 fix: Detect host mode networking (#1033) 2025-09-30 10:32:00 +02:00
KroeseandGitHub 138742c953 feat: Increase default disksize (#1030) 2025-09-28 18:22:44 +02:00
KroeseandGitHub 2c6efc45f2 feat: Make webserver port configurable (#1028) 2025-09-27 11:44:13 +02:00
KroeseandGitHub 24d795fbe3 buid: Add ethtool package (#1027) 2025-09-27 10:45:09 +02:00
KroeseandGitHub 7fae62d286 feat: Detect host mode networking (#1026) 2025-09-27 10:44:02 +02:00
KroeseandGitHub 2135df07ea docs: Additional info for user-mode networking (#1025) 2025-09-27 10:08:11 +02:00
KroeseandGitHub 521beedf1c feat: Add note for MAC address availability (#1024) 2025-09-27 09:49:11 +02:00
KroeseandGitHub e362c9a8a9 feat: Update error message for KVM acceleration (#1023) 2025-09-24 16:10:32 +02:00
KroeseandGitHub 78817ecfc1 fix: Remove default model (#1022) 2025-09-23 16:04:44 +02:00
KroeseandGitHub 8de7f56ff8 feat: Add KVM warning (#1021) 2025-09-23 16:02:42 +02:00
KroeseandGitHub 2e2017470e fix: Syntax for arithmetic operations (#1020) 2025-09-22 20:24:23 +02:00
KroeseandGitHub 0a0cd98de3 feat: Add "max" setting to automaticly set CPU cores and RAM (#1019) 2025-09-22 16:59:02 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
17187dd23a chore(deps): update hadolint/hadolint-action action to v3.3.0 (#1018)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 16:56:58 +02:00
KroeseandGitHub 10237b31cf revert: Simplify conditional checks (#1017)
This reverts commit 6883efb857.
2025-09-21 23:08:00 +02:00
KroeseandGitHub 6883efb857 fix: Simplify conditional checks (#1016) 2025-09-21 15:09:52 +02:00
KroeseandGitHub 1ca55cad8f feat: Limit CPU_CORES to amount of physical cores (#1015) 2025-09-21 13:41:20 +02:00
KroeseandGitHub f841eb1ef1 fix: Simplify conditional checks (#1014) 2025-09-20 23:47:00 +02:00
KroeseandGitHub 1ee49332f3 feat: Improve CPU detection (#1013) 2025-09-20 21:43:35 +02:00
KroeseandGitHub 095e618785 feat: Make webserver optional (#1012) 2025-09-18 23:45:05 +02:00
KroeseandGitHub 57a902ad9f feat: add UDP support to USER_PORTS (#1011)
Allow USER_PORTS entries in the form PORT or PORT/PROTO (tcp or udp). When the protocol is omitted, TCP is assumed for backward compatibility. This enables forwarding of UDP services when running the container in user‑mode networking.
2025-09-17 21:49:20 +02:00
xrh0905andGitHub a7e229aaae feat: Add IPQuery.io as additional comparison source for the country code (#1006) 2025-09-17 17:55:54 +02:00
KroeseandGitHub 10466d7851 feat: Parse CPU flags (#1010) 2025-09-17 17:54:50 +02:00
KroeseandGitHub 238ebd273b build: Disable automatic builds (#1009)
Removed push triggers and paths to ignore from build workflow.
2025-09-14 11:54:51 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0b08f4212e chore(deps): update hadolint/hadolint-action action to v3.2.0 (#1008)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-03 16:43:41 +02:00
KroeseandGitHub 9aec5d20e3 feat: Check if storage folder is writeable (#1005) 2025-08-27 22:50:23 +02:00
KroeseandGitHub a19bf2f066 feat: Check if storage folder is writeable (#1004) 2025-08-27 22:48:23 +02:00
KroeseandGitHub bee68ee548 feat: Add syntax parser directive (#1003) 2025-08-27 21:29:28 +02:00
xrh0905andGitHub 520c70ab22 feat: Allow shutdown timeout override (#995)
Mitigation #987
2025-08-27 19:58:02 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
67a7fbc94b build(deps): Bump actions/checkout from 4 to 5 (#1001)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-27 19:56:41 +02:00
KroeseandGitHub 1b8054e847 fix: Podman detection (#990) 2025-05-27 00:50:40 +02:00
KroeseandGitHub 631a558a9f feat: Enable IPv6 support for user-mode container networking (#983) 2025-04-27 11:28:54 +02:00
KroeseandGitHub d5805b4e08 feat: Check CPU vendor (#982) 2025-04-27 11:21:37 +02:00
KroeseandGitHub 1dc15ce2e0 docs: Add input types (#981) 2025-04-23 12:54:22 +02:00
KroeseandGitHub 4145e811df feat: Improve CPU detection (#980) 2025-04-20 21:43:02 +02:00
KroeseandGitHub fe8615d7d3 docs: Add quotes around $PWD (#977) 2025-04-16 12:10:59 +02:00
KroeseandGitHub 27ea5506bc feat: Default to 2 CPU cores and 2GB of RAM (#976) 2025-04-16 11:56:02 +02:00
KroeseandGitHub 394131a0d7 feat: Podman detection (#972) 2025-04-09 09:01:01 +02:00
KroeseandGitHub 4d0d16023f feat: Podman detection (#971) 2025-04-09 08:58:02 +02:00
KroeseandGitHub 60dd794b29 fix: Avoid pipe to head on find (#970) 2025-04-09 08:03:41 +02:00
KroeseandGitHub f13d104968 build: Add root-user-action flag (#968) 2025-04-08 07:53:17 +02:00
KroeseandGitHub 914099fd12 build: Add --root-user-action flag (#967) 2025-04-07 18:47:36 +02:00
KroeseandGitHub 639725957d fix: Permission errors on QNAP (#966) 2025-04-07 18:36:47 +02:00
KroeseandGitHub 64bbe82c4a fix: KVM warning (#965) 2025-04-07 17:44:26 +02:00
KroeseandGitHub 73a13e5697 fix: QNAP permission errors (#964) 2025-04-07 17:20:14 +02:00
KroeseandGitHub e8ec5fb8ed feat: Support 4k sector sizes (#963) 2025-04-07 13:25:20 +02:00
KroeseandGitHub 0b500ca377 docs: Disk pass-through (#960) 2025-04-03 10:22:26 +02:00
KroeseandGitHub df58745ed8 fix: Ignore missing custom .pat after install (#959) 2025-04-03 01:13:14 +02:00
KroeseandGitHub 55e8ab4930 docs: Github Codespaces (#956) 2025-03-27 01:48:40 +01:00
KroeseandGitHub 4882fd3bf6 fix: Local file support (#955) 2025-03-26 19:51:58 +01:00
KroeseandGitHub 3e69f4bcc9 feat: New extraction method (#954) 2025-03-26 09:24:13 +01:00
KroeseandGitHub 39428909d6 docs: Installation (#953) 2025-03-26 02:47:28 +01:00
KroeseandGitHub 71d2ed40db docs: Github Codespaces (#952) 2025-03-25 14:49:46 +01:00
KroeseandGitHub 9ad21a28a6 docs: Disk pass-through (#951) 2025-03-25 12:18:38 +01:00
KroeseandGitHub 0c7acd6e71 fix: Remove non-printable characters (#949) 2025-03-24 13:52:38 +01:00
KroeseandGitHub ad26129375 docs: KVM information (#947) 2025-03-20 23:21:41 +01:00
KroeseandGitHub 4e7822fedd docs: Compatibility chart (#946) 2025-03-20 23:07:14 +01:00
KroeseandGitHub 4dfcbe4ab1 docs: Add Podman (#945) 2025-03-20 20:09:53 +01:00
KroeseandGitHub 8fb6f1f9ad feat: Podman detection (#944) 2025-03-20 11:54:26 +01:00
KroeseandGitHub 11d4fafa6d fix: User-mode networking (#943) 2025-03-20 03:07:01 +01:00
KroeseandGitHub be15557798 fix: User-mode networking (#942) 2025-03-20 03:05:50 +01:00
KroeseandGitHub 1e83757494 fix: Set user-mode IP address (#941) 2025-03-19 12:55:53 +01:00
KroeseandGitHub fad463a439 feat: Add devcontainer (#940) 2025-03-19 09:17:48 +01:00
KroeseandGitHub 608563d029 feat: Add devcontainer (#939) 2025-03-18 19:25:27 +01:00
KroeseandGitHub 5fcd22b09f docs: Formatting (#938) 2025-03-18 14:24:05 +01:00
KroeseandGitHub 65548da2ef docs: Github Codespaces (#937) 2025-03-18 14:10:08 +01:00
KroeseandGitHub 111e513dac docs: Github Codespaces (#936) 2025-03-18 14:09:10 +01:00
KroeseandGitHub 7fce3a98fe feat: Refactor helper functions (#935) 2025-03-18 12:57:52 +01:00
KroeseandGitHub 4018eeadb4 fix: Remove port 80 (#934) 2025-03-18 05:03:54 +01:00
KroeseandGitHub a8e4647fa6 feat: IPv6 support (#933) 2025-03-18 03:59:58 +01:00
KroeseandGitHub 36d3fca4fc fix: Fallback to POSIX fallocate (#932) 2025-03-17 11:19:04 +01:00
KroeseandGitHub 89b28f36d3 docs: Disk pass-through (#930) 2025-03-16 12:30:06 +01:00
KroeseandGitHub b4f7d70a7a docs: Readme (#929) 2025-03-16 06:52:14 +01:00
KroeseandGitHub 902bafbd0c docs: Readme (#928) 2025-03-16 06:40:38 +01:00
KroeseandGitHub 7ad5c7fa70 fix: Display available memory (#926) 2025-03-15 14:09:17 +01:00
KroeseandGitHub 4d29f056b7 fix: Format filesizes (#925) 2025-03-14 18:53:53 +01:00
KroeseandGitHub 36af9a3483 feat: Validate configured RAM (#924) 2025-03-14 14:42:08 +01:00
KroeseandGitHub 5e6f931433 feat: Detect clock source (#923) 2025-03-14 14:16:10 +01:00
KroeseandGitHub beadfe720c feat: Improve CPU detection (#921) 2025-03-14 05:23:49 +01:00
KroeseandGitHub 92b4bfc383 feat: Validate configured RAM (#920) 2025-03-13 11:35:08 +01:00
KroeseandGitHub 092ed23085 feat: Check CPU core configuration (#919) 2025-03-13 10:47:25 +01:00
KroeseandGitHub c70fa3d00a feat: Validate specified size (#918) 2025-03-12 21:17:47 +01:00
KroeseandGitHub fea0ba09f6 docs: Use relative paths (#917) 2025-03-12 12:31:50 +01:00
KroeseandGitHub 7d2af63eac docs: Kubernetes deployment (#916) 2025-03-07 00:42:29 +01:00
KroeseandGitHub 2e73bf560e docs: Add link to download (#915) 2025-03-07 00:22:29 +01:00
KroeseandGitHub bfc8d7a9c6 fix: Network shutdown (#912) 2025-03-05 04:59:57 +01:00
KroeseandGitHub a1e9936572 fix: Set MTU value (#911) 2025-03-04 15:37:37 +01:00
KroeseandGitHub 3675a50129 fix: Gateway MAC generation (#910) 2025-03-03 13:57:53 +01:00
KroeseandGitHub 91229152bd feat: Set MTU size for TAP interface (#909) 2025-03-03 13:40:15 +01:00
KroeseandGitHub a1993e590a feat: Automaticly match MTU size (#908) 2025-03-03 12:20:16 +01:00
KroeseandGitHub 52fe712b6f docs: Readme (#907) 2025-03-01 14:23:51 +01:00
KroeseandGitHub 7f400b6b59 feat: Improve CPU detection (#905) 2025-02-27 11:52:48 +01:00
KroeseandGitHub 9cb88a99e6 feat: Allow bridge networks (#904) 2025-02-27 11:46:38 +01:00
KroeseandGitHub b967a471b5 fix: Add e2fsprogs package (#902) 2025-02-26 10:03:46 +01:00
KroeseandGitHub f40127df01 feat: Make app name configurable (#900) 2025-02-25 15:13:57 +01:00
KroeseandGitHub 8c5e0ee274 fix: Generate local MAC address (#899) 2025-02-24 21:01:55 +01:00
KroeseandGitHub 2adf0b292b fix: Preserve gateway MAC address (#898) 2025-02-24 03:48:42 +01:00
KroeseandGitHub 1c9b793c75 fix: Move nginx config (#893) 2025-02-15 02:36:07 +01:00
KroeseandGitHub 00c4ef7795 feat: Remove existing TAP interface (#892) 2025-02-14 20:19:12 +01:00
KroeseandGitHub 619657adf2 docs: Add restart policy (#888) 2025-02-10 00:31:32 +01:00
KroeseandGitHub 41db7c1035 feat: Improve CPU detection (#884) 2025-02-06 02:19:39 +01:00
KroeseandGitHub d71834a777 build: Enable ARM64 platform (#873) 2025-01-10 18:44:37 +01:00
KroeseandGitHub d078af0397 fix: TUN device error (#863) 2024-12-03 11:50:56 +01:00
KroeseandGitHub 2827d1d375 docs: Add TUN device (#861) 2024-12-01 17:57:00 +01:00
KroeseandGitHub 898499a4e3 feat: Make network adapter configurable (#859) 2024-11-26 20:01:37 +01:00
KroeseandGitHub eb010cc215 feat: Improve network error handling (#856) 2024-11-20 16:24:07 +01:00
KroeseandGitHub 84440d5159 fix: Use relative URL's (#855) 2024-11-20 13:21:20 +01:00
KroeseandGitHub ff3744ead9 feat: Improve CPU detection (#854) 2024-11-20 13:13:43 +01:00
KroeseandGitHub d00fe4b3eb docs: Readme (#848) 2024-11-13 03:45:21 +01:00
KroeseandGitHub 72a86a5d7f docs: Add Kubernetes URL (#847) 2024-11-13 03:35:50 +01:00
KroeseandGitHub 811ab622df docs: Add compatibility chart (#846) 2024-11-13 03:26:15 +01:00
KroeseandGitHub e76b72cddf feat: Disable HTTP keepalives (#845) 2024-11-13 02:48:27 +01:00
KroeseandGitHub e9edacc9c3 feat: Support image commit (#844) 2024-11-13 00:39:48 +01:00
KroeseandGitHub a6694a6b29 feat: Rename host to kernel (#843) 2024-11-11 16:24:47 +01:00
KroeseandGitHub 59323cd375 docs: KVM troubleshooting (#842) 2024-11-11 14:16:21 +01:00
KroeseandGitHub 6dc714e449 feat: Display unknown filesystem (#841) 2024-11-10 15:00:38 +01:00
KroeseandGitHub 5d75a9b039 feat: Improve CPU detection (#840) 2024-11-10 11:21:51 +01:00
KroeseandGitHub 92b4cf5997 build: Use latest Debian image (#832) 2024-10-19 22:09:52 +02:00
KroeseandGitHub 906e61b1b2 feat: Improve CPU detection (#831) 2024-10-15 10:27:51 +02:00
KroeseandGitHub dab230f9d5 build: Remove ARM64 platform (#830) 2024-10-15 00:37:28 +02:00
KroeseandGitHub 5e8bcda9fc feat: Improve CPU detection (#829) 2024-10-14 18:06:02 +02:00
KroeseandGitHub d4bf83ae86 feat: Add NVME disk type (#828) 2024-10-13 03:03:32 +02:00
xrh0905andGitHub 8244a48511 Correct the possible DISK_IO (io_uring) (#827) 2024-10-06 16:26:35 +02:00
KroeseandGitHub 43ffa18a5f fix: Remove scsi parameter from virtio-blk-pci (#824) 2024-10-01 21:49:31 +02:00
KroeseandGitHub b131a32d0c buid: Pin Debian version (#818) 2024-09-27 14:40:56 +02:00
D-JyandGitHub c81787b837 feat: Allow custom rendernode (#817) 2024-09-17 23:30:58 +02:00
KroeseandGitHub f9df3c6db6 feat: Update to VirtualDSM 7.2.2 (#815) 2024-09-11 19:20:43 +02:00
Liang Ying-RueiandGitHub e383ec30e3 fix: Splits $USER_PORTS correctly by commas (#813) 2024-09-09 15:43:57 +02:00
KroeseandGitHub 1197c4791e fix: Port forwarding warning (#809) 2024-09-05 18:58:23 +02:00
KroeseandGitHub 106c684389 docs: Update package URL (#808) 2024-09-03 15:09:33 +02:00
KroeseandGitHub a199ced77b docs: Update package URL (#803) 2024-08-27 16:07:09 +02:00
KroeseandGitHub 77ac73666e fix: Progress calculation (#799) 2024-08-18 17:55:07 +02:00
KroeseandGitHub 64975557c2 fix: Validate lscpu output (#798) 2024-08-18 04:40:20 +02:00
KroeseandGitHub b62321806a docs: Fix badge (#796) 2024-08-13 20:51:55 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
7c392082b1 chore(deps): update docker/build-push-action action to v6 (#775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 12:45:23 +02:00
KroeseandGitHub 392e9a6417 docs: Networking (#774) 2024-06-16 06:09:26 +02:00
KroeseandGitHub fb5f684e7e fix: Don't set script with file descriptor (#772) 2024-06-14 04:35:40 +02:00
KroeseandGitHub 0dbc794223 feat: Customize image filenames (#771) 2024-06-14 03:01:27 +02:00
KroeseandGitHub 6295ed3b7b docs: Removed Kubevirt dependancy (#770) 2024-06-13 19:31:00 +02:00
KroeseandGitHub 0f2d889858 fix: Assume GB when no unit is present (#769) 2024-06-13 18:59:13 +02:00
KroeseandGitHub 60e6b01982 docs: Add markdown alerts (#768) 2024-06-13 18:31:25 +02:00
KroeseandGitHub 1dc69f9e22 docs: Add GHCR badge (#767) 2024-06-11 23:26:38 +02:00
KroeseandGitHub fcca41ad93 docs: Readme (#766) 2024-06-11 21:48:18 +02:00
KroeseandGitHub 9897747425 docs: Add icons (#765) 2024-06-11 21:06:38 +02:00
KroeseandGitHub 4dbe9dcefd docs: KVM information (#764) 2024-06-11 19:56:14 +02:00
KroeseandGitHub be8bee90f2 feat: Implement usermode networking (#762) 2024-06-11 02:13:53 +02:00
KroeseandGitHub f8879029ec fix: Do not use IO threading for SATA disks (#760) 2024-06-09 18:34:55 +02:00
KroeseandGitHub 7b491b3cee feat: Verify clocksource is set to TSC (#759) 2024-06-09 17:44:15 +02:00
KroeseandGitHub 2ece865417 fix: Download error messages (#756) 2024-06-05 18:18:29 +02:00
KroeseandGitHub 0d8c693c65 build: Update qemu-host to v2.05 (#755) 2024-06-05 14:32:21 +02:00
KroeseandGitHub 9f7d1396b6 docs: Readme (#753) 2024-06-03 02:00:04 +02:00
KroeseandGitHub 5ad323486e feat: Print QEMU version on boot (#752) 2024-06-02 23:00:40 +02:00
KroeseandGitHub 19b4248929 feat: Print QEMU version on boot (#751) 2024-06-02 21:04:09 +02:00
KroeseandGitHub c135c4cac3 feat: Add automatic device type (#749) 2024-05-27 17:25:52 +02:00
KroeseandGitHub fb1751ff26 docs: Updated issue templates (#747) 2024-05-25 14:07:30 +02:00
KroeseandGitHub 34f32d4ac6 docs: Docker CLI example (#746) 2024-05-22 07:55:38 +02:00
KroeseandGitHub 36f1e47c0a fix: Check for Podman IP ranges (#745) 2024-05-21 13:48:05 +02:00
KroeseandGitHub c5dd5c2e46 feat: Print arguments in debug mode (#743) 2024-05-21 09:17:51 +02:00
KroeseandGitHub d1d920372a feat: Support more device types (#742) 2024-05-21 09:10:30 +02:00
KroeseandGitHub 12d8fd3ed0 feat: Support Kubernetes interfaces (#741) 2024-05-21 07:44:44 +02:00
KroeseandGitHub 729aed536e feat: Add flag to disable RAM check (#740) 2024-05-19 23:59:14 +02:00
KroeseandGitHub b588f8c90d feat: Display KVM warning on ARM64 (#739) 2024-05-19 21:19:58 +02:00
KroeseandGitHub 1f1007a0f1 fix: Display reason for network failure (#738) 2024-05-17 16:09:47 +02:00
KroeseandGitHub 2ec37e2802 docs: Docker CLI (#737) 2024-05-16 03:22:58 +02:00
SlavikandGitHub 3126b3847b feat: Add Kubernetes manifest (#735) 2024-05-16 01:42:58 +02:00
KroeseandGitHub 41e0157e9d docs: Update issue templates (#736) 2024-05-16 01:12:16 +02:00
KroeseandGitHub 1d64410849 docs: Update issue template (#734) 2024-05-15 22:04:25 +02:00
KroeseandGitHub 55034b0f40 feat: Additional disk device (#733) 2024-05-15 17:56:12 +02:00
KroeseandGitHub acffcf3774 docs: Remove restart policy (#732) 2024-05-15 17:23:09 +02:00
KroeseandGitHub fba0eb527b docs: Remove version from compose (#731) 2024-05-15 16:54:17 +02:00
KroeseandGitHub d9fc2714a6 build: Declare extra variable (#730) 2024-05-13 04:02:25 +02:00
KroeseandGitHub d1f1772d74 build: Optimize Dockerfile (#729) 2024-05-13 03:48:29 +02:00
KroeseandGitHub bf1d47e4f3 docs: Readme (#728) 2024-05-12 20:55:50 +02:00
KroeseandGitHub 3da564dfd1 feat: Support install from local PAT file (#727) 2024-05-12 20:19:30 +02:00
KroeseandGitHub abd30b9d91 feat: Detect Windows and MacOS (#726) 2024-05-11 22:11:11 +02:00
KroeseandGitHub c86408cbd6 fix: Additional pass-through mounts (#722) 2024-05-08 23:23:17 +02:00
KroeseandGitHub 1f51974c48 fix: Set download timeout (#719) 2024-05-04 17:24:21 +02:00
KroeseandGitHub 29f4cde296 feat: Show download percentage (#718) 2024-05-04 16:34:30 +02:00
KroeseandGitHub c4a0035062 feat: Display RAM amount warning (#717) 2024-05-03 11:18:20 +02:00
KroeseandGitHub 6724ddbd7d feat: Check the amount of RAM available (#716) 2024-05-02 20:21:21 +02:00
KroeseandGitHub 8d8ed63122 docs: Disk pass-through (#715) 2024-05-01 11:57:56 +02:00
KroeseandGitHub 6f4ea81907 feat: New disk pass-through method (#714) 2024-05-01 00:13:26 +02:00
KroeseandGitHub 6d162744ec feat: Improved networking (#712) 2024-04-30 00:30:44 +02:00
KroeseandGitHub 145b4aab5b docs: Update issue templates (#708) 2024-04-26 16:53:15 +02:00
KroeseandGitHub 2e4eb56d0b fix: Curl error on Chinese mirror (#707) 2024-04-26 16:32:08 +02:00
KroeseandGitHub 39c019193e fix: Curl error on Chinese mirror (#706) 2024-04-26 16:30:30 +02:00
KroeseandGitHub faec563b4a feat: Display kernel version (#704) 2024-04-26 13:59:51 +02:00
KroeseandGitHub 9840f8e07a feat: Support ecryptfs filesystem (#703) 2024-04-26 06:04:48 +02:00
KroeseandGitHub 3a5895fa0f build: Remove armv7 support (#702) 2024-04-26 04:16:46 +02:00
KroeseandGitHub 1bac5c8a7f feat: Print system info (#701) 2024-04-25 14:31:49 +02:00
KroeseandGitHub dd76c60e2a fix: CPU detection (#697) 2024-04-22 16:48:41 +02:00
KroeseandGitHub ac78cc7dc5 feat: Display system info on boot (#696) 2024-04-22 16:29:23 +02:00
KroeseandGitHub 66ac2d2002 docs: Update issue template (#692) 2024-04-17 19:03:17 +02:00
KroeseandGitHub 0bd099d704 docs: Update issue templates (#691) 2024-04-17 18:32:43 +02:00
KroeseandGitHub d2dac3cfb4 docs: Add issue templates (#690) 2024-04-17 18:14:51 +02:00
KroeseandGitHub e81dc0f31d fix: Verify files are not empty (#689) 2024-04-16 15:35:35 +02:00
KroeseandGitHub 5015597183 fix: Ignore empty MAC address (#688) 2024-04-13 23:33:17 +02:00
KroeseandGitHub 64e2af9fa2 fix: Continue if file is missing (#682) 2024-04-08 09:54:42 +02:00
KroeseandGitHub debb4b69fc fix: Continue when range request fails (#680) 2024-04-08 04:53:30 +02:00
KroeseandGitHub c6d3dda171 docs: Readme (#677) 2024-04-07 01:59:50 +02:00
KroeseandGitHub 7c0693c2ff build: Update qemu-host to v2.04 (#670) 2024-03-31 05:24:54 +02:00
KroeseandGitHub 76355d4857 fix: TUN error message (#669) 2024-03-31 04:57:56 +02:00
KroeseandGitHub 404aaadefc build: Dockerfile (#663) 2024-03-25 16:49:25 +01:00
KroeseandGitHub be027e10be fix: Disable IPv6 in Nginx (#662) 2024-03-25 13:53:30 +01:00
KroeseandGitHub 1c8cad92f8 fix: Disable kernel networking in bridge mode (#656) 2024-03-12 01:50:43 +01:00
KroeseandGitHub fabb8ea3b7 docs: Readme (#650) 2024-02-28 20:43:27 +01:00
KroeseandGitHub 2ee4abca54 docs: Docker run command (#647) 2024-02-28 08:51:55 +01:00
KroeseandGitHub 5896928030 feat: Persistant MAC address (#646) 2024-02-28 08:40:00 +01:00
KroeseandGitHub 8652544982 docs: Readme (#638) 2024-02-19 21:32:22 +01:00
KroeseandGitHub a70338ec3c feat: Print filesystem on error (#635) 2024-02-17 05:56:40 +01:00
KroeseandGitHub a84878abfc fix: Detect Mac Journal filesystem (#634) 2024-02-17 03:55:30 +01:00
KroeseandGitHub 8421a391b7 fix: Prevent re-entry during shutdown (#633) 2024-02-16 16:03:37 +01:00
KroeseandGitHub f9340ec3d6 docs: Readme (#630) 2024-02-10 00:33:21 +01:00
KroeseandGitHub 0cca9c5f83 feat: Disable CoW check on XFS (#629) 2024-02-09 23:53:18 +01:00
KroeseandGitHub 13d60b7f47 build: Notify after build (#628) 2024-02-09 14:45:38 +01:00
KroeseandGitHub f74771a9cc fix: Convert MAC address to uppercase (#627) 2024-02-08 17:33:11 +01:00
KroeseandGitHub f24ba41930 fix: Convert dashes in custom MAC addresses (#626) 2024-02-08 17:03:30 +01:00
KroeseandGitHub f412580a4a feat: Add DNS entry for container (#624) 2024-02-07 22:26:29 +01:00
KroeseandGitHub 5cde1b4438 feat: Set process name (#623) 2024-02-07 13:04:29 +01:00
KroeseandGitHub 7cfb57b1bc docs: Readme (#621) 2024-02-05 16:18:13 +01:00
KroeseandGitHub a478b58f97 feat: Set KVM tick policy (#620) 2024-02-05 12:09:12 +01:00
KroeseandGitHub 8297f4f880 fix: Support CPU's without SSE4 (#619) 2024-02-05 07:41:47 +01:00
KroeseandGitHub 4c67343d33 feat: Enable L3 cache and multi-threaded TCG (#618) 2024-02-04 19:25:22 +01:00
KroeseandGitHub 53cc6998f0 fix: CPU features 2024-02-02 22:44:43 +01:00
KroeseandGitHub d857d71e0d fix: Merge drive function (#614) 2024-02-01 11:05:33 +01:00
KroeseandGitHub 003c2766ce docs: Readme (#613) 2024-01-31 04:28:24 +01:00
KroeseandGitHub 78594098cc feat: Disable CoW check on ZFS (#612) 2024-01-31 03:54:40 +01:00
KroeseandGitHub 3c31bc91e4 feat: Generate unique MAC address (#611) 2024-01-30 04:46:44 +01:00
KroeseandGitHub 72141bab7a build: Lint Dockerfile (#610) 2024-01-29 11:51:28 +01:00
KroeseandGitHub bc52463aa4 fix: Process signal faster (#609) 2024-01-29 05:54:22 +01:00
KroeseandGitHub 9fa68908a9 feat: Show download progress (#608) 2024-01-29 05:40:06 +01:00
KroeseandGitHub 740dbec1b1 build: Exclude web folder (#607) 2024-01-29 02:29:05 +01:00
KroeseandGitHub 440d203730 fix: Stylesheet (#606) 2024-01-29 02:27:04 +01:00
KroeseandGitHub 1a83c67e2c feat: Font smoothing (#605) 2024-01-29 02:01:51 +01:00
KroeseandGitHub 34a707a2a5 docs: Readme (#603) 2024-01-27 19:51:26 +01:00
KroeseandGitHub cabb2cdfc9 docs: Readme (#602) 2024-01-27 19:10:43 +01:00
KroeseandGitHub dc52ccf172 docs: Readme (#601) 2024-01-27 19:06:10 +01:00
KroeseandGitHub bdd7fec3c3 fix: Space after URL (#600) 2024-01-27 02:01:27 +01:00
KroeseandGitHub bd8b03d089 docs: Readme (#599) 2024-01-26 06:29:15 +01:00
KroeseandGitHub a10588b0ce fix: Check dnsmasq (#598) 2024-01-26 02:19:31 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3503b86e12 chore(deps): update peter-evans/dockerhub-description action to v4 (#597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-25 17:05:28 +01:00
KroeseandGitHub 9e124980cd fix: Disk message (#596) 2024-01-25 17:02:50 +01:00
KroeseandGitHub 675aa5e122 docs: Readme (#595) 2024-01-23 21:49:18 +01:00
KroeseandGitHub 2a62d4e938 feat: Display console arguments (#594) 2024-01-23 19:32:15 +01:00
KroeseandGitHub 9cbb51cc86 feat: Display QEMU version (#593) 2024-01-23 19:29:07 +01:00
KroeseandGitHub 7790f81d15 fix: Trap exit code (#592) 2024-01-23 18:46:47 +01:00
KroeseandGitHub fdbff4879b fix: Incorrect path (#591) 2024-01-23 03:06:29 +01:00
KroeseandGitHub 739e679a66 feat: Check for SHM (#590) 2024-01-23 03:04:47 +01:00
KroeseandGitHub 0dea507d85 feat: Shorter messages (#588) 2024-01-23 00:15:11 +01:00
KroeseandGitHub 4f524c47d8 docs: Readme (#587) 2024-01-22 03:24:00 +01:00
KroeseandGitHub 0c74201eb4 feat: CPU flags (#586) 2024-01-21 20:52:53 +01:00
KroeseandGitHub 1e13258bc9 feat: Dynamic page content (#585) 2024-01-21 18:35:55 +01:00
KroeseandGitHub 2c7cea042f feat: Display progress via web (#584) 2024-01-20 19:59:44 +01:00
KroeseandGitHub fc92b66ff4 fix: Echo (#583) 2024-01-19 15:12:02 +01:00
KroeseandGitHub 89ae24a2ac feat: Add warning macro (#582) 2024-01-19 15:10:40 +01:00
KroeseandGitHub bd4a23b287 docs: Readme (#581) 2024-01-19 12:05:54 +01:00
KroeseandGitHub 1b8c4d9f08 docs: Readme (#580) 2024-01-19 12:01:31 +01:00
KroeseandGitHub a1187decb5 docs: Readme (#579) 2024-01-19 08:09:49 +01:00
KroeseandGitHub b9d7aa182d docs: Readme (#578) 2024-01-19 07:50:07 +01:00
KroeseandGitHub b908c1118d fix: Sanitize filename (#577) 2024-01-19 04:17:09 +01:00
KroeseandGitHub fab776764f fix: Strip query parameters from filename (#576) 2024-01-19 03:04:26 +01:00
KroeseandGitHub f3e17e399d feat: Custom VGA adaptor (#573) 2024-01-17 19:42:30 +01:00
KroeseandGitHub 3706ca873b docs: Remove latest (#572) 2024-01-15 13:58:23 +01:00
KroeseandGitHub 10c565f32b docs: Grammar (#571) 2024-01-15 13:31:21 +01:00
KroeseandGitHub d237e5b9e6 docs: Disk passthrough (#570) 2024-01-15 11:54:57 +01:00
KroeseandGitHub 3c7e1ce12f docs: DHCP mode (#568) 2024-01-15 05:00:15 +01:00
KroeseandGitHub f422f64325 docs: Readme (#567) 2024-01-14 21:22:13 +01:00
KroeseandGitHub df0656b345 docs: Readme (#566) 2024-01-14 20:12:51 +01:00
KroeseandGitHub 1fc9c56c8f style: Quote variables (#565) 2024-01-14 16:01:15 +01:00
KroeseandGitHub 893a013ae9 style: Quote variables (#563) 2024-01-14 01:11:58 +01:00
KroeseandGitHub 6d3812d1d0 fix: Remove cat (#562) 2024-01-14 00:37:36 +01:00
KroeseandGitHub 6422aec780 fix: Remove cat (#561) 2024-01-14 00:00:59 +01:00
KroeseandGitHub fcd7b8a825 fix: Use /tmp for server (#560) 2024-01-13 20:46:05 +01:00
KroeseandGitHub 575da1f574 feat: Store config in RAM (#559) 2024-01-13 20:25:57 +01:00
KroeseandGitHub 3a507f5bf6 fix: Display QEMU output (#558) 2024-01-13 18:16:17 +01:00
KroeseandGitHub a3d6e3740c docs: Readme (#557) 2024-01-13 14:51:57 +01:00
KroeseandGitHub 53e0330e21 feat: Change qcow allocation (#555) 2024-01-12 23:50:04 +01:00
KroeseandGitHub f935c1e28a docs: Readme (#554) 2024-01-12 23:19:01 +01:00
KroeseandGitHub 6a0c708224 fix: Device support (#552) 2024-01-12 18:01:20 +01:00
KroeseandGitHub a407d2d94d build: Install apt-utils (#551) 2024-01-10 17:58:50 +01:00
KroeseandGitHub 53605bd6e8 fix: Add package (#546) 2024-01-08 01:46:21 +01:00
KroeseandGitHub 944faaa927 fix: Remove slash (#545) 2024-01-07 23:56:06 +01:00
KroeseandGitHub fb7cfc09de fix: Set Debian flag (#544) 2024-01-07 21:23:42 +01:00
KroeseandGitHub b9ae73e322 build: Remove apt-get upgrade (#543) 2024-01-06 03:17:50 +01:00
KroeseandGitHub c28dbb6b9b feat: Add FUSE warning (#542)
* feat: Add FUSE warning
2024-01-05 13:24:54 +01:00
KroeseandGitHub dcc26b67a6 fix: Diskspace check (#541)
* fix: Diskspace check
2024-01-05 02:27:15 +01:00
KroeseandGitHub 2627d320f3 fix: Remove VNC support (#540)
* fix: Remove VNC support
2024-01-05 00:02:49 +01:00
KroeseandGitHub fd4bc28835 fix: Console mode (#538) 2024-01-04 23:24:34 +01:00
KroeseandGitHub 63e4d588a2 docs: Readme (#535) 2024-01-04 05:33:30 +01:00
KroeseandGitHub feb1680909 build: Update location (#534) 2024-01-04 05:31:34 +01:00
IP2LocationandGitHub 9d21489b8e Added api.ip2location.io (#533) 2024-01-04 04:11:20 +01:00
KroeseandGitHub e70ed1900f fix: Port forwarding (#530) 2024-01-03 14:02:16 +01:00
KroeseandGitHub d65b5a089a fix: KVM check (#529) 2024-01-03 13:33:38 +01:00
KroeseandGitHub 84643647cc fix: Compose (#527) 2023-12-31 15:11:20 +01:00
KroeseandGitHub 57f487db6d build: Remove agent
* build: Remove agent
2023-12-31 01:56:03 +01:00
KroeseandGitHub 0862cad2ce fix: Port forwarding (#525)
* fix: Port forwarding
2023-12-30 00:01:12 +01:00
KroeseandGitHub 5ae4f59315 fix: QEMU monitor (#524) 2023-12-29 19:05:51 +01:00
KroeseandGitHub 3fc3005ba5 fix: Processor (#523)
* fix: Processor
2023-12-29 18:27:51 +01:00
KroeseandGitHub 20f48edd00 fix: Serial port (#522)
* fix: Serial port
2023-12-29 18:15:39 +01:00
KroeseandGitHub b854aad830 fix: Use single IO thread (#521) 2023-12-29 17:34:23 +01:00
KroeseandGitHub 6cbe03f656 fix: Port forwarding (#520) 2023-12-29 17:20:18 +01:00
KroeseandGitHub 63cac9a75e fix: Display config (#519)
* fix: Display config
2023-12-29 16:56:49 +01:00
KroeseandGitHub 08616f1057 build: Update Dockerfile (#518) 2023-12-29 00:24:36 +01:00
KroeseandGitHub e6193b1020 fix: Port forwarding (#517) 2023-12-28 21:30:28 +01:00
KroeseandGitHub f28b9903f3 fix: iptables for NAT (#516) 2023-12-28 21:20:38 +01:00
KroeseandGitHub 7bf2d119ea feat: Validate mac address (#515) 2023-12-28 20:54:33 +01:00
KroeseandGitHub 527bded1b2 feat: Detect default interface
* feat: Detect default interface
2023-12-28 20:25:04 +01:00
KroeseandGitHub 1208c53ebb feat: Check network interface (#513) 2023-12-28 18:26:56 +01:00
KroeseandGitHub 973efa2d27 feat: Show daemon log
* feat: Show daemon log
2023-12-28 17:58:07 +01:00
KroeseandGitHub d09588b915 fix: Refactor
* fix: Refactor
2023-12-28 16:08:12 +01:00
KroeseandGitHub 19aa313753 fix: Shellcheck (#509) 2023-12-28 08:35:51 +01:00
KroeseandGitHub 9db12cd25f fix: Device detection
* fix: Device detection
2023-12-28 08:31:32 +01:00
KroeseandGitHub 69e785e6ee fix: Shutdown message
* fix: Shutdown message
2023-12-28 05:26:53 +01:00
KroeseandGitHub 159fce6839 fix: Detect device
* fix: Detect device
2023-12-28 05:04:40 +01:00
KroeseandGitHub 08e4084458 feat: Daemonize QEMU
* feat: Daemonize QEMU
2023-12-28 03:42:06 +01:00
KroeseandGitHub 06f210846c fix: KVM flag (#504) 2023-12-27 16:28:24 +01:00
KroeseandGitHub 74629e4b55 fix: Installation (#501) 2023-12-27 04:07:45 +01:00
KroeseandGitHub 6e8af6e52f fix: Host CPU (#500) 2023-12-27 03:23:39 +01:00
KroeseandGitHub 38611a7af2 fix: Host CPU (#499) 2023-12-27 03:18:03 +01:00
KroeseandGitHub f089acc01a fix: CPU features (#496) 2023-12-25 05:58:14 +01:00
KroeseandGitHub 5a7ecb48d6 fix: Error messages (#495) 2023-12-25 05:03:00 +01:00
KroeseandGitHub 5b3880aa5e fix: Error messages (#494) 2023-12-25 04:48:18 +01:00
KroeseandGitHub 4653aafbee docs: Readme (#493) 2023-12-25 04:21:50 +01:00
KroeseandGitHub 281f2992ff fix: Close file descriptors
* fix: Close file descriptors
2023-12-25 04:04:01 +01:00
KroeseandGitHub 4bdcf8bfe1 fix: Skip mknod errors (#491) 2023-12-24 14:39:37 +01:00
KroeseandGitHub 62acaa95bf fix: Check attribute (#490) 2023-12-24 14:27:29 +01:00
KroeseandGitHub 369bff339d fix: Update Dockerfile (#489) 2023-12-24 02:54:57 +01:00
KroeseandGitHub 5332d387f4 fix: Set file attribute (#488)
* fix: Set file attribute
2023-12-24 02:41:44 +01:00
KroeseandGitHub f0d08ef263 fix: Remove flag (#487)
* fix: Remove flag
2023-12-23 22:58:45 +01:00
KroeseandGitHub e4334f9499 fix: Ignore mknod errors (#486) 2023-12-23 22:28:25 +01:00
KroeseandGitHub 627ec56262 feat: LINUX_IMMUTABLE flag (#485)
* feat: LINUX_IMMUTABLE flag
2023-12-23 21:26:23 +01:00
KroeseandGitHub 251cf8121e feat: Add LINUX_IMMUTABLE flag (#484)
To change directory attributes on COW filesystems
2023-12-23 20:35:06 +01:00
KroeseandGitHub 87fad1b0e9 feat: Set directory attributes (#483)
* feat: Set directory attributes
2023-12-23 20:01:27 +01:00
KroeseandGitHub 698516ac8c feat: Detect country from timezone (#482) 2023-12-23 18:46:14 +01:00
dae5d75674 feat: Improve support for unprivileged hosts (including LXC) (#479)
* * Add fakeroot to extract the dsm system without elevated permissions
* Remove obsolete docker variable "DEV" used to exclude extraction of device nodes

* feat: Detect unprivileged container

* fix: Use fakeroot for mke2fs

---------

Co-authored-by: Kroese <kroese@users.noreply.github.com>
2023-12-23 18:04:43 +01:00
KroeseandGitHub 95facffa9b fix: Use specified LAN adaptor (#481)
* fix: Use specified LAN adaptor
2023-12-23 15:23:36 +01:00
KroeseandGitHub 682e0a9952 feat: Check filesystem (#477)
* feat: Check filesystem
2023-12-22 15:00:22 +01:00
KroeseandGitHub 9a97dfdc70 fix: Check filesystem (#476) 2023-12-22 06:15:33 +01:00
KroeseandGitHub 2f383699f9 feat: Firewall info
feat: Firewall info
2023-12-22 05:20:44 +01:00
KroeseandGitHub 8137a137b3 fix: Disable device nodes 2023-12-22 05:10:22 +01:00
KroeseandGitHub 1339d51796 feat: Firewall info 2023-12-22 04:47:58 +01:00
KroeseandGitHub dce447c974 fix: Quit message 2023-12-22 04:24:48 +01:00
KroeseandGitHub ef5b650991 fix: Shutdown loop (#474) 2023-12-20 12:09:25 +01:00
KroeseandGitHub fd19c7b4f3 feat: Log creation info (#473) 2023-12-20 03:34:26 +01:00
KroeseandGitHub 727297642c fix: Exit counter (#472) 2023-12-20 02:00:07 +01:00
KroeseandGitHub cd457801e7 fix: Set IP in bridge mode
* fix: Set IP in bridge mode
2023-12-20 01:52:55 +01:00
KroeseandGitHub 392e7afdfe fix: Allocate after conversion
fix: Allocate after conversion
2023-12-19 08:54:43 +01:00
KroeseandGitHub b425e34907 fix: Allocate after conversion 2023-12-19 08:54:08 +01:00
KroeseandGitHub 7c2e2fc7b1 feat: Enable IO threading
feat: Enable IO threading
2023-12-19 06:16:28 +01:00
KroeseandGitHub 9bac0c94a8 feat: Detect COW on btrfs 2023-12-19 06:11:50 +01:00
KroeseandGitHub 631568681e feat: Detect COW on BTRFS 2023-12-19 06:01:50 +01:00
KroeseandGitHub 6599861dbb feat: Detect COW on BTRFS 2023-12-19 05:46:49 +01:00
KroeseandGitHub 3bcd831531 fix: Display timeout 2023-12-19 04:30:01 +01:00
KroeseandGitHub fafd4a4fca feat: Enable IO threading 2023-12-19 03:59:19 +01:00
KroeseandGitHub 5b69178f08 docs: Allocation 2023-12-19 03:33:41 +01:00
KroeseandGitHub 479a30369d feat: Enable IO threading 2023-12-19 02:34:48 +01:00
KroeseandGitHub ba522a4acb feat: Increase clustersize for qcow2
* feat: Increase clustersize for qcow2
2023-12-18 17:34:40 +01:00
KroeseandGitHub 3ab6d2c418 docs: Allocation 2023-12-18 16:48:01 +01:00
KroeseandGitHub b71b2245cb fix: Check diskspace
* fix: Check diskspace
2023-12-18 16:44:26 +01:00
KroeseandGitHub bbea0eb429 docs: Readme 2023-12-18 12:39:11 +01:00
KroeseandGitHub c28c5cfbaa docs: Allocation 2023-12-18 12:36:03 +01:00
KroeseandGitHub be3fd30cb2 feat: Honor allocation flag for qcow2
* feat: Honor allocation flag for qcow2
2023-12-18 12:18:28 +01:00
KroeseandGitHub e3942da906 feat: Set NOCOW flag for btrfs
feat: Set NOCOW flag for btrfs
2023-12-17 11:42:08 +01:00
KroeseandGitHub d66be1a228 fix: Do not set flags on resize 2023-12-17 11:25:42 +01:00
KroeseandGitHub 72085d3711 fix: Set qcow2 flags 2023-12-17 11:17:26 +01:00
KroeseandGitHub e7cdbb1db5 feat: Optimize qcow2 flags 2023-12-17 10:51:30 +01:00
KroeseandGitHub 7a592e0cea docs: DHCP mode 2023-12-17 10:08:55 +01:00
KroeseandGitHub 107a4b87d5 fix: Quotes 2023-12-17 10:04:00 +01:00
KroeseandGitHub 8b0ec3bef7 fix: Remove healthcheck exception 2023-12-17 09:57:50 +01:00
KroeseandGitHub aaded40a4f fix: Cleanup server files 2023-12-17 09:54:07 +01:00
KroeseandGitHub 7f77bb88ab fix: Grammar 2023-12-17 09:50:07 +01:00
KroeseandGitHub 95c3b2caad fix: Default folder 2023-12-17 09:39:19 +01:00
KroeseandGitHub 150c450bf6 docs: Default folder 2023-12-17 09:37:36 +01:00
KroeseandGitHub 932c23afba fix: Check SSE4.2 2023-12-16 15:57:30 +01:00
KroeseandGitHub 2e0107e46f fix: Bash shebang
* fix: Bash shebang
2023-12-16 07:42:57 +01:00
KroeseandGitHub d22a3a4c7d feat: Support more CPU models
feat: Support more CPU models
2023-12-16 06:44:58 +01:00
KroeseandGitHub f93f870626 feat: CPU features 2023-12-16 06:31:43 +01:00
KroeseandGitHub a2e55c5dda fix: Configuration variables 2023-12-16 05:11:20 +01:00
KroeseandGitHub 32748509ea fix: CPU configuration 2023-12-16 05:08:34 +01:00
KroeseandGitHub 970a662170 fix: CPU configuration 2023-12-16 05:04:17 +01:00
KroeseandGitHub 8925323a6e feat: KVM flag 2023-12-16 04:55:40 +01:00
KroeseandGitHub 10915a601c feat: Display emulated CPU 2023-12-16 04:44:15 +01:00
KroeseandGitHub 2cc1af19b1 fix: Configure CPU 2023-12-16 04:38:15 +01:00
KroeseandGitHub 6670ca4fe1 fix: Configuration 2023-12-16 04:36:56 +01:00
KroeseandGitHub d3f77c848c feat: Emulate SSE4.2 on ARM64 2023-12-16 04:36:00 +01:00
KroeseandGitHub 3f2ca67051 feat: Emulate SSE4.2 on ARM64 2023-12-16 04:22:21 +01:00
KroeseandGitHub 3812101366 feat: Add KVM flag 2023-12-16 04:02:11 +01:00
KroeseandGitHub db72acfc4f feat: Install DSM 7.2 on ARM64 2023-12-16 03:12:55 +01:00
KroeseandGitHub 1b3d760f5f fix: Set CPU model 2023-12-16 03:07:08 +01:00
KroeseandGitHub 539f5de6d9 fix: Add qemu-user package on arm64 2023-12-16 02:45:16 +01:00
KroeseandGitHub fe2d072056 fix: Check for SSE4.2 support 2023-12-16 02:05:54 +01:00
KroeseandGitHub 469ee67942 fix: Error codes 2023-12-16 01:42:02 +01:00
KroeseandGitHub 95991d8f5d fix: Error codes 2023-12-16 01:36:33 +01:00
KroeseandGitHub 7e12585429 fix: Error codes 2023-12-16 01:30:34 +01:00
KroeseandGitHub c335078aac feat: Display emulated CPU 2023-12-16 01:00:42 +01:00
KroeseandGitHub f1fbbb5623 feat: Configure CPU model 2023-12-16 00:35:08 +01:00
KroeseandGitHub b6502e0a38 fix: Simplify healthcheck
fix: Simplify healthcheck
2023-12-15 09:17:53 +01:00
KroeseandGitHub 2fab3e5897 fix: Simplify healthcheck 2023-12-15 09:01:19 +01:00
KroeseandGitHub a4ea89d6e7 fix: Extended error message 2023-12-15 08:49:37 +01:00
KroeseandGitHub c451f253fa build: Release token (#454) 2023-12-14 03:45:32 +01:00
KroeseandGitHub 03121b6c6d build: Renovate (#452) 2023-12-11 00:32:18 +01:00
KroeseandGitHub 007d20c315 fix: Message variables
* fix: Message variables
2023-12-10 16:54:02 +01:00
KroeseandGitHub 26d6fa9fcc feat: Improve shutdown
* feat: Improve shutdown
2023-12-10 15:58:37 +01:00
KroeseandGitHub b9f3e52ba4 feat: Improve shutdown (#448)
* feat: Improve shutdown
2023-12-10 09:22:35 +01:00
49 changed files with 7266 additions and 1459 deletions
+19
View File
@@ -0,0 +1,19 @@
services:
dsm:
container_name: dsm
image: ghcr.io/vdsm/virtual-dsm
environment:
RAM_SIZE: "half"
DISK_SIZE: "max"
CPU_CORES: "max"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- ./dsm:/storage
restart: on-failure
stop_grace_period: 2m
+15
View File
@@ -0,0 +1,15 @@
{
"name": "Virtual DSM",
"service": "dsm",
"forwardPorts": [5000],
"portsAttributes": {
"5000": {
"label": "Web",
"onAutoForward": "notify"
}
},
"otherPortsAttributes": {
"onAutoForward": "ignore"
},
"dockerComposeFile": "codespaces.yml"
}
+4
View File
@@ -1,4 +1,5 @@
.dockerignore .dockerignore
.devcontainer
.git .git
.github .github
.gitignore .gitignore
@@ -6,7 +7,10 @@
.gitmodules .gitmodules
Dockerfile Dockerfile
Dockerfile.archive Dockerfile.archive
compose.yml
compose.yaml
docker-compose.yml docker-compose.yml
docker-compose.yaml
*.md *.md
+41
View File
@@ -0,0 +1,41 @@
name: "\U0001F6A8 Technical issue"
description: When you're experiencing problems using the container
body:
- type: input
id: os
attributes:
label: Operating system
description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: textarea
id: summary
attributes:
label: Description
description: A clear and concise description of your issue.
validations:
required: true
- type: textarea
id: compose
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations:
required: true
- type: textarea
id: log
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
render: shell
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: Screenshots (optional)
description: Screenshots that might help to make the problem more clear.
validations:
required: false
+37
View File
@@ -0,0 +1,37 @@
name: "\U0001F680 Feature request"
description: Suggest an idea for improving the container
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: Is your proposal related to a problem?
description: |
Provide a clear and concise description of what the problem is.
For example, "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like.
description: |
Provide a clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered.
description: |
Let us know about other solutions you've tried or researched.
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional context
description: |
Is there anything else you can add about the proposal?
You might want to link to related issues here, if you haven't already.
+43
View File
@@ -0,0 +1,43 @@
name: "\U0001F41E Bug report"
description: Create a report to help us improve the container
title: "[Bug]: "
labels: ["bug"]
body:
- type: input
id: os
attributes:
label: Operating system
description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: textarea
id: summary
attributes:
label: Description
description: Describe the expected behaviour, the actual behaviour, and the steps to reproduce.
validations:
required: true
- type: textarea
id: compose
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
render: yaml
validations:
required: true
- type: textarea
id: log
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
render: shell
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: Screenshots (optional)
description: Screenshots that might help to make the problem more clear.
validations:
required: false
+26
View File
@@ -0,0 +1,26 @@
name: "\U00002753 General question"
description: Questions about the container not related to an issue
title: "[Question]: "
labels: ["question"]
body:
- type: checkboxes
attributes:
label: Is your question not already answered in the FAQ?
description: Please read the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md) carefully to avoid asking duplicate questions.
options:
- label: I made sure the question is not listed in the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md).
required: true
- type: checkboxes
attributes:
label: Is this a general question and not a technical issue?
description: For questions related to issues you must use the [technical issue](https://github.com/vdsm/virtual-dsm/issues/new?assignees=&labels=&projects=&template=1-issue.yml) form instead. It contains all the right fields (system info, logfiles, etc.) we need in order to be able to help you.
options:
- label: I am sure my question is not about a technical issue.
required: true
- type: textarea
id: question
attributes:
label: Question
description: What's the question you have about the container?
validations:
required: true
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+11
View File
@@ -1,10 +1,21 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: docker - package-ecosystem: docker
directory: / directory: /
schedule: schedule:
interval: weekly interval: weekly
cooldown:
default-days: 7
- package-ecosystem: github-actions - package-ecosystem: github-actions
directory: / directory: /
schedule: schedule:
interval: weekly interval: weekly
cooldown:
default-days: 7
ignore:
- dependency-name: "*"
update-types:
- version-update:semver-minor
- version-update:semver-patch
+2 -4
View File
@@ -1,6 +1,4 @@
{ {
"extends": [ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"config:base", "extends": ["config:recommended", ":disableDependencyDashboard"]
":disableDependencyDashboard"
]
} }
+21 -21
View File
@@ -2,16 +2,6 @@ name: Build
on: on:
workflow_dispatch: workflow_dispatch:
push:
branches:
- master
paths-ignore:
- '**/*.md'
- '**/*.yml'
- '.gitignore'
- '.dockerignore'
- '.github/**'
- '.github/workflows/**'
concurrency: concurrency:
group: build group: build
@@ -32,13 +22,13 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- -
name: Docker metadata name: Docker metadata
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v6
with: with:
context: git context: git
images: | images: |
@@ -50,45 +40,43 @@ jobs:
labels: | labels: |
org.opencontainers.image.title=${{ vars.NAME }} org.opencontainers.image.title=${{ vars.NAME }}
env: env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
- -
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v4
- -
name: Login into Docker Hub name: Login into Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v4
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- -
name: Login to GitHub Container Registry name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v4
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- -
name: Build Docker image name: Build Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v7
with: with:
context: . context: .
push: true push: true
provenance: false provenance: false
platforms: linux/amd64,linux/arm64,linux/arm platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}
build-args: | build-args: |
VCS_REF=${GITHUB_SHA::8}
VERSION_ARG=${{ steps.meta.outputs.version }} VERSION_ARG=${{ steps.meta.outputs.version }}
- -
name: Create a release name: Create a release
uses: action-pack/github-release@v2 uses: action-pack/github-release@v2
env:
GITHUB_TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}
with: with:
tag: "v${{ steps.meta.outputs.version }}" tag: "v${{ steps.meta.outputs.version }}"
title: "v${{ steps.meta.outputs.version }}" title: "v${{ steps.meta.outputs.version }}"
token: ${{ secrets.REPO_ACCESS_TOKEN }}
- -
name: Increment version variable name: Increment version variable
uses: action-pack/bump@v2 uses: action-pack/bump@v2
@@ -101,3 +89,15 @@ jobs:
url: ${{ secrets.GITLAB_URL }} url: ${{ secrets.GITLAB_URL }}
token: ${{ secrets.GITLAB_TOKEN }} token: ${{ secrets.GITLAB_TOKEN }}
username: ${{ secrets.GITLAB_USERNAME }} username: ${{ secrets.GITLAB_USERNAME }}
-
name: Send mail
uses: action-pack/send-mail@v1
with:
to: ${{secrets.MAILTO}}
from: Github Actions <${{secrets.MAILTO}}>
connection_url: ${{secrets.MAIL_CONNECTION}}
subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed
body: |
The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully!
See https://github.com/${{ github.repository }}/actions for more information.
+28 -5
View File
@@ -1,5 +1,7 @@
on: [workflow_call] on: [workflow_call]
name: "Check" name: "Check"
permissions: {} permissions: {}
jobs: jobs:
@@ -7,8 +9,29 @@ jobs:
name: shellcheck name: shellcheck
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 -
- name: Run ShellCheck name: Checkout
uses: ludeeus/action-shellcheck@master uses: actions/checkout@v7
env: - parallel:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2002 -e SC2223 -e SC2034 -e SC2064 -e SC2317 -e SC2028 -e SC2153 -e SC2004 -
name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
env:
SHELLCHECK_OPTS: >-
-x
--source-path=src
-e SC1091
-e SC2001
-e SC2034
-e SC2317
-e SC2153
-
name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.4.0
with:
dockerfile: Dockerfile
ignore: DL3008
failure-threshold: warning
-
name: Validate JSON and YML files
uses: GrantBirki/json-yaml-validate@v5
+12 -10
View File
@@ -12,13 +12,15 @@ jobs:
dockerHubDescription: dockerHubDescription:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 -
- name: Checkout repo
name: Docker Hub Description uses: actions/checkout@v7
uses: peter-evans/dockerhub-description@v3 -
with: name: Docker Hub Description
username: ${{ secrets.DOCKERHUB_USERNAME }} uses: peter-evans/dockerhub-description@v5
password: ${{ secrets.DOCKERHUB_TOKEN }} with:
repository: ${{ secrets.DOCKERHUB_REPO }} username: ${{ secrets.DOCKERHUB_USERNAME }}
short-description: ${{ github.event.repository.description }} password: ${{ secrets.DOCKERHUB_TOKEN }}
readme-filepath: ./readme.md repository: ${{ secrets.DOCKERHUB_REPO }}
short-description: ${{ github.event.repository.description }}
readme-filepath: ./readme.md
+14
View File
@@ -0,0 +1,14 @@
on:
pull_request:
name: "Review"
permissions:
contents: read
pull-requests: write
checks: write
jobs:
review:
name: review
uses: action-pack/.github/.github/workflows/review.yml@master
-4
View File
@@ -1,10 +1,6 @@
on: on:
workflow_dispatch: workflow_dispatch:
pull_request: pull_request:
paths:
- '**/*.sh'
- '.github/workflows/test.yml'
- '.github/workflows/check.yml'
name: "Test" name: "Test"
permissions: {} permissions: {}
+268 -1
View File
@@ -1 +1,268 @@
build.sh ##############################
# Operating System Files
##############################
.DS_Store
.AppleDouble
.LSOverride
Thumbs.db
ehthumbs.db
Desktop.ini
Icon?
$RECYCLE.BIN/
.Spotlight-V100/
.Trashes/
.fseventsd
##############################
# IDEs
##############################
.vscode/
.idea/
*.iml
*.ipr
*.iws
##############################
# VS Code
##############################
.history/
*.code-workspace
##############################
# Vim
##############################
*.swp
*.swo
Session.vim
##############################
# Sublime
##############################
*.sublime-workspace
*.sublime-project
##############################
# Temporary Files
##############################
*.tmp
*.temp
*.bak
*.old
*.orig
*.rej
*.save
##############################
# Logs
##############################
*.log
logs/
log/
*.out
*.err
*.trace
##############################
# Runtime
##############################
*.pid
*.seed
*.pid.lock
##############################
# Secrets
##############################
.env
.env.*
!.env.example
*.pem
*.key
*.crt
*.cer
*.p12
*.pfx
*.kdbx
*.secret
*.token
##############################
# SSH
##############################
.ssh/
##############################
# Docker
##############################
docker-compose.override.yml
docker-compose.local.yml
##############################
# VM Storage
##############################
storage/
windows/
downloads/
##############################
# Disk Images
##############################
*.qcow2
*.qcow
*.vhd
*.vhdx
*.vdi
*.raw
*.img
*.iso
*.bin
##############################
# QEMU
##############################
*.nvram
*.fd
*.efi
*.sock
*.monitor
*.serial
##############################
# Samba
##############################
shared/
share/
##############################
# Backups
##############################
backup/
backups/
*.backup
##############################
# Cache
##############################
.cache/
.cache-loader/
.tmp/
temp/
tmp/
##############################
# Python
##############################
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.venv/
venv/
##############################
# Node
##############################
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
##############################
# Build
##############################
dist/
build/
out/
release/
##############################
# Coverage
##############################
coverage/
.coverage
coverage.xml
##############################
# Archives
##############################
*.zip
*.tar
*.tar.gz
*.tgz
*.7z
*.rar
##############################
# Generated Config
##############################
config.local.*
settings.local.*
local.env
##############################
# Test Files
##############################
test-output/
playwright-report/
##############################
# macOS
##############################
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
##############################
# Linux
##############################
*~
.nfs*
##############################
# Windows
##############################
*.stackdump
##############################
# Misc
##############################
*.cache
*.lock
*.lock.json
*.bak.*
##############################
# Keep Examples
##############################
!.gitkeep
!.env.example
+83 -51
View File
@@ -1,59 +1,91 @@
FROM qemux/qemu-host as builder # syntax=docker/dockerfile:1
# FROM golang as builder
# WORKDIR /
# RUN git clone https://github.com/qemu-tools/qemu-host.git
# WORKDIR /qemu-host/src
# RUN go mod download
# RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /qemu-host.bin .
FROM qemux/qemu-host:2.06 AS builder
FROM debian:trixie-slim FROM debian:trixie-slim
ARG DEBCONF_NOWARNINGS="yes" ARG TARGETARCH
ARG DEBIAN_FRONTEND noninteractive ARG TARGETPLATFORM
RUN apt-get update && apt-get -y upgrade && \
apt-get --no-install-recommends -y install \
jq \
tini \
curl \
cpio \
wget \
fdisk \
unzip \
socat \
procps \
xz-utils \
iptables \
iproute2 \
dnsmasq \
net-tools \
qemu-utils \
ca-certificates \
netcat-openbsd \
qemu-system-x86 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY ./src /run/
COPY --from=builder /qemu-host.bin /run/host.bin
RUN chmod +x /run/*.sh && chmod +x /run/*.bin
VOLUME /storage
EXPOSE 22
EXPOSE 80
EXPOSE 139
EXPOSE 445
EXPOSE 5000
ENV RAM_SIZE "1G"
ENV DISK_SIZE "16G"
ENV CPU_CORES "1"
ARG VERSION_ARG="0.0" ARG VERSION_ARG="0.0"
RUN echo "$VERSION_ARG" > /run/version ARG VERSION_CSTRUCT="4.7"
ARG VERSION_PASST="2026_07_28"
HEALTHCHECK --interval=60s --start-period=45s --retries=2 CMD /run/check.sh ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
ARG DEBCONF_NONINTERACTIVE_SEEN="true"
RUN <<EOF
set -eu
apt-get update
apt-get --no-install-recommends -y install \
jq \
tini \
curl \
wget \
fdisk \
unzip \
nginx \
procps \
ipcalc \
ethtool \
python3 \
python3-pip \
python3-msgpack \
python3-pysodium \
xz-utils \
iptables \
iproute2 \
dnsmasq \
fakeroot \
apt-utils \
net-tools \
e2fsprogs \
diffutils \
qemu-utils \
websocketd \
iputils-ping \
inotify-tools \
ca-certificates \
netcat-openbsd \
qemu-system-x86
# Install Passt package
wget "https://github.com/qemus/passt/releases/download/v${VERSION_PASST}/passt_${VERSION_PASST}_${TARGETARCH}.deb" -O /tmp/passt.deb -q --timeout=10
dpkg -i /tmp/passt.deb
apt-get clean
# Install Python dependencies
pip3 install --no-cache-dir --break-system-packages --root-user-action=ignore "dissect.cstruct==$VERSION_CSTRUCT"
# Configure QEMU
mkdir -p /etc/qemu
echo "allow br0" > /etc/qemu/bridge.conf
# Configure nginx
unlink /etc/nginx/sites-enabled/default
sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf
# Set version file
echo "$VERSION_ARG" > /etc/version
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
EOF
COPY --chmod=755 ./src /run/
COPY --chmod=755 ./web /var/www/
COPY --chmod=755 --from=builder /qemu-host.bin /run/host.bin
COPY --chmod=744 ./web/conf/nginx.conf /etc/nginx/default.conf
ADD --chmod=775 https://raw.githubusercontent.com/sud0woodo/patology/refs/heads/main/patology.py /run/extract.py
VOLUME /storage
EXPOSE 22 139 445 5000
ENV RAM_SIZE="2G"
ENV CPU_CORES="2"
ENV DISK_SIZE="256G"
HEALTHCHECK --interval=60s --start-period=45s --retries=2 CMD ["/run/check.sh"]
ENTRYPOINT ["/usr/bin/tini", "-s", "/run/entry.sh"] ENTRYPOINT ["/usr/bin/tini", "-s", "/run/entry.sh"]
-140
View File
@@ -1,140 +0,0 @@
#!/usr/bin/env bash
set -u
VERSION="9"
HEADER="VirtualDSM Agent"
# Functions
error () { echo -e "\E[1;31m ERROR: $1\E[0m" ; }
info () { echo -e "\E[1;34m\E[1;36m $1\E[0m" ; }
finish() {
echo " $HEADER: Shutting down.."
exit
}
function checkNMI {
local nmi
nmi=$(cat /proc/interrupts | grep NMI | sed 's/[^1-9]*//g')
if [ "$nmi" != "" ]; then
info "Received shutdown request through NMI.."
/usr/syno/sbin/synoshutdown -s > /dev/null
finish
fi
}
function downloadUpdate {
TMP="/tmp/agent.sh"
rm -f "${TMP}"
# Auto update the agent
URL="https://raw.githubusercontent.com/vdsm/virtual-dsm/master/agent/agent.sh"
remote_size=$(curl -sIk -m 4 "${URL}" | grep -i "content-length:" | tr -d " \t" | cut -d ':' -f 2)
remote_size=${remote_size//$'\r'}
[[ "$remote_size" == "" || "$remote_size" == "0" ]] && return
remote_size=$(($remote_size+0))
((remote_size<100)) && return
SCRIPT=$(readlink -f "${BASH_SOURCE[0]}")
local_size=$(stat -c%s "$SCRIPT")
local_size=$(($local_size+0))
[[ remote_size -eq local_size ]] && return
if ! curl -sfk -m 10 -o "${TMP}" "${URL}"; then
error "$HEADER: curl error ($?)" && return
fi
if [ ! -f "${TMP}" ]; then
error "$HEADER: update error, file not found.." && return
fi
line=$(head -1 "${TMP}")
if [[ "$line" != "#!/usr/bin/env bash" ]]; then
error "$HEADER: update error, invalid header: $line" && return
fi
if cmp --silent -- "${TMP}" "${SCRIPT}"; then
error "$HEADER: update file is already equal? (${local_size} / ${remote_size})" && return
fi
mv -f "${TMP}" "${SCRIPT}"
chmod 755 "${SCRIPT}"
info "$HEADER: succesfully installed update..."
}
function installPackages {
for filename in /usr/local/packages/*.spk; do
if [ -f "$filename" ]; then
BASE=$(basename "$filename" .spk)
BASE="${BASE%%-*}"
[[ $BASE == "ActiveInsight" ]] && continue
info "Installing package ${BASE}.."
/usr/syno/bin/synopkg install "$filename" > /dev/null
/usr/syno/bin/synopkg start "$BASE" > /dev/null &
rm "$filename"
fi
done
}
trap finish SIGINT SIGTERM
ts=$(date +%s%N)
echo ""
echo " Started $HEADER v$VERSION..."
checkNMI
# Install packages
first_run=false
for filename in /usr/local/packages/*.spk; do
if [ -f "$filename" ]; then
first_run=true
fi
done
if [ "$first_run" = true ]; then
installPackages
else
downloadUpdate
fi
# Wait for NMI interrupt as a shutdown signal
while true; do
checkNMI
sleep 2 & wait $!
done
-87
View File
@@ -1,87 +0,0 @@
#!/bin/bash
PIDFILE="/var/run/agent.pid"
SCRIPT="/usr/local/bin/agent.sh"
error () { echo -e "\E[1;31m ERROR: $1\E[0m" ; }
info () { echo -e "\E[1;34m\E[1;36m $1\E[0m" ; }
status() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
echo 'Service running'
return 1
fi
return 0
}
start() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
echo 'Service already running'
return 1
fi
echo 'Starting agent service...'
chmod 666 /dev/ttyS0
if [ ! -f "$SCRIPT" ]; then
URL="https://raw.githubusercontent.com/vdsm/virtual-dsm/master/agent/agent.sh"
if ! curl -sfk -m 10 -o "${SCRIPT}" "${URL}"; then
error 'Failed to download agent script.' > /dev/ttyS0
rm -f "${SCRIPT}"
return 1
else
info 'Agent script was missing?' > /dev/ttyS0
fi
chmod 755 "${SCRIPT}"
fi
echo "-" > /var/lock/subsys/agent.sh
"$SCRIPT" &> /dev/ttyS0 & echo $! > "$PIDFILE"
return 0
}
stop() {
if [ ! -f "$PIDFILE" ] || ! kill -0 "$(cat "$PIDFILE")"; then
echo 'Service not running'
return 1
fi
echo 'Stopping agent service...'
chmod 666 /dev/ttyS0
info 'Stopping agent service...' > /dev/ttyS0
kill -15 "$(cat "$PIDFILE")" && rm -f "$PIDFILE"
rm -f /var/lock/subsys/agent.sh
echo 'Service stopped'
return 0
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
+17
View File
@@ -0,0 +1,17 @@
services:
dsm:
container_name: dsm
image: vdsm/virtual-dsm
environment:
DISK_SIZE: "256G"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- ./dsm:/storage
restart: always
stop_grace_period: 2m
-23
View File
@@ -1,23 +0,0 @@
version: "3"
services:
dsm:
container_name: dsm
image: vdsm/virtual-dsm:latest
environment:
DISK_SIZE: "16G"
RAM_SIZE: "1G"
CPU_CORES: "1"
devices:
- /dev/kvm
- /dev/net/tun
- /dev/vhost-net
device_cgroup_rules:
- 'c *:* rwm'
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- /opt/dsm:/storage
restart: on-failure
stop_grace_period: 1m
+100
View File
@@ -0,0 +1,100 @@
# Environment Variables
This page lists all the environment variables that can be used to configure the container.
An empty default means the variable is unset and its value is determined automatically when applicable.
## 💽 Virtual DSM
| Variable | Default | Description |
|---|---|---|
| `URL` | | URL or local path to a custom `.pat` installation file. |
| `COUNTRY` | | Country code used to select the Synology download mirror. |
| `HOST_MAC` | | MAC address reported to DSM. |
| `HOST_MODEL` | | Synology host model reported to DSM. |
| `HOST_SERIAL` | | Synology host serial number reported to DSM. |
| `GUEST_SERIAL` | | Synology guest serial number reported to DSM. |
## 🧠 CPU and Memory
| Variable | Default | Description |
|---|---|---|
| `CPU_CORES` | `2` | Number of virtual CPU cores, such as `4`, `half`, or `max`. |
| `CPU_MODEL` | `host` | QEMU CPU model. |
| `CPU_FLAGS` | | Additional QEMU CPU flags. |
| `HOST_CPU` | | CPU name reported to DSM. Selected automatically when unset. |
| `KVM` | `Y` | Enables KVM hardware acceleration. |
| `RAM_SIZE` | `2G` | Amount of RAM assigned to DSM, such as `2G`, `4G`, `half`, or `max`. |
| `RAM_CHECK` | `Y` | Checks whether enough host memory is available before starting DSM. |
## 💾 Storage
| Variable | Default | Description |
|---|---|---|
| `DISK_SIZE` | `256G` | Size of the main data disk. |
| `DISK_FMT` | `raw` | Disk image format: `raw` or `qcow2`. |
| `DISK_TYPE` | `scsi` | Disk device type, such as `sata`, `scsi`, `nvme`, or `blk`. |
| `DISK_CACHE` | `none` | Disk cache mode, such as `none` or `writeback`. |
| `DISK_IO` | `native` | Disk I/O mode, such as `native`, `threads`, or `io_uring`. |
| `DISK_DISCARD` | `unmap` | Discard/TRIM mode for the primary disk. |
| `DISK_ROTATION` | `1` | Rotation rate reported to the guest. Use `1` to identify the disk as an SSD. |
| `DISK_FLAGS` | | Additional options used when creating `qcow2` disks. |
| `DISK_OPTIONS` | | Additional options appended to QEMU disk devices. |
| `ALLOCATE` | `N` | Preallocates space for the data disks. |
| `STORAGE` | `/storage` | Storage directory used for disks, settings, and downloads. |
## 🌐 Networking
| Variable | Default | Description |
|---|---|---|
| `NETWORK` | | Network mode, such as `nat`, `user`, or `N` to disable networking. |
| `DHCP` | `N` | Enables macvtap networking so DSM receives a DHCP address. |
| `HOST` | | Hostname assigned to the machine on the network. |
| `IP` | | Overrides the automatically selected guest IPv4 address. |
| `MAC` | | Guest network adapter MAC address. |
| `ADAPTER` | `virtio-net-pci` | QEMU network adapter model. |
| `DEV` | `eth0` | Container network interface used as the uplink. |
| `MTU` | | MTU assigned to the guest network interface. |
| `MASK` | `255.255.255.0` | IPv4 netmask for guest network. |
| `TAP` | `dsm` | TAP or macvtap interface name. |
| `BRIDGE` | `docker` | Bridge name used for NAT networking. |
| `HOST_PORTS` | | Ports excluded from guest forwarding. |
| `USER_PORTS` | | Additional ports to forward to DSM when using user-mode networking. |
| `DNSMASQ_OPTS` | | Additional options passed to dnsmasq. |
| `DNSMASQ_DEBUG` | `N` | Enables dnsmasq debug output. |
| `DNSMASQ_DISABLE` | `N` | Disables the internal dnsmasq resolver. |
| `PASST_OPTS` | | Additional options passed to passt. |
| `PASST_DEBUG` | `N` | Enables passt debug output. |
## 🖥️ Display
| Variable | Default | Description |
|---|---|---|
| `DISPLAY` | `none` | Display backend, such as `vnc`, `disabled`, or `none`. |
| `LOSSY` | `N` | Enables lossy VNC compression to reduce bandwidth usage. |
| `VGA` | `none` | QEMU video adapter model. |
| `GPU` | `N` | Enables Intel iGPU acceleration. |
| `RENDERNODE` | `/dev/dri/renderD128` | Render node used for GPU acceleration. |
## ⚙️ System
| Variable | Default | Description |
|---|---|---|
| `MACHINE` | `q35` | QEMU machine type. |
| `ARGUMENTS` | | Additional raw arguments appended to the QEMU command line. |
## 🔌 Shutdown
| Variable | Default | Description |
|---|---|---|
| `SHUTDOWN` | `Y` | Enables graceful shutdown. |
| `TIMEOUT` | `115` | Maximum time, in seconds, to wait before forcing DSM to stop. |
| `API_TIMEOUT` | `90` | Maximum time, in seconds, to wait for the shutdown API call. |
## 🐞 Debugging
| Variable | Default | Description |
|---|---|---|
| `DEBUG` | `N` | Enables verbose debug output. |
| `TRACE` | `N` | Enables shell command tracing. |
| `HOST_DEBUG` | `N` | Enables debug output for the DSM host helper. |
+79
View File
@@ -0,0 +1,79 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dsm-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 256Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dsm
labels:
name: dsm
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: dsm
template:
metadata:
labels:
app: dsm
spec:
containers:
- name: dsm
image: vdsm/virtual-dsm
env:
- name: DISK_SIZE
value: "256G"
ports:
- containerPort: 5000
name: http
protocol: TCP
securityContext:
capabilities:
add:
- NET_ADMIN
privileged: true
volumeMounts:
- mountPath: /storage
name: storage
- mountPath: /dev/kvm
name: dev-kvm
- mountPath: /dev/net/tun
name: dev-tun
terminationGracePeriodSeconds: 120
volumes:
- name: storage
persistentVolumeClaim:
claimName: dsm-pvc
- hostPath:
path: /dev/kvm
name: dev-kvm
- hostPath:
path: /dev/net/tun
type: CharDevice
name: dev-tun
---
apiVersion: v1
kind: Service
metadata:
name: dsm
spec:
internalTrafficPolicy: Cluster
ports:
- name: http
port: 5000
protocol: TCP
targetPort: 5000
selector:
app: dsm
type: ClusterIP
+211 -133
View File
@@ -1,220 +1,298 @@
<h1 align="center">Virtual DSM for Docker<br /> <h1 align="center">Virtual DSM<br />
<div align="center"> <div align="center">
<img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" /> <a href="https://github.com/vdsm/virtual-dsm"><img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" /></a>
</div> </div>
<div align="center"> <div align="center">
[![Build]][build_url] [![Build]][build_url]
[![Version]][tag_url] [![Version]][tag_url]
[![Size]][tag_url] [![Size]][tag_url]
[![Package]][pkg_url]
[![Pulls]][hub_url] [![Pulls]][hub_url]
</div></h1> </div></h1>
Virtual DSM in a docker container. Virtual DSM in a Docker container.
## Features ## Features
- Multiple disks - Runs Virtual DSM inside a Docker container
- KVM acceleration - Automatic download of the installation files
- GPU passthrough - Web-based access to the DSM desktop
- Upgrades supported - Near-native performance with KVM acceleration
- Customizable CPU, memory, and storage allocation
## Usage - Supports multiple disks and physical disk passthrough
- Supports NAT, user-mode, macvlan, and macvtap networking
Via `docker-compose.yml` ## Usage 🐳
##### Docker Compose:
```yaml ```yaml
version: "3"
services: services:
dsm: dsm:
container_name: dsm container_name: dsm
image: vdsm/virtual-dsm:latest image: vdsm/virtual-dsm
environment: environment:
DISK_SIZE: "16G" DISK_SIZE: "256G"
devices: devices:
- /dev/kvm - /dev/kvm
- /dev/net/tun
cap_add: cap_add:
- NET_ADMIN - NET_ADMIN
ports: ports:
- 5000:5000 - 5000:5000
volumes: volumes:
- /opt/dsm:/storage - ./dsm:/storage
restart: on-failure restart: always
stop_grace_period: 1m stop_grace_period: 2m
``` ```
Via `docker run` ##### Docker CLI:
```bash ```bash
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 60 vdsm/virtual-dsm:latest docker run -it --rm --name dsm -e "DISK_SIZE=256G" -p 5000:5000 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/dsm:/storage" --stop-timeout 120 docker.io/vdsm/virtual-dsm
``` ```
## FAQ ##### Kubernetes:
* ### How do I change the size of the virtual disk? ```shell
kubectl apply -f https://raw.githubusercontent.com/vdsm/virtual-dsm/refs/heads/master/kubernetes.yml
```
To expand the default size of 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity: ##### GitHub Codespaces:
```yaml [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/vdsm/virtual-dsm)
environment:
DISK_SIZE: "128G"
```
This can also be used to resize the existing disk to a larger capacity without any data loss.
* ### How do I change the location of the virtual disk? ## Requirements ⚙️
To change the virtual disk's location from the default Docker volume, include the following bind mount in your compose file: - Docker or Podman on a Linux host with KVM support.
- Docker Desktop or Podman (Desktop) on Windows 11 with nested virtualization enabled.
- At least 2 GB of available RAM.
- At least 32 GB of free disk space.
```yaml > [!NOTE]
volumes: > Docker Desktop on Linux, macOS, and Windows 10 does not currently provide KVM access to containers and is therefore not supported.
- /home/user/data:/storage
```
Replace the example path `/home/user/data` with the desired storage folder. ## FAQ 💬
* ### How do I add multiple disks? ### How do I use it?
To create additional disks, modify your compose file like this: Very simple! These are the steps:
```yaml - Start the container and connect to [port 5000](http://127.0.0.1:5000/) using your web browser.
environment:
DISK2_SIZE: "32G"
DISK3_SIZE: "64G"
volumes:
- /home/example:/storage2
- /mnt/data/example:/storage3
```
* ### How do I create a growable disk? - Wait until DSM finishes its installation
- Choose a username and password, and you will be taken to the desktop.
Enjoy your brand new NAS, and don't forget to star this repo!
By default, the entire capacity of the disk is reserved in advance. To create a growable disk that only allocates space that is actually used, add the following environment variable: ### How do I change the storage location?
```yaml To change the storage location, include the following bind mount in your compose file:
environment:
DISK_FMT: "qcow2"
```
This can also be used to convert any existing disks to the ```qcow2``` format. ```yaml
volumes:
- ./dsm:/storage
```
* ### How do I increase the amount of CPU or RAM? Replace the example path `./dsm` with the desired storage folder or named volume.
### How do I change the size of the disk?
By default, a single core and 1 GB of RAM are allocated to the container. To increase this, add the following environment variables: To expand the default size of 256 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
```yaml ```yaml
environment: environment:
RAM_SIZE: "4G" DISK_SIZE: "512G"
CPU_CORES: "4" ```
```
> [!TIP]
> This can also be used to resize an existing disk to a larger capacity without any data loss.
* ### How do I verify if my system supports KVM? ### How do I add multiple disks?
To verify if your system supports KVM, run the following commands: To create additional disks, modify your compose file like this:
```yaml
environment:
DISK2_SIZE: "500G"
DISK3_SIZE: "750G"
volumes:
- ./example2:/storage2
- ./example3:/storage3
```
```bash ### How do I pass through a disk?
sudo apt install cpu-checker
sudo kvm-ok
```
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check your BIOS settings. You can pass through disk devices or partitions directly by adding them to your compose file in this way:
* ### How do I assign an individual IP address to the container? ```yaml
devices:
- /dev/sdb:/disk1
- /dev/sdc1:/disk2
```
By default, the container uses bridge networking, which shares the IP address with the host. Make sure it is totally empty (without any filesystem), otherwise DSM may not format it as a volume.
If you want to assign an individual IP address to the container, you can create a macvlan network as follows: ### How do I change the amount of CPU or RAM?
```bash By default, Virtual DSM will be allowed to use 2 CPU cores and 2 GB of RAM.
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
Once you have created the network, change your compose file to look as follows: If you want to adjust this, you can specify the desired amount using the following environment variables:
```yaml ```yaml
services: environment:
dsm: RAM_SIZE: "4G"
container_name: dsm CPU_CORES: "4"
..<snip>.. ```
networks:
vdsm:
ipv4_address: 192.168.0.100
networks: ### How do I assign an individual IP address to the container?
vdsm:
external: true
```
An added benefit of this approach is that you won't have to perform any port mapping anymore since all ports will be exposed by default.
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround. By default, the container uses bridge networking, which shares the IP address with the host.
* ### How can the container acquire an IP address from my router? If you want to assign an individual IP address to the container, you can create a macvlan network as follows:
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices. ```bash
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
To enable this feature, add the following lines to your compose file: Once you have created the network, change your compose file to look as follows:
```yaml ```yaml
environment: services:
DHCP: "Y" dsm:
devices: container_name: dsm
- /dev/vhost-net ..<snip>..
device_cgroup_rules: networks:
- 'c *:* rwm' vdsm:
``` ipv4_address: 192.168.0.100
Please note that even if you don't need DHCP, it's still recommended to enable this feature as it prevents NAT issues and increases performance by using a `macvtap` interface. networks:
vdsm:
external: true
```
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
* ### How do I passthrough the GPU? > [!IMPORTANT]
> This IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
To passthrough your Intel GPU, add the following lines to your compose file: ### How can DSM acquire an IP address from my router?
```yaml After configuring the container for [macvlan](#how-do-i-assign-an-individual-ip-address-to-the-container), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
environment:
GPU: "Y"
devices:
- /dev/dri
```
This can be used to enable the facial recognition function in Synology Photos for example. To enable this mode, in which the container and DSM will have separate IP addresses, add the following lines to your compose file:
* ### How do I install a specific version of vDSM? ```yaml
environment:
DHCP: "Y"
devices:
- /dev/vhost-net
device_cgroup_rules:
- 'c *:* rwm'
```
By default, version 7.2.1 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows: ### How do I pass through the GPU?
```yaml To pass through your Intel GPU, add the following lines to your compose file:
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
With this method, it is even possible to switch between different versions while keeping all your file data intact. ```yaml
environment:
GPU: "Y"
devices:
- /dev/dri
```
* ### What are the differences compared to the standard DSM? > [!NOTE]
> This can be used to enable the facial recognition function in Synology Photos, but does not provide hardware transcoding for video.
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses. ### How do I install a specific version of vDSM?
* ### Is this project legal?
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project would be considered legal. By default, version 7.2 will be installed, but if you prefer an older version, you can add the download URL of the `.pat` file to your compose file as follows:
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this project on an official Synology NAS, as any other use will be a violation of their terms and conditions.
## Disclaimer ```yaml
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc. With this method, it is even possible to switch back and forth between versions while keeping your file data intact.
Alternatively, you can also skip the download and use a local file instead, by binding it in your compose file in this way:
```yaml
volumes:
- ./DSM_VirtualDSM_42218.pat:/boot.pat
```
Replace the example path `./DSM_VirtualDSM_42218.pat` with the filename of your desired `.pat` file. The value of `URL` will be ignored in this case.
### Are these all available options?
No. For a complete overview of all supported settings, see the [environment variables](docs/environment.md) page.
### How do I verify that KVM is available?
First, make sure your platform and container runtime meet the [requirements](#requirements-) listed above.
On a Linux host, install `cpu-checker` and run:
```bash
sudo apt install cpu-checker
sudo kvm-ok
```
A working configuration should report:
```text
KVM acceleration can be used
```
You can also verify that the KVM device exists:
```bash
ls -l /dev/kvm
```
If KVM is unavailable, check whether:
- Hardware virtualization (`Intel VT-x` or `AMD-V`) is enabled in your BIOS or UEFI.
- Nested virtualization is enabled when the host itself is a virtual machine.
- Your VPS or cloud provider supports nested virtualization.
If `kvm-ok` succeeds but the container still reports that KVM is unavailable, you can temporarily add `privileged: true` to your Compose file to rule out a permission or device-access issue.
### What are the differences compared to the standard DSM?
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
### Is this project legal?
Yes, this project contains only open-source code and does not distribute any material owned by Synology. Neither does it try to circumvent any copyright protection measures.
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this container on an official Synology NAS, as any other use will be a violation of their terms and conditions.
## Stars 🌟
[![Stargazers](https://raw.githubusercontent.com/star-stats/stars/refs/heads/data/charts/vdsm-virtual-dsm.svg)](https://github.com/vdsm/virtual-dsm/stargazers)
## Disclaimer ⚖️
*Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc.*
[build_url]: https://github.com/vdsm/virtual-dsm/ [build_url]: https://github.com/vdsm/virtual-dsm/
[hub_url]: https://hub.docker.com/r/vdsm/virtual-dsm [hub_url]: https://hub.docker.com/r/vdsm/virtual-dsm
[tag_url]: https://hub.docker.com/r/vdsm/virtual-dsm/tags [tag_url]: https://hub.docker.com/r/vdsm/virtual-dsm/tags
[pkg_url]: https://github.com/vdsm/virtual-dsm/pkgs/container/virtual-dsm
[Build]: https://github.com/vdsm/virtual-dsm/actions/workflows/build.yml/badge.svg [Build]: https://github.com/vdsm/virtual-dsm/actions/workflows/build.yml/badge.svg
[Size]: https://img.shields.io/docker/image-size/vdsm/virtual-dsm/latest?color=066da5&label=size [Size]: https://img.shields.io/docker/image-size/vdsm/virtual-dsm/latest?color=066da5&label=size
[Pulls]: https://img.shields.io/docker/pulls/kroese/virtual-dsm.svg?style=flat&label=pulls&logo=docker [Pulls]: https://img.shields.io/docker/pulls/vdsm/virtual-dsm.svg?style=flat&label=pulls&logo=docker
[Version]: https://img.shields.io/docker/v/vdsm/virtual-dsm/latest?arch=amd64&sort=semver&color=066da5 [Version]: https://img.shields.io/docker/v/vdsm/virtual-dsm/latest?arch=amd64&sort=semver&color=066da5
[Package]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fipitio.github.io%2Fbackage%2Fvdsm%2Fvirtual-dsm%2Fvirtual-dsm.json&query=%24.downloads&logo=github&style=flat&color=066da5&label=pulls
+24 -33
View File
@@ -1,46 +1,37 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
[ ! -f "/run/qemu.pid" ] && echo "QEMU not running yet.." && exit 0 cd /run
[ -f "/run/qemu.count" ] && echo "QEMU is shutting down.." && exit 1 . utils.sh # Load functions
file="/run/dsm.url" : "${DHCP:="N"}"
: "${NETWORK:="Y"}"
if [ ! -f "$file" ]; then [ -f "/run/shm/qemu.end" ] && echo "QEMU is shutting down..." && exit 1
[ ! -s "/run/shm/qemu.pid" ] && echo "QEMU is not running yet..." && exit 0
disabled "$NETWORK" && echo "Networking is disabled." && exit 0
# Retrieve IP from guest VM for Docker healthcheck file="/run/shm/dsm.url"
address="/run/shm/qemu.ip"
gateway="/run/shm/qemu.gw"
{ json=$(curl -m 30 -sk http://127.0.0.1:2210/read?command=10); rc=$?; } || : [ ! -s "$file" ] && echo "DSM has not enabled networking yet..." && exit 0
(( rc != 0 )) && echo "Failed to connect to guest: curl error $rc" && exit 1
{ result=$(echo "$json" | jq -r '.status'); rc=$?; } || : location=$(<"$file")
(( rc != 0 )) && echo "Failed to parse response from guest: jq error $rc ( $json )" && exit 1
[[ "$result" == "null" ]] && echo "Guest returned invalid response: $json" && exit 1
if [[ "$result" != "success" ]] ; then
{ msg=$(echo "$json" | jq -r '.message'); rc=$?; } || :
echo "Guest replied $result: $msg" && exit 1
fi
{ port=$(echo "$json" | jq -r '.data.data.dsm_setting.data.http_port'); rc=$?; } || :
(( rc != 0 )) && echo "Failed to parse response from guest: jq error $rc ( $json )" && exit 1
[[ "$port" == "null" ]] && echo "Guest has not set a portnumber yet.." && exit 1
[ -z "$port" ] && echo "Guest has not set a portnumber yet.." && exit 1
{ ip=$(echo "$json" | jq -r '.data.data.ip.data[] | select((.name=="eth0") and has("ip")).ip'); rc=$?; } || :
(( rc != 0 )) && echo "Failed to parse response from guest: jq error $rc ( $json )" && exit 1
[[ "$ip" == "null" ]] && echo "Guest returned invalid response: $json" && exit 1
[ -z "$ip" ] && echo "Guest has not received an IP yet.." && exit 1
echo "$ip:$port" > $file
fi
location=$(cat "$file")
if ! curl -m 20 -ILfSs "http://$location/" > /dev/null; then if ! curl -m 20 -ILfSs "http://$location/" > /dev/null; then
echo "Failed to reach http://$location"
exit 1 if enabled "$DHCP"; then
ip=$(<"$address")
echo "Failed to reach DSM at http://$location"
else
ip=$(<"$gateway")
port="${location##*:}"
echo "Failed to reach DSM at port $port"
fi
echo "You might need to whitelist IP $ip in the DSM firewall." && exit 1
fi fi
echo "Healthcheck OK" echo "Healthcheck OK"
+54 -31
View File
@@ -1,40 +1,63 @@
#!/bin/bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
KVM_ERR="" DEF_OPTS="-nodefaults -boot strict=on"
KVM_OPTS="" DEV_OPTS=""
if [ -e /dev/kvm ] && sh -c 'echo -n > /dev/kvm' &> /dev/null; then configureProcessor() {
if ! grep -q -e vmx -e svm /proc/cpuinfo; then
KVM_ERR="(vmx/svm disabled)"
fi
else
[ -e /dev/kvm ] && KVM_ERR="(no write access)" || KVM_ERR="(device file missing)"
fi
if [ -n "$KVM_ERR" ]; then CPU_OPTS="-cpu $CPU_FLAGS"
if [ "$ARCH" == "amd64" ]; then CPU_OPTS+=" -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
error "KVM acceleration not detected $KVM_ERR, see the FAQ about this."
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
else
KVM_OPTS=",accel=kvm -enable-kvm -cpu host"
fi
DEF_OPTS="-nographic -nodefaults -boot strict=on -display none" return 0
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g') }
CPU_OPTS="-smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
MAC_OPTS="-machine type=q35,usb=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
EXTRA_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
EXTRA_OPTS="$EXTRA_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
EXTRA_OPTS="$EXTRA_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
if [[ "$GPU" == [Yy1]* ]] && [[ "$ARCH" == "amd64" ]]; then configureMemory() {
DEF_OPTS="-nodefaults -boot strict=on -display egl-headless,rendernode=/dev/dri/renderD128"
DEF_OPTS="$DEF_OPTS -device virtio-vga,id=video0,max_outputs=1,bus=pcie.0,addr=0x1"
fi
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $EXTRA_OPTS $ARGUMENTS" RAM_OPTS=$(echo "-m ${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
return 0
}
configureMonitor() {
MON_OPTS="-name $PROCESS,process=$PROCESS,debug-threads=on"
MON_OPTS+=" -pidfile $QEMU_PID"
return 0
}
configureMachine() {
MAC_OPTS="-machine type=$MACHINE,smm=off,usb=off"
MAC_OPTS+=",vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
return 0
}
configureVirtioDevices() {
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
DEV_OPTS+=" -object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
return 0
}
buildArguments() {
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $DEV_OPTS $ARGUMENTS"
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
return 0
}
configureMemory
configureMonitor
configureMachine
configureProcessor
configureVirtioDevices
buildArguments
return 0 return 0
+749 -262
View File
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Docker environment variables
: "${GPU:="N"}" # GPU passthrough
: "${VGA:="virtio"}" # VGA adaptor
: "${DISPLAY:="none"}" # Display type
: "${LOSSY:="N"}" # Lossy VNC compression
: "${RENDERNODE:="/dev/dri/renderD128"}" # Render node
# Sanitize variables
VGA=$(strip "$VGA")
LOSSY=$(strip "$LOSSY")
DISPLAY=$(strip "$DISPLAY")
RENDERNODE=$(strip "$RENDERNODE")
CPU_VENDOR=$(lscpu | awk '/Vendor ID/{print $3}')
if ! enabled "$GPU" || isAmdCpu || [[ "$ARCH" != "amd64" ]]; then
[[ "${DISPLAY,,}" == "none" ]] && VGA="none"
if enabled "$LOSSY" && [[ "${DISPLAY,,}" == vnc=* ]]; then
DISPLAY+=",lossy=on"
fi
DISPLAY_OPTS="-display ${DISPLAY} -vga ${VGA}"
return 0
fi
msg="Configuring display drivers..."
html "$msg"
enabled "$DEBUG" && echo "$msg"
DISPLAY_OPTS="-display egl-headless,rendernode=${RENDERNODE}"
DISPLAY_OPTS+=" -vga $VGA"
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
# Extract the card number from the render node
CARD_NUMBER=$(echo "$RENDERNODE" | grep -oP '(?<=renderD)\d+')
CARD_DEVICE="/dev/dri/card$((CARD_NUMBER - 128))"
if [ ! -c "$CARD_DEVICE" ]; then
if mknod "$CARD_DEVICE" c 226 $((CARD_NUMBER - 128)); then
chmod 666 "$CARD_DEVICE"
fi
fi
if [ ! -c "$RENDERNODE" ]; then
if mknod "$RENDERNODE" c 226 "$CARD_NUMBER"; then
chmod 666 "$RENDERNODE"
fi
fi
if [ ! -c "$RENDERNODE" ] || [ ! -r "$RENDERNODE" ] || [ ! -w "$RENDERNODE" ]; then
warn "render device '${RENDERNODE}' is unavailable or inaccessible."
fi
addPackage "xserver-xorg-video-intel" "Intel GPU drivers"
addPackage "qemu-system-modules-opengl" "OpenGL module"
return 0
+30 -14
View File
@@ -1,33 +1,49 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
echo " Starting Virtual DSM for Docker v$(</run/version)..." : "${PLATFORM:="x64"}"
echo " For support visit https://github.com/vdsm/virtual-dsm/" : "${APP:="Virtual DSM"}"
: "${SUPPORT:="https://github.com/vdsm/virtual-dsm"}"
cd /run cd /run
. start.sh # Startup hook
. utils.sh # Load functions
. reset.sh # Initialize system . reset.sh # Initialize system
. server.sh # Start webserver
. install.sh # Run installation . install.sh # Run installation
. disk.sh # Initialize disks . disk.sh # Initialize disks
. display.sh # Initialize graphics
. network.sh # Initialize network . network.sh # Initialize network
. gpu.sh # Initialize graphics . proc.sh # Initialize processor
. serial.sh # Initialize serialport . serial.sh # Initialize serialport
. power.sh # Configure shutdown . power.sh # Configure shutdown
. memory.sh # Check available memory
. config.sh # Configure arguments . config.sh # Configure arguments
. finish.sh # Finish initialization
trap - ERR trap - ERR
if [[ "$CONSOLE" == [Yy]* ]]; then cmd=(qemu-system-x86_64)
exec qemu-system-x86_64 -pidfile "$QEMU_PID" ${ARGS:+ $ARGS} version=$("${cmd[@]}" --version | awk 'NR==1 { print $4 }')
exit $? info "Booting $APP using QEMU v$version..." && echo
if ! enabled "$SHUTDOWN"; then
exec "${cmd[@]}" ${ARGS:+ $ARGS}
fi fi
set -m if ! interactive; then
( "${cmd[@]}" ${ARGS:+ $ARGS} &
[[ "$DEBUG" == [Yy1]* ]] && info "$VERS" && set -x else
qemu-system-x86_64 ${ARGS:+ $ARGS} & echo $! > "$QEMU_PID" startConsole
{ set +x; } 2>/dev/null startQemu "${cmd[@]}" ${ARGS:+ $ARGS}
) fi
set +m
tail --pid "$(cat "$QEMU_PID")" --follow /dev/null & wait $! pid=$!
rc=0
wait "$pid" || rc=$?
[ -f "$QEMU_END" ] && exit "$rc"
sleep 1 & wait $!
finish "$rc"
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -Eeuo pipefail
if enabled "$DEBUG"; then
printf "QEMU arguments:\n\n %s\n\n" "${ARGS// -/$'\n -'}"
fi
return 0
-24
View File
@@ -1,24 +0,0 @@
#!/bin/bash
set -Eeuo pipefail
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
return 0
fi
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
if [ ! -c /dev/dri/card0 ]; then
mknod /dev/dri/card0 c 226 0
fi
if [ ! -c /dev/dri/renderD128 ]; then
mknod /dev/dri/renderD128 c 226 128
fi
chmod 666 /dev/dri/card0
chmod 666 /dev/dri/renderD128
addPackage "xserver-xorg-video-intel" "Intel GPU drivers"
addPackage "qemu-system-modules-opengl" "OpenGL module"
return 0
+239 -208
View File
@@ -1,24 +1,52 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
: ${URL:=''} # URL of the PAT file to be downloaded. : "${URL:=""}" # URL of the PAT file to be downloaded.
: ${DEV:='Y'} # Controls whether device nodes are created.
if [ -f "$STORAGE"/dsm.ver ]; then if [ -f "$STORAGE/dsm.ver" ]; then
BASE=$(cat "$STORAGE/dsm.ver") BASE=$(<"$STORAGE/dsm.ver")
BASE="${BASE//[![:print:]]/}"
[ -z "$BASE" ] && BASE="DSM_VirtualDSM_69057"
else else
# Fallback for old installs # Fallback for old installs
BASE="DSM_VirtualDSM_42962" BASE="DSM_VirtualDSM_42962"
fi fi
[ -n "$URL" ] && BASE=$(basename "$URL" .pat) FN="boot.pat"
DIR=$(find / -maxdepth 1 -type d -iname "$FN" -print -quit)
[ ! -d "$DIR" ] && DIR=$(find "$STORAGE" -maxdepth 1 -type d -iname "$FN" -print -quit)
if [[ -f "$STORAGE/$BASE.boot.img" ]] && [[ -f "$STORAGE/$BASE.system.img" ]]; then if [ -d "$DIR" ]; then
BASE="DSM_VirtualDSM" && URL="file://$DIR"
if [[ ! -s "$STORAGE/$BASE.boot.img" || ! -s "$STORAGE/$BASE.system.img" ]]; then
error "The bind $DIR maps to a file that does not exist!" && exit 65
fi
fi
FILE=$(find / -maxdepth 1 -type f -iname "$FN" -print -quit)
[ ! -s "$FILE" ] && FILE=$(find "$STORAGE" -maxdepth 1 -type f -iname "$FN" -print -quit)
[ -s "$FILE" ] && BASE="DSM_VirtualDSM" && URL="file://$FILE"
URL=$(strip "$URL")
if [ -n "$URL" ] && [ ! -s "$FILE" ] && [ ! -d "$DIR" ]; then
BASE=$(basename "$URL" .pat)
if [ ! -s "$STORAGE/$BASE.system.img" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
if [[ "${URL,,}" != "http"* && "${URL,,}" != "file:"* ]]; then
[ ! -s "$STORAGE/$BASE.pat" ] && error "Invalid URL: $URL" && exit 65
URL="file://$STORAGE/$BASE.pat"
fi
fi
if [[ -s "$STORAGE/$BASE.boot.img" && -s "$STORAGE/$BASE.system.img" ]]; then
return 0 # Previous installation found return 0 # Previous installation found
fi fi
# Display wait message html "Please wait while Virtual DSM is being installed..."
/run/server.sh 5000 install &
DL="" DL=""
DL_CHINA="https://cndl.synology.cn/download/DSM" DL_CHINA="https://cndl.synology.cn/download/DSM"
@@ -29,166 +57,152 @@ DL_GLOBAL="https://global.synologydownload.com/download/DSM"
if [ -z "$DL" ]; then if [ -z "$DL" ]; then
[ -z "$COUNTRY" ] && setCountry [ -z "$COUNTRY" ] && setCountry
[ -z "$COUNTRY" ] && info "Warning: could not detect country to select mirror!"
[[ "${COUNTRY^^}" == "CN" ]] && DL="$DL_CHINA" || DL="$DL_GLOBAL" [[ "${COUNTRY^^}" == "CN" ]] && DL="$DL_CHINA" || DL="$DL_GLOBAL"
fi fi
if [ -z "$URL" ]; then if [ -z "$URL" ]; then
if [ "$ARCH" == "amd64" ]; then URL="$DL/release/7.2.2/72806/DSM_VirtualDSM_72806.pat"
URL="$DL/release/7.2.1/69057-1/DSM_VirtualDSM_69057.pat"
else
URL="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
fi
fi fi
BASE=$(basename "$URL" .pat) if [ ! -s "$FILE" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
printf -v BASE '%b' "${BASE//%/\\x}"
BASE="${BASE//[!A-Za-z0-9._-]/_}"
fi
if [[ "$URL" != "file://$STORAGE/$BASE.pat" ]]; then if [[ "$URL" != "file://$STORAGE/$BASE.pat" ]]; then
rm -f "$STORAGE"/"$BASE".pat rm -f "$STORAGE/$BASE.pat"
fi fi
rm -f "$STORAGE"/"$BASE".agent rm -f "$STORAGE/$BASE.agent"
rm -f "$STORAGE"/"$BASE".boot.img rm -f "$STORAGE/$BASE.boot.img"
rm -f "$STORAGE"/"$BASE".system.img rm -f "$STORAGE/$BASE.system.img"
[[ "$DEBUG" == [Yy1]* ]] && set -x
# Check filesystem # Check filesystem
MIN_ROOT=471859200
MIN_SPACE=6442450944
FS=$(stat -f -c %T "$STORAGE") FS=$(stat -f -c %T "$STORAGE")
if [[ "$FS" == "overlay"* ]]; then if [[ "${FS,,}" == "overlay"* && "${ENGINE,,}" == "docker" ]]; then
info "Warning: the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!" warn "the filesystem of $STORAGE is OverlayFS, this usually means it was binded to an invalid path!"
fi fi
if [[ "$FS" != "fat"* && "$FS" != "vfat"* && "$FS" != "exfat"* && \ if [[ "${FS,,}" == "fuse"* ]]; then
"$FS" != "ntfs"* && "$FS" != "fuse"* && "$FS" != "msdos"* ]]; then warn "the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
fi
if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
warn "the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if [[ "${FS,,}" == "fat"* || "${FS,,}" == "vfat"* || "${FS,,}" == "msdos"* ]]; then
error "Unable to install on $FS filesystems, please use a different filesystem for /storage." && exit 61
fi
if [[ "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "unknown"* ]]; then
TMP="$STORAGE/tmp" TMP="$STORAGE/tmp"
rm -rf "$TMP"
if ! makeDir "$TMP"; then
error "Failed to create directory \"$TMP\" !" && exit 93
fi
else else
TMP="/tmp/dsm" TMP="/tmp/dsm"
TMP_SPACE=2147483648
SPACE=$(df --output=avail -B 1 /tmp | tail -n 1) SPACE=$(df --output=avail -B 1 /tmp | tail -n 1)
if (( MIN_SPACE > SPACE )); then SPACE_MB=$(formatBytes "$SPACE")
TMP="$STORAGE/tmp" if (( TMP_SPACE > SPACE )); then
info "Warning: the $FS filesystem of $STORAGE does not support UNIX permissions.." error "Not enough free space inside the container, have $SPACE_MB available but need at least 2 GB." && exit 93
fi fi
rm -rf "$TMP" && mkdir -p "$TMP"
fi fi
rm -rf "$TMP" && mkdir -p "$TMP"
# Check free diskspace # Check free diskspace
ROOT_SPACE=536870912
SPACE=$(df --output=avail -B 1 / | tail -n 1) SPACE=$(df --output=avail -B 1 / | tail -n 1)
(( MIN_ROOT > SPACE )) && error "Not enough free space in container root, need at least 450 MB available." && exit 96 SPACE_MB=$(formatBytes "$SPACE" "down")
(( ROOT_SPACE > SPACE )) && error "Not enough free space inside the container, have $SPACE_MB available but need at least 500 MB." && exit 96
SPACE=$(df --output=avail -B 1 "$TMP" | tail -n 1) MIN_SPACE=15032385536
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 )) SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB GB available but need at least 6 GB." && exit 95 SPACE_GB=$(formatBytes "$SPACE")
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB available but need at least 14 GB." && exit 94
if [[ "$TMP" != "$STORAGE/tmp" ]]; then if [[ "$URL" == "file://"* ]]; then
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1) MSG="Copying DSM"
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 )) ERR="Failed to copy ${URL:7}"
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB GB available but need at least 6 GB." && exit 94 info "Install: Copying installation image..."
fi
# Check if output is to interactive TTY
if [ -t 1 ]; then
PROGRESS="--progress=bar:noscroll"
else else
PROGRESS="--progress=dot:giga" MSG="Downloading DSM"
ERR="Failed to download $URL"
info "Install: Downloading $BASE.pat..."
fi fi
# Download the required files from the Synology website html "$MSG..."
RDC="$STORAGE/dsm.rd"
if [ ! -f "$RDC" ]; then
info "Install: Downloading installer..."
RD="$TMP/rd.gz"
POS="65627648-71021835"
VERIFY="b4215a4b213ff5154db0488f92c87864"
LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
{ curl -r "$POS" -sfk -S -o "$RD" "$LOC"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
if [ "$SUM" != "$VERIFY" ]; then
PAT="/install.pat"
rm "$RD"
rm -f "$PAT"
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
rm "$PAT"
fi
cp "$RD" "$RDC"
fi
if [ -f "$RDC" ]; then
{ xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || :
(( rc != 1 )) && error "Failed to unxz $RDC, reason $rc" && exit 91
if [[ "$DEV" == [Nn]* ]]; then
# Exclude dev/ from cpio extract
{ (cd "$TMP" && cpio -it < "$TMP/rd" | grep -Ev 'dev/' | while read -r entry; do cpio -idm "$entry" < "$TMP/rd" 2>/dev/null; done); rc=$?; } || :
else
{ (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || :
fi
(( rc != 0 )) && error "Failed to extract $RDC, reason $rc" && exit 92
mkdir -p /run/extract
for file in $TMP/usr/lib/libcurl.so.4 \
$TMP/usr/lib/libmbedcrypto.so.5 \
$TMP/usr/lib/libmbedtls.so.13 \
$TMP/usr/lib/libmbedx509.so.1 \
$TMP/usr/lib/libmsgpackc.so.2 \
$TMP/usr/lib/libsodium.so \
$TMP/usr/lib/libsynocodesign-ng-virtual-junior-wins.so.7 \
$TMP/usr/syno/bin/scemd; do
cp "$file" /run/extract/
done
if [ "$ARCH" != "amd64" ]; then
mkdir -p /lib64/
cp "$TMP/usr/lib/libc.so.6" /lib64/
cp "$TMP/usr/lib/libpthread.so.0" /lib64/
cp "$TMP/usr/lib/ld-linux-x86-64.so.2" /lib64/
fi
mv /run/extract/scemd /run/extract/syno_extract_system_patch
chmod +x /run/extract/syno_extract_system_patch
fi
rm -rf "$TMP" && mkdir -p "$TMP"
info "Install: Downloading $(basename "$URL")..."
PAT="/$BASE.pat" PAT="/$BASE.pat"
rm -f "$PAT" rm -f "$PAT"
if [[ "$URL" == "file://"* ]]; then if [[ "$URL" == "file://"* ]]; then
if [ ! -f "${URL:7}" ]; then
error "File '${URL:7}' does not exist!" && exit 65
fi
cp "${URL:7}" "$PAT" cp "${URL:7}" "$PAT"
else else
{ wget "$URL" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || : SIZE=0
(( rc != 0 )) && error "Failed to download $URL, reason: $rc" && exit 69 REASON=""
PROGRESS=()
OUTPUT=""
LOG=$(mktemp)
[[ "${URL,,}" == *"_72806.pat" ]] && SIZE=361010261
[[ "${URL,,}" == *"_69057.pat" ]] && SIZE=363837333
[[ "${URL,,}" == *"_42218.pat" ]] && SIZE=379637760
# Use Wget's progress bar in a terminal and progress.sh in container logs.
if [ -t 1 ]; then
PROGRESS=( --show-progress --progress=bar:noscroll )
else
OUTPUT="log"
fi
/run/progress.sh "$PAT" "$SIZE" "$MSG ([P])..." "$OUTPUT" 52428800 &
{
LC_ALL=C wget "$URL" -O "$PAT" --no-verbose --no-check-certificate \
--timeout=30 --no-http-keep-alive "${PROGRESS[@]}" \
--output-file="$LOG"
rc=$?
} || :
fKill "progress.sh"
if (( rc != 0 )); then
REASON=$(sed -n \
-e 's/^wget: //p' \
-e 's/^[0-9-]\{10\} [0-9:]\{8\} ERROR //p' \
"$LOG" | tail -n 1)
fi
rm -f "$LOG"
if (( rc == 3 )); then
error "$ERR because the file could not be written (disk full?)."
exit 69
elif (( rc != 0 )); then
if [ -n "$REASON" ]; then
error "$ERR: ${REASON%.}."
else
error "$ERR with exit status $rc."
fi
exit 69
fi
fi fi
[ ! -f "$PAT" ] && error "Failed to download $URL" && exit 69 [ ! -s "$PAT" ] && error "$ERR" && exit 69
SIZE=$(stat -c%s "$PAT") SIZE=$(stat -c%s "$PAT")
@@ -196,123 +210,140 @@ if ((SIZE<250000000)); then
error "The specified PAT file is probably an update pack as it's too small." && exit 62 error "The specified PAT file is probably an update pack as it's too small." && exit 62
fi fi
MSG="Extracting installation image..."
info "Install: $MSG" && html "$MSG"
if { tar tf "$PAT"; } >/dev/null 2>&1; then if { tar tf "$PAT"; } >/dev/null 2>&1; then
info "Install: Extracting downloaded image..."
tar xpf "$PAT" -C "$TMP/." tar xpf "$PAT" -C "$TMP/."
else else
[ "$ARCH" != "amd64" ] && addPackage "qemu-user" "QEMU" { (cd "$TMP" && python3 /run/extract.py -i "$PAT" -d 2>/run/extract.log); rc=$?; } || :
info "Install: Extracting downloaded image..." if (( rc != 0 )); then
cat /run/extract.log
export LD_LIBRARY_PATH="/run/extract" error "Failed to extract PAT file, reason $rc" && exit 63
if [ "$ARCH" == "amd64" ]; then
{ /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || :
else
{ qemu-x86_64 /run/extract/syno_extract_system_patch "$PAT" "$TMP/."; rc=$?; } || :
fi fi
export LD_LIBRARY_PATH=""
(( rc != 0 )) && error "Failed to extract PAT file, reason $rc" && exit 63
fi fi
MSG="Preparing system partition..."
info "Install: $MSG" && html "$MSG"
BOOT=$(find "$TMP" -name "*.bin.zip" -print -quit)
[ -z "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
[ ! -s "$BOOT" ] && error "The PAT boot image archive is empty." && exit 67
unzip -q -o "$BOOT" -d "$TMP"
BOOT="${BOOT%.zip}"
SYSTEM="$STORAGE/$BASE.system.img"
rm -f "$SYSTEM"
# Check free diskspace
SYSTEM_SIZE=10738466816
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_MB=$(formatBytes "$SPACE")
if (( SYSTEM_SIZE > SPACE )); then
error "Not enough free space in $STORAGE to create a 10 GB system disk, have only $SPACE_MB available." && exit 97
fi
if ! touch "$SYSTEM"; then
error "Could not create file $SYSTEM for the system disk." && exit 98
fi
setOwner "$SYSTEM" || warn "failed to set the owner for \"$SYSTEM\" !"
if [[ "${FS,,}" == "btrfs" ]]; then
{ chattr +C "$SYSTEM"; } || :
FA=$(lsattr "$SYSTEM")
if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem."
fi
fi
if ! fallocate -l "$SYSTEM_SIZE" "$SYSTEM" &>/dev/null; then
if ! fallocate -l -x "$SYSTEM_SIZE" "$SYSTEM"; then
if ! truncate -s "$SYSTEM_SIZE" "$SYSTEM"; then
rm -f "$SYSTEM"
error "Could not allocate file $SYSTEM for the system disk." && exit 98
fi
fi
fi
PART="$TMP/partition.fdisk"
{
echo "label: dos"
echo "label-id: 0x6f9ee2e9"
echo "device: $SYSTEM"
echo "unit: sectors"
echo "sector-size: 512"
echo ""
echo "${SYSTEM}1 : start= 2048, size= 16777216, type=83"
echo "${SYSTEM}2 : start= 16779264, size= 4194304, type=82"
} > "$PART"
sfdisk -q "$SYSTEM" < "$PART"
MOUNT="$TMP/system"
rm -rf "$MOUNT"
if ! makeDir "$MOUNT"; then
error "Failed to create directory \"$MOUNT\" !" && exit 93
fi
MSG="Extracting system partition..."
info "Install: $MSG" && html "$MSG"
HDA="$TMP/hda1" HDA="$TMP/hda1"
IDB="$TMP/indexdb" IDB="$TMP/indexdb"
PKG="$TMP/packages" PKG="$TMP/packages"
HDP="$TMP/synohdpack_img" HDP="$TMP/synohdpack_img"
[ ! -f "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64 [ ! -s "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
BOOT=$(find "$TMP" -name "*.bin.zip")
[ ! -f "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
BOOT=$(echo "$BOOT" | head -c -5)
unzip -q -o "$BOOT".zip -d "$TMP"
SYSTEM="$TMP/sys.img"
SYSTEM_SIZE=4954537983
# Check free diskspace
SPACE=$(df --output=avail -B 1 "$TMP" | tail -n 1)
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
(( SYSTEM_SIZE > SPACE )) && error "Not enough free space to create a 4 GB system disk, have only $SPACE_GB GB available." && exit 87
if ! fallocate -l "$SYSTEM_SIZE" "$SYSTEM"; then
if ! truncate -s "$SYSTEM_SIZE" "$SYSTEM"; then
rm -f "$SYSTEM" && error "Could not allocate a file for the system disk." && exit 88
fi
fi
# Check if file exists
[ ! -f "$SYSTEM" ] && error "System disk does not exist ($SYSTEM)" && exit 89
# Check the filesize
SIZE=$(stat -c%s "$SYSTEM")
[[ SIZE -ne SYSTEM_SIZE ]] && rm -f "$SYSTEM" && error "System disk has the wrong size: $SIZE" && exit 90
PART="$TMP/partition.fdisk"
{ echo "label: dos"
echo "label-id: 0x6f9ee2e9"
echo "device: $SYSTEM"
echo "unit: sectors"
echo "sector-size: 512"
echo ""
echo "${SYSTEM}1 : start= 2048, size= 4980480, type=83"
echo "${SYSTEM}2 : start= 4982528, size= 4194304, type=82"
} > "$PART"
sfdisk -q "$SYSTEM" < "$PART"
info "Install: Extracting system partition..."
MOUNT="$TMP/system"
rm -rf "$MOUNT" && mkdir -p "$MOUNT"
mv "$HDA.tgz" "$HDA.txz" mv "$HDA.tgz" "$HDA.txz"
if [[ "$DEV" == [Nn]* ]]; then
# Exclude dev/ from tar extract
tar xpfJ "$HDA.txz" --absolute-names --exclude="dev" -C "$MOUNT/"
else
tar xpfJ "$HDA.txz" --absolute-names -C "$MOUNT/"
fi
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/" [ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"* rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
[ -f "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/" INDEX_DB="$MOUNT/usr/syno/synoman/indexdb"
[ -f "$IDB.txz" ] && tar xpfJ "$IDB.txz" --absolute-names -C "$MOUNT/usr/syno/synoman/indexdb/"
info "Install: Installing system partition..." if [ -s "$IDB.txz" ]; then
mkdir -p "$INDEX_DB"
fi
LABEL="1.44.1-42218" LABEL="1.44.1-42218"
OFFSET="1048576" # 2048 * 512 OFFSET="1048576" # 2048 * 512
NUMBLOCKS="622560" # (4980480 * 512) / 4096 NUMBLOCKS="2097152" # (16777216 * 512) / 4096
MSG="Installing system partition..."
mke2fs -q -t ext4 -b 4096 -d "$MOUNT/" -L "$LABEL" -F -E "offset=$OFFSET" "$SYSTEM" "$NUMBLOCKS" fakeroot -- bash -c "set -Eeu;\
[ -s $HDP.txz ] && tar xpfJ $HDP.txz --absolute-names -C $MOUNT/;\
[ -s $IDB.txz ] && tar xpfJ $IDB.txz --absolute-names -C $INDEX_DB/;\
tar xpfJ $HDA.txz --absolute-names --skip-old-files -C $MOUNT/;\
printf '%b%s%b' '\E[1;34m \E[1;36m' 'Install: $MSG' '\E[0m\n';\
mke2fs -q -t ext4 -b 4096 -d $MOUNT/ -L $LABEL -F -E offset=$OFFSET $SYSTEM $NUMBLOCKS"
rm -rf "$MOUNT" rm -rf "$MOUNT"
echo "$BASE" > "$STORAGE/dsm.ver"
echo "$BASE" > "$STORAGE"/dsm.ver setOwner "$STORAGE/dsm.ver" || warn "failed to set the owner for \"$STORAGE/dsm.ver\" !"
if [[ "$URL" == "file://$STORAGE/$BASE.pat" ]]; then if [[ "$URL" == "file://$STORAGE/$BASE.pat" ]]; then
rm -f "$PAT" rm -f "$PAT"
else else
mv -f "$PAT" "$STORAGE"/"$BASE".pat mv -f "$PAT" "$STORAGE/$BASE.pat"
fi fi
mv -f "$BOOT" "$STORAGE"/"$BASE".boot.img if [ -f "$STORAGE/$BASE.pat" ]; then
mv -f "$SYSTEM" "$STORAGE"/"$BASE".system.img setOwner "$STORAGE/$BASE.pat" || warn "failed to set the owner for \"$STORAGE/$BASE.pat\" !"
fi
mv -f "$BOOT" "$STORAGE/$BASE.boot.img"
setOwner "$STORAGE/$BASE.boot.img" || warn "failed to set the owner for \"$STORAGE/$BASE.boot.img\" !"
rm -rf "$TMP" rm -rf "$TMP"
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
return 0 return 0
+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env bash
set -Eeuo pipefail
msg="Checking memory..."
enabled "$DEBUG" && echo "$msg"
app() {
echo "Virtual DSM"
return 0
}
checkConfiguredMemory() {
if disabled "$RAM_CHECK" || [[ "${RAM_SIZE,,}" == "max" || "${RAM_SIZE,,}" == "half" ]]; then
return 0
fi
local wanted msg avail_mem
wanted=$(numfmt --from=iec "$RAM_SIZE")
avail_mem=$(formatBytes "$RAM_AVAIL")
if (( (wanted + RAM_SPARE) > RAM_AVAIL )); then
msg="Your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is too high for the $avail_mem of free memory available,"
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
else
RAM_SIZE="max"
warn "$msg it will automatically be adjusted to a lower amount."
fi
else
if (( (wanted + (RAM_SPARE * 3)) > RAM_AVAIL )); then
msg="your configured RAM_SIZE of ${RAM_SIZE/G/ GB} is very close to the $avail_mem of free memory available,"
if [[ "${FS,,}" == "zfs" ]]; then
info "$msg but since ZFS is active this will be ignored."
else
warn "$msg please consider a lower amount."
fi
fi
fi
return 0
}
configureHalfMemory() {
local wanted
if [[ "${RAM_SIZE,,}" != "half" ]]; then
return 0
fi
if (( (RAM_AVAIL / 2) > RAM_SPARE )); then
wanted=$(( (RAM_AVAIL / 2) / 1048577 ))
RAM_SIZE="${wanted}M"
info "Allocated $wanted MB of RAM for $(app)."
else
RAM_SIZE="max"
fi
return 0
}
configureMaxMemory() {
local wanted
if [[ "${RAM_SIZE,,}" != "max" ]]; then
return 0
fi
if (( RAM_AVAIL < (RAM_SPARE * 2) )); then
wanted=$(( RAM_AVAIL / 2 ))
else
wanted=$(( RAM_AVAIL - (RAM_SPARE * 3) ))
if (( wanted < (RAM_SPARE * 6) )); then
wanted=$(( RAM_AVAIL - RAM_SPARE ))
fi
fi
wanted=$(( wanted / 1048577 ))
RAM_SIZE="${wanted}M"
info "Allocated $wanted MB of RAM for $(app)."
return 0
}
checkMinimumMemory() {
local wanted
wanted=$(numfmt --from=iec "$RAM_SIZE")
if [ "$wanted" -lt "$RAM_MINIMUM" ]; then
wanted=$(( wanted / 1048577 ))
error "Not enough memory available, there is only $wanted MB left!"
exit 16
fi
return 0
}
getMemoryInfo
checkConfiguredMemory
configureHalfMemory
configureMaxMemory
checkMinimumMemory
return 0
+2224 -143
View File
File diff suppressed because it is too large Load Diff
+352 -42
View File
@@ -1,74 +1,384 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
: "${SHUTDOWN:="Y"}" # Graceful ACPI shutdown
: "${TIMEOUT:="105"}" # QEMU termination timeout
: "${API_TIMEOUT:="90"}" # External API call timeout
# Configure QEMU for graceful shutdown # Configure QEMU for graceful shutdown
QEMU_PORT=7100 API_CMD=6
QEMU_TIMEOUT=50
QEMU_PID=/run/qemu.pid
QEMU_COUNT=/run/qemu.count
rm -f "$QEMU_PID" SHUTDOWN_SKIP=0
rm -f "$QEMU_COUNT" SHUTDOWN_SIGNAL=0
_trap(){ QEMU_END="$QEMU_DIR/qemu.end"
func="$1" ; shift CONSOLE_PID="$QEMU_DIR/console.pid"
for sig ; do CONSOLE_SOCKET="$QEMU_DIR/console.sock"
trap "$func $sig" "$sig" QEMU_START_PID="$QEMU_DIR/qemu.start.pid"
done
_trap() {
local func="$1"; shift
local sig
TRAP_PID=$BASHPID
for sig; do
# Capture the local callback and signal while registering the trap.
# shellcheck disable=SC2064
trap "$func $sig" "$sig"
done
return 0
} }
_graceful_shutdown() { signalCode() {
set +e local sig="$1"
local cnt response
[ ! -f "$QEMU_PID" ] && exit 130 case "$sig" in
[ -f "$QEMU_COUNT" ] && return SIGHUP) echo 129 ;;
SIGINT) echo 130 ;;
SIGQUIT) echo 131 ;;
SIGABRT) echo 134 ;;
SIGTERM) echo 143 ;;
*) echo 0 ;;
esac
echo 0 > "$QEMU_COUNT" return 0
echo && info "Received $1 signal, shutting down..." }
# Don't send the powerdown signal because vDSM ignores ACPI signals displayReason() {
# echo 'system_powerdown' | nc -q 1 -w 1 localhost "${QEMU_PORT}" > /dev/null
# Send shutdown command to guest agent via serial port local reason="$1"
response=$(curl -sk -m 30 -S http://127.0.0.1:2210/read?command=6 2>&1)
if [[ ! "$response" =~ "\"success\"" ]]; then case "$reason" in
129 ) echo "SIGHUP" ;;
130 ) echo "SIGINT" ;;
131 ) echo "SIGQUIT" ;;
134 ) echo "SIGABRT" ;;
143 ) echo "SIGTERM" ;;
* ) echo "$reason" ;;
esac
echo && error "Failed to send shutdown command ( $response )." return 0
}
kill -15 "$(cat "$QEMU_PID")" readQemuPid() {
pkill -f qemu-system-x86_64 || true
readPidFile "$1" "$QEMU_START_PID" && return 0
readPidFile "$1" "$QEMU_PID"
}
qemuPidFile() {
local -n _file="$1"
_file="$QEMU_PID"
[ -s "$QEMU_START_PID" ] && _file="$QEMU_START_PID"
return 0
}
waitQemuExit() {
local timeout="${1:-10}"
local file
qemuPidFile file
waitPidFile "$file" "$timeout"
}
waitQemuPid() {
local cnt=0
while ! readQemuPid "$1"; do
sleep 0.02
cnt=$((cnt + 1))
(( cnt >= 50 )) && return 1
done
return 0
}
forceKillQemu() {
local reason="$1"
local pid display
readQemuPid pid || return 0
isAlive "$pid" || return 0
display=$(displayReason "$reason")
error "Forcefully terminating $(app), reason: $display..."
{ disown "$pid" || :; kill -9 -- "$pid" || :; } 2>/dev/null
return 0
}
cleanupHelpers() {
local pids=( "${HOST_PID:-}" "${WSD_PID:-}" "${CONSOLE_PID:-}" \
"${WEB_PID:-}" "${PASST_PID:-}" "${DNSMASQ_PID:-}" )
mKill "${pids[@]}"
fKill "print.sh"
rm -f -- "$HOST_API_SOCKET" "$HOST_AGENT_SOCKET"
closeNetwork
return 0
}
startConsole() {
local output="${1:-/dev/tty}"
local cnt=0
rm -f -- "$CONSOLE_SOCKET" "$CONSOLE_PID"
if ! stty -icanon -echo isig -ixon min 1 time 0 </dev/tty; then
error "Failed to configure serial console terminal!"
return 1
fi fi
while [ "$(cat $QEMU_COUNT)" -lt "$QEMU_TIMEOUT" ]; do (
trap '' INT QUIT
exec nc -lU "$CONSOLE_SOCKET" </dev/tty >"$output"
) &
# Increase the counter local pid="$!"
echo $(($(cat $QEMU_COUNT)+1)) > "$QEMU_COUNT" echo "$pid" > "$CONSOLE_PID"
# Try to connect to qemu while [ ! -S "$CONSOLE_SOCKET" ]; do
if echo 'info version'| nc -q 1 -w 1 localhost "$QEMU_PORT" >/dev/null 2>&1 ; then
sleep 1 if ! isAlive "$pid"; then
rm -f -- "$CONSOLE_PID"
error "Serial console relay exited unexpectedly!"
return 1
fi
cnt="$(cat $QEMU_COUNT)/$QEMU_TIMEOUT" sleep 0.02
[[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt)" cnt=$((cnt + 1))
if (( cnt > 100 )); then
error "Failed to start serial console relay!"
return 1
fi fi
done done
echo && echo " Quitting..." return 0
echo 'quit' | nc -q 1 -w 1 localhost "$QEMU_PORT" >/dev/null 2>&1 || true
closeNetwork
return
} }
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT stopConsole() {
MON_OPTS="-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay" mKill "$CONSOLE_PID"
return 0
}
startQemu() {
rm -f -- "$QEMU_START_PID"
(
trap '' INT QUIT
# shellcheck disable=SC2016
exec setsid -f -w sh -c '
file=$1
shift
"$@" &
pid=$!
printf "%s\n" "$pid" > "$file" || exit 1
rc=0
wait "$pid" 2>/dev/null || rc=$?
exit "$rc"
' sh "$QEMU_START_PID" "$@"
) </dev/null &
return 0
}
finish() {
local reason=$1 failed=0
if [ ! -f "$QEMU_END" ] && (( reason != 0 )); then
failed=1
fi
touch "$QEMU_END"
forceKillQemu "$reason"
cleanupHelpers
if ! waitQemuExit 10; then
warn "Timed out while waiting for $(app) to exit!"
fi
echo
if (( failed == 0 )); then
echo " Shutdown completed!"
else
error "QEMU exited unexpectedly!"
fi
exit "$reason"
}
sendGuestShutdown() {
local pid="$1"
local response
# Don't send the powerdown signal because vDSM ignores ACPI signals
# nc -q 1 -w 1 -U "$QEMU_DIR/monitor.sock" &> /dev/null <<<'system_powerdown' || :
# Send shutdown command to guest agent via serial port
API_TIMEOUT=$(strip "$API_TIMEOUT")
local url="http://localhost/read?command=$API_CMD&timeout=$API_TIMEOUT"
response=$(curl --unix-socket "$HOST_API_SOCKET" -sk -m "$(( API_TIMEOUT+2 ))" -S "$url" 2>&1)
if [[ "$response" =~ "\"success\"" ]]; then
echo && info "Virtual DSM is now ready to shutdown..."
else
response="${response#*message\"\: \"}"
[ -z "$response" ] && response="second signal"
echo && error "Forcefully terminating because of: ${response%%\"*}"
kill -15 -- "$pid" 2>/dev/null || :
fi
return 0
}
normalizeTimeout() {
local term_grace=3 # seconds before loop ends to send SIGTERM
local cleanup_grace=3 # seconds reserved after the loop for cleanup
TIMEOUT=$(strip "$TIMEOUT")
if [[ ! "$TIMEOUT" =~ ^[0-9]+$ ]]; then
TIMEOUT=105
fi
if (( TIMEOUT >= 30 )); then
term_grace=5
cleanup_grace=5
elif (( TIMEOUT >= 15 )); then
term_grace=4
cleanup_grace=4
fi
local elapsed=$((SECONDS - start))
local timeout_left=$((TIMEOUT - elapsed))
local min=$((term_grace + cleanup_grace + 1))
(( timeout_left < min )) && timeout_left=$min
wait_until=$((timeout_left - cleanup_grace))
sigterm_at=$((wait_until - term_grace))
return 0
}
waitForShutdown() {
local cnt=0
local pid="$1"
local name="$APP"
while (( cnt <= wait_until && SHUTDOWN_SKIP == 0 )); do
sleep 1 &
local slp=$!
# Stop waiting if the process has exited
isAlive "$pid" || break
# Workaround for stale/zombie QEMU pid file
[ ! -s "$QEMU_START_PID" ] && [ ! -s "$QEMU_PID" ] && break
if (( cnt == sigterm_at )); then
info "${name^} is still running, sending SIGTERM... ($cnt/$wait_until)"
kill -15 -- "$pid" 2>/dev/null || :
elif (( cnt > 0 )) && enabled "${DEBUG:-}"; then
info "Waiting for $name to shut down... ($cnt/$wait_until)"
fi
wait "$slp" || :
(( cnt++ ))
done
return 0
}
graceful_shutdown() {
local sig="$1"
local pid code
[[ $BASHPID != "$TRAP_PID" ]] && return
code=$(signalCode "$sig")
if [ -f "$QEMU_END" ]; then
if (( code == 130 && SHUTDOWN_SIGNAL == code )); then
SHUTDOWN_SKIP=1
echo && info "Received SIGINT again, forcing shutdown..."
return
fi
echo && info "Received $sig signal while already shutting down..."
return
fi
set +e
start=$SECONDS
SHUTDOWN_SIGNAL=$code
touch "$QEMU_END"
echo && info "Received $sig signal, sending shutdown command..."
if ! readQemuPid pid; then
if ! interactive || ! waitQemuPid pid; then
warn "QEMU PID file does not exist?"
finish "$code"
fi
fi
if [ -z "$pid" ] || ! isAlive "$pid"; then
warn "QEMU process with PID $pid does not exist?"
finish "$code"
fi
sendGuestShutdown "$pid"
normalizeTimeout
waitForShutdown "$pid"
finish "$code"
}
enabled "$SHUTDOWN" || return 0
[ -n "${QEMU_TIMEOUT:-}" ] && TIMEOUT="$QEMU_TIMEOUT"
if interactive; then
_trap graceful_shutdown SIGINT
fi
_trap graceful_shutdown SIGTERM SIGHUP SIGABRT SIGQUIT
return 0
+189 -35
View File
@@ -1,66 +1,220 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# shellcheck disable=SC2329
set -Eeuo pipefail set -Eeuo pipefail
: "${DHCP:="N"}"
: "${NETWORK:="Y"}"
cd /run
. utils.sh # Load functions
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n" >&2; } info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;33m " "WARNING: $1" "\E[0m\n" >&2; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; } error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; }
file="/run/dsm.url" disabled "$NETWORK" && exit 0
while [ ! -f "$file" ] file="/run/shm/dsm.url"
do msgs="/run/shm/msg.html"
driver="/run/shm/qemu.nic"
page="/run/shm/index.html"
address="/run/shm/qemu.ip"
shutdown="/run/shm/qemu.end"
socket="/run/shm/qemu-host-api.sock"
template="/var/www/index.html"
url="http://localhost/read?command=10"
sleep 3 resp_err="Guest returned an invalid response:"
[ -f "$file" ] && continue curl_err="Failed to connect to guest: curl error"
jq_err="Failed to parse response from guest: jq error"
# Retrieve IP from guest VM exitIfShuttingDown() {
{ json=$(curl -m 30 -sk http://127.0.0.1:2210/read?command=10); rc=$?; } || : [ -f "$shutdown" ] && exit 1
(( rc != 0 )) && error "Failed to connect to guest: curl error $rc" && continue
{ result=$(echo "$json" | jq -r '.status'); rc=$?; } || : return 0
(( rc != 0 )) && error "Failed to parse response from guest: jq error $rc ( $json )" && continue }
[[ "$result" == "null" ]] && error "Guest returned invalid response: $json" && continue
if [[ "$result" != "success" ]] ; then queryGuest() {
{ msg=$(echo "$json" | jq -r '.message'); rc=$?; } || :
error "Guest replied $result: $msg" && continue { json=$(curl --unix-socket "$socket" -m 20 -sk "$url"); local rc=$?; } || :
exitIfShuttingDown
if (( rc != 0 )); then
error "$curl_err $rc"
return 1
fi fi
{ port=$(echo "$json" | jq -r '.data.data.dsm_setting.data.http_port'); rc=$?; } || : return 0
(( rc != 0 )) && error "Failed to parse response from guest: jq error $rc ( $json )" && continue }
[[ "$port" == "null" ]] && error "Guest returned invalid response: $json" && continue
[ -z "$port" ] && continue
{ ip=$(echo "$json" | jq -r '.data.data.ip.data[] | select((.name=="eth0") and has("ip")).ip'); rc=$?; } || : readJsonField() {
(( rc != 0 )) && error "Failed to parse response from guest: jq error $rc ( $json )" && continue
[[ "$ip" == "null" ]] && error "Guest returned invalid response: $json" && continue
[ -z "$ip" ] && continue
echo "$ip:$port" > $file local query="$1"
local result
done { result=$(jq -r "$query" <<< "$json"); local rc=$?; } || :
location=$(cat "$file") if (( rc != 0 )); then
error "$jq_err $rc ( $json )"
return 1
fi
if [[ "$location" != "20.20"* ]]; then if [[ "$result" == "null" ]]; then
error "$resp_err $json"
return 1
fi
printf '%s\n' "$result"
return 0
}
readGuestStatus() {
local result msg
result=$(readJsonField '.status') || return 1
if [[ "$result" != "success" ]]; then
{ msg=$(jq -r '.message // empty' <<< "$json"); local rc=$?; } || :
if (( rc != 0 )); then
error "$jq_err $rc ( $json )"
return 1
fi
error "Guest replied $result: $msg"
return 1
fi
return 0
}
readGuestPort() {
port=$(readJsonField '.data.data.dsm_setting.data.http_port') || return 1
[ -z "$port" ] && return 1
return 0
}
readGuestIp() {
ip=$(readJsonField '.data.data.ip.data[] | select(.name=="eth0" and has("ip")) | .ip | select(test("^[0-9]+\\."))') || return 1
[ -z "$ip" ] && return 1
return 0
}
writeDsmLocation() {
echo "$ip:$port" > "$file"
return 0
}
pollGuestLocation() {
while [ ! -s "$file" ]; do
# Check if not shutting down
exitIfShuttingDown
sleep 3
exitIfShuttingDown
[ -s "$file" ] && break
# Retrieve network info from guest VM
queryGuest || continue
readGuestStatus || continue
readGuestPort || continue
readGuestIp || continue
writeDsmLocation
done
return 0
}
checkAddressConflict() {
local guest_ip="${location%:*}"
local container_ip=""
[ -s "$address" ] && container_ip=$(<"$address")
[ -z "$container_ip" ] && return 0
[[ "$guest_ip" != "$container_ip" ]] && return 0
warn "DSM is using the same IP as the container, this will cause connectivity issues."
warn "change the container's macvlan IP or assign DSM a different address in your router."
return 0
}
writeDhcpPage() {
local html
msg="http://$location" msg="http://$location"
local title="<title>Virtual DSM</title>"
local body="The location of DSM is <a href='http://$location'>http://$location</a>"
local script="<script>setTimeout(function(){ window.location.assign('http://$location'); }, 3000);</script>"
else html=$(<"$template")
html="${html/\[1\]/$title}"
html="${html/\[2\]/$script}"
html="${html/\[3\]/$body}"
html="${html/\[4\]/}"
html="${html/\[5\]/}"
ip=$(ip address show dev eth0 | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/) echo "$html" > "$page"
port="${location##*:}" echo "$body" > "$msgs"
if [[ "$ip" == "172."* ]]; then return 0
}
buildStaticMessage() {
local nic ip
nic=$(<"$driver")
ip=$(<"$address")
local port="${location##*:}"
if [[ "${nic,,}" != "macvlan" ]]; then
msg="port $port" msg="port $port"
else else
msg="http://$ip:$port" msg="http://$ip:$port"
fi fi
return 0
}
printLoginMessage() {
echo "" >&2
info "-----------------------------------------------------------"
info " You can now login to DSM at $msg"
info "-----------------------------------------------------------"
echo "" >&2
return 0
}
pollGuestLocation
exitIfShuttingDown
location=$(<"$file")
if enabled "$DHCP"; then
checkAddressConflict
writeDhcpPage
else
buildStaticMessage
fi fi
echo "" >&2 printLoginMessage
info "-----------------------------------------------------------"
info " You can now login to DSM at $msg" exit 0
info "-----------------------------------------------------------"
echo "" >&2
+199
View File
@@ -0,0 +1,199 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Docker environment variables
: "${HOST_CPU:=""}"
: "${CPU_FLAGS:=""}"
: "${CPU_MODEL:=""}"
HOST_CPU=$(strip "$HOST_CPU")
CPU_FLAGS=$(strip "$CPU_FLAGS")
CPU_MODEL=$(strip "$CPU_MODEL")
selectClocksource() {
CLOCKSOURCE="tsc"
[[ "${ARCH,,}" == "arm64" ]] && CLOCKSOURCE="arch_sys_counter"
CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource"
return 0
}
checkClocksource() {
local result
if [ ! -f "$CLOCK" ]; then
warn "file \"$CLOCK\" cannot be found?"
return 0
fi
result=$(<"$CLOCK")
result="${result//[![:print:]]/}"
case "${result,,}" in
"${CLOCKSOURCE,,}" ) ;;
"kvm-clock" ) info "Nested KVM virtualization detected.." ;;
"hyperv_clocksource_tsc_page" ) info "Nested Hyper-V virtualization detected.." ;;
"hpet" ) warn "unsupported clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
*) warn "unexpected clock source detected: '$result'. Please set host clock source to '$CLOCKSOURCE'." ;;
esac
return 0
}
checkSse42() {
if ! hasFlag "sse4_2"; then
error "Your CPU does not have the SSE4 instruction set that Virtual DSM requires!"
enabled "$DEBUG" || exit 88
fi
return 0
}
trimSpaces() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
echo "$value"
return 0
}
removeCpuArgument() {
local args=" ${ARGUMENTS:-} "
while [[ "$args" =~ [[:space:]]-cpu([[:space:]][^[:space:]]+|=[^[:space:]]+)? ]]; do
local cpu="${BASH_REMATCH[0]}"
args="${args/$cpu/ }"
warn "Ignoring '${cpu#" "}' from ARGUMENTS, use CPU_MODEL and CPU_FLAGS instead."
done
ARGUMENTS=$(trimSpaces "$args")
return 0
}
configureKvmCpuModel() {
CPU_FEATURES="kvm=on,l3-cache=on,+hypervisor"
KVM_OPTS=",accel=kvm -enable-kvm -global kvm-pit.lost_tick_policy=discard"
if [ -z "$CPU_MODEL" ]; then
CPU_MODEL="host"
CPU_FEATURES+=",migratable=no"
fi
return 0
}
appendKvmInvtscFeature() {
if hasFlag "svm"; then
# AMD processor
if hasFlag "tsc_scale"; then
CPU_FEATURES+=",+invtsc"
fi
else
# Intel processor
local vmx
vmx=$(sed -ne '/^vmx flags/s/^.*: //p' /proc/cpuinfo)
if grep -qw "tsc_scaling" <<< "$vmx"; then
CPU_FEATURES+=",+invtsc"
fi
fi
return 0
}
configureKvm() {
configureKvmCpuModel
checkSse42
appendKvmInvtscFeature
return 0
}
configureTcgCpuModel() {
if [ -n "$CPU_MODEL" ]; then
return 0
fi
if [[ "$ARCH" == "amd64" ]]; then
CPU_MODEL="max"
CPU_FEATURES+=",migratable=no"
else
CPU_MODEL="qemu64"
fi
return 0
}
configureTcg() {
KVM_OPTS=""
CPU_FEATURES="l3-cache=on,+hypervisor"
if [[ "$ARCH" == "amd64" ]]; then
KVM_OPTS=" -accel tcg,thread=multi"
fi
configureTcgCpuModel
CPU_FEATURES+=",+ssse3,+sse4.1,+sse4.2"
return 0
}
composeCpuFlags() {
CPU_FLAGS="${CPU_MODEL}${CPU_FEATURES:+,$CPU_FEATURES}${CPU_FLAGS:+,$CPU_FLAGS}"
return 0
}
configureHostCpuName() {
if [ -z "$HOST_CPU" ]; then
[[ "${CPU,,}" != "unknown" ]] && HOST_CPU="$CPU"
fi
if [ -n "$HOST_CPU" ]; then
HOST_CPU="${HOST_CPU%%,*},,"
else
HOST_CPU="QEMU, Virtual CPU,"
if [ "$ARCH" == "amd64" ]; then
HOST_CPU+=" X86_64"
else
HOST_CPU+=" $ARCH"
fi
fi
return 0
}
selectClocksource
checkClocksource
if ! disabled "$KVM"; then
configureKvm
else
configureTcg
fi
removeCpuArgument
composeCpuFlags
configureHostCpuName
return 0
+302
View File
@@ -0,0 +1,302 @@
#!/usr/bin/env bash
set -Eeuo pipefail
info="/run/shm/msg.html"
info_tmp="${info}.${BASHPID}.tmp"
escape() {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
s=${s//"'"/\&#39;}
printf '%s' "$s"
return 0
}
writeInfo() {
local content="$1"
if ! printf '%s\n' "$content" > "$info_tmp"; then
rm -f -- "$info_tmp"
return 1
fi
if ! mv -f -- "$info_tmp" "$info"; then
rm -f -- "$info_tmp"
return 1
fi
return 0
}
getBytes() {
local path="$1"
local mode="$2"
local bytes="0"
if [[ "$mode" == "counter" ]]; then
if [ -r "$path" ]; then
read -r bytes < "$path" || bytes="0"
fi
[[ "$bytes" =~ ^[0-9]+$ ]] || bytes="0"
printf '%s\n' "$bytes"
return 0
fi
if [ ! -s "$path" ] && [ ! -d "$path" ]; then
printf '0\n'
return 0
fi
if [[ "$mode" == "allocated" ]]; then
bytes=$(du -sB1 -- "$path" 2>/dev/null | cut -f1) || bytes="0"
else
bytes=$(du -sb -- "$path" 2>/dev/null | cut -f1) || bytes="0"
fi
printf '%s\n' "$bytes"
return 0
}
getStatus() {
local file="$1"
local bytes total extra=""
[ -r "$file" ] || return 1
read -r bytes total extra < "$file" || return 1
if [[ ! "$bytes" =~ ^[0-9]+$ ||
! "$total" =~ ^[0-9]+$ ||
-n "$extra" ]]; then
return 1
fi
printf '%s %s\n' "$bytes" "$total"
return 0
}
formatSize() {
local bytes="$1"
local size
size=$(numfmt --to=iec --suffix=B "$bytes" |
sed -r 's/([A-Z])/ \1/') ||
size="${bytes} bytes"
printf '%s' "$size"
return 0
}
printPercentProgress() {
local percent="$1"
while (( next_percent <= percent && next_percent <= 100 )); do
if [[ "$printed" == "Y" ]]; then
printf ' → %s%%' "$next_percent"
else
printf '%s%%' "$next_percent"
fi
printed="Y"
next_percent=$((next_percent + 10))
done
return 0
}
printCurrentSize() {
local bytes="$1"
local size
size=$(formatSize "$bytes")
if [[ "$printed" == "Y" ]]; then
printf ' → %s' "$size"
else
printf '%s' "$size"
fi
printed="Y"
return 0
}
printSizeProgress() {
local bytes="$1"
local size
while (( bytes >= next_bytes )); do
size=$(formatSize "$next_bytes")
if [[ "$printed" == "Y" ]]; then
printf ' → %s' "$size"
else
printf '%s' "$size"
fi
printed="Y"
next_bytes=$((next_bytes + step_bytes))
done
return 0
}
stopProgress() {
if [ -z "$status_file" ]; then
exit 0
fi
stopping="Y"
return 0
}
finishProgress() {
rm -f -- "$info_tmp"
if [[ "$output" == "log" && "$printed" == "Y" ]]; then
printf '\n'
fi
return 0
}
path="$1"
total="$2"
body=$(escape "$3")
output="${4:-}"
step_bytes="${5:-536870912}"
mode="${6:-apparent}"
status_file="${7:-}"
if [[ -n "$total" && ! "$total" =~ ^(0|[1-9][0-9]*)$ ]]; then
printf 'Invalid total size: %s\n' "$total" >&2
exit 2
fi
if [[ ! "$step_bytes" =~ ^[1-9][0-9]*$ ]]; then
printf 'Invalid progress interval: %s\n' "$step_bytes" >&2
exit 2
fi
case "$mode" in
apparent | allocated | counter ) ;;
* )
printf 'Invalid progress mode: %s\n' "$mode" >&2
exit 2
;;
esac
case "$output" in
"" | log ) ;;
* )
printf 'Invalid progress output: %s\n' "$output" >&2
exit 2
;;
esac
printed="N"
next_percent=10
next_bytes="$step_bytes"
log_mode="percent"
stopping="N"
if [ -z "$total" ] || [[ "$total" == "0" ]]; then
log_mode="size"
fi
trap finishProgress EXIT
trap 'exit 0' HUP INT QUIT
trap stopProgress TERM
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body::-3}</p>"
fi
while true; do
final_pass="${stopping:-}"
bytes=$(getBytes "$path" "$mode")
effective_total="$total"
if [ -n "$status_file" ] && status=$(getStatus "$status_file"); then
read -r status_bytes status_total <<< "$status"
bytes="$status_bytes"
if (( status_total > 0 )); then
effective_total="$status_total"
fi
fi
# A real total may become available shortly after aria2 starts.
if [[ "$log_mode" == "size" &&
"$printed" == "N" &&
-n "$effective_total" &&
"$effective_total" != "0" ]]; then
log_mode="percent"
fi
if (( bytes > 4096 )); then
write_html="Y"
if [ -z "$effective_total" ] ||
[[ "$effective_total" == "0" ]] ||
(( bytes > effective_total )); then
size=$(formatSize "$bytes")
if [[ "$output" == "log" ]]; then
if [[ "$log_mode" == "percent" ]]; then
printCurrentSize "$bytes"
next_bytes=$(((bytes / step_bytes + 1) * step_bytes))
log_mode="size"
else
printSizeProgress "$bytes"
fi
fi
else
# Truncate to one decimal so progress is never reported early.
progress=$((bytes * 1000 / effective_total))
(( progress > 1000 )) && progress=1000
percent=$((progress / 10))
printf -v size '%d.%d%%' \
"$((progress / 10))" \
"$((progress % 10))"
if [[ "$output" == "log" ]]; then
if [[ "$log_mode" == "size" ]]; then
printSizeProgress "$bytes"
else
printPercentProgress "$percent"
fi
fi
# Do not update the web viewer until at least 0.1% is reached.
(( progress == 0 )) && write_html="N"
fi
if [[ "$write_html" == "Y" ]]; then
writeInfo "${body//(\[P\])/($size)}"
fi
fi
[[ "$final_pass" == "Y" ]] && break
sleep 1 &
wait $! || :
done
+332 -82
View File
@@ -1,105 +1,355 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; }
trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
enabled "${TRACE:-}" && set -o functrace && trap 'echo "# $BASH_COMMAND" >&2' DEBUG
[ ! -f "/run/entry.sh" ] && error "Script must run inside Docker container!" && exit 11 [ ! -f "/run/entry.sh" ] && error "Script must be run inside the container!" && exit 11
[ "$(id -u)" -ne "0" ] && error "Script must be executed with root privileges." && exit 12 [ "$(id -u)" -ne "0" ] && error "Script must be executed with root privileges." && exit 12
# Docker environment variables # Docker environment variables
: ${GPU:='N'} # Enable GPU passthrough : "${TZ:=""}" # System timezone
: ${DEBUG:='N'} # Enable debugging mode : "${KVM:="Y"}" # KVM acceleration
: ${COUNTRY:=''} # Country code for mirror : "${DEBUG:="N"}" # Disable debugging mode
: ${CONSOLE:='N'} # Start in console mode : "${COUNTRY:=""}" # Country code for mirror
: ${ALLOCATE:='Y'} # Preallocate diskspace : "${MACHINE:="q35"}" # Machine type selection
: ${ARGUMENTS:=''} # Extra QEMU parameters : "${ALLOCATE:=""}" # Preallocate diskspace
: ${CPU_CORES:='1'} # Amount of CPU cores : "${ARGUMENTS:=""}" # Extra QEMU parameters
: ${RAM_SIZE:='1G'} # Maximum RAM amount : "${CPU_CORES:="2"}" # Amount of CPU cores
: ${DISK_SIZE:='16G'} # Initial data disk size : "${RAM_SIZE:="2G"}" # Maximum RAM amount
: "${RAM_CHECK:="Y"}" # Check available RAM
: "${DISK_SIZE:="16G"}" # Initial data disk size
: "${STORAGE:="/storage"}" # Storage folder location
detectEngine() {
if [ -f "/run/.containerenv" ]; then
ENGINE="${container:-}"
if [[ "${ENGINE,,}" == *"podman"* ]]; then
ENGINE="Podman"
else
[ -z "$ENGINE" ] && ENGINE="Kubernetes"
fi
elif [ -f "/.dockerenv" ]; then
ENGINE="Docker"
fi
return 0
}
detectRootless() {
local uid_map
uid_map=$(awk '{$1=$1; print}' /proc/self/uid_map 2>/dev/null || true)
if [[ "$uid_map" == "0 0 4294967295" ]]; then
ROOTLESS="N"
else
ROOTLESS="Y"
fi
return 0
}
checkPrivileged() {
local cap_bnd
local last_cap
# Get the capability bounding set
cap_bnd=$(grep '^CapBnd:' /proc/$$/status | awk '{print $2}')
cap_bnd=$(printf "%d" "0x${cap_bnd}")
# Get the last capability number
last_cap=$(cat /proc/sys/kernel/cap_last_cap)
# Calculate the maximum capability value
local max_cap=$(((1 << (last_cap + 1)) - 1))
if [ "$cap_bnd" -eq "$max_cap" ]; then
PRIVILEGED="Y"
fi
return 0
}
normalizeCpuCores() {
CPU_CORES=$(strip "$CPU_CORES")
[ -z "$CPU_CORES" ] && CPU_CORES=2
[[ "${CPU_CORES,,}" == "max" ]] && CPU_CORES="$CORES"
[[ "${CPU_CORES,,}" == "half" ]] && CPU_CORES=$(( CORES / 2 ))
[ -z "${CPU_CORES##*[!0-9]*}" ] && error "Invalid amount of CPU_CORES: $CPU_CORES" && exit 15
[ "$CPU_CORES" -lt "1" ] && CPU_CORES=1
if [ "$CPU_CORES" -gt "$CORES" ]; then
warn "The amount for CPU_CORES (${CPU_CORES}) exceeds the amount of logical cores available (${CORES}) and will be limited."
CPU_CORES="$CORES"
fi
return 0
}
checkStorage() {
# Check system
QEMU_DIR="/run/shm"
if [ ! -d "/dev/shm" ]; then
error "Directory /dev/shm not found!" && exit 14
else
[ ! -d "$QEMU_DIR" ] && ln -s /dev/shm "$QEMU_DIR"
fi
QEMU_PID="$QEMU_DIR/qemu.pid"
# Check folder
if [[ "${STORAGE,,}" != "/storage" ]]; then
mkdir -p "$STORAGE"
fi
if [ ! -d "$STORAGE" ]; then
error "Storage folder ($STORAGE) not found!" && exit 13
fi
if [ ! -w "$STORAGE" ]; then
msg="Storage folder ($STORAGE) is not writeable!"
msg+=" If SELinux is active, you need to add the \":Z\" flag to the bind mount."
error "$msg" && exit 13
fi
return 0
}
checkFilesystem() {
# Check filesystem
FS=$(stat -f -c %T "$STORAGE")
if [[ "${FS,,}" == "ecryptfs" || "${FS,,}" == "tmpfs" ]]; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
return 0
}
finiteMemoryLimit() {
local limit="$1"
local sentinel="4611686018427387904"
local i
[[ "$limit" =~ ^[0-9]+$ ]] || return 1
(( ${#limit} < ${#sentinel} )) && return 0
(( ${#limit} > ${#sentinel} )) && return 1
for (( i=0; i<${#sentinel}; i++ )); do
local left="${limit:i:1}"
local right="${sentinel:i:1}"
(( left < right )) && return 0
(( left > right )) && return 1
done
return 1
}
getMemoryInfo() {
local limit="" current=""
local host_total host_avail
host_total=$(free -b | awk '/^Mem:/ {print $2; exit}')
host_avail=$(free -b | awk '/^Mem:/ {print $7; exit}')
RAM_TOTAL="$host_total"
RAM_AVAIL="$host_avail"
if [ -r /sys/fs/cgroup/memory.max ] && [ -r /sys/fs/cgroup/memory.current ]; then
limit=$(< /sys/fs/cgroup/memory.max)
current=$(< /sys/fs/cgroup/memory.current)
elif [ -r /sys/fs/cgroup/memory/memory.limit_in_bytes ] && [ -r /sys/fs/cgroup/memory/memory.usage_in_bytes ]; then
limit=$(< /sys/fs/cgroup/memory/memory.limit_in_bytes)
current=$(< /sys/fs/cgroup/memory/memory.usage_in_bytes)
fi
if finiteMemoryLimit "$limit" && [[ "$current" =~ ^[0-9]+$ ]]; then
(( limit < RAM_TOTAL )) && RAM_TOTAL="$limit"
local available=$(( limit - current ))
(( available < 0 )) && available=0
(( available < RAM_AVAIL )) && RAM_AVAIL="$available"
fi
return 0
}
normalizeRamSize() {
# Read host and container memory limits.
getMemoryInfo
RAM_SPARE=500000000
RAM_MINIMUM=136314880
RAM_SIZE=$(strip "$RAM_SIZE")
RAM_SIZE="${RAM_SIZE// /}"
[ -z "$RAM_SIZE" ] && RAM_SIZE="2G"
if [[ "${RAM_SIZE,,}" != "max" && "${RAM_SIZE,,}" != "half" ]]; then
if [ -z "${RAM_SIZE//[0-9. ]}" ]; then
[ "${RAM_SIZE%%.*}" -lt "130" ] && RAM_SIZE="${RAM_SIZE}G" || RAM_SIZE="${RAM_SIZE}M"
fi
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
numfmt --from=iec "$RAM_SIZE" &>/dev/null || { error "Invalid RAM_SIZE: $RAM_SIZE" && exit 16; }
wanted=$(numfmt --from=iec "$RAM_SIZE")
[ "$wanted" -lt "$RAM_MINIMUM" ] && error "RAM_SIZE is too low: $RAM_SIZE" && exit 16
fi
return 0
}
checkKvm() {
# Check KVM support
if [[ "${PLATFORM,,}" == "x64" ]]; then
TARGET="amd64"
else
TARGET="arm64"
fi
if disabled "$KVM"; then
warn "KVM acceleration is disabled, this will cause the machine to run about 10 times slower!"
else
if [[ "${ARCH,,}" != "$TARGET" ]]; then
KVM="N"
warn "your CPU architecture is ${ARCH^^} and cannot provide KVM acceleration for ${PLATFORM^^} instructions, so the machine will run about 10 times slower."
fi
fi
if ! disabled "$KVM"; then
KVM_ERR=""
if [ ! -e /dev/kvm ]; then
KVM_ERR="(/dev/kvm is missing)"
else
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(/dev/kvm is unwriteable)"
else
if [[ "${PLATFORM,,}" == "x64" ]]; then
flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo)
if ! grep -qw "vmx\|svm" <<< "$flags"; then
KVM_ERR="(not enabled in BIOS)"
fi
if ! grep -qw "sse4_2" <<< "$flags"; then
error "Your CPU does not have the SSE4 instruction set that Virtual DSM requires!"
enabled "$DEBUG" || exit 88
fi
fi
fi
fi
if [ -n "$KVM_ERR" ]; then
KVM="N"
if [[ "$OSTYPE" =~ ^darwin ]]; then
warn "you are using macOS which has no KVM support, so the machine will run about 10 times slower."
else
kernel=$(uname -a)
case "${kernel,,}" in
*"microsoft"* )
error "Please bind '/dev/kvm' as a volume in the optional container settings when using Docker Desktop." ;;
*"synology"* )
error "Please make sure that Synology VMM (Virtual Machine Manager) is installed and that '/dev/kvm' is binded to this container." ;;
*)
error "KVM acceleration is not available $KVM_ERR, this will cause the machine to run about 10 times slower."
error "See the FAQ for possible causes, or disable acceleration by adding the \"KVM=N\" variable (not recommended)." ;;
esac
enabled "$DEBUG" || exit 88
fi
fi
fi
return 0
}
# Sanitize variables
TZ=$(strip "$TZ")
STORAGE=$(strip "$STORAGE")
COUNTRY=$(strip "$COUNTRY")
DISK_SIZE=$(strip "$DISK_SIZE")
# Helper variables # Helper variables
ROOTLESS="N"
PRIVILEGED="N"
ENGINE="Docker"
PROCESS="${APP,,}"
PROCESS="${PROCESS// /-}"
KERNEL=$(uname -r | cut -b 1) detectEngine
MINOR=$(uname -r | cut -d '.' -f2) detectRootless
echo " Starting $APP for $ENGINE v$(</etc/version)..."
echo " For support visit $SUPPORT"
checkPrivileged
INFO="/run/shm/msg.html"
PAGE="/run/shm/index.html"
TEMPLATE="/var/www/index.html"
FOOTER1="$APP for $ENGINE v$(</etc/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
SOCKETS=1
CPU=$(cpu)
SYS=$(uname -r)
ARCH=$(dpkg --print-architecture) ARCH=$(dpkg --print-architecture)
VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1) IFS=. read -r KERNEL MINOR _ <<< "$SYS"
CORES=$(grep -c '^processor' /proc/cpuinfo)
# Check folder if grep -qi "socket(s)" <<< "$(lscpu)"; then
SOCKETS=$(lscpu | grep -m 1 -i 'socket(s)' | awk '{print $2}')
[ -z "${SOCKETS##*[!0-9]*}" ] && SOCKETS=1
[ "$SOCKETS" -lt "1" ] && SOCKETS=1
fi
STORAGE="/storage" normalizeCpuCores
[ ! -d "$STORAGE" ] && error "Storage folder ($STORAGE) not found!" && exit 13 checkStorage
checkFilesystem
normalizeRamSize
# Print system info
SYS="${SYS/-generic/}"
FS="${FS/UNKNOWN //}"
FS="${FS/ext2\/ext3/ext4}"
FS=$(echo "$FS" | sed 's/[)(]//g')
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(formatBytes "$SPACE" "down")
AVAIL_MEM=$(formatBytes "$RAM_AVAIL" "down")
TOTAL_MEM=$(formatBytes "$RAM_TOTAL" "up")
echo " CPU: ${CPU} | RAM: ${AVAIL_MEM/ GB/}/$TOTAL_MEM | DISK: $SPACE_GB (${FS}) | KERNEL: ${SYS}"
echo
checkKvm
# Cleanup files # Cleanup files
rm -f "$QEMU_DIR"/dsm.url
rm -f /run/dsm.url rm -f "$QEMU_DIR"/{qemu.*,*.{pid,sock,pipe}}
rm -f /run/qemu.pid
rm -f /run/qemu.count
# Cleanup dirs # Cleanup dirs
rm -rf /tmp/dsm rm -rf /tmp/dsm
rm -rf "$STORAGE/tmp" rm -rf "$STORAGE/tmp"
# Helper functions
getCountry () {
local url=$1
local query=$2
local rc json result
{ json=$(curl -m 5 -H "Accept: application/json" -sfk "$url"); rc=$?; } || :
(( rc != 0 )) && return 0
{ result=$(echo "$json" | jq -r "$query" 2> /dev/null); rc=$?; } || :
(( rc != 0 )) && return 0
[[ ${#result} -ne 2 ]] && return 0
[[ "${result^^}" == "XX" ]] && return 0
COUNTRY="${result^^}"
return 0
}
setCountry () {
[ -z "$COUNTRY" ] && getCountry "https://api.ipapi.is" ".location.country_code"
[ -z "$COUNTRY" ] && getCountry "https://ifconfig.co/json" ".country_iso"
[ -z "$COUNTRY" ] && getCountry "https://ipinfo.io/json" ".country"
[ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc"
return 0
}
addPackage () {
local pkg=$1
local desc=$2
if apt-mark showinstall | grep -qx "$pkg"; then
return 0
fi
info "Installing $desc..."
export DEBCONF_NOWARNINGS="yes"
export DEBIAN_FRONTEND="noninteractive"
[ -z "$COUNTRY" ] && setCountry
if [[ "${COUNTRY^^}" == "CN" ]]; then
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
fi
apt-get -qq update
apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null
return 0
}
return 0 return 0
+122 -52
View File
@@ -1,72 +1,142 @@
#!/bin/bash #!/usr/bin/env bash
set -Eeuo pipefail set -Eeuo pipefail
# Docker environment variables # Docker environment variables
: ${HOST_CPU:=''} : "${HOST_MAC:=""}"
: ${HOST_MAC:=''} : "${HOST_DEBUG:=""}"
: ${HOST_DEBUG:=''} : "${HOST_MODEL:=""}"
: ${HOST_SERIAL:=''} : "${HOST_SERIAL:=""}"
: ${HOST_MODEL:=''} : "${GUEST_SERIAL:=""}"
: ${GUEST_SERIAL:=''}
if [ -z "$HOST_CPU" ]; then # Sanitize variables
HOST_CPU=$(lscpu | grep 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g') HOST_MAC=$(strip "$HOST_MAC")
fi HOST_MODEL=$(strip "$HOST_MODEL")
HOST_SERIAL=$(strip "$HOST_SERIAL")
GUEST_SERIAL=$(strip "$GUEST_SERIAL")
if [ -n "$HOST_CPU" ]; then HOST_PID="$QEMU_DIR/host.pid"
HOST_CPU="$HOST_CPU,," HOST_API_SOCKET="$QEMU_DIR/qemu-host-api.sock"
else HOST_AGENT_SOCKET="$QEMU_DIR/qemu-host-agent.sock"
if [ "$ARCH" == "amd64" ]; then
HOST_CPU="QEMU, Virtual CPU, X86_64" validateHostMac() {
else local m
HOST_CPU="QEMU, Virtual CPU, $ARCH"
if [ -z "$HOST_MAC" ]; then
return 0
fi fi
fi
HOST_ARGS=() HOST_MAC="${HOST_MAC//-/:}"
HOST_ARGS+=("-cpu=$CPU_CORES")
HOST_ARGS+=("-cpu_arch=$HOST_CPU")
[ -n "$HOST_MAC" ] && HOST_ARGS+=("-mac=$HOST_MAC") if [[ ${#HOST_MAC} == 12 ]]; then
[ -n "$HOST_MODEL" ] && HOST_ARGS+=("-model=$HOST_MODEL") m="$HOST_MAC"
[ -n "$HOST_SERIAL" ] && HOST_ARGS+=("-hostsn=$HOST_SERIAL") HOST_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
[ -n "$GUEST_SERIAL" ] && HOST_ARGS+=("-guestsn=$GUEST_SERIAL") fi
if [[ "$HOST_DEBUG" == [Yy1]* ]]; then if [[ ${#HOST_MAC} != 17 ]]; then
set -x error "Invalid HOST_MAC address: '$HOST_MAC', should be 12 or 17 digits long!" && exit 28
./host.bin "${HOST_ARGS[@]}" & fi
{ set +x; } 2>/dev/null
echo
else
./host.bin "${HOST_ARGS[@]}" >/dev/null &
fi
cnt=0 return 0
sleep 0.2 }
while ! nc -z -w2 127.0.0.1 2210 > /dev/null 2>&1; do buildHostArguments() {
sleep 0.1
cnt=$((cnt + 1))
(( cnt > 50 )) && error "Failed to connect to qemu-host.." && exit 58
done
cnt=0 HOST_ARGS=()
HOST_ARGS+=("-cpu=$CPU_CORES")
HOST_ARGS+=("-cpu_arch=$HOST_CPU")
HOST_ARGS+=("-api=$HOST_API_SOCKET")
HOST_ARGS+=("-addr=$HOST_AGENT_SOCKET")
while ! nc -z -w2 127.0.0.1 12345 > /dev/null 2>&1; do [ -n "$HOST_MAC" ] && HOST_ARGS+=("-mac=$HOST_MAC")
sleep 0.1 [ -n "$HOST_MODEL" ] && HOST_ARGS+=("-model=$HOST_MODEL")
cnt=$((cnt + 1)) [ -n "$HOST_SERIAL" ] && HOST_ARGS+=("-hostsn=$HOST_SERIAL")
(( cnt > 50 )) && error "Failed to connect to qemu-host.." && exit 59 [ -n "$GUEST_SERIAL" ] && HOST_ARGS+=("-guestsn=$GUEST_SERIAL")
done
# Configure serial ports return 0
}
SERIAL_OPTS="\ startHostBinary() {
-serial mon:stdio \
local pid
rm -f -- "$HOST_PID" "$HOST_API_SOCKET" "$HOST_AGENT_SOCKET" || return 1
if enabled "$HOST_DEBUG"; then
set -x
./host.bin "${HOST_ARGS[@]}" &
{ set +x; } 2>/dev/null
pid=$!
echo
else
./host.bin "${HOST_ARGS[@]}" >/dev/null &
pid=$!
fi
printf '%s\n' "$pid" > "$HOST_PID"
return 0
}
waitForSocket() {
local socket="$1"
local exit_code="$2"
local timeout=5 pid
local deadline=$((SECONDS + timeout))
while [ ! -S "$socket" ]; do
if ! readPidFile pid "$HOST_PID" || ! isAlive "$pid"; then
error "qemu-host exited unexpectedly!"
exit "$exit_code"
fi
if (( SECONDS >= deadline )); then
error "Failed to create qemu-host socket: $socket"
exit "$exit_code"
fi
sleep 0.1
done
return 0
}
configureSerialPorts() {
if enabled "${SHUTDOWN:-Y}" && interactive; then
CONSOLE_SOCKET="$QEMU_DIR/console.sock"
MONITOR_SOCKET="$QEMU_DIR/monitor.sock"
SERIAL_OPTS="-chardev socket,id=console0,path=$CONSOLE_SOCKET,reconnect-ms=1000 \
-serial chardev:console0 \
-chardev socket,id=monitor0,path=$MONITOR_SOCKET,server=on,wait=off \
-mon chardev=monitor0,mode=readline"
else
SERIAL_OPTS="-serial mon:stdio"
fi
SERIAL_OPTS+=" \
-device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \ -device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \
-chardev pty,id=charserial0 \ -chardev socket,id=charchannel0,path=$HOST_AGENT_SOCKET,reconnect-ms=1000 \
-device isa-serial,chardev=charserial0,id=serial0 \
-chardev socket,id=charchannel0,host=127.0.0.1,port=12345,reconnect=10 \
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel" -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel"
return 0
}
validateHostMac
buildHostArguments
startHostBinary
waitForSocket "$HOST_API_SOCKET" 58
waitForSocket "$HOST_AGENT_SOCKET" 59
configureSerialPorts
return 0 return 0
+140 -54
View File
@@ -1,66 +1,152 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -eu set -Eeuo pipefail
TMP_FILE=$(mktemp -q /tmp/server.XXXXXX) : "${WEB_PORT:="5000"}" # Webserver port
: "${WSD_PORT:="8004"}" # Websockets port
stop() { # Sanitize port variables
trap - SIGINT EXIT WEB_PORT=$(strip "$WEB_PORT")
{ pkill -f socat || true; } 2>/dev/null WSD_PORT=$(strip "$WSD_PORT")
[ -f "$TMP_FILE" ] && rm -f "$TMP_FILE"
WEB_PID="/run/nginx.pid"
WSD_LOG="/var/log/websocketd.log"
WSD_PID="$QEMU_DIR/websocketd.pid"
prepareWebFiles() {
cp -r /var/www/* "$QEMU_DIR" || return 1
rm -f -- "$WSD_PID" "$WEB_PID" "$WSD_LOG" || return 1
return 0
} }
trap 'stop' EXIT SIGINT SIGTERM SIGHUP configureWebPorts() {
html() if ! sed -i \
{ -e "s|listen 5000 default_server;|listen $WEB_PORT default_server;|g" \
local h="<!DOCTYPE html><HTML><HEAD><TITLE>VirtualDSM</TITLE>" -e "s|proxy_pass http://127.0.0.1:8004/;|proxy_pass http://127.0.0.1:$WSD_PORT/;|g" \
h="$h<STYLE>body { color: white; background-color: #125bdb; font-family: Verdana," /etc/nginx/sites-enabled/web.conf; then
h="$h Arial,sans-serif; } a, a:hover, a:active, a:visited { color: white; }</STYLE></HEAD>" error "Failed to configure webserver ports!"
h="$h<BODY><BR><BR><H1><CENTER>$1</CENTER></H1></BODY></HTML>" return 1
echo "$h"
}
if [[ "$2" != "/"* ]]; then
BODY="$2"
if [[ "$BODY" == "install" ]]; then
BODY="Please wait while Virtual DSM is being installed..."
BODY="$BODY<script>setTimeout(() => { document.location.reload(); }, 9999);</script>"
fi fi
HTML=$(html "$BODY") return 0
printf '%b' "HTTP/1.1 200 OK\nContent-Length: ${#HTML}\nConnection: close\n\n$HTML" > "$TMP_FILE" }
socat TCP4-LISTEN:80,reuseaddr,fork,crlf SYSTEM:"cat $TMP_FILE" 2> /dev/null & configureIpv6Listen() {
socat TCP4-LISTEN:"${1:-5000}",reuseaddr,fork,crlf SYSTEM:"cat $TMP_FILE" 2> /dev/null & wait $!
if [ -f /proc/net/if_inet6 ] && [[ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null)" != "1" ]]; then
exit
if ! sed -i \
"s/listen $WEB_PORT default_server;/listen [::]:$WEB_PORT default_server ipv6only=off;/g" \
/etc/nginx/sites-enabled/web.conf; then
error "Failed to configure IPv6 webserver listener!"
return 1
fi
fi
return 0
}
configureWebServer() {
mkdir -p /etc/nginx/sites-enabled
cp /etc/nginx/default.conf /etc/nginx/sites-enabled/web.conf
configureWebPorts || return 1
configureIpv6Listen || return 1
return 0
}
stopWebServer() {
local pid
if readPidFile pid "$WEB_PID"; then
pKill "$pid" 2
if isAlive "$pid"; then
kill -9 -- "$pid" 2>/dev/null || :
fi
fi
rm -f -- "$WEB_PID"
return 0
}
startWebServer() {
# Start webserver
nginx -e stderr || return 1
return 0
}
stopWebsocketServer() {
local pid
if readPidFile pid "$WSD_PID"; then
pKill "$pid" 2
if isAlive "$pid"; then
kill -9 -- "$pid" 2>/dev/null || :
fi
fi
rm -f -- "$WSD_PID"
return 0
}
startWebsocketServer() {
# Start websocket server
websocketd \
--address 127.0.0.1 \
--port="$WSD_PORT" \
/run/socket.sh \
>"$WSD_LOG" 2>&1 &
local pid=$!
if ! echo "$pid" > "$WSD_PID"; then
kill "$pid" 2>/dev/null || :
rm -f -- "$WSD_PID"
return 1
fi
local i
for (( i = 1; i <= 5; i++ )); do
if ! isAlive "$pid"; then
rm -f -- "$WSD_PID"
[ -s "$WSD_LOG" ] && cat "$WSD_LOG" >&2
error "Failed to start websocket server!"
return 1
fi
sleep 0.1
done
return 0
}
prepareWebFiles
html "Starting $APP for $ENGINE..."
disabled "${WEB:-}" && return 0
configureWebServer
if startWebServer && startWebsocketServer; then
return 0
fi fi
if [[ "$2" != "/run/ip.sh" ]]; then stopWebsocketServer || :
stopWebServer || :
cp "$2" "$TMP_FILE" return 1
else
BODY="The location of DSM is <a href='http://\$LOCATION'>http://\$LOCATION</a><script>"
BODY="$BODY setTimeout(function(){ window.location.assign('http://\$LOCATION'); }, 3000);</script>"
WAIT="Please wait while discovering IP...<script>setTimeout(() => { document.location.reload(); }, 4999);</script>"
HTML=$(html "xxx")
{ echo "#!/bin/bash"
echo "[ -f \"/run/dsm.url\" ] && LOCATION=\$(cat \"/run/dsm.url\")"
echo "HTML=\"$HTML\"; [ -z \"\$LOCATION\" ] && BODY=\"$WAIT\" || BODY=\"$BODY\"; HTML=\${HTML/xxx/\$BODY}"
echo "printf '%b' \"HTTP/1.1 200 OK\\nContent-Length: \${#HTML}\\nConnection: close\\n\\n\$HTML\""
} > "$TMP_FILE"
fi
chmod +x "$TMP_FILE"
socat TCP4-LISTEN:80,reuseaddr,fork,crlf SYSTEM:"$TMP_FILE" 2> /dev/null &
socat TCP4-LISTEN:"${1:-5000}",reuseaddr,fork,crlf SYSTEM:"$TMP_FILE" 2> /dev/null & wait $!
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -Eeuo pipefail
lastmsg=""
path="/run/shm/msg.html"
dir=$(dirname -- "$path")
name=$(basename -- "$path")
refresh() {
[ ! -f "$path" ] && return 0
[ ! -s "$path" ] && return 0
msg=$(< "$path") || return 0
msg="${msg%$'\n'}"
[ -z "$msg" ] && return 0
[[ "$msg" == "$lastmsg" ]] && return 0
lastmsg="$msg"
echo "s: $msg"
return 0
}
refresh
inotifywait \
-m -q \
-e close_write,moved_to,delete \
--format '%e %f' \
"$dir" |
while read -r event file; do
[[ "$file" == "$name" ]] || continue
case "${event,,}" in
"delete"* )
echo "c: vnc" ;;
"close_write"* | "moved_to"* )
refresh ;;
esac
done
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# You can override this hook to execute a script before startup!
return 0
+549
View File
@@ -0,0 +1,549 @@
#!/usr/bin/env bash
set -Eeuo pipefail
# Helper functions
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "${1:-}" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: ${1:-}" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m " "Warning: ${1:-}" "\E[0m\n" >&2; }
readPidFile() {
local -n _pid="$1"
_pid=""
if ! _pid=$(cat -- "$2" 2>/dev/null); then
_pid=""
return 1
fi
if [[ ! "$_pid" =~ ^[1-9][0-9]*$ ]]; then
_pid=""
return 1
fi
return 0
}
hasFlag() {
# Match a whitespace-delimited token in /proc/cpuinfo
grep -m1 '^flags[[:space:]]*:' /proc/cpuinfo | grep -Fqw -- "$1"
}
hasFeature() {
# Match a whitespace-delimited token in /proc/cpuinfo
grep -m1 '^Features[[:space:]]*:' /proc/cpuinfo | grep -Fqw -- "$1"
}
isAmdCpu() {
local vendor
vendor=$(awk -F ': *' '/^vendor_id/{print $2; exit}' /proc/cpuinfo)
[[ "$vendor" == "AuthenticAMD" ]]
}
interactive() {
[ -t 0 ] && : 2>/dev/null </dev/tty >/dev/tty
}
strip() {
local value="${1:-}"
# Remove surrounding whitespace
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
# Remove leading/trailing single/double quotes
value="${value%\"}"
value="${value#\"}"
value="${value%\'}"
value="${value#\'}"
# Remove surrounding whitespace again
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
printf '%s' "$value"
}
enabled() {
local value
value=$(strip "${1:-}")
case "${value,,}" in
y|yes|true|1|on|enable|enabled) return 0 ;;
*) return 1 ;;
esac
}
disabled() {
local value
value=$(strip "${1:-}")
case "${value,,}" in
n|no|none|false|0|off|disable|disabled) return 0 ;;
*) return 1 ;;
esac
}
formatBytes() {
local result
if ! result=$(numfmt --to=iec --suffix=B "$1" | sed -r 's/([A-Z])/ \1/' | sed 's/ B/ bytes/g;'); then
return 1
fi
local unit="${result//[0-9. ]}"
result="${result//[a-zA-Z ]/}"
if [[ "${2:-}" == "up" ]]; then
if [[ "$result" == *"."* ]]; then
result="${result%%.*}"
result=$((result+1))
fi
else
if [[ "${2:-}" == "down" ]]; then
result="${result%%.*}"
fi
fi
echo "$result $unit"
return 0
}
isAlive() {
local pid="$1"
[ -z "$pid" ] && return 1
if kill -0 "$pid" 2>/dev/null; then
return 0
fi
return 1
}
waitPid() {
local pid="$1"
local timeout="${2:-10}"
local deadline=$((SECONDS + timeout))
while [ -n "$pid" ] && isAlive "$pid"; do
(( SECONDS >= deadline )) && return 1
sleep 0.2
done
return 0
}
waitPidFile() {
local pid
local file="$1"
local timeout="${2:-10}"
local deadline=$((SECONDS + timeout))
readPidFile pid "$file" || return 0
while [ -s "$file" ] && isAlive "$pid"; do
(( SECONDS >= deadline )) && return 1
sleep 0.2
done
rm -f -- "$file"
return 0
}
pKill() {
local pid="$1"
local timeout="${2:-10}"
{ kill -15 -- "$pid" || :; } 2>/dev/null
if ! waitPid "$pid" "$timeout"; then
warn "Timed out while waiting for PID $pid"
fi
return 0
}
fWait() {
local name="$1"
local timeout="${2:-10}"
local deadline=$((SECONDS + timeout))
[ -z "$name" ] && return 0
while pgrep -f -l "$name" >/dev/null; do
if (( SECONDS >= deadline )); then
warn "Timed out while waiting for process: $name"
break
fi
sleep 0.2
done
return 0
}
fKill() {
local name="$1"
local timeout="${2:-10}"
[ -z "$name" ] && return 0
{ pkill -f "$name" || :; } 2>/dev/null
fWait "$name" "$timeout"
return 0
}
sKill() {
local pid
local file="$1"
readPidFile pid "$file" || return 0
if isAlive "$pid"; then
{ kill -15 -- "$pid" || :; } 2>/dev/null
fi
return 0
}
mKill() {
local timeout=10
local files=("$@")
for file in "${files[@]}"; do
sKill "$file"
done
for file in "${files[@]}"; do
if ! waitPidFile "$file" "$timeout"; then
warn "Timed out while waiting for PID file: $file"
fi
done
return 0
}
setOwner() {
local file="$1"
local dir uid gid
[ ! -f "$file" ] && return 1
dir=$(dirname -- "$file")
uid=$(stat -c '%u' "$dir") || return 1
gid=$(stat -c '%g' "$dir") || return 1
chown "$uid:$gid" "$file" || return 1
return 0
}
makeDir() {
local path="$1"
local dir uid gid
[ -d "$path" ] && return 0
mkdir -p "$path" || return 1
dir=$(dirname -- "$path")
if ! uid=$(stat -c '%u' "$dir") || ! gid=$(stat -c '%g' "$dir"); then
warn "failed to determine the owner for \"$path\"."
return 0
fi
if ! chown "$uid:$gid" "$path"; then
warn "failed to set the owner for \"$path\"."
return 0
fi
return 0
}
stateFile() {
local name="$1"
local prefix="${2:-$PROCESS}"
[[ "$name" == */* ]] && printf '%s\n' "$name" && return 0
printf '%s/%s.%s\n' "$STORAGE" "$prefix" "$name"
return 0
}
writeFile() {
local txt="$1"
local path="$2"
if ! printf '%s\n' "$txt" > "$path"; then
error "Failed to write file \"$path\" !"
return 1
fi
if ! setOwner "$path"; then
warn "failed to set the owner for \"$path\"."
fi
return 0
}
writeAtomic() {
local path="$1"
local content="$2"
local tmp="${path}.${BASHPID}.tmp"
if ! printf '%s\n' "$content" > "$tmp"; then
rm -f -- "$tmp"
return 1
fi
if ! mv -f -- "$tmp" "$path"; then
rm -f -- "$tmp"
return 1
fi
return 0
}
readFile() {
local path="$1"
local value
[ -s "$path" ] || return 0
value=$(<"$path") || return 1
value="${value//[![:print:]]/}"
printf '%s\n' "$value"
return 0
}
writeState() {
local name="$1"
local value="$2"
local prefix="${3:-$PROCESS}"
local path
[ -z "$value" ] && return 0
path=$(stateFile "$name" "$prefix") || return 1
writeFile "$value" "$path"
return $?
}
readState() {
local name="$1"
local prefix="${2:-$PROCESS}"
local path
path=$(stateFile "$name" "$prefix") || return 1
readFile "$path"
return $?
}
restoreState() {
local var="$1"
local name="$2"
local force="${3:-N}"
local prefix="${4:-$PROCESS}"
local value
if ! enabled "$force"; then
[ -z "${!var:-}" ] || return 0
fi
value=$(readState "$name" "$prefix") || return 1
[ -n "$value" ] || return 0
printf -v "$var" '%s' "$value" || return 1
return 0
}
escape () {
local s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
escapeXML() {
printf '%s' "$1" | sed \
-e 's/&/\&amp;/g' \
-e 's/</\&lt;/g' \
-e 's/>/\&gt;/g' \
-e 's/"/\&quot;/g' \
-e "s/'/\&apos;/g"
return 0
}
html() {
local title
local body
local script="${2:-}"
local footer
title=$(escape "$APP")
title="<title>$title</title>"
footer=$(escape "$FOOTER1")
body=$(escape "$1")
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
local HTML
HTML=$(<"$TEMPLATE")
HTML="${HTML/\[1\]/$title}"
HTML="${HTML/\[2\]/$script}"
HTML="${HTML/\[3\]/$body}"
HTML="${HTML/\[4\]/$footer}"
HTML="${HTML/\[5\]/$FOOTER2}"
writeAtomic "$PAGE" "$HTML" || return 1
writeAtomic "$INFO" "$body" || return 1
return 0
}
cpu() {
local ret
local cpu=""
ret=$(lscpu)
if grep -qi "model name" <<< "$ret"; then
cpu=$(echo "$ret" | grep -m 1 -i 'model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi
if [ -z "${cpu// /}" ] && grep -qi "model:" <<< "$ret"; then
cpu=$(echo "$ret" | grep -m 1 -i 'model:' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi
cpu="${cpu// CPU/}"
cpu="${cpu// [0-9][0-9][0-9] Core}"
cpu="${cpu// [0-9][0-9] Core}"
cpu="${cpu// [0-9] Core}"
cpu="${cpu//[0-9][0-9]th Gen }"
cpu="${cpu//[0-9]th Gen }"
cpu="${cpu// Processor/}"
cpu="${cpu// Quad core/}"
cpu="${cpu// Dual core/}"
cpu="${cpu// Octa core/}"
cpu="${cpu// Hexa core/}"
cpu="${cpu// Core TM/ Core}"
cpu="${cpu// with Radeon Graphics/}"
cpu="${cpu// with Radeon Vega Graphics/}"
cpu="${cpu// with Radeon Vega Mobile Gfx/}"
cpu="${cpu// w Radeon [0-9][0-9][0-9]M Graphics/}"
[ -z "${cpu// /}" ] && cpu="Unknown"
echo "$cpu"
return 0
}
getCountry() {
local url=$1
local query=$2
local json result
{ json=$(curl -m 5 -H "Accept: application/json" -sfk "$url"); local rc=$?; } || :
(( rc != 0 )) && return 0
{ result=$(echo "$json" | jq -r "$query" 2> /dev/null); rc=$?; } || :
(( rc != 0 )) && return 0
[[ ${#result} -ne 2 ]] && return 0
[[ "${result^^}" == "XX" ]] && return 0
COUNTRY="${result^^}"
return 0
}
setCountry() {
[[ "${TZ,,}" == "asia/harbin" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/beijing" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/urumqi" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/kashgar" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/shanghai" ]] && COUNTRY="CN"
[[ "${TZ,,}" == "asia/chongqing" ]] && COUNTRY="CN"
[ -z "$COUNTRY" ] && getCountry "https://api.ipapi.is" ".location.country_code"
[ -z "$COUNTRY" ] && getCountry "https://ifconfig.co/json" ".country_iso"
[ -z "$COUNTRY" ] && getCountry "https://api.ip2location.io" ".country_code"
[ -z "$COUNTRY" ] && getCountry "https://ipinfo.io/json" ".country"
[ -z "$COUNTRY" ] && getCountry "https://api.ipquery.io/?format=json" ".location.country_code"
[ -z "$COUNTRY" ] && getCountry "https://api.myip.com" ".cc"
return 0
}
addPackage() {
local pkg=$1
local desc=$2
if apt-mark showinstall | grep -qx "$pkg"; then
return 0
fi
MSG="Installing $desc..."
info "$MSG" && html "$MSG"
[ -z "$COUNTRY" ] && setCountry
if [[ "${COUNTRY^^}" == "CN" ]]; then
sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
fi
DEBIAN_FRONTEND=noninteractive apt-get -qq update || return 1
DEBIAN_FRONTEND=noninteractive apt-get -qq --no-install-recommends -y install "$pkg" > /dev/null || return 1
return 0
}
return 0
+44
View File
@@ -0,0 +1,44 @@
server {
listen 5000 default_server;
autoindex on;
tcp_nodelay on;
server_tokens off;
absolute_redirect off;
error_log /dev/null;
access_log /dev/null;
include /etc/nginx/mime.types;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 500;
gzip_disable "msie6";
gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
add_header Cache-Control "no-cache";
location / {
root /run/shm;
index index.html;
}
location /status {
proxy_http_version 1.1;
proxy_set_header Connection 'upgrade';
proxy_set_header Upgrade $http_upgrade;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_pass http://127.0.0.1:8004/;
}
}
+167
View File
@@ -0,0 +1,167 @@
body {
color: white;
background-color: #125bdb;
font-smoothing: antialiased;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: Verdana, Geneva, sans-serif;
}
#info {
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.25);
}
#content {
text-align: center;
padding: 20px;
margin-top: 50px;
}
footer {
width: 98%;
position: fixed;
bottom: 0px;
height: 40px;
text-align: center;
color: #0c8aeb;
text-shadow: 0 0 1px #0c8aeb;
}
#empty {
height: 40px;
/* Same height as footer */
}
a,
a:hover,
a:active,
a:visited {
color: white;
}
footer a:link,
footer a:visited,
footer a:active {
color: #0c8aeb;
}
footer a:hover {
color: #73e6ff;
}
.loading:after {
content: " .";
animation: dots 1s steps(5, end) infinite;
}
@keyframes dots {
0%,
20% {
color: rgba(0, 0, 0, 0);
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
}
40% {
color: white;
text-shadow: 0.25em 0 0 rgba(0, 0, 0, 0), 0.5em 0 0 rgba(0, 0, 0, 0);
}
60% {
text-shadow: 0.25em 0 0 white, 0.5em 0 0 rgba(0, 0, 0, 0);
}
80%,
100% {
text-shadow: 0.25em 0 0 white, 0.5em 0 0 white;
}
}
.spinner_LWk7 {
animation: spinner_GWy6 1.2s linear infinite, spinner_BNNO 1.2s linear infinite
}
.spinner_yOMU {
animation: spinner_GWy6 1.2s linear infinite, spinner_pVqn 1.2s linear infinite;
animation-delay: .15s
}
.spinner_KS4S {
animation: spinner_GWy6 1.2s linear infinite, spinner_6uKB 1.2s linear infinite;
animation-delay: .3s
}
.spinner_zVee {
animation: spinner_GWy6 1.2s linear infinite, spinner_Qw4x 1.2s linear infinite;
animation-delay: .45s
}
@keyframes spinner_GWy6 {
0%,
50% {
width: 9px;
height: 9px
}
10% {
width: 11px;
height: 11px
}
}
@keyframes spinner_BNNO {
0%,
50% {
x: 1.5px;
y: 1.5px
}
10% {
x: .5px;
y: .5px
}
}
@keyframes spinner_pVqn {
0%,
50% {
x: 13.5px;
y: 1.5px
}
10% {
x: 12.5px;
y: .5px
}
}
@keyframes spinner_6uKB {
0%,
50% {
x: 13.5px;
y: 13.5px
}
10% {
x: 12.5px;
y: 12.5px
}
}
@keyframes spinner_Qw4x {
0%,
50% {
x: 1.5px;
y: 13.5px
}
10% {
x: .5px;
y: 12.5px
}
}
+1
View File
@@ -0,0 +1 @@
<svg id="Capa_1" enable-background="new 0 0 511.962 511.962" height="512" viewBox="0 0 511.962 511.962" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m489.965 120.063c0-5.77-3.31-11.028-8.512-13.524l-218.984-105.063c-4.102-1.967-8.875-1.967-12.977 0l-218.985 105.063c-5.202 2.496-8.511 7.755-8.511 13.524l-.003 271.834c0 5.77 3.31 11.028 8.512 13.524l218.989 105.064c2.051.983 4.27 1.476 6.488 1.476 2.219 0 4.438-.492 6.488-1.476l218.989-105.064c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#4e6ba6"/><path d="m489.965 120.063c0-5.77-3.31-11.028-8.512-13.524l-218.984-105.063c-2.051-.984-4.269-1.476-6.488-1.476v511.962c2.219 0 4.438-.492 6.488-1.476l218.989-105.064c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#28487a"/><path d="m425.812 160.441c0-2.27-.519-4.457-1.457-6.432l-336.701-.095c-.967 1.999-1.504 4.22-1.504 6.526l-.002 191.081c0 5.769 3.31 11.028 8.512 13.524l154.833 74.285c2.051.983 4.27 1.476 6.488 1.476 2.219 0 4.438-.492 6.488-1.476l154.834-74.285c5.202-2.496 8.512-7.755 8.512-13.524z" fill="#8dc2eb"/><path d="m424.354 154.009h-168.373v286.798c2.219 0 4.438-.492 6.488-1.476l154.834-74.285c5.202-2.496 8.512-7.755 8.512-13.524l-.003-191.081c0-2.27-.52-4.458-1.458-6.432z" fill="#5e9ff6"/><path d="m417.3 146.916-154.831-74.284c-4.102-1.967-8.875-1.967-12.977 0l-154.831 74.284c-3.122 1.498-5.555 3.996-7.007 6.998l168.328 80.812 168.374-80.717c-1.448-3.044-3.9-5.579-7.056-7.093z" fill="#ecf9fd"/><path d="m417.3 146.916-154.831-74.284c-2.051-.983-4.27-1.476-6.488-1.476v163.569l168.374-80.717c-1.447-3.043-3.899-5.578-7.055-7.092z" fill="#d9f3fc"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+34
View File
@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
[1]
<meta http-equiv="Cache-Control" content="no-cache" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
<link rel="icon" href="img/favicon.svg" type="image/x-icon">
[2]
</head>
<body>
<div id="page">
<div id="content">
<svg id="spinner" width="64" height="64" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<rect class="spinner_LWk7" fill="#0c8aeb" x="1.5" y="1.5" rx="1" width="9" height="9"/>
<rect class="spinner_yOMU" fill="#0c8aeb" x="13.5" y="1.5" rx="1" width="9" height="9"/>
<rect class="spinner_KS4S" fill="#0c8aeb" x="13.5" y="13.5" rx="1" width="9" height="9"/>
<rect class="spinner_zVee" fill="#0c8aeb" x="1.5" y="13.5" rx="1" width="9" height="9"/>
</svg>
<h1 id="info">[3]</h1>
</div>
<div id="empty">
</div>
<footer id="footer">
[4]<br />
[5]
</footer>
</div>
<script type="text/javascript" src="js/script.js"></script>
</body>
</html>
+248
View File
@@ -0,0 +1,248 @@
var timer;
var request;
var booting = false;
var interval = 1000;
function abortRequest() {
if (!request) {
return false;
}
request.onreadystatechange = null;
request.abort();
request = null;
return true;
}
function getInfo() {
var url = "msg.html";
try {
abortRequest();
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else {
throw new Error("XMLHttpRequest not available!");
}
request.onreadystatechange = processInfo;
request.open("GET", url, true);
request.send();
} catch (e) {
setError("Error: " + e.message);
}
}
function getURL() {
var protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
var path = window.location.pathname.replace(/[^/]*$/, '').replace(/\/$/, '');
return protocol + "//" + window.location.host + path;
}
function processMsg(msg) {
if (msg.toLowerCase().indexOf("href=") !== -1) {
var div = document.createElement("div");
div.innerHTML = msg;
var url = div.querySelector("a").href;
setTimeout(() => {
window.location.assign(url);
}, 3000);
}
setInfo(msg);
return true;
}
function processInfo() {
try {
if (request.readyState != 4) {
return true;
}
var response = request;
request = null;
var status = response.status;
if (status == 502 || status == 503 || status == 504) {
schedule();
return true;
}
var msg = response.responseText;
if (msg == null || msg.length == 0) {
if (booting) {
schedule();
return true;
}
window.location.reload();
return false;
}
var notFound = (status == 404);
if (status == 200) {
if (msg.toLowerCase().indexOf("<html>") !== -1) {
notFound = true;
} else {
processMsg(msg);
if (msg.toLowerCase().indexOf("href=") == -1) {
schedule();
}
return true;
}
}
if (notFound) {
setInfo("Connecting to web portal", true);
reload();
return true;
}
setError("Error: Received statuscode " + status);
return false;
} catch (e) {
setError("Error: " + e.message);
return false;
}
}
function extractContent(s) {
var span = document.createElement('span');
span.innerHTML = s;
return span.textContent || span.innerText;
};
function setInfo(msg, loading, error) {
try {
if (msg == null || msg.length == 0) {
return false;
}
if (msg.includes("Booting ")) {
booting = true;
}
var el = document.getElementById("info");
if (el.innerText == msg || el.innerHTML == msg) {
return true;
}
var spin = document.getElementById("spinner");
error = !!error;
if (!error) {
spin.style.visibility = 'visible';
} else {
spin.style.visibility = 'hidden';
}
var p = "<p class=\"loading\">";
loading = !!loading;
if (loading) {
msg = p + msg + "</p>";
}
if (msg.includes(p)) {
if (el.innerHTML.includes(p)) {
el.getElementsByClassName('loading')[0].textContent = extractContent(msg);
return true;
}
}
el.innerHTML = msg;
return true;
} catch (e) {
console.log("Error: " + e.message);
return false;
}
}
function setError(text) {
console.warn(text);
return setInfo(text, false, true);
}
function schedule() {
clearTimeout(timer);
timer = setTimeout(getInfo, interval);
}
function reload() {
setTimeout(() => {
window.location.reload();
}, 3000);
}
function connect() {
var wsUrl = getURL() + "/status";
var ws = new WebSocket(wsUrl);
ws.onmessage = function(e) {
var pos = e.data.indexOf(":");
var cmd = e.data.substring(0, pos);
var msg = e.data.substring(pos + 2);
switch (cmd) {
case "s":
var aborted = abortRequest();
processMsg(msg);
if (aborted &&
msg.toLowerCase().indexOf("href=") == -1) {
schedule();
}
break;
case "e":
if (abortRequest()) {
schedule();
}
setError(msg);
break;
default:
console.warn("Unknown event: " + cmd);
break;
}
};
ws.onclose = function(e) {
setTimeout(function() {
connect();
}, interval);
};
ws.onerror = function(e) {
ws.close();
if (!booting) {
window.location.reload();
}
};
}
schedule();
connect();