Compare commits

..

6 Commits

Author SHA1 Message Date
CanbiZ
f338036ed2 Update copyright years to 2026 in core scripts
Updated the copyright year from 2025 to 2026 in alpine-install.func, api.func, and cloud-init.func to reflect the new year. No functional changes were made.
2026-01-07 20:43:01 +01:00
CanbiZ
b38083e8c9 Update error-handler.func 2026-01-07 20:42:10 +01:00
CanbiZ
633612cd8f Enhance hardware acceleration and MariaDB setup
Refactors and expands the hardware acceleration setup to support multiple GPU types (Intel, AMD, NVIDIA), adds user selection for GPU configuration, and improves driver installation logic for Debian and Ubuntu. Adds runtime directory persistence for MariaDB using tmpfiles.d to ensure /run/mysqld exists after reboot. Includes minor robustness improvements and error handling throughout the script.
2026-01-07 20:41:58 +01:00
CanbiZ
e6d11196bd update install.func 2026-01-07 20:41:34 +01:00
CanbiZ
cf36b1b86a Add advanced container features and IP range scanning
Introduces support for scanning and assigning the first free IP from a user-specified range, and expands advanced LXC container settings to include GPU passthrough, TUN/TAP, nesting, keyctl, mknod, timezone, protection, and APT cacher options. Refactors advanced_settings wizard to support these new features, updates variable handling and defaults, and improves summary and output formatting. Also enhances SSH key configuration, storage/template validation, and GPU passthrough logic.
2026-01-07 20:40:33 +01:00
CanbiZ
be7fadeee2 update core.func 2026-01-07 20:36:54 +01:00
9 changed files with 634 additions and 667 deletions

View File

@@ -4,7 +4,7 @@
## 🔗 Related PR / Issue ## 🔗 Related PR / Issue
Fixes: # Link: #
## ✅ Prerequisites (**X** in brackets) ## ✅ Prerequisites (**X** in brackets)

View File

@@ -1 +1 @@
0.5.4 0.5.2

841
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,33 +25,33 @@
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@prisma/adapter-better-sqlite3": "^7.2.0", "@prisma/adapter-better-sqlite3": "^7.1.0",
"@prisma/client": "^7.2.0", "@prisma/client": "^7.1.0",
"@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-slot": "^1.2.4",
"@t3-oss/env-nextjs": "^0.13.10", "@t3-oss/env-nextjs": "^0.13.10",
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
"@tanstack/react-query": "^5.90.16", "@tanstack/react-query": "^5.90.12",
"@trpc/client": "^11.8.1", "@trpc/client": "^11.8.0",
"@trpc/react-query": "^11.8.1", "@trpc/react-query": "^11.8.1",
"@trpc/server": "^11.8.1", "@trpc/server": "^11.8.0",
"@types/react-syntax-highlighter": "^15.5.13", "@types/react-syntax-highlighter": "^15.5.13",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"@xterm/addon-fit": "^0.11.0", "@xterm/addon-fit": "^0.10.0",
"@xterm/addon-web-links": "^0.12.0", "@xterm/addon-web-links": "^0.11.0",
"@xterm/xterm": "^6.0.0", "@xterm/xterm": "^5.5.0",
"axios": "^1.13.2", "axios": "^1.13.2",
"bcryptjs": "^3.0.3", "bcryptjs": "^3.0.3",
"better-sqlite3": "^12.6.0", "better-sqlite3": "^12.5.0",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"cron-validator": "^1.4.0", "cron-validator": "^1.4.0",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"jsonwebtoken": "^9.0.3", "jsonwebtoken": "^9.0.3",
"lucide-react": "^0.562.0", "lucide-react": "^0.561.0",
"next": "^16.1.1", "next": "^16.0.10",
"node-cron": "^4.2.1", "node-cron": "^4.2.1",
"node-pty": "^1.1.0", "node-pty": "^1.0.0",
"react": "^19.2.3", "react": "^19.2.3",
"react-dom": "^19.2.3", "react-dom": "^19.2.3",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
@@ -62,37 +62,37 @@
"strip-ansi": "^7.1.2", "strip-ansi": "^7.1.2",
"superjson": "^2.2.6", "superjson": "^2.2.6",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"ws": "^8.19.0", "ws": "^8.18.3",
"zod": "^4.3.5" "zod": "^4.1.13"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/postcss": "^4.1.18", "@tailwindcss/postcss": "^4.1.18",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1", "@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1", "@testing-library/user-event": "^14.6.1",
"@types/bcryptjs": "^3.0.0", "@types/bcryptjs": "^3.0.0",
"@types/better-sqlite3": "^7.6.13", "@types/better-sqlite3": "^7.6.13",
"@types/jsonwebtoken": "^9.0.10", "@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.10.4", "@types/node": "^24.10.4",
"@types/node-cron": "^3.0.11", "@types/node-cron": "^3.0.11",
"@types/react": "^19.2.8", "@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3", "@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2", "@vitejs/plugin-react": "^5.1.2",
"@vitest/coverage-v8": "^4.0.17", "@vitest/coverage-v8": "^4.0.15",
"@vitest/ui": "^4.0.17", "@vitest/ui": "^4.0.14",
"baseline-browser-mapping": "^2.9.14", "baseline-browser-mapping": "^2.9.3",
"eslint": "^9.39.2", "eslint": "^9.39.1",
"eslint-config-next": "^16.1.1", "eslint-config-next": "^16.1.0",
"jsdom": "^27.4.0", "jsdom": "^27.3.0",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"prettier": "^3.7.4", "prettier": "^3.7.4",
"prettier-plugin-tailwindcss": "^0.7.2", "prettier-plugin-tailwindcss": "^0.7.2",
"prisma": "^7.2.0", "prisma": "^7.1.0",
"tailwindcss": "^4.1.18", "tailwindcss": "^4.1.18",
"tsx": "^4.21.0", "tsx": "^4.21.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"typescript-eslint": "^8.53.0", "typescript-eslint": "^8.48.1",
"vitest": "^4.0.17" "vitest": "^4.0.14"
}, },
"ct3aMetadata": { "ct3aMetadata": {
"initVersion": "7.39.3" "initVersion": "7.39.3"

View File

@@ -517,16 +517,11 @@ base_settings() {
fi fi
fi fi
# Format optional network variables with proper prefixes for pct create MTU=${var_mtu:-""}
# Also strip any spaces from nameserver values (multiple IPs must be comma-separated without spaces) SD=${var_storage:-""}
local _ns_clean="${var_ns:-}" NS=${var_ns:-""}
_ns_clean="${_ns_clean// /}" # Remove all spaces from nameserver value MAC=${var_mac:-""}
VLAN=${var_vlan:-""}
[[ -n "${var_mtu:-}" ]] && MTU=",mtu=${var_mtu}" || MTU=""
[[ -n "${var_searchdomain:-}" ]] && SD="-searchdomain=${var_searchdomain}" || SD=""
[[ -n "$_ns_clean" ]] && NS="-nameserver=${_ns_clean}" || NS=""
[[ -n "${var_mac:-}" ]] && MAC=",hwaddr=${var_mac}" || MAC=""
[[ -n "${var_vlan:-}" ]] && VLAN=",tag=${var_vlan}" || VLAN=""
SSH=${var_ssh:-"no"} SSH=${var_ssh:-"no"}
SSH_AUTHORIZED_KEY=${var_ssh_authorized_key:-""} SSH_AUTHORIZED_KEY=${var_ssh_authorized_key:-""}
UDHCPC_FIX=${var_udhcpc_fix:-""} UDHCPC_FIX=${var_udhcpc_fix:-""}
@@ -2028,11 +2023,10 @@ Advanced:
var_apt_cacher="$_apt_cacher" var_apt_cacher="$_apt_cacher"
var_apt_cacher_ip="$_apt_cacher_ip" var_apt_cacher_ip="$_apt_cacher_ip"
# Format optional values (strip spaces from nameserver - multiple IPs must be comma-separated without spaces) # Format optional values
local _ns_clean="${_ns// /}"
[[ -n "$_mtu" ]] && MTU=",mtu=$_mtu" || MTU="" [[ -n "$_mtu" ]] && MTU=",mtu=$_mtu" || MTU=""
[[ -n "$_sd" ]] && SD="-searchdomain=$_sd" || SD="" [[ -n "$_sd" ]] && SD="-searchdomain=$_sd" || SD=""
[[ -n "$_ns_clean" ]] && NS="-nameserver=$_ns_clean" || NS="" [[ -n "$_ns" ]] && NS="-nameserver=$_ns" || NS=""
[[ -n "$_mac" ]] && MAC=",hwaddr=$_mac" || MAC="" [[ -n "$_mac" ]] && MAC=",hwaddr=$_mac" || MAC=""
[[ -n "$_vlan" ]] && VLAN=",tag=$_vlan" || VLAN="" [[ -n "$_vlan" ]] && VLAN=",tag=$_vlan" || VLAN=""

View File

@@ -16,7 +16,7 @@ export function Footer({ onOpenReleaseNotes }: FooterProps) {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="flex flex-col sm:flex-row items-center justify-between gap-2 text-sm text-muted-foreground"> <div className="flex flex-col sm:flex-row items-center justify-between gap-2 text-sm text-muted-foreground">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span>© 2026 PVE Scripts Local</span> <span>© 2024 PVE Scripts Local</span>
{versionData?.success && versionData.version && ( {versionData?.success && versionData.version && (
<Button <Button
variant="ghost" variant="ghost"

View File

@@ -1,22 +1,9 @@
import 'dotenv/config' import 'dotenv/config'
import { PrismaClient } from '../../prisma/generated/prisma/client.ts' import { PrismaClient } from '../../prisma/generated/prisma/client.ts'
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3' import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
import { existsSync, mkdirSync } from 'fs'
import { dirname } from 'path'
const globalForPrisma = globalThis; const globalForPrisma = globalThis;
// Ensure database directory exists before initializing Prisma
// DATABASE_URL format: file:/path/to/database.db
const dbUrl = process.env.DATABASE_URL || 'file:./data/settings.db';
const dbPath = dbUrl.replace(/^file:/, '');
const dbDir = dirname(dbPath);
if (!existsSync(dbDir)) {
console.log(`Creating database directory: ${dbDir}`);
mkdirSync(dbDir, { recursive: true });
}
const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL }); const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL });
export const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter }); export const prisma = globalForPrisma.prisma ?? new PrismaClient({ adapter });

View File

@@ -1,22 +1,9 @@
import 'dotenv/config' import 'dotenv/config'
import { PrismaClient } from '../../prisma/generated/prisma/client' import { PrismaClient } from '../../prisma/generated/prisma/client'
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3' import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
import { existsSync, mkdirSync } from 'fs'
import { dirname } from 'path'
const globalForPrisma = globalThis as { prisma?: PrismaClient }; const globalForPrisma = globalThis as { prisma?: PrismaClient };
// Ensure database directory exists before initializing Prisma
// DATABASE_URL format: file:/path/to/database.db
const dbUrl = process.env.DATABASE_URL || 'file:./data/settings.db';
const dbPath = dbUrl.replace(/^file:/, '');
const dbDir = dirname(dbPath);
if (!existsSync(dbDir)) {
console.log(`Creating database directory: ${dbDir}`);
mkdirSync(dbDir, { recursive: true });
}
const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL! }); const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL! });
export const prisma: PrismaClient = globalForPrisma.prisma ?? new PrismaClient({ export const prisma: PrismaClient = globalForPrisma.prisma ?? new PrismaClient({

View File

@@ -418,12 +418,6 @@ restore_backup_files() {
verify_database_restored() { verify_database_restored() {
log "Verifying database was restored correctly..." log "Verifying database was restored correctly..."
# Ensure data directory exists (will be auto-created by app if needed)
if [ ! -d "data" ]; then
log "Creating data directory..."
mkdir -p data
fi
# Check for both possible database filenames # Check for both possible database filenames
local db_file="" local db_file=""
if [ -f "data/database.sqlite" ]; then if [ -f "data/database.sqlite" ]; then
@@ -431,10 +425,8 @@ verify_database_restored() {
elif [ -f "data/settings.db" ]; then elif [ -f "data/settings.db" ]; then
db_file="data/settings.db" db_file="data/settings.db"
else else
# Database doesn't exist yet - this is OK for new installations log_error "Database file not found after restore! (checked database.sqlite and settings.db)"
# The app will create it automatically via Prisma migrations return 1
log_warning "No existing database file found - will be created automatically on first start"
return 0
fi fi
local db_size=$(stat -f%z "$db_file" 2>/dev/null || stat -c%s "$db_file" 2>/dev/null) local db_size=$(stat -f%z "$db_file" 2>/dev/null || stat -c%s "$db_file" 2>/dev/null)
@@ -489,9 +481,11 @@ check_service() {
fi fi
} }
# Stop the application before updating # Stop the application before updating
stop_application() { stop_application() {
# Change to the application directory if we're not already there # Change to the application directory if we're not already there
local app_dir local app_dir
if [ -f "package.json" ] && [ -f "server.js" ]; then if [ -f "package.json" ] && [ -f "server.js" ]; then
@@ -630,6 +624,7 @@ update_files() {
log_success "Application files updated successfully ($files_copied files)" log_success "Application files updated successfully ($files_copied files)"
} }
# Install dependencies and build # Install dependencies and build
install_and_build() { install_and_build() {
log "Installing dependencies..." log "Installing dependencies..."
@@ -710,14 +705,11 @@ install_and_build() {
log "Building application..." log "Building application..."
# Set NODE_ENV to production for build # Set NODE_ENV to production for build
export NODE_ENV=production export NODE_ENV=production
# Unset TURBOPACK to prevent "Multiple bundler flags" error with --webpack
unset TURBOPACK 2>/dev/null || true
export TURBOPACK=''
# Create temporary file for npm build output # Create temporary file for npm build output
local build_log="/tmp/npm_build_$$.log" local build_log="/tmp/npm_build_$$.log"
if ! TURBOPACK='' npm run build >"$build_log" 2>&1; then if ! npm run build > "$build_log" 2>&1; then
log_error "Failed to build application" log_error "Failed to build application"
log_error "npm run build output:" log_error "npm run build output:"
cat "$build_log" | while read -r line; do cat "$build_log" | while read -r line; do
@@ -784,23 +776,6 @@ start_with_npm() {
fi fi
} }
# Re-enable the systemd service on failure to prevent users from being locked out
re_enable_service_on_failure() {
if check_service; then
log "Re-enabling systemd service after failure..."
if systemctl enable pvescriptslocal.service 2>/dev/null; then
log_success "Service re-enabled"
if systemctl start pvescriptslocal.service 2>/dev/null; then
log_success "Service started"
else
log_warning "Failed to start service - manual intervention may be required"
fi
else
log_warning "Failed to re-enable service - manual intervention may be required"
fi
fi
}
# Rollback function # Rollback function
rollback() { rollback() {
log_warning "Rolling back to previous version..." log_warning "Rolling back to previous version..."
@@ -872,9 +847,6 @@ rollback() {
log_error "No backup directory found for rollback" log_error "No backup directory found for rollback"
fi fi
# Re-enable the service so users aren't locked out
re_enable_service_on_failure
log_error "Update failed. Please check the logs and try again." log_error "Update failed. Please check the logs and try again."
exit 1 exit 1
} }
@@ -893,14 +865,14 @@ check_node_version() {
log "Detected Node.js version: $current" log "Detected Node.js version: $current"
if ((major_version == 24)); then if (( major_version < 24 )); then
log_success "Node.js 24 already installed"
elif ((major_version < 24)); then
log_warning "Node.js < 24 detected → upgrading to Node.js 24 LTS..." log_warning "Node.js < 24 detected → upgrading to Node.js 24 LTS..."
upgrade_node_to_24 upgrade_node_to_24
else elif (( major_version > 24 )); then
log_warning "Node.js > 24 detected → script tested only up to Node 24" log_warning "Node.js > 24 detected → script tested only up to Node 24"
log "Continuing anyway…" log "Continuing anyway…"
else
log_success "Node.js 24 already installed"
fi fi
} }
@@ -908,39 +880,22 @@ check_node_version() {
upgrade_node_to_24() { upgrade_node_to_24() {
log "Preparing Node.js 24 upgrade…" log "Preparing Node.js 24 upgrade…"
# Remove old nodesource repo files if they exist # Remove old nodesource repo if it exists
if [ -f /etc/apt/sources.list.d/nodesource.list ]; then if [ -f /etc/apt/sources.list.d/nodesource.list ]; then
log "Removing old nodesource.list file..."
rm -f /etc/apt/sources.list.d/nodesource.list rm -f /etc/apt/sources.list.d/nodesource.list
fi fi
if [ -f /etc/apt/sources.list.d/nodesource.sources ]; then
log "Removing old nodesource.sources file..."
rm -f /etc/apt/sources.list.d/nodesource.sources
fi
# Update apt cache first
log "Updating apt cache..."
apt-get update >>"$LOG_FILE" 2>&1 || true
# Install NodeSource repo for Node.js 24 # Install NodeSource repo for Node.js 24
log "Downloading Node.js 24 setup script..." curl -fsSL https://deb.nodesource.com/setup_24.x -o /tmp/node24_setup.sh
if ! curl -fsSL https://deb.nodesource.com/setup_24.x -o /tmp/node24_setup.sh; then
log_error "Failed to download Node.js 24 setup script"
re_enable_service_on_failure
exit 1
fi
if ! bash /tmp/node24_setup.sh > /tmp/node24_setup.log 2>&1; then if ! bash /tmp/node24_setup.sh > /tmp/node24_setup.log 2>&1; then
log_error "Failed to configure Node.js 24 repository" log_error "Failed to configure Node.js 24 repository"
tail -20 /tmp/node24_setup.log | while read -r line; do log_error "$line"; done tail -20 /tmp/node24_setup.log | while read -r line; do log_error "$line"; done
re_enable_service_on_failure
exit 1 exit 1
fi fi
log "Installing Node.js 24…" log "Installing Node.js 24…"
if ! apt-get install -y nodejs >> "$LOG_FILE" 2>&1; then if ! apt-get install -y nodejs >> "$LOG_FILE" 2>&1; then
log_error "Failed to install Node.js 24" log_error "Failed to install Node.js 24"
re_enable_service_on_failure
exit 1 exit 1
fi fi
@@ -1015,6 +970,9 @@ main() {
# Check Node.js version # Check Node.js version
check_node_version check_node_version
#Update Node.js to 24
upgrade_node_to_24
# Download and extract release # Download and extract release
local source_dir local source_dir
source_dir=$(download_release "$release_info") source_dir=$(download_release "$release_info")