mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-14 18:56:52 +00:00
scope the change journal to host changes, in three sections
The change journal exists so a sysadmin sees what ProxMenux changed on the host — its own configuration, packages and services — not how it uses the host or configures a guest. Several scripts recorded operations that are neither: disk passthrough to a VM, container conversions, VM import/export, mounting a share into an LXC. Those are restored to their original, uninstrumented form. Scripts that operate on the host while also installing a package now record only the package: format-disk keeps its exFAT-tools install, the UUP ISO builder its build dependencies, and the share/host scripts their packages, services and /etc/fstab writes, while the mount and unmount operations they used to log are dropped. The page now reads in three sections: what ProxMenux optimized after install (each function under its menu name), what its other host scripts changed (by script), and what it installed (packages and utilities, each referencing the script that installed it). A file reads as created or modified with its diff, a service shows its state transition, and the undo line appears only when a revert is possible.
This commit is contained in:
@@ -81,6 +81,67 @@ function undoKey(change: { revert: string; exactness: string }): string {
|
||||
return `exactness.${change.exactness}`
|
||||
}
|
||||
|
||||
const FN_LABEL: Record<string, string> = {
|
||||
apply_amd_fixes: "Apply AMD CPU fixes",
|
||||
apply_network_optimizations: "Apply network optimizations",
|
||||
apt_upgrade: "Update and upgrade system",
|
||||
cleanup_duplicate_repos_pve9: "Configure Proxmox APT repositories",
|
||||
configure_fastfetch: "Install and configure Fastfetch",
|
||||
configure_figurine: "Install Figurine",
|
||||
configure_kernel_panic: "Enable restart on kernel panic",
|
||||
configure_log2ram: "Install and configure Log2RAM",
|
||||
configure_pigz: "Use pigz for faster gzip compression",
|
||||
configure_time_sync: "Synchronize time automatically",
|
||||
customize_bashrc: "Customize bashrc",
|
||||
disable_rpc: "Disable portmapper/rpcbind",
|
||||
enable_ha: "Enable High Availability services",
|
||||
enable_kexec: "Enable fast reboots",
|
||||
enable_tcp_fast_open: "Enable TCP BBR/Fast Open control",
|
||||
enable_vfio_iommu: "Enable VFIO IOMMU support",
|
||||
enable_zfs_autotrim: "Enable ZFS autotrim (SSD/NVMe pools)",
|
||||
force_apt_ipv4: "Force APT to use IPv4",
|
||||
increase_system_limits: "Increase various system limits",
|
||||
install_ceph: "Add latest Ceph support",
|
||||
install_guest_agent: "Install relevant guest agent",
|
||||
install_log2ram: "Install and configure Log2RAM",
|
||||
install_log2ram_auto: "Install and configure Log2RAM",
|
||||
install_openvswitch: "Install Open vSwitch",
|
||||
install_ovh_rtm: "Install OVH Real Time Monitoring",
|
||||
install_system_utils: "Install common system utilities",
|
||||
install_zfs_auto_snapshot: "Install ZFS auto-snapshot",
|
||||
optimize_journald: "Optimize journald",
|
||||
optimize_logrotate: "Optimize logrotate",
|
||||
optimize_memory_settings: "Optimize Memory",
|
||||
optimize_vzdump: "Increase vzdump backup speed",
|
||||
optimize_zfs_arc: "Optimize ZFS ARC size",
|
||||
remove_subscription_banner: "Remove subscription banner",
|
||||
setup_motd: "Set up custom MOTD banner",
|
||||
setup_persistent_network: "Interface Names (persistent)",
|
||||
setup_proxmox_repositories: "Configure Proxmox APT repositories",
|
||||
skip_apt_languages: "Skip downloading additional languages",
|
||||
update_pve8: "Update and upgrade system",
|
||||
update_pve9: "Update and upgrade system",
|
||||
update_pve_appliance_manager: "Update Proxmox VE Appliance Manager",
|
||||
}
|
||||
|
||||
// Post-install functions run from the auto/customizable scripts; everything
|
||||
// else is a general host script (nvidia/tpu installers, PVE update, vfio…).
|
||||
const POST_INSTALL_SOURCES = new Set(["auto", "customizable"])
|
||||
|
||||
// Which of the three sections a change belongs to: installations are their
|
||||
// own block, post-install optimizations another, general scripts the rest.
|
||||
function blockOf(c: { class: string; source: string }): "installs" | "postInstall" | "scripts" {
|
||||
if (c.class === "installation") return "installs"
|
||||
if (POST_INSTALL_SOURCES.has(c.source)) return "postInstall"
|
||||
return "scripts"
|
||||
}
|
||||
|
||||
// A post-install function shows its menu name; anything else shows the script
|
||||
// that made the change.
|
||||
function groupLabel(fn: string, source: string): string {
|
||||
return FN_LABEL[fn] || source || fn || "—"
|
||||
}
|
||||
|
||||
const CLASS_STYLE: Record<string, { chip: string; Icon: typeof Settings2 }> = {
|
||||
configuration: { chip: "bg-blue-500/10 text-blue-400 border-blue-400/20", Icon: Settings2 },
|
||||
installation: { chip: "bg-green-500/10 text-green-500 border-green-500/20", Icon: Package },
|
||||
@@ -226,6 +287,62 @@ function ChangeCard({ change, expanded, onToggle, t, when }: {
|
||||
)
|
||||
}
|
||||
|
||||
function GroupSection({ title, groups, openFn, toggleFn, open, toggle, t, when }: {
|
||||
title: string
|
||||
groups: { key: string; label: string; version: string; last: number; items: Change[] }[]
|
||||
openFn: Set<string>; toggleFn: (k: string) => void
|
||||
open: Set<number>; toggle: (id: number) => void
|
||||
t: (k: string, params?: Record<string, string>) => string
|
||||
when: (n: number) => string
|
||||
}) {
|
||||
if (groups.length === 0) return null
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-sm font-semibold text-foreground px-1">{title}</h3>
|
||||
{groups.map((g) => {
|
||||
const fnOpen = openFn.has(g.key)
|
||||
return (
|
||||
<Card key={g.key} className="bg-card border-border">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleFn(g.key)}
|
||||
aria-expanded={fnOpen}
|
||||
className="w-full text-left p-3 flex flex-wrap items-center gap-2
|
||||
rounded-lg hover:bg-white/5 transition-colors cursor-pointer"
|
||||
>
|
||||
{fnOpen
|
||||
? <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
: <ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />}
|
||||
<FileCode className="h-4 w-4 shrink-0 text-blue-400" />
|
||||
<span className="min-w-0 text-sm font-medium text-foreground break-words">
|
||||
{g.label}
|
||||
</span>
|
||||
{g.version && (
|
||||
<Badge variant="outline" className="text-xs shrink-0">v{g.version}</Badge>
|
||||
)}
|
||||
<Badge variant="outline" className="text-xs tabular-nums shrink-0">
|
||||
{t("audit.changes.count", { count: String(g.items.length) })}
|
||||
</Badge>
|
||||
<span className="ml-auto shrink-0 text-xs text-muted-foreground">
|
||||
{when(g.last)}
|
||||
</span>
|
||||
</button>
|
||||
{fnOpen && (
|
||||
<CardContent className="pt-0 pl-10 pr-3 space-y-2">
|
||||
{g.items.map((change) => (
|
||||
<ChangeCard key={change.id} change={change}
|
||||
expanded={open.has(change.id)} onToggle={() => toggle(change.id)}
|
||||
t={t} when={when} />
|
||||
))}
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function AuditChanges() {
|
||||
const t = useT()
|
||||
const { language } = useI18n()
|
||||
@@ -234,7 +351,6 @@ export function AuditChanges() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [open, setOpen] = useState<Set<number>>(new Set())
|
||||
const [filter, setFilter] = useState<string>("all")
|
||||
|
||||
const load = useCallback(async () => {
|
||||
try {
|
||||
@@ -268,26 +384,27 @@ export function AuditChanges() {
|
||||
return next
|
||||
})
|
||||
|
||||
const visible = useMemo(
|
||||
() => changes.filter((c) => filter === "all" || c.class === filter),
|
||||
[changes, filter],
|
||||
)
|
||||
|
||||
// A sysadmin asks "what did each ProxMenux function do to my host?" — so
|
||||
// the changes are grouped under the function that made them. Each group is
|
||||
// one card; opening it reveals that function's individual file changes.
|
||||
const groups = useMemo(() => {
|
||||
const byFn = new Map<string, { function: string; version: string; last: number; items: Change[] }>()
|
||||
for (const c of visible) {
|
||||
const key = c.function || "—"
|
||||
const g = byFn.get(key) || { function: key, version: c.function_version || "", last: 0, items: [] }
|
||||
// A sysadmin reads this in three sections: what ProxMenux optimized
|
||||
// (post-install), what its other scripts changed, and what it installed.
|
||||
// Within each, changes are grouped under a card that opens to reveal them.
|
||||
type Group = { key: string; label: string; version: string; last: number; items: Change[] }
|
||||
const blocks = useMemo(() => {
|
||||
const mk = () => new Map<string, Group>()
|
||||
const post = mk(), scripts = mk(), installs = mk()
|
||||
const pick = (b: string) => b === "installs" ? installs : b === "postInstall" ? post : scripts
|
||||
for (const c of changes) {
|
||||
const target = pick(blockOf(c))
|
||||
const key = c.function || c.source || "—"
|
||||
const label = groupLabel(c.function, c.source)
|
||||
const g = target.get(key) || { key, label, version: c.function_version || "", last: 0, items: [] }
|
||||
g.items.push(c)
|
||||
if (c.recorded_at > g.last) g.last = c.recorded_at
|
||||
if (c.function_version) g.version = c.function_version
|
||||
byFn.set(key, g)
|
||||
target.set(key, g)
|
||||
}
|
||||
return Array.from(byFn.values()).sort((a, b) => b.last - a.last)
|
||||
}, [visible])
|
||||
const sort = (m: Map<string, Group>) => Array.from(m.values()).sort((a, b) => b.last - a.last)
|
||||
return { post: sort(post), scripts: sort(scripts), installs: sort(installs) }
|
||||
}, [changes])
|
||||
|
||||
const when = (epoch: number) => new Date(epoch * 1000).toLocaleString(language)
|
||||
|
||||
@@ -315,81 +432,22 @@ export function AuditChanges() {
|
||||
{t("audit.changes.since", { date: when(summary.journal_started) })}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{(["all", "configuration", "installation", "execution", "registration"] as const)
|
||||
.filter((key) => key === "all" || summary?.by_class?.[key])
|
||||
.map((key) => (
|
||||
<button
|
||||
key={key}
|
||||
type="button"
|
||||
onClick={() => setFilter(key)}
|
||||
className={`px-3 py-1 rounded-md text-sm transition-colors ${
|
||||
filter === key
|
||||
? "bg-blue-500 text-white"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-background/60"
|
||||
}`}
|
||||
>
|
||||
{t(`audit.changes.class.${key}`)}
|
||||
{key !== "all" && summary?.by_class?.[key] !== undefined && (
|
||||
<span className="ml-1.5 tabular-nums">{summary.by_class[key]}</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="space-y-2">
|
||||
{groups.map((g) => {
|
||||
const fnOpen = openFn.has(g.function)
|
||||
return (
|
||||
<Card key={g.function} className="bg-card border-border">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toggleFn(g.function)}
|
||||
aria-expanded={fnOpen}
|
||||
className="w-full text-left p-3 flex flex-wrap items-center gap-2
|
||||
rounded-lg hover:bg-white/5 transition-colors cursor-pointer"
|
||||
>
|
||||
{fnOpen
|
||||
? <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
: <ChevronRight className="h-4 w-4 shrink-0 text-muted-foreground" />}
|
||||
<FileCode className="h-4 w-4 shrink-0 text-blue-400" />
|
||||
<span className="min-w-0 font-mono text-sm font-medium text-foreground break-all">
|
||||
{g.function}
|
||||
</span>
|
||||
{g.version && (
|
||||
<Badge variant="outline" className="text-xs shrink-0">v{g.version}</Badge>
|
||||
)}
|
||||
<Badge variant="outline" className="text-xs tabular-nums shrink-0">
|
||||
{t("audit.changes.count", { count: String(g.items.length) })}
|
||||
</Badge>
|
||||
<span className="ml-auto shrink-0 text-xs text-muted-foreground">
|
||||
{when(g.last)}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{fnOpen && (
|
||||
<CardContent className="pt-0 pl-10 pr-3 space-y-2">
|
||||
{g.items.map((change) => (
|
||||
<ChangeCard
|
||||
key={change.id}
|
||||
change={change}
|
||||
expanded={open.has(change.id)}
|
||||
onToggle={() => toggle(change.id)}
|
||||
t={t}
|
||||
when={when}
|
||||
/>
|
||||
))}
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
)
|
||||
})}
|
||||
{groups.length === 0 && summary && summary.total > 0 && (
|
||||
<p className="text-sm text-muted-foreground px-1">{t("audit.changes.noneInFilter")}</p>
|
||||
)}
|
||||
</div>
|
||||
<GroupSection title={t("audit.changes.section.postInstall")}
|
||||
groups={blocks.post} openFn={openFn} toggleFn={toggleFn}
|
||||
open={open} toggle={toggle} t={t} when={when} />
|
||||
<GroupSection title={t("audit.changes.section.scripts")}
|
||||
groups={blocks.scripts} openFn={openFn} toggleFn={toggleFn}
|
||||
open={open} toggle={toggle} t={t} when={when} />
|
||||
<GroupSection title={t("audit.changes.section.installs")}
|
||||
groups={blocks.installs} openFn={openFn} toggleFn={toggleFn}
|
||||
open={open} toggle={toggle} t={t} when={when} />
|
||||
{summary && summary.total > 0
|
||||
&& blocks.post.length + blocks.scripts.length + blocks.installs.length === 0 && (
|
||||
<p className="text-sm text-muted-foreground px-1">{t("audit.changes.empty")}</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5875,7 +5875,7 @@
|
||||
"changes": {
|
||||
"loading": "Änderungsjournal wird gelesen…",
|
||||
"failed": "Das Änderungsjournal war nicht lesbar",
|
||||
"intro": "Was ProxMenux auf diesem Host geändert hat und was vor jeder Änderung vorhanden war. Gezeigt wird die Differenz, nicht das Skript, das sie angewandt hat.",
|
||||
"intro": "Was ProxMenux auf diesem Host geändert hat und was vor jeder Änderung vorhanden war. Gezeigt wird die Differenz.",
|
||||
"empty": "Auf diesem Host wurde noch nichts aufgezeichnet.",
|
||||
"since": "Aufzeichnung seit {date}. Früher Angewandtes erscheint als angewandt, ohne den ersetzten Zustand.",
|
||||
"byFunction": "Nach Funktion",
|
||||
@@ -5925,6 +5925,11 @@
|
||||
"undo": {
|
||||
"remove": "Löscht die Datei (vorher war keine vorhanden)",
|
||||
"restore": "Stellt exakt den vorherigen Zustand wieder her"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Post-Install-Optimierungen",
|
||||
"scripts": "ProxMenux-Skripte",
|
||||
"installs": "Installierte Pakete und Werkzeuge"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -5941,7 +5941,7 @@
|
||||
"changes": {
|
||||
"loading": "Reading the change journal…",
|
||||
"failed": "The change journal could not be read",
|
||||
"intro": "What ProxMenux changed on this host and what was there before each change. The difference is shown, not the script that applied it.",
|
||||
"intro": "What ProxMenux changed on this host and what was there before each change. The difference is shown.",
|
||||
"empty": "Nothing has been recorded on this host yet.",
|
||||
"since": "Recording since {date}. Anything applied before that appears as applied, without the state it replaced.",
|
||||
"byFunction": "By function",
|
||||
@@ -5991,6 +5991,11 @@
|
||||
"undo": {
|
||||
"remove": "Deletes the file (there was none before)",
|
||||
"restore": "Restores exactly what was there"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Post-install optimizations",
|
||||
"scripts": "ProxMenux scripts",
|
||||
"installs": "Installed packages and utilities"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -4306,7 +4306,7 @@
|
||||
},
|
||||
"profile": {
|
||||
"custom": "Personalizado",
|
||||
"customDescription": "Elija exactamente qué rutas deben incluirse.",
|
||||
"customDescription": "Elija qué rutas deben incluirse.",
|
||||
"default": "Por defecto",
|
||||
"defaultDescription": "Configuración de host recomendada y datos de ProxMenux.",
|
||||
"defaultDescriptionShort": "Configuración de host recomendada.",
|
||||
@@ -5875,7 +5875,7 @@
|
||||
"changes": {
|
||||
"loading": "Leyendo el registro de cambios…",
|
||||
"failed": "No se ha podido leer el registro de cambios",
|
||||
"intro": "Qué ha cambiado ProxMenux en este host y qué había antes de cada cambio. Se muestra la diferencia, no el script que la aplicó.",
|
||||
"intro": "Qué ha cambiado ProxMenux en este host y qué había antes de cada cambio. Se muestra la diferencia.",
|
||||
"empty": "Todavía no se ha registrado nada en este host.",
|
||||
"since": "Registrando desde el {date}. Lo aplicado antes figura como aplicado, sin el estado al que sustituyó.",
|
||||
"byFunction": "Por función",
|
||||
@@ -5925,6 +5925,11 @@
|
||||
"undo": {
|
||||
"remove": "Elimina el fichero (no había ninguno antes)",
|
||||
"restore": "Restaura exactamente lo que había"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Optimizaciones de post-install",
|
||||
"scripts": "Scripts de ProxMenux",
|
||||
"installs": "Paquetes y utilidades instalados"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -5875,7 +5875,7 @@
|
||||
"changes": {
|
||||
"loading": "Lecture du journal des modifications…",
|
||||
"failed": "Le journal des modifications n'a pas pu être lu",
|
||||
"intro": "Ce que ProxMenux a changé sur cet hôte et ce qui existait avant chaque changement. C'est la différence qui est montrée, non le script qui l'a appliquée.",
|
||||
"intro": "Ce que ProxMenux a changé sur cet hôte et ce qui existait avant chaque changement. C'est la différence qui est montrée.",
|
||||
"empty": "Rien n'a encore été enregistré sur cet hôte.",
|
||||
"since": "Enregistrement depuis le {date}. Ce qui a été appliqué avant figure comme appliqué, sans l'état remplacé.",
|
||||
"byFunction": "Par fonction",
|
||||
@@ -5925,6 +5925,11 @@
|
||||
"undo": {
|
||||
"remove": "Supprime le fichier (il n'y en avait aucun avant)",
|
||||
"restore": "Restaure exactement ce qui existait"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Optimisations post-installation",
|
||||
"scripts": "Scripts ProxMenux",
|
||||
"installs": "Paquets et utilitaires installés"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -5875,7 +5875,7 @@
|
||||
"changes": {
|
||||
"loading": "Lettura del registro delle modifiche…",
|
||||
"failed": "Non è stato possibile leggere il registro delle modifiche",
|
||||
"intro": "Cosa ha cambiato ProxMenux su questo host e cosa c'era prima di ogni modifica. Viene mostrata la differenza, non lo script che l'ha applicata.",
|
||||
"intro": "Cosa ha cambiato ProxMenux su questo host e cosa c'era prima di ogni modifica. Viene mostrata la differenza.",
|
||||
"empty": "Su questo host non è ancora stato registrato nulla.",
|
||||
"since": "Registrazione dal {date}. Ciò che è stato applicato prima risulta applicato, senza lo stato sostituito.",
|
||||
"byFunction": "Per funzione",
|
||||
@@ -5925,6 +5925,11 @@
|
||||
"undo": {
|
||||
"remove": "Elimina il file (prima non ce n'era nessuno)",
|
||||
"restore": "Ripristina esattamente ciò che c'era"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Ottimizzazioni post-installazione",
|
||||
"scripts": "Script di ProxMenux",
|
||||
"installs": "Pacchetti e utilità installati"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -5875,7 +5875,7 @@
|
||||
"changes": {
|
||||
"loading": "A ler o registo de alterações…",
|
||||
"failed": "Não foi possível ler o registo de alterações",
|
||||
"intro": "O que o ProxMenux alterou neste host e o que existia antes de cada alteração. Mostra-se a diferença, não o script que a aplicou.",
|
||||
"intro": "O que o ProxMenux alterou neste host e o que existia antes de cada alteração. Mostra-se a diferença.",
|
||||
"empty": "Ainda não foi registado nada neste anfitrião.",
|
||||
"since": "A registar desde {date}. O que foi aplicado antes figura como aplicado, sem o estado que substituiu.",
|
||||
"byFunction": "Por função",
|
||||
@@ -5925,6 +5925,11 @@
|
||||
"undo": {
|
||||
"remove": "Elimina o ficheiro (não existia nenhum antes)",
|
||||
"restore": "Restaura exatamente o que existia"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Otimizações pós-instalação",
|
||||
"scripts": "Scripts do ProxMenux",
|
||||
"installs": "Pacotes e utilitários instalados"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -5941,7 +5941,7 @@
|
||||
"changes": {
|
||||
"loading": "Načítava sa denník zmien…",
|
||||
"failed": "Denník zmien sa nepodarilo prečítať",
|
||||
"intro": "Čo ProxMenux na tomto hostiteľovi zmenil a čo tam bolo pred každou zmenou. Zobrazuje sa rozdiel, nie skript, ktorý ho aplikoval.",
|
||||
"intro": "Čo ProxMenux na tomto hostiteľovi zmenil a čo tam bolo pred každou zmenou. Zobrazuje sa rozdiel.",
|
||||
"empty": "Na tomto hostiteľovi zatiaľ nebolo nič zaznamenané.",
|
||||
"since": "Zaznamenáva sa od {date}. Čo bolo použité skôr, figuruje ako použité, bez stavu, ktorý nahradilo.",
|
||||
"byFunction": "Podľa funkcie",
|
||||
@@ -5991,6 +5991,11 @@
|
||||
"undo": {
|
||||
"remove": "Odstráni súbor (predtým žiadny nebol)",
|
||||
"restore": "Obnoví presne to, čo tam bolo"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Optimalizácie po inštalácii",
|
||||
"scripts": "Skripty ProxMenux",
|
||||
"installs": "Nainštalované balíky a nástroje"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -5876,7 +5876,7 @@
|
||||
"changes": {
|
||||
"loading": "Läser ändringsjournalen…",
|
||||
"failed": "Ändringsjournalen kunde inte läsas",
|
||||
"intro": "Vad ProxMenux ändrat på den här värden och vad som fanns före varje ändring. Skillnaden visas, inte skriptet som tillämpade den.",
|
||||
"intro": "Vad ProxMenux ändrat på den här värden och vad som fanns före varje ändring. Skillnaden visas.",
|
||||
"empty": "Inget har ännu registrerats på den här värden.",
|
||||
"since": "Registrerar sedan {date}. Det som tillämpades dessförinnan står som tillämpat, utan det tillstånd det ersatte.",
|
||||
"byFunction": "Per funktion",
|
||||
@@ -5926,6 +5926,11 @@
|
||||
"undo": {
|
||||
"remove": "Tar bort filen (det fanns ingen tidigare)",
|
||||
"restore": "Återställer exakt vad som fanns"
|
||||
},
|
||||
"section": {
|
||||
"postInstall": "Optimeringar efter installation",
|
||||
"scripts": "ProxMenux-skript",
|
||||
"installs": "Installerade paket och verktyg"
|
||||
}
|
||||
},
|
||||
"comparison": {
|
||||
|
||||
@@ -5,10 +5,6 @@ if [[ -n "${__PROXMENUX_VM_STORAGE_HELPERS__}" ]]; then
|
||||
fi
|
||||
__PROXMENUX_VM_STORAGE_HELPERS__=1
|
||||
|
||||
if [[ -f "/usr/local/share/proxmenux/scripts/global/pmx_journal.sh" ]]; then
|
||||
source "/usr/local/share/proxmenux/scripts/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
function _array_contains() {
|
||||
local needle="$1"
|
||||
shift
|
||||
@@ -375,8 +371,6 @@ function _vm_storage_register_vfio_iommu_tool() {
|
||||
}
|
||||
|
||||
function _vm_storage_enable_iommu_cmdline() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "_vm_storage_enable_iommu_cmdline" "$FUNC_VERSION"
|
||||
local cpu_vendor iommu_param
|
||||
cpu_vendor=$(grep -m1 "vendor_id" /proc/cpuinfo 2>/dev/null | awk '{print $3}')
|
||||
|
||||
@@ -394,15 +388,13 @@ function _vm_storage_enable_iommu_cmdline() {
|
||||
if [[ -f "$cmdline_file" ]] && grep -qE 'root=ZFS=|root=ZFS/' "$cmdline_file" 2>/dev/null; then
|
||||
if ! grep -q "$iommu_param" "$cmdline_file"; then
|
||||
cp "$cmdline_file" "${cmdline_file}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||
pmx_edit_file "$cmdline_file" "s|\\s*$| ${iommu_param} iommu=pt|"
|
||||
pmx_record_execution "refresh Proxmox boot entries" "proxmox-boot-tool refresh"
|
||||
sed -i "s|\\s*$| ${iommu_param} iommu=pt|" "$cmdline_file"
|
||||
proxmox-boot-tool refresh >/dev/null 2>&1 || true
|
||||
fi
|
||||
elif [[ -f "$grub_file" ]]; then
|
||||
if ! grep -q "$iommu_param" "$grub_file"; then
|
||||
cp "$grub_file" "${grub_file}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||
pmx_edit_file "$grub_file" "/GRUB_CMDLINE_LINUX_DEFAULT=/ s|\"$| ${iommu_param} iommu=pt\"|"
|
||||
pmx_record_execution "regenerate GRUB configuration" "update-grub"
|
||||
sed -i "/GRUB_CMDLINE_LINUX_DEFAULT=/ s|\"$| ${iommu_param} iommu=pt\"|" "$grub_file"
|
||||
update-grub >/dev/null 2>&1 || true
|
||||
fi
|
||||
else
|
||||
|
||||
@@ -23,10 +23,6 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -57,9 +53,6 @@ select_privileged_container() {
|
||||
}
|
||||
|
||||
validate_container_id() {
|
||||
local FUNC_VERSION="1.1"
|
||||
pmx_journal_context "validate_container_id" "$FUNC_VERSION"
|
||||
|
||||
if [ -z "$CONTAINER_ID" ]; then
|
||||
msg_error "$(translate 'Container ID not defined. Make sure to select a container first.')"
|
||||
exit 1
|
||||
@@ -73,8 +66,6 @@ validate_container_id() {
|
||||
|
||||
if pct status "$CONTAINER_ID" | grep -q "running"; then
|
||||
msg_info "$(translate 'Stopping the container before conversion...')"
|
||||
pmx_record_execution "stop CT ${CONTAINER_ID} for privileged-to-unprivileged conversion" \
|
||||
"pct stop ${CONTAINER_ID}"
|
||||
pct stop "$CONTAINER_ID"
|
||||
msg_ok "$(translate 'Container stopped.')"
|
||||
fi
|
||||
@@ -98,12 +89,7 @@ show_backup_warning() {
|
||||
}
|
||||
|
||||
convert_direct_method() {
|
||||
local FUNC_VERSION="1.1"
|
||||
pmx_journal_context "convert_direct_method" "$FUNC_VERSION"
|
||||
|
||||
msg_info2 "$(translate 'Starting direct conversion of container') $CONTAINER_ID..."
|
||||
pmx_record_execution "convert CT ${CONTAINER_ID} filesystem ownership to unprivileged IDs" \
|
||||
"mount rootfs, remap ownership by 100000, and update CT configuration"
|
||||
|
||||
TEMP_DIR="/tmp/lxc_convert_$CONTAINER_ID"
|
||||
mkdir -p "$TEMP_DIR"
|
||||
@@ -239,9 +225,9 @@ convert_direct_method() {
|
||||
|
||||
CONFIG_FILE="/etc/pve/lxc/$CONTAINER_ID.conf"
|
||||
if ! grep -q "^unprivileged:" "$CONFIG_FILE"; then
|
||||
echo "unprivileged: 1" | pmx_append_file "$CONFIG_FILE"
|
||||
echo "unprivileged: 1" >> "$CONFIG_FILE"
|
||||
else
|
||||
pmx_edit_file "$CONFIG_FILE" 's/^unprivileged:.*/unprivileged: 1/'
|
||||
sed -i 's/^unprivileged:.*/unprivileged: 1/' "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
msg_ok "$(translate 'Direct conversion completed for container') $CONTAINER_ID"
|
||||
@@ -252,12 +238,9 @@ convert_direct_method() {
|
||||
}
|
||||
|
||||
cleanup_and_finalize() {
|
||||
local FUNC_VERSION="1.1"
|
||||
pmx_journal_context "cleanup_and_finalize" "$FUNC_VERSION"
|
||||
|
||||
if whiptail --yesno "$(translate 'Do you want to start the converted unprivileged container') $CONTAINER_ID $(translate 'now?')" 10 60; then
|
||||
msg_info2 "$(translate 'Starting unprivileged container...')"
|
||||
pmx_record_execution "start converted unprivileged CT ${CONTAINER_ID}" "pct start ${CONTAINER_ID}"
|
||||
pct start "$CONTAINER_ID"
|
||||
msg_ok "$(translate 'Unprivileged container') $CONTAINER_ID $(translate 'started successfully.')"
|
||||
fi
|
||||
|
||||
@@ -25,10 +25,6 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -73,19 +69,12 @@ show_backup_warning() {
|
||||
}
|
||||
|
||||
convert_to_privileged() {
|
||||
local FUNC_VERSION="2.0"
|
||||
pmx_journal_context "convert_to_privileged" "$FUNC_VERSION"
|
||||
|
||||
CONF_FILE="/etc/pve/lxc/$CONTAINER_ID.conf"
|
||||
pmx_record_execution "convert CT ${CONTAINER_ID} to privileged mode" \
|
||||
"stop CT if running and update ${CONF_FILE}"
|
||||
|
||||
CONTAINER_STATUS=$(pct status "$CONTAINER_ID" | awk '{print $2}')
|
||||
|
||||
if [ "$CONTAINER_STATUS" == "running" ]; then
|
||||
msg_info "$(translate 'Stopping container') $CONTAINER_ID..."
|
||||
pmx_record_execution "stop CT ${CONTAINER_ID} for unprivileged-to-privileged conversion" \
|
||||
"pct shutdown ${CONTAINER_ID}"
|
||||
pct shutdown "$CONTAINER_ID"
|
||||
|
||||
# Wait for container to stop
|
||||
@@ -112,8 +101,8 @@ convert_to_privileged() {
|
||||
msg_ok "$(translate 'Configuration backup created:') $CONF_FILE.bak"
|
||||
|
||||
msg_info "$(translate 'Converting container to privileged...')"
|
||||
pmx_edit_file "$CONF_FILE" '/^unprivileged: 1/d'
|
||||
echo "unprivileged: 0" | pmx_append_file "$CONF_FILE"
|
||||
sed -i '/^unprivileged: 1/d' "$CONF_FILE"
|
||||
echo "unprivileged: 0" >> "$CONF_FILE"
|
||||
|
||||
msg_ok "$(translate 'Container successfully converted to privileged.')"
|
||||
|
||||
@@ -123,12 +112,9 @@ convert_to_privileged() {
|
||||
}
|
||||
|
||||
finalize_conversion() {
|
||||
local FUNC_VERSION="2.0"
|
||||
pmx_journal_context "finalize_conversion" "$FUNC_VERSION"
|
||||
|
||||
if whiptail --yesno "$(translate 'Do you want to start the privileged container') $CONTAINER_ID $(translate 'now?')" 10 60; then
|
||||
msg_info "$(translate 'Starting privileged container...')"
|
||||
pmx_record_execution "start converted privileged CT ${CONTAINER_ID}" "pct start ${CONTAINER_ID}"
|
||||
pct start "$CONTAINER_ID"
|
||||
msg_ok "$(translate 'Privileged container') $CONTAINER_ID $(translate 'started successfully.')"
|
||||
fi
|
||||
|
||||
@@ -486,8 +486,6 @@ format_and_mount_disk() {
|
||||
14 80; then
|
||||
return 1
|
||||
fi
|
||||
pmx_record_execution "format disk ${disk} as ${filesystem} for ${mount_path}" \
|
||||
"wipe disk, create partition and format as ${filesystem}"
|
||||
show_proxmenux_logo
|
||||
if [[ "$MODE_PVESM" -eq 1 && "$MODE_FSTAB" -eq 1 ]]; then
|
||||
msg_title "$(translate "Add Local Disk (Proxmox storage + host mount)")"
|
||||
@@ -572,8 +570,6 @@ mount_disk_permanently() {
|
||||
msg_ok "$(translate "Mount point created")"
|
||||
|
||||
msg_info "$(translate "Mounting disk...")"
|
||||
pmx_record_execution "mount ${partition} at ${mount_path}" \
|
||||
"mount -t ${filesystem} ${partition} ${mount_path}"
|
||||
if ! mount -t "$filesystem" "$partition" "$mount_path" 2>/dev/null; then
|
||||
msg_error "$(translate "Failed to mount disk")"
|
||||
return 1
|
||||
@@ -622,8 +618,6 @@ _apply_lxc_bind_mount_perms() {
|
||||
[[ -d "$mount_path" ]] || return 0
|
||||
|
||||
msg_info "$(translate "Applying host permissions for unprivileged LXC bind-mounts...")"
|
||||
pmx_record_execution "apply LXC bind-mount permissions to ${mount_path}" \
|
||||
"chmod o+rwx and setfacl on ${mount_path}"
|
||||
chmod o+rwx "$mount_path" 2>/dev/null || true
|
||||
if command -v setfacl >/dev/null 2>&1; then
|
||||
setfacl -m o::rwx "$mount_path" 2>/dev/null || true
|
||||
@@ -653,7 +647,6 @@ mount_existing_disk() {
|
||||
msg_ok "$(translate "Mount point created")"
|
||||
|
||||
msg_info "$(translate "Mounting existing") $existing_fs $(translate "filesystem...")"
|
||||
pmx_record_execution "mount existing disk ${disk} at ${mount_path}" "mount ${disk} ${mount_path}"
|
||||
if ! mount "$disk" "$mount_path" 2>/dev/null; then
|
||||
msg_error "$(translate "Failed to mount disk")"
|
||||
return 1
|
||||
@@ -702,7 +695,6 @@ add_proxmox_dir_storage() {
|
||||
8 60; then
|
||||
return 0
|
||||
fi
|
||||
pmx_record_execution "remove existing Proxmox storage ${storage_id}" "pvesm remove ${storage_id}"
|
||||
pvesm remove "$storage_id" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
@@ -710,16 +702,12 @@ add_proxmox_dir_storage() {
|
||||
local pvesm_output
|
||||
local add_ok=false
|
||||
if [[ "$storage_kind" == "zfspool" ]]; then
|
||||
pmx_record_execution "add ZFS pool ${pool_name} as Proxmox storage ${storage_id}" \
|
||||
"pvesm add zfspool ${storage_id} --pool ${pool_name} --content ${content}"
|
||||
if pvesm_output=$(pvesm add zfspool "$storage_id" \
|
||||
--pool "$pool_name" \
|
||||
--content "$content" 2>&1); then
|
||||
add_ok=true
|
||||
fi
|
||||
else
|
||||
pmx_record_execution "add directory ${path} as Proxmox storage ${storage_id}" \
|
||||
"pvesm add dir ${storage_id} --path ${path} --content ${content}"
|
||||
if pvesm_output=$(pvesm add dir "$storage_id" \
|
||||
--path "$path" \
|
||||
--content "$content" 2>&1); then
|
||||
@@ -1048,7 +1036,6 @@ _remove_pvesm_storage() {
|
||||
|
||||
# Step 1: Remove from Proxmox
|
||||
msg_info "$(translate "Removing storage from Proxmox...")"
|
||||
pmx_record_execution "remove Proxmox storage ${storage_id}" "pvesm remove ${storage_id}"
|
||||
if ! pvesm remove "$storage_id" 2>/dev/null; then
|
||||
msg_error "$(translate "Failed to remove storage from Proxmox.")"
|
||||
echo ""
|
||||
@@ -1061,7 +1048,6 @@ _remove_pvesm_storage() {
|
||||
# Step 2: Unmount if mounted (dir-backed storages only)
|
||||
if [[ -n "$path" ]] && mountpoint -q "$path" 2>/dev/null; then
|
||||
msg_info "$(translate "Unmounting disk...")"
|
||||
pmx_record_execution "unmount disk from ${path}" "umount ${path}"
|
||||
if umount "$path" 2>/dev/null; then
|
||||
msg_ok "$(translate "Disk unmounted from") $path"
|
||||
else
|
||||
@@ -1088,7 +1074,6 @@ _remove_pvesm_storage() {
|
||||
# Step 3b: Export ZFS pool if applicable
|
||||
if [[ -n "$pool" ]] && zpool list "$pool" >/dev/null 2>&1; then
|
||||
msg_info "$(translate "Exporting ZFS pool...") $pool"
|
||||
pmx_record_execution "export ZFS pool ${pool}" "zpool export ${pool}"
|
||||
if zpool export "$pool" 2>/dev/null; then
|
||||
msg_ok "$(translate "ZFS pool exported:") $pool"
|
||||
else
|
||||
@@ -1105,7 +1090,6 @@ _remove_pvesm_storage() {
|
||||
read -r
|
||||
echo ""
|
||||
msg_warn "$(translate "Rebooting the system...")"
|
||||
pmx_record_execution "reboot host after removing storage ${storage_id}" "reboot"
|
||||
reboot
|
||||
else
|
||||
echo ""
|
||||
@@ -1161,7 +1145,6 @@ _remove_fstab_entry() {
|
||||
|
||||
if $mounted; then
|
||||
msg_info "$(translate "Unmounting") $mount_point..."
|
||||
pmx_record_execution "unmount disk from ${mount_point}" "umount ${mount_point}"
|
||||
if umount "$mount_point" 2>/dev/null; then
|
||||
msg_ok "$(translate "Unmounted successfully")"
|
||||
else
|
||||
|
||||
@@ -244,8 +244,6 @@ add_proxmox_iscsi_storage() {
|
||||
8 60 --title "$(translate "Storage Exists")"; then
|
||||
return 0
|
||||
fi
|
||||
pmx_record_execution "remove existing Proxmox iSCSI storage ${storage_id}" \
|
||||
"pvesm remove ${storage_id}"
|
||||
pvesm remove "$storage_id" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
@@ -253,8 +251,6 @@ add_proxmox_iscsi_storage() {
|
||||
msg_info "$(translate "Adding iSCSI storage to Proxmox...")"
|
||||
|
||||
local pvesm_output pvesm_result
|
||||
pmx_record_execution "add iSCSI target ${target} as Proxmox storage ${storage_id}" \
|
||||
"pvesm add iscsi ${storage_id} --portal ${portal} --target ${target} --content ${content}"
|
||||
pvesm_output=$(pvesm add iscsi "$storage_id" \
|
||||
--portal "$portal" \
|
||||
--target "$target" \
|
||||
@@ -418,7 +414,6 @@ remove_iscsi_storage() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Remove iSCSI Storage")"
|
||||
|
||||
pmx_record_execution "remove Proxmox iSCSI storage ${SELECTED}" "pvesm remove ${SELECTED}"
|
||||
if pvesm remove "$SELECTED" 2>/dev/null; then
|
||||
msg_ok "$(translate "Storage") $SELECTED $(translate "removed successfully from Proxmox.")"
|
||||
else
|
||||
|
||||
@@ -42,10 +42,6 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
SHARE_COMMON_FILE="$LOCAL_SCRIPTS/global/share-common.func"
|
||||
if ! source "$SHARE_COMMON_FILE" 2>/dev/null; then
|
||||
msg_error "$(translate "Could not load shared functions. Script cannot continue.")"
|
||||
@@ -68,14 +64,9 @@ fi
|
||||
|
||||
lsm_apply_multi_unpriv_permissions() {
|
||||
local dir="$1"
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "lsm_apply_multi_unpriv_permissions" "$FUNC_VERSION"
|
||||
|
||||
[[ -z "$dir" || ! -d "$dir" ]] && return 1
|
||||
|
||||
pmx_record_execution "apply shared LXC permission profile to ${dir}" \
|
||||
"chown root:root; chmod 1777; chmod -R a+rwX; apply default ACLs when available"
|
||||
|
||||
# root:root ownership — no new group needed.
|
||||
chown root:root "$dir" 2>/dev/null || true
|
||||
|
||||
@@ -233,9 +224,6 @@ lsm_select_host_mount_point_dialog() {
|
||||
}
|
||||
|
||||
create_shared_directory() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "create_shared_directory" "$FUNC_VERSION"
|
||||
|
||||
lsm_select_host_mount_point_dialog "$(translate "Select Shared Directory Location")" "shared"
|
||||
[[ -z "$LSM_SELECTED_MOUNT_POINT" ]] && return
|
||||
SHARED_DIR="$LSM_SELECTED_MOUNT_POINT"
|
||||
@@ -243,7 +231,6 @@ create_shared_directory() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create Shared Directory")"
|
||||
|
||||
pmx_record_execution "create shared directory ${SHARED_DIR}" "mkdir -p ${SHARED_DIR}"
|
||||
if ! mkdir -p "$SHARED_DIR" 2>/dev/null; then
|
||||
msg_error "$(translate "Failed to create directory:") $SHARED_DIR"
|
||||
echo ""
|
||||
|
||||
@@ -30,10 +30,6 @@
|
||||
BASE_DIR="/usr/local/share/proxmenux"
|
||||
source "$BASE_DIR/utils.sh"
|
||||
|
||||
if [[ -f "/usr/local/share/proxmenux/scripts/global/pmx_journal.sh" ]]; then
|
||||
source "/usr/local/share/proxmenux/scripts/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -293,8 +289,6 @@ select_lxc_container() {
|
||||
select_container_mount_point() {
|
||||
local ctid="$1"
|
||||
local host_dir="$2"
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "select_container_mount_point" "$FUNC_VERSION"
|
||||
local base_name
|
||||
base_name=$(basename "$host_dir")
|
||||
|
||||
@@ -339,8 +333,6 @@ select_container_mount_point() {
|
||||
local ct_status
|
||||
ct_status=$(pct status "$ctid" 2>/dev/null | awk '{print $2}')
|
||||
if [[ "$ct_status" == "running" ]]; then
|
||||
pmx_record_execution "create mount directory ${mount_point} in CT ${ctid}" \
|
||||
"pct exec ${ctid} -- mkdir -p ${mount_point}"
|
||||
pct exec "$ctid" -- mkdir -p "$mount_point" 2>/dev/null
|
||||
fi
|
||||
|
||||
@@ -375,8 +367,6 @@ add_bind_mount() {
|
||||
local ctid="$1"
|
||||
local host_path="$2"
|
||||
local ct_path="$3"
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "add_bind_mount" "$FUNC_VERSION"
|
||||
|
||||
if [[ ! "$ctid" =~ ^[0-9]+$ || -z "$host_path" || -z "$ct_path" ]]; then
|
||||
msg_error "$(translate "Invalid parameters for bind mount")"
|
||||
@@ -393,8 +383,6 @@ add_bind_mount() {
|
||||
mpidx=$(get_next_mp_index "$ctid")
|
||||
|
||||
local result
|
||||
pmx_record_execution "add bind mount ${host_path} to CT ${ctid} at ${ct_path}" \
|
||||
"pct set ${ctid} -mp${mpidx} ${host_path},mp=${ct_path},shared=1,backup=0"
|
||||
result=$(pct set "$ctid" -mp${mpidx} "$host_path,mp=$ct_path,shared=1,backup=0" 2>&1)
|
||||
|
||||
if [[ $? -eq 0 ]]; then
|
||||
@@ -463,9 +451,6 @@ view_mount_points() {
|
||||
}
|
||||
|
||||
remove_mount_point() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "remove_mount_point" "$FUNC_VERSION"
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Remove LXC Mount Point")"
|
||||
|
||||
@@ -547,8 +532,6 @@ $(translate "Proceed with removal")?"
|
||||
msg_title "$(translate "Remove LXC Mount Point")"
|
||||
msg_info "$(translate "Removing mount point") $selected_mp $(translate "from container") $container_id..."
|
||||
|
||||
pmx_record_execution "remove mount point ${selected_mp} from CT ${container_id}" \
|
||||
"pct set ${container_id} --delete ${selected_mp}"
|
||||
if pct set "$container_id" --delete "$selected_mp" 2>/dev/null; then
|
||||
msg_ok "$(translate "Mount point removed successfully")"
|
||||
|
||||
@@ -558,8 +541,6 @@ $(translate "Proceed with removal")?"
|
||||
echo ""
|
||||
if whiptail --yesno "$(translate "Container is running. Restart to apply changes?")" 8 60; then
|
||||
msg_info "$(translate "Restarting container...")"
|
||||
pmx_record_execution "restart CT ${container_id} after removing ${selected_mp}" \
|
||||
"pct reboot ${container_id}"
|
||||
if pct reboot "$container_id"; then
|
||||
sleep 3
|
||||
msg_ok "$(translate "Container restarted successfully")"
|
||||
@@ -592,8 +573,6 @@ $(translate "Proceed with removal")?"
|
||||
lmm_fix_cifs_access() {
|
||||
local host_dir="$1"
|
||||
local is_unprivileged="$2"
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "lmm_fix_cifs_access" "$FUNC_VERSION"
|
||||
|
||||
# CIFS mounted by Proxmox GUI uses uid=0/gid=0 by default (root only).
|
||||
# The fix: remount with uid/gid that the LXC can access.
|
||||
@@ -641,16 +620,13 @@ $(translate "Apply fix now? (The share will be briefly remounted)")" \
|
||||
18 84 3>&1 1>&2 2>&3; then
|
||||
|
||||
msg_info "$(translate "Remounting CIFS share with open permissions...")"
|
||||
pmx_record_execution "remount CIFS share ${mount_src} at ${host_dir}" \
|
||||
"umount ${host_dir}; mount -t cifs ${mount_src} ${host_dir} -o ${new_opts}"
|
||||
if umount "$host_dir" 2>/dev/null && \
|
||||
mount -t cifs "$mount_src" "$host_dir" -o "$new_opts" 2>/dev/null; then
|
||||
msg_ok "$(translate "CIFS share remounted — LXC containers can now read and write")"
|
||||
|
||||
# Update fstab if the mount is there
|
||||
if grep -qF "$host_dir" /etc/fstab 2>/dev/null; then
|
||||
pmx_edit_file /etc/fstab \
|
||||
"s|^\(${mount_src}[[:space:]].*${host_dir}.*cifs[[:space:]]\).*|\1${new_opts} 0 0|" 2>/dev/null || true
|
||||
sed -i "s|^\(${mount_src}[[:space:]].*${host_dir}.*cifs[[:space:]]\).*|\1${new_opts} 0 0|" /etc/fstab 2>/dev/null || true
|
||||
msg_ok "$(translate "/etc/fstab updated — permissions will persist after reboot")"
|
||||
fi
|
||||
else
|
||||
@@ -663,8 +639,6 @@ lmm_fix_nfs_access() {
|
||||
local host_dir="$1"
|
||||
local is_unprivileged="$2"
|
||||
local uid_shift="${3:-100000}"
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "lmm_fix_nfs_access" "$FUNC_VERSION"
|
||||
|
||||
# NFS: the host cannot override server-side permissions.
|
||||
# BUT: if the server exports with root_squash (default), we can check
|
||||
@@ -704,8 +678,6 @@ $(translate "If it still fails, the NFS server export options must be changed on
|
||||
$(translate "Apply fix now?")" \
|
||||
18 84 3>&1 1>&2 2>&3; then
|
||||
|
||||
pmx_record_execution "apply LXC access permissions to NFS directory ${host_dir}" \
|
||||
"chmod 1777 and setfacl on ${host_dir}"
|
||||
if chmod 1777 "$host_dir" 2>/dev/null; then
|
||||
msg_ok "$(translate "NFS directory permissions set — containers should now be able to write")"
|
||||
else
|
||||
@@ -744,8 +716,6 @@ $(translate "You can still mount this share for READ-ONLY access.")" \
|
||||
lmm_offer_host_permissions() {
|
||||
local host_dir="$1"
|
||||
local is_unprivileged="$2"
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "lmm_offer_host_permissions" "$FUNC_VERSION"
|
||||
|
||||
# Privileged containers: UID 0 inside = UID 0 on host — always accessible
|
||||
[[ "$is_unprivileged" != "1" ]] && return 0
|
||||
@@ -779,8 +749,6 @@ $(translate "Apply read+write access for 'others' on the host directory?")\n\n\
|
||||
$(translate "(Only the host directory is modified. Nothing inside the container is changed.")" \
|
||||
16 80 3>&1 1>&2 2>&3; then
|
||||
|
||||
pmx_record_execution "grant mapped LXC users access to host directory ${host_dir}" \
|
||||
"chmod o+rwx and setfacl on ${host_dir}"
|
||||
chmod o+rwx "$host_dir" 2>/dev/null || true
|
||||
if command -v setfacl >/dev/null 2>&1; then
|
||||
setfacl -m o::rwx "$host_dir" 2>/dev/null || true
|
||||
@@ -830,8 +798,6 @@ _lmm_verify_writable() {
|
||||
# ==========================================================
|
||||
|
||||
mount_host_directory_minimal() {
|
||||
local FUNC_VERSION="1.0"
|
||||
|
||||
# Step 1: Select container
|
||||
local container_id
|
||||
container_id=$(select_lxc_container)
|
||||
@@ -934,13 +900,10 @@ $(translate "Proceed")?"
|
||||
# bind-mount is supposed to spare them.
|
||||
local ct_status
|
||||
ct_status=$(pct status "$container_id" 2>/dev/null | awk '{print $2}')
|
||||
pmx_journal_context "mount_host_directory_minimal" "$FUNC_VERSION"
|
||||
echo ""
|
||||
if [[ "$ct_status" == "running" ]]; then
|
||||
if whiptail --yesno "$(translate "Restart container to activate mount?")" 8 60; then
|
||||
msg_info "$(translate "Restarting container...")"
|
||||
pmx_record_execution "restart CT ${container_id} to activate bind mount" \
|
||||
"pct reboot ${container_id}"
|
||||
if pct reboot "$container_id"; then
|
||||
sleep 5
|
||||
msg_ok "$(translate "Container restarted successfully")"
|
||||
@@ -955,8 +918,6 @@ $(translate "Proceed")?"
|
||||
# declines, fall back to the informational line.
|
||||
if whiptail --yesno "$(translate "Container is stopped. Start it now to verify the mount works?")" 8 70; then
|
||||
msg_info "$(translate "Starting container...")"
|
||||
pmx_record_execution "start CT ${container_id} to activate and verify bind mount" \
|
||||
"pct start ${container_id}"
|
||||
if pct start "$container_id"; then
|
||||
sleep 5
|
||||
msg_ok "$(translate "Container started successfully")"
|
||||
|
||||
@@ -71,8 +71,6 @@ install_nfs_client() {
|
||||
fi
|
||||
|
||||
msg_info "$(translate "Installing NFS client packages...")"
|
||||
pmx_record_execution "install NFS client packages in CT ${CTID}" \
|
||||
"pct exec ${CTID} -- apt-get update and apt-get install -y nfs-common"
|
||||
if ! pct exec "$CTID" -- apt-get update >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to update package list.")"
|
||||
msg_success "$(translate "Press Enter to return to menu...")"
|
||||
@@ -408,8 +406,6 @@ mount_nfs_share() {
|
||||
configure_mount_options || return
|
||||
|
||||
pmx_journal_context "mount_nfs_share" "$FUNC_VERSION"
|
||||
pmx_record_execution "mount NFS export ${NFS_SERVER}:${NFS_EXPORT} in CT ${CTID} at ${MOUNT_POINT}" \
|
||||
"pct exec ${CTID} -- mount NFS; persistent=${PERMANENT_MOUNT}"
|
||||
|
||||
|
||||
if ! pct exec "$CTID" -- test -d "$MOUNT_POINT"; then
|
||||
@@ -585,8 +581,6 @@ unmount_nfs_share() {
|
||||
msg_title "$(translate "Unmount NFS Share")"
|
||||
|
||||
# Remove from fstab
|
||||
pmx_record_execution "remove NFS mount ${SELECTED_MOUNT} from CT ${CTID}" \
|
||||
"remove CT fstab entry and unmount ${SELECTED_MOUNT}"
|
||||
pct exec "$CTID" -- sed --in-place "\|[[:space:]]$SELECTED_MOUNT[[:space:]]|d" /etc/fstab
|
||||
msg_ok "$(translate "Removed from /etc/fstab.")"
|
||||
|
||||
@@ -643,8 +637,6 @@ test_nfs_connectivity() {
|
||||
else
|
||||
echo "$(translate "RPC Bind Service: STOPPED")"
|
||||
msg_warn "$(translate "Starting rpcbind service...")"
|
||||
pmx_record_execution "start rpcbind in CT ${CTID}" \
|
||||
"pct exec ${CTID} -- systemctl start rpcbind"
|
||||
pct exec "$CTID" -- systemctl start rpcbind 2>/dev/null || true
|
||||
fi
|
||||
|
||||
|
||||
@@ -276,15 +276,11 @@ add_proxmox_nfs_storage() {
|
||||
8 60 --title "$(translate "Storage Exists")"; then
|
||||
return 0
|
||||
fi
|
||||
pmx_record_execution "remove existing Proxmox NFS storage ${storage_id}" \
|
||||
"pvesm remove ${storage_id}"
|
||||
pvesm remove "$storage_id" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
msg_ok "$(translate "Storage ID is available")"
|
||||
msg_info "$(translate "NFS storage adding in progress...")"
|
||||
pmx_record_execution "add NFS export ${server}:${export} as Proxmox storage ${storage_id}" \
|
||||
"pvesm add nfs ${storage_id} --server ${server} --export ${export} --content ${content}"
|
||||
if pvesm_output=$(pvesm add nfs "$storage_id" \
|
||||
--server "$server" \
|
||||
--export "$export" \
|
||||
@@ -411,8 +407,6 @@ mount_nfs_via_fstab() {
|
||||
msg_ok "$(translate "Mount point ready:") $mount_path"
|
||||
|
||||
msg_info "$(translate "Mounting NFS share...")"
|
||||
pmx_record_execution "mount NFS export ${server}:${export_path} at ${mount_path}" \
|
||||
"mount -t nfs -o ${mount_opts} ${server}:${export_path} ${mount_path}"
|
||||
if ! mount -t nfs -o "$mount_opts" "${server}:${export_path}" "$mount_path" >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to mount NFS share on host.")"
|
||||
return 1
|
||||
@@ -440,7 +434,6 @@ mount_nfs_via_fstab() {
|
||||
echo "${server}:${export_path} $mount_path nfs $mount_opts 0 0" | pmx_append_file /etc/fstab
|
||||
msg_ok "$(translate "Added to /etc/fstab.")"
|
||||
|
||||
pmx_record_execution "reload systemd units after NFS fstab update" "systemctl daemon-reload"
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
|
||||
echo -e ""
|
||||
@@ -742,7 +735,6 @@ remove_nfs_storage() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Remove NFS Storage")"
|
||||
|
||||
pmx_record_execution "remove Proxmox NFS storage ${target}" "pvesm remove ${target}"
|
||||
if pvesm remove "$target" 2>/dev/null; then
|
||||
msg_ok "$(translate "Storage") $target $(translate "removed successfully from Proxmox.")"
|
||||
else
|
||||
@@ -767,7 +759,6 @@ remove_nfs_storage() {
|
||||
|
||||
# Try umount only if currently mounted; never force.
|
||||
if mount | grep -q " on ${mount_path} type "; then
|
||||
pmx_record_execution "unmount NFS path ${mount_path}" "umount ${mount_path}"
|
||||
if umount "$mount_path" 2>/dev/null; then
|
||||
msg_ok "$(translate "Unmounted:") $mount_path"
|
||||
else
|
||||
@@ -789,7 +780,6 @@ remove_nfs_storage() {
|
||||
msg_error "$(translate "Failed to edit /etc/fstab — remove the line manually.")"
|
||||
fi
|
||||
|
||||
pmx_record_execution "reload systemd units after NFS fstab removal" "systemctl daemon-reload"
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
|
||||
# Try to remove the directory if empty; keep it otherwise.
|
||||
|
||||
@@ -31,10 +31,6 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
# Load shared functions
|
||||
SHARE_COMMON_FILE="$LOCAL_SCRIPTS/global/share-common.func"
|
||||
if ! source "$SHARE_COMMON_FILE" 2>/dev/null; then
|
||||
@@ -53,10 +49,6 @@ select_privileged_lxc
|
||||
|
||||
setup_universal_sharedfiles_group() {
|
||||
local ctid="$1"
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "setup_universal_sharedfiles_group" "$FUNC_VERSION"
|
||||
pmx_record_execution "configure sharedfiles group and UID mappings in CT ${ctid}" \
|
||||
"pct exec ${ctid} -- manage sharedfiles group, memberships and remapped users"
|
||||
|
||||
msg_info "$(translate "Setting sharedfiles group with UID remapping...")"
|
||||
|
||||
@@ -143,9 +135,6 @@ setup_universal_sharedfiles_group() {
|
||||
|
||||
|
||||
select_mount_point() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "select_mount_point" "$FUNC_VERSION"
|
||||
|
||||
while true; do
|
||||
METHOD=$(whiptail --backtitle "ProxMenux" --title "$(translate "Select Folder")" \
|
||||
--menu "$(translate "How do you want to select the folder to export?")" 15 60 5 \
|
||||
@@ -192,8 +181,6 @@ select_mount_point() {
|
||||
--msgbox "$(translate "No mount point was specified.")" 8 50
|
||||
continue
|
||||
fi
|
||||
pmx_record_execution "create NFS export directory ${MOUNT_POINT} in CT ${CTID}" \
|
||||
"pct exec ${CTID} -- mkdir -p ${MOUNT_POINT}"
|
||||
pct exec "$CTID" -- mkdir -p "$MOUNT_POINT" 2>/dev/null
|
||||
return 0
|
||||
;;
|
||||
@@ -265,7 +252,6 @@ select_export_options() {
|
||||
|
||||
|
||||
create_nfs_export() {
|
||||
local FUNC_VERSION="1.0"
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create LXC server NFS")"
|
||||
@@ -276,10 +262,6 @@ create_nfs_export() {
|
||||
get_network_config || return
|
||||
select_export_options || return
|
||||
|
||||
pmx_journal_context "create_nfs_export" "$FUNC_VERSION"
|
||||
pmx_record_execution "configure NFS export ${MOUNT_POINT} in CT ${CTID}" \
|
||||
"install and enable NFS services, update /etc/exports and reload exports"
|
||||
|
||||
|
||||
msg_ok "$(translate "Directory successfully.")"
|
||||
|
||||
@@ -287,7 +269,7 @@ create_nfs_export() {
|
||||
if ! pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
|
||||
msg_info "$(translate "Installing NFS server packages inside the CT...")"
|
||||
pct exec "$CTID" -- bash -c "apt-get update && apt-get install -y nfs-kernel-server nfs-common rpcbind"
|
||||
pct exec "$CTID" -- systemctl --now enable rpcbind nfs-kernel-server
|
||||
pct exec "$CTID" -- systemctl enable --now rpcbind nfs-kernel-server
|
||||
msg_ok "$(translate "NFS server installed successfully.")"
|
||||
else
|
||||
msg_ok "$(translate "NFS server is already installed.")"
|
||||
@@ -314,8 +296,8 @@ create_nfs_export() {
|
||||
if pct exec "$CTID" -- grep -q "^$MOUNT_POINT " /etc/exports; then
|
||||
if dialog --yesno "$(translate "Do you want to update the existing export?")" \
|
||||
10 60 --title "$(translate "Update Export")"; then
|
||||
pct exec "$CTID" -- sed --in-place "\|^$MOUNT_POINT |d" /etc/exports
|
||||
pct exec "$CTID" -- bash -c "printf '%s\\n' '$EXPORT_LINE' | tee -a /etc/exports >/dev/null"
|
||||
pct exec "$CTID" -- sed -i "\|^$MOUNT_POINT |d" /etc/exports
|
||||
pct exec "$CTID" -- bash -c "echo '$EXPORT_LINE' >> /etc/exports"
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create LXC server NFS")"
|
||||
msg_ok "$(translate "Directory successfully.")"
|
||||
@@ -325,7 +307,7 @@ create_nfs_export() {
|
||||
|
||||
fi
|
||||
else
|
||||
pct exec "$CTID" -- bash -c "printf '%s\\n' '$EXPORT_LINE' | tee -a /etc/exports >/dev/null"
|
||||
pct exec "$CTID" -- bash -c "echo '$EXPORT_LINE' >> /etc/exports"
|
||||
msg_ok "$(translate "Export added successfully.")"
|
||||
fi
|
||||
|
||||
@@ -423,9 +405,6 @@ view_exports() {
|
||||
}
|
||||
|
||||
delete_export() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "delete_export" "$FUNC_VERSION"
|
||||
|
||||
if ! pct exec "$CTID" -- test -f /etc/exports; then
|
||||
dialog --title "$(translate "Error")" --msgbox "\n$(translate "No exports file found.")" 8 50
|
||||
return
|
||||
@@ -456,9 +435,7 @@ delete_export() {
|
||||
if whiptail --yesno "$(translate "Are you sure you want to delete this export?")\n\n$EXPORT_LINE" 10 70 --title "$(translate "Confirm Deletion")"; then
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Delete Export")"
|
||||
pmx_record_execution "remove NFS export line ${SELECTED_NUM} from CT ${CTID}" \
|
||||
"edit /etc/exports and restart nfs-kernel-server"
|
||||
pct exec "$CTID" -- sed --in-place "${SELECTED_NUM}d" /etc/exports
|
||||
pct exec "$CTID" -- sed -i "${SELECTED_NUM}d" /etc/exports
|
||||
pct exec "$CTID" -- exportfs -ra
|
||||
pct exec "$CTID" -- systemctl restart nfs-kernel-server
|
||||
msg_ok "$(translate "Export deleted and NFS service restarted.")"
|
||||
@@ -529,9 +506,6 @@ check_nfs_status() {
|
||||
}
|
||||
|
||||
uninstall_nfs() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "uninstall_nfs" "$FUNC_VERSION"
|
||||
|
||||
if ! pct exec "$CTID" -- dpkg -s nfs-kernel-server &>/dev/null; then
|
||||
dialog --title "$(translate "NFS Not Installed")" --msgbox "\n$(translate "NFS server is not installed in this CT.")" 8 60
|
||||
return
|
||||
@@ -545,8 +519,6 @@ uninstall_nfs() {
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Uninstall NFS Server")"
|
||||
pmx_record_execution "uninstall NFS server from CT ${CTID}" \
|
||||
"stop and disable NFS services, clear exports, remove users, groups and packages"
|
||||
|
||||
msg_info "$(translate "Stopping NFS services...")"
|
||||
pct exec "$CTID" -- systemctl stop nfs-kernel-server 2>/dev/null || true
|
||||
|
||||
@@ -55,8 +55,6 @@ select_privileged_lxc
|
||||
install_samba_client() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "install_samba_client" "$FUNC_VERSION"
|
||||
pmx_record_execution "install and prepare Samba client in CT ${CTID}" \
|
||||
"pct exec ${CTID} -- install cifs-utils and smbclient; create ${CREDENTIALS_DIR}"
|
||||
|
||||
if pct exec "$CTID" -- dpkg -s cifs-utils &>/dev/null && pct exec "$CTID" -- dpkg -s smbclient &>/dev/null; then
|
||||
pct exec "$CTID" -- mkdir -p "$CREDENTIALS_DIR"
|
||||
@@ -699,8 +697,6 @@ create_credentials_file() {
|
||||
|
||||
CRED_FILE="$CREDENTIALS_DIR/${SAMBA_SERVER}_${SAMBA_SHARE}.cred"
|
||||
|
||||
pmx_record_execution "create Samba credentials file ${CRED_FILE} in CT ${CTID}" \
|
||||
"pct exec ${CTID} -- write credentials file and chmod 600"
|
||||
|
||||
pct exec "$CTID" -- bash -c "cat > '$CRED_FILE' << EOF
|
||||
username=$USERNAME
|
||||
@@ -773,8 +769,6 @@ mount_samba_share() {
|
||||
configure_mount_options || return
|
||||
|
||||
pmx_journal_context "mount_samba_share" "$FUNC_VERSION"
|
||||
pmx_record_execution "mount Samba share //${SAMBA_SERVER}/${SAMBA_SHARE} in CT ${CTID} at ${MOUNT_POINT}" \
|
||||
"pct exec ${CTID} -- mount CIFS share; persistent=${PERMANENT_MOUNT}"
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Installing Samba Client in LXC")"
|
||||
@@ -978,8 +972,6 @@ unmount_samba_share() {
|
||||
msg_title "$(translate "Unmount Samba Share")"
|
||||
|
||||
CRED_FILE=$(pct exec "$CTID" -- grep -E "\s+$SELECTED_MOUNT\s+" /etc/fstab 2>/dev/null | grep -o "credentials=[^, ]*" | cut -d= -f2 || true)
|
||||
pmx_record_execution "remove Samba mount ${SELECTED_MOUNT} from CT ${CTID}" \
|
||||
"remove CT fstab entry and credentials file when present"
|
||||
pct exec "$CTID" -- sed --in-place "\|[[:space:]]$SELECTED_MOUNT[[:space:]]|d" /etc/fstab
|
||||
msg_ok "$(translate "Removed from /etc/fstab.")"
|
||||
|
||||
|
||||
@@ -297,8 +297,6 @@ add_proxmox_cifs_storage() {
|
||||
8 60 --title "$(translate "Storage Exists")"; then
|
||||
return 0
|
||||
fi
|
||||
pmx_record_execution "remove Proxmox CIFS storage ${storage_id}" \
|
||||
"pvesm remove ${storage_id}"
|
||||
pvesm remove "$storage_id" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
@@ -306,8 +304,6 @@ add_proxmox_cifs_storage() {
|
||||
msg_info "$(translate "Adding CIFS storage to Proxmox...")"
|
||||
|
||||
local pvesm_result pvesm_output
|
||||
pmx_record_execution "add Proxmox CIFS storage ${storage_id}" \
|
||||
"pvesm add cifs ${storage_id} --server ${server} --share ${share} --content ${content}"
|
||||
if [[ "$USE_GUEST" == "true" ]]; then
|
||||
pvesm_output=$(pvesm add cifs "$storage_id" \
|
||||
--server "$server" \
|
||||
@@ -435,8 +431,6 @@ write_host_credentials_file() {
|
||||
return 0
|
||||
fi
|
||||
local creds_dir="/etc/samba/credentials"
|
||||
pmx_record_execution "create Samba credentials directory ${creds_dir}" \
|
||||
"mkdir -p ${creds_dir}; chmod 0700 ${creds_dir}"
|
||||
mkdir -p "$creds_dir"
|
||||
chmod 0700 "$creds_dir"
|
||||
HOST_CRED_FILE="${creds_dir}/$(echo "${SAMBA_SERVER}_${SAMBA_SHARE}" | tr -c 'A-Za-z0-9._-' '_').cred"
|
||||
@@ -464,8 +458,6 @@ mount_cifs_via_fstab() {
|
||||
msg_info "$(translate "Preparing host mount...")"
|
||||
|
||||
if [[ ! -d "$mount_path" ]]; then
|
||||
pmx_record_execution "create CIFS mount point ${mount_path}" \
|
||||
"mkdir -p ${mount_path}"
|
||||
if ! mkdir -p "$mount_path" 2>/dev/null; then
|
||||
msg_error "$(translate "Failed to create mount point:") $mount_path"
|
||||
return 1
|
||||
@@ -481,8 +473,6 @@ mount_cifs_via_fstab() {
|
||||
fi
|
||||
|
||||
msg_info "$(translate "Mounting CIFS share...")"
|
||||
pmx_record_execution "mount CIFS share //${server}/${share} at ${mount_path}" \
|
||||
"mount -t cifs //${server}/${share} ${mount_path}"
|
||||
if ! mount -t cifs -o "$mount_opts" "//${server}/${share}" "$mount_path" >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to mount CIFS share on host.")"
|
||||
return 1
|
||||
@@ -503,7 +493,6 @@ mount_cifs_via_fstab() {
|
||||
echo "//${server}/${share} $mount_path cifs $mount_opts 0 0" | pmx_append_file /etc/fstab
|
||||
msg_ok "$(translate "Added to /etc/fstab.")"
|
||||
|
||||
pmx_record_execution "reload systemd after CIFS fstab update" "systemctl daemon-reload"
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
|
||||
echo -e ""
|
||||
@@ -815,8 +804,6 @@ remove_cifs_storage() {
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Remove CIFS Storage")"
|
||||
|
||||
pmx_record_execution "remove Proxmox CIFS storage ${target}" \
|
||||
"pvesm remove ${target}"
|
||||
if pvesm remove "$target" 2>/dev/null; then
|
||||
msg_ok "$(translate "Storage") $target $(translate "removed successfully from Proxmox.")"
|
||||
else
|
||||
@@ -850,8 +837,6 @@ remove_cifs_storage() {
|
||||
msg_title "$(translate "Remove CIFS fstab Mount")"
|
||||
|
||||
if mount | grep -q " on ${mount_path} type "; then
|
||||
pmx_record_execution "unmount CIFS path ${mount_path}" \
|
||||
"umount ${mount_path}"
|
||||
if umount "$mount_path" 2>/dev/null; then
|
||||
msg_ok "$(translate "Unmounted:") $mount_path"
|
||||
else
|
||||
@@ -872,7 +857,6 @@ remove_cifs_storage() {
|
||||
msg_error "$(translate "Failed to edit /etc/fstab — remove the line manually.")"
|
||||
fi
|
||||
|
||||
pmx_record_execution "reload systemd after CIFS fstab removal" "systemctl daemon-reload"
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
|
||||
# Remove credentials file if it's under the standard ProxMenux dir
|
||||
|
||||
@@ -32,10 +32,6 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
|
||||
SHARE_COMMON_FILE="$LOCAL_SCRIPTS/global/share-common.func"
|
||||
if ! source "$SHARE_COMMON_FILE" 2>/dev/null; then
|
||||
@@ -52,9 +48,6 @@ select_privileged_lxc
|
||||
|
||||
|
||||
select_mount_point() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "select_mount_point" "$FUNC_VERSION"
|
||||
|
||||
while true; do
|
||||
METHOD=$(whiptail --backtitle "ProxMenux" --title "$(translate "Select Folder")" \
|
||||
--menu "$(translate "How do you want to select the folder to share?")" 15 60 5 \
|
||||
@@ -111,16 +104,12 @@ select_mount_point() {
|
||||
|
||||
|
||||
create_share() {
|
||||
local FUNC_VERSION="1.0"
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Create Samba server service")"
|
||||
sleep 2
|
||||
|
||||
select_mount_point || return
|
||||
pmx_journal_context "create_share" "$FUNC_VERSION"
|
||||
pmx_record_execution "configure Samba share ${MOUNT_POINT} in CT ${CTID}" \
|
||||
"pct exec ${CTID} -- install and configure Samba share ${MOUNT_POINT}"
|
||||
|
||||
|
||||
if ! pct exec "$CTID" -- test -d "$MOUNT_POINT"; then
|
||||
@@ -322,7 +311,7 @@ EOF
|
||||
msg_warn "$(translate "The share already exists in smb.conf:") [$SHARE_NAME]"
|
||||
if whiptail --yesno "$(translate "Do you want to update the existing share?")" 10 60 --title "$(translate "Update Share")"; then
|
||||
|
||||
pct exec "$CTID" -- sed --in-place "/^\[$SHARE_NAME\]/,/^$/d" /etc/samba/smb.conf
|
||||
pct exec "$CTID" -- sed -i "/^\[$SHARE_NAME\]/,/^$/d" /etc/samba/smb.conf
|
||||
pct exec "$CTID" -- bash -c "echo '$CONFIG' >> /etc/samba/smb.conf"
|
||||
msg_ok "$(translate "Share updated successfully.")"
|
||||
else
|
||||
@@ -417,9 +406,6 @@ view_shares() {
|
||||
|
||||
|
||||
delete_share() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "delete_share" "$FUNC_VERSION"
|
||||
|
||||
if ! pct exec "$CTID" -- test -f /etc/samba/smb.conf; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Error")" --msgbox "\n$(translate "No smb.conf file found.")" 8 50
|
||||
return
|
||||
@@ -452,9 +438,7 @@ delete_share() {
|
||||
msg_title "$(translate "Delete Share")"
|
||||
|
||||
|
||||
pmx_record_execution "remove Samba share ${SELECTED_SHARE} from CT ${CTID}" \
|
||||
"pct exec ${CTID} -- remove share ${SELECTED_SHARE} from /etc/samba/smb.conf and restart smbd"
|
||||
pct exec "$CTID" -- sed --in-place "/^\[$SELECTED_SHARE\]/,/^$/d" /etc/samba/smb.conf
|
||||
pct exec "$CTID" -- sed -i "/^\[$SELECTED_SHARE\]/,/^$/d" /etc/samba/smb.conf
|
||||
pct exec "$CTID" -- systemctl restart smbd.service
|
||||
msg_ok "$(translate "Share deleted and Samba service restarted.")"
|
||||
fi
|
||||
@@ -511,7 +495,6 @@ check_samba_status() {
|
||||
|
||||
|
||||
uninstall_samba() {
|
||||
local FUNC_VERSION="1.0"
|
||||
|
||||
if ! pct exec "$CTID" -- dpkg -s samba &>/dev/null; then
|
||||
dialog --backtitle "ProxMenux" --title "$(translate "Samba Not Installed")" --msgbox "\n$(translate "Samba server is not installed in this CT.")" 8 60
|
||||
@@ -527,9 +510,6 @@ uninstall_samba() {
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Uninstall Samba Server")"
|
||||
pmx_journal_context "uninstall_samba" "$FUNC_VERSION"
|
||||
pmx_record_execution "uninstall Samba server from CT ${CTID}" \
|
||||
"pct exec ${CTID} -- stop services, preserve smb.conf backup, remove Samba users and packages"
|
||||
|
||||
|
||||
msg_info "$(translate "Stopping Samba services...")"
|
||||
|
||||
@@ -39,9 +39,6 @@ if [[ -f "$LOCAL_SCRIPTS_LOCAL/global/pci_passthrough_helpers.sh" ]]; then
|
||||
elif [[ -f "$LOCAL_SCRIPTS_DEFAULT/global/pci_passthrough_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS_DEFAULT/global/pci_passthrough_helpers.sh"
|
||||
fi
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -77,9 +74,6 @@ register_vfio_iommu_tool() {
|
||||
}
|
||||
|
||||
enable_iommu_cmdline() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "enable_iommu_cmdline" "$FUNC_VERSION"
|
||||
|
||||
local silent="${1:-}"
|
||||
local cpu_vendor iommu_param
|
||||
cpu_vendor=$(grep -m1 "vendor_id" /proc/cpuinfo 2>/dev/null | awk '{print $3}')
|
||||
@@ -101,8 +95,7 @@ enable_iommu_cmdline() {
|
||||
if [[ -f "$cmdline_file" ]] && grep -qE 'root=ZFS=|root=ZFS/' "$cmdline_file" 2>/dev/null; then
|
||||
if ! grep -q "$iommu_param" "$cmdline_file" || ! grep -q "iommu=pt" "$cmdline_file"; then
|
||||
cp "$cmdline_file" "${cmdline_file}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||
pmx_edit_file "$cmdline_file" "s|\\s*$| ${iommu_param} iommu=pt|"
|
||||
pmx_record_execution "refresh Proxmox boot entries" "proxmox-boot-tool refresh"
|
||||
sed -i "s|\\s*$| ${iommu_param} iommu=pt|" "$cmdline_file"
|
||||
proxmox-boot-tool refresh >/dev/null 2>&1 || true
|
||||
[[ "$silent" != "silent" ]] && msg_ok "$(translate "IOMMU parameters added to /etc/kernel/cmdline")"
|
||||
else
|
||||
@@ -111,8 +104,7 @@ enable_iommu_cmdline() {
|
||||
elif [[ -f "$grub_file" ]]; then
|
||||
if ! grep -q "$iommu_param" "$grub_file" || ! grep -q "iommu=pt" "$grub_file"; then
|
||||
cp "$grub_file" "${grub_file}.bak.$(date +%Y%m%d_%H%M%S)"
|
||||
pmx_edit_file "$grub_file" "/GRUB_CMDLINE_LINUX_DEFAULT=/ s|\"$| ${iommu_param} iommu=pt\"|"
|
||||
pmx_record_execution "regenerate GRUB configuration" "update-grub"
|
||||
sed -i "/GRUB_CMDLINE_LINUX_DEFAULT=/ s|\"$| ${iommu_param} iommu=pt\"|" "$grub_file"
|
||||
update-grub >/dev/null 2>&1 || true
|
||||
[[ "$silent" != "silent" ]] && msg_ok "$(translate "IOMMU parameters added to GRUB")"
|
||||
else
|
||||
@@ -529,9 +521,6 @@ prompt_controller_conflict_policy() {
|
||||
|
||||
# ── DIALOG PHASE: resolve all conflicts before terminal ───────────────────────
|
||||
resolve_disk_conflicts() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "resolve_disk_conflicts" "$FUNC_VERSION"
|
||||
|
||||
local -a new_pci_list=()
|
||||
local pci vmid action slot_base scope_key has_running
|
||||
|
||||
@@ -570,18 +559,13 @@ resolve_disk_conflicts() {
|
||||
case "$action" in
|
||||
keep_disable_onboot)
|
||||
for vmid in "${source_vms[@]}"; do
|
||||
if _vm_onboot_is_enabled "$vmid"; then
|
||||
pmx_record_execution "disable autostart for source VM ${vmid}" "qm set ${vmid} -onboot 0"
|
||||
qm set "$vmid" -onboot 0 >/dev/null 2>&1
|
||||
fi
|
||||
_vm_onboot_is_enabled "$vmid" && qm set "$vmid" -onboot 0 >/dev/null 2>&1
|
||||
done
|
||||
new_pci_list+=("$pci")
|
||||
;;
|
||||
move_remove_source)
|
||||
slot_base=$(_pci_slot_base "$pci")
|
||||
for vmid in "${source_vms[@]}"; do
|
||||
pmx_record_execution "remove PCI slot ${slot_base} from source VM ${vmid}" \
|
||||
"_remove_pci_slot_from_vm_config ${vmid} ${slot_base}"
|
||||
_remove_pci_slot_from_vm_config "$vmid" "$slot_base"
|
||||
done
|
||||
new_pci_list+=("$pci")
|
||||
@@ -632,15 +616,10 @@ resolve_disk_conflicts() {
|
||||
for gid in "${guest_ids[@]}"; do
|
||||
gtype="${gid%%:*}"; gid_num="${gid##*:}"
|
||||
if [[ "$gtype" == "VM" ]]; then
|
||||
if _vm_onboot_is_enabled "$gid_num"; then
|
||||
pmx_record_execution "disable autostart for VM ${gid_num}" "qm set ${gid_num} -onboot 0"
|
||||
qm set "$gid_num" -onboot 0 >/dev/null 2>&1
|
||||
fi
|
||||
_vm_onboot_is_enabled "$gid_num" && qm set "$gid_num" -onboot 0 >/dev/null 2>&1
|
||||
else
|
||||
if grep -qE '^onboot:\s*1' "/etc/pve/lxc/$gid_num.conf" 2>/dev/null; then
|
||||
pmx_record_execution "disable autostart for CT ${gid_num}" "pct set ${gid_num} -onboot 0"
|
||||
grep -qE '^onboot:\s*1' "/etc/pve/lxc/$gid_num.conf" 2>/dev/null && \
|
||||
pct set "$gid_num" -onboot 0 >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
;;
|
||||
@@ -650,15 +629,11 @@ resolve_disk_conflicts() {
|
||||
if [[ "$gtype" == "VM" ]]; then
|
||||
while IFS= read -r slot; do
|
||||
[[ -z "$slot" ]] && continue
|
||||
pmx_record_execution "remove disk slot ${slot} from VM ${gid_num}" \
|
||||
"qm set ${gid_num} -delete ${slot}"
|
||||
qm set "$gid_num" -delete "$slot" >/dev/null 2>&1
|
||||
done < <(_find_disk_slots_in_vm "$gid_num" "$disk")
|
||||
else
|
||||
while IFS= read -r slot; do
|
||||
[[ -z "$slot" ]] && continue
|
||||
pmx_record_execution "remove disk slot ${slot} from CT ${gid_num}" \
|
||||
"pct set ${gid_num} -delete ${slot}"
|
||||
pct set "$gid_num" -delete "$slot" >/dev/null 2>&1
|
||||
done < <(_find_disk_slots_in_ct "$gid_num" "$disk")
|
||||
fi
|
||||
@@ -672,9 +647,6 @@ resolve_disk_conflicts() {
|
||||
}
|
||||
|
||||
apply_assignment() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "apply_assignment" "$FUNC_VERSION"
|
||||
|
||||
: >"$LOG_FILE"
|
||||
set_title
|
||||
|
||||
@@ -709,8 +681,6 @@ apply_assignment() {
|
||||
local display_name
|
||||
display_name=$(_pci_storage_display_name "$pci")
|
||||
msg_info "$(translate "Adding") ${display_name} (${pci}) → hostpci${hostpci_idx}..."
|
||||
pmx_record_execution "assign PCI device ${pci} to VM ${SELECTED_VMID} as hostpci${hostpci_idx}" \
|
||||
"qm set ${SELECTED_VMID} --hostpci${hostpci_idx} ${pci},pcie=1"
|
||||
if qm set "$SELECTED_VMID" "--hostpci${hostpci_idx}" "${pci},pcie=1" >>"$LOG_FILE" 2>&1; then
|
||||
msg_ok "$(translate "Controller/NVMe assigned") (hostpci${hostpci_idx} → ${pci})"
|
||||
assigned_count=$((assigned_count + 1))
|
||||
@@ -739,7 +709,6 @@ apply_assignment() {
|
||||
msg_success "$(translate "Press Enter to continue...")"
|
||||
read -r
|
||||
msg_warn "$(translate "Rebooting the system...")"
|
||||
pmx_record_execution "reboot host after enabling IOMMU" "reboot"
|
||||
reboot
|
||||
else
|
||||
msg_info2 "$(translate "To use the VM without issues, the host must be restarted before starting it.")"
|
||||
|
||||
@@ -48,12 +48,6 @@ elif [[ -f "$LOCAL_SCRIPTS_DEFAULT/global/vm_storage_helpers.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS_DEFAULT/global/vm_storage_helpers.sh"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
FUNC_VERSION="1.3"
|
||||
|
||||
BACKTITLE="ProxMenux"
|
||||
UI_MENU_H=20
|
||||
UI_MENU_W=84
|
||||
@@ -126,20 +120,12 @@ get_preferred_disk_path() {
|
||||
install_fs_tools_in_ct() {
|
||||
local ctid="$1"
|
||||
local pkg="$2"
|
||||
local FUNC_VERSION="1.3"
|
||||
pmx_journal_context "install_fs_tools_in_ct" "$FUNC_VERSION"
|
||||
|
||||
if pct exec "$ctid" -- sh -c "[ -f /etc/alpine-release ]"; then
|
||||
pmx_record_execution "install ${pkg} in CT ${ctid}" \
|
||||
"pct exec ${ctid} -- apk update and apk add ${pkg}"
|
||||
pct exec "$ctid" -- sh -c "apk update >/dev/null 2>&1 && apk add --no-progress $pkg >/dev/null 2>&1"
|
||||
elif pct exec "$ctid" -- sh -c "grep -qi 'arch' /etc/os-release 2>/dev/null"; then
|
||||
pmx_record_execution "install ${pkg} in CT ${ctid}" \
|
||||
"pct exec ${ctid} -- pacman -Sy --noconfirm ${pkg}"
|
||||
pct exec "$ctid" -- sh -c "pacman -Sy --noconfirm $pkg >/dev/null 2>&1"
|
||||
elif pct exec "$ctid" -- sh -c "grep -qiE 'debian|ubuntu' /etc/os-release 2>/dev/null"; then
|
||||
pmx_record_execution "install ${pkg} in CT ${ctid}" \
|
||||
"pct exec ${ctid} -- apt-get update and apt-get install ${pkg}"
|
||||
pct exec "$ctid" -- sh -c "apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq $pkg >/dev/null 2>&1"
|
||||
else
|
||||
return 1
|
||||
@@ -261,15 +247,12 @@ msg_ok "$(translate "CT $CTID selected successfully.")"
|
||||
|
||||
if [ "$CONVERT_PRIVILEGED" = true ]; then
|
||||
|
||||
pmx_journal_context "disk_passthrough_ct" "$FUNC_VERSION"
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Import Disk to LXC")"
|
||||
|
||||
CURRENT_CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
|
||||
if [ "$CURRENT_CT_STATUS" == "running" ]; then
|
||||
msg_info "$(translate "Stopping container") $CTID..."
|
||||
pmx_record_execution "stop CT ${CTID} for privileged conversion" "pct shutdown ${CTID}"
|
||||
pct shutdown "$CTID" &>/dev/null
|
||||
for i in {1..10}; do
|
||||
sleep 1
|
||||
@@ -283,13 +266,12 @@ if [ "$CONVERT_PRIVILEGED" = true ]; then
|
||||
fi
|
||||
|
||||
cp "$CONF_FILE" "$CONF_FILE.bak"
|
||||
pmx_edit_file "$CONF_FILE" '/^unprivileged: 1/d'
|
||||
echo "unprivileged: 0" | pmx_append_file "$CONF_FILE"
|
||||
sed -i '/^unprivileged: 1/d' "$CONF_FILE"
|
||||
echo "unprivileged: 0" >> "$CONF_FILE"
|
||||
msg_ok "$(translate "Container successfully converted to privileged.")"
|
||||
|
||||
if [ "$CT_RUNNING" = true ]; then
|
||||
msg_info "$(translate "Starting container") $CTID..."
|
||||
pmx_record_execution "start CT ${CTID} after privileged conversion" "pct start ${CTID}"
|
||||
pct start "$CTID" &>/dev/null
|
||||
sleep 2
|
||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
||||
@@ -585,8 +567,6 @@ msg_title "$(translate "Import Disk to LXC")"
|
||||
msg_ok "$(translate "CT $CTID selected successfully.")"
|
||||
msg_ok "$(translate "Disks to process:") ${#DISK_LIST[@]}"
|
||||
for i in "${!DISK_LIST[@]}"; do
|
||||
pmx_journal_context "disk_passthrough_ct" "$FUNC_VERSION"
|
||||
|
||||
IFS=$'\t' read -r _desc_model _desc_size <<< "${DISK_DESCRIPTIONS[$i]}"
|
||||
echo -e "${TAB}${BL}${DISK_LIST[$i]} $_desc_model $_desc_size${CL}"
|
||||
done
|
||||
@@ -610,8 +590,6 @@ for i in "${!DISK_LIST[@]}"; do
|
||||
|
||||
if [ "$NEEDS_PARTITION" = true ]; then
|
||||
msg_info "$(translate "Creating partition table and partition...")"
|
||||
pmx_record_execution "create GPT partition on ${DISK} for CT ${CTID}" \
|
||||
"parted -s ${DISK} mklabel gpt mkpart primary 0% 100%"
|
||||
if ! parted -s "$DISK" mklabel gpt mkpart primary 0% 100% >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to create partition table on disk") $DISK_INFO."
|
||||
continue
|
||||
@@ -638,8 +616,6 @@ for i in "${!DISK_LIST[@]}"; do
|
||||
|
||||
if [ "$SKIP_FORMAT" != true ]; then
|
||||
msg_info "$(translate "Formatting partition") $PARTITION $(translate "with") $FORMAT_TYPE..."
|
||||
pmx_record_execution "format ${PARTITION} as ${FORMAT_TYPE} for CT ${CTID}" \
|
||||
"mkfs ${FORMAT_TYPE} ${PARTITION}"
|
||||
if ! case "$FORMAT_TYPE" in
|
||||
"ext4") mkfs.ext4 -F "$PARTITION" >/dev/null 2>&1 ;;
|
||||
"xfs") mkfs.xfs -f "$PARTITION" >/dev/null 2>&1 ;;
|
||||
@@ -682,7 +658,6 @@ for i in "${!DISK_LIST[@]}"; do
|
||||
--yesno "$(translate "The filesystem") $FORMAT_TYPE $(translate "requires the package") $FS_PKG $(translate "installed inside CT") $CTID.\n\n$(translate "The container is currently stopped. Do you want to start it now to install the package?")\n\n$(translate "If you choose No, install") $FS_PKG $(translate "manually inside the container before starting it.")" \
|
||||
$UI_YESNO_H $UI_YESNO_W; then
|
||||
msg_info "$(translate "Starting CT") $CTID..."
|
||||
pmx_record_execution "start CT ${CTID} to install filesystem tools" "pct start ${CTID}"
|
||||
pct start "$CTID" &>/dev/null
|
||||
sleep 2
|
||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
||||
@@ -710,14 +685,9 @@ for i in "${!DISK_LIST[@]}"; do
|
||||
PERSISTENT_PARTITION=$(get_preferred_disk_path "$PARTITION")
|
||||
|
||||
msg_info "$(translate "Applying passthrough to CT") $CTID..."
|
||||
pmx_journal_context "disk_passthrough_ct" "$FUNC_VERSION"
|
||||
if [ "$FORMAT_TYPE" == "xfs" ]; then
|
||||
pmx_record_execution "assign ${PERSISTENT_PARTITION} to CT ${CTID} at ${MOUNT_POINT}" \
|
||||
"pct set ${CTID} -mp${INDEX} ${PERSISTENT_PARTITION},mp=${MOUNT_POINT},backup=0,ro=0"
|
||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0" 2>&1)
|
||||
else
|
||||
pmx_record_execution "assign ${PERSISTENT_PARTITION} to CT ${CTID} at ${MOUNT_POINT}" \
|
||||
"pct set ${CTID} -mp${INDEX} ${PERSISTENT_PARTITION},mp=${MOUNT_POINT},backup=0,ro=0,acl=1"
|
||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$PERSISTENT_PARTITION,mp=$MOUNT_POINT,backup=0,ro=0,acl=1" 2>&1)
|
||||
fi
|
||||
SET_STATUS=$?
|
||||
|
||||
@@ -64,9 +64,6 @@ elif [[ -f "$LOCAL_SCRIPTS_DEFAULT/global/utils-install-functions.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS_DEFAULT/global/utils-install-functions.sh"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
BACKTITLE="ProxMenux"
|
||||
UI_MENU_H=20
|
||||
@@ -674,16 +671,18 @@ prompt_zfs_pool_name() {
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
ensure_fs_tool() {
|
||||
local FUNC_VERSION="2.0"
|
||||
pmx_journal_context "ensure_fs_tool" "$FUNC_VERSION"
|
||||
|
||||
case "$FORMAT_TYPE" in
|
||||
exfat)
|
||||
command -v mkfs.exfat >/dev/null 2>&1 && return 0
|
||||
if declare -F ensure_repositories >/dev/null 2>&1; then
|
||||
ensure_repositories || true
|
||||
fi
|
||||
if pmx_install_pkg exfatprogs; then
|
||||
# Installing exfatprogs modifies the host, so it is recorded;
|
||||
# the format operation itself is not. Falls back to raw apt if
|
||||
# the journal helper is not loaded.
|
||||
if { declare -F pmx_install_pkg >/dev/null 2>&1 \
|
||||
&& PMX_JOURNAL_SOURCE="format-disk.sh" pmx_install_pkg exfatprogs; } \
|
||||
|| DEBIAN_FRONTEND=noninteractive apt-get install -y exfatprogs >/dev/null 2>&1; then
|
||||
command -v mkfs.exfat >/dev/null 2>&1 && {
|
||||
msg_ok "$(translate "exFAT tools installed successfully.")"
|
||||
return 0
|
||||
@@ -727,9 +726,6 @@ wait_for_enter_to_main() {
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
main() {
|
||||
local FUNC_VERSION="2.0"
|
||||
pmx_journal_context "main" "$FUNC_VERSION"
|
||||
|
||||
select_target_disk || exit 0
|
||||
select_operation_mode || exit 0
|
||||
confirm_format_action || exit 0
|
||||
@@ -774,10 +770,6 @@ main() {
|
||||
export DOH_SHOW_PROGRESS=0
|
||||
export DOH_ENABLE_STACK_RELEASE=0
|
||||
|
||||
pmx_record_execution \
|
||||
"disk operation ${OPERATION_MODE} on ${SELECTED_DISK}" \
|
||||
"format-disk operation=${OPERATION_MODE} disk=${SELECTED_DISK} filesystem=${FORMAT_TYPE:-none} zfs_pool=${ZFS_POOL_NAME:-none}"
|
||||
|
||||
if [[ "$OPERATION_MODE" == "wipe_all" ]]; then
|
||||
msg_info "$(translate "Wiping partitions and metadata...")"
|
||||
doh_wipe_disk "$SELECTED_DISK"
|
||||
|
||||
@@ -41,10 +41,6 @@ if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -138,9 +134,6 @@ select_vm() {
|
||||
}
|
||||
|
||||
ensure_vm_stopped() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "ensure_vm_stopped" "$FUNC_VERSION"
|
||||
|
||||
local status
|
||||
status=$(qm status "$VMID" 2>/dev/null | awk '{print $2}')
|
||||
|
||||
@@ -153,7 +146,6 @@ ensure_vm_stopped() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
pmx_record_execution "shut down VM ${VMID} for export" "qm shutdown ${VMID} --timeout 120"
|
||||
qm shutdown "$VMID" --timeout 120 >/dev/null 2>&1 || true
|
||||
|
||||
local i
|
||||
@@ -165,7 +157,6 @@ ensure_vm_stopped() {
|
||||
|
||||
if dialog --backtitle "ProxMenux" --title "$(translate "Shutdown timeout")" --yesno \
|
||||
"$(translate "Graceful shutdown timed out.")\n\n$(translate "Force stop VM now?")" 10 60; then
|
||||
pmx_record_execution "force stop VM ${VMID} for export" "qm stop ${VMID}"
|
||||
qm stop "$VMID" >/dev/null 2>&1 || true
|
||||
sleep 2
|
||||
status=$(qm status "$VMID" 2>/dev/null | awk '{print $2}')
|
||||
@@ -525,17 +516,12 @@ print_export_result() {
|
||||
}
|
||||
|
||||
run_export() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "run_export" "$FUNC_VERSION"
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Export VM to OVA or OVF")"
|
||||
|
||||
msg_ok "$(translate "VM selected:") $VMID ($VM_NAME)"
|
||||
msg_ok "$(translate "Export mode:") ${EXPORT_MODE^^}"
|
||||
msg_ok "$(translate "Destination:") $DEST_DIR"
|
||||
pmx_record_execution "export VM ${VMID} as ${EXPORT_MODE^^} to ${DEST_DIR}" \
|
||||
"convert ${DISK_COUNT} VM disk(s), generate OVF metadata and package ${EXPORT_MODE^^}"
|
||||
|
||||
local ts vm_safe base_name
|
||||
ts=$(date +%Y%m%d_%H%M%S)
|
||||
|
||||
@@ -49,9 +49,6 @@ INSTALL_HELPERS="$LOCAL_SCRIPTS/global/utils-install-functions.sh"
|
||||
|
||||
[[ -f "$UTILS_FILE" ]] && source "$UTILS_FILE"
|
||||
[[ -f "$INSTALL_HELPERS" ]] && source "$INSTALL_HELPERS"
|
||||
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
||||
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
||||
fi
|
||||
load_language
|
||||
initialize_cache
|
||||
|
||||
@@ -90,9 +87,6 @@ BRIDGE="vmbr0"
|
||||
# with "syntax error at or near ,". Returns 0 on success, 1 if install
|
||||
# fails (caller is expected to abort with a clear error).
|
||||
ensure_gawk() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "ensure_gawk" "$FUNC_VERSION"
|
||||
|
||||
if command -v gawk >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
@@ -117,7 +111,7 @@ ensure_gawk() {
|
||||
# Fallback when utils-install-functions.sh was not sourced.
|
||||
# Here we own the spinner: msg_info opens it, msg_ok / msg_error closes it.
|
||||
msg_info "$(translate "Installing gawk (required for OVF parsing)...")"
|
||||
if apt-get update -qq >/dev/null 2>&1 && pmx_install_pkg gawk; then
|
||||
if apt-get update -qq >/dev/null 2>&1 && apt-get install -y gawk >/dev/null 2>&1; then
|
||||
msg_ok "$(translate "gawk installed")"
|
||||
return 0
|
||||
fi
|
||||
@@ -484,9 +478,6 @@ confirm_import() {
|
||||
# -------------------------------------------------------
|
||||
|
||||
run_import() {
|
||||
local FUNC_VERSION="1.0"
|
||||
pmx_journal_context "run_import" "$FUNC_VERSION"
|
||||
|
||||
show_proxmenux_logo
|
||||
msg_title "$(translate "Import VM from OVA or OVF")"
|
||||
|
||||
@@ -497,8 +488,6 @@ run_import() {
|
||||
|
||||
# 1. Create VM shell
|
||||
msg_info "$(translate "Creating VM...")"
|
||||
pmx_record_execution "import ${SOURCE_FILE} as VM ${NEW_VMID} on storage ${STORAGE}" \
|
||||
"qm create ${NEW_VMID}; qm importdisk for ${#OVF_DISK_FILES[@]} disk(s); attach disks and configure boot"
|
||||
if ! qm create "$NEW_VMID" \
|
||||
--name "$NEW_VM_NAME" \
|
||||
--memory "$OVF_MEMORY_MB" \
|
||||
@@ -635,7 +624,6 @@ print_import_result() {
|
||||
# -------------------------------------------------------
|
||||
|
||||
main() {
|
||||
local FUNC_VERSION="1.0"
|
||||
if ! command -v pveversion >/dev/null 2>&1; then
|
||||
dialog --backtitle "$BACKTITLE" --title "$(translate "Error")" \
|
||||
--msgbox "$(translate "This script must be run on a Proxmox host.")" 8 60
|
||||
@@ -706,9 +694,6 @@ main() {
|
||||
--yesno "$(translate "Remove the partial VM ($NEW_VMID) and its imported disks?")" 8 60; then
|
||||
clear
|
||||
msg_info "$(translate "Removing partial VM") $NEW_VMID..."
|
||||
pmx_journal_context "main" "$FUNC_VERSION"
|
||||
pmx_record_execution "remove partial imported VM ${NEW_VMID}" \
|
||||
"qm destroy ${NEW_VMID} --destroy-unreferenced-disks 1"
|
||||
if qm destroy "$NEW_VMID" --destroy-unreferenced-disks 1 &>/dev/null; then
|
||||
msg_ok "$(translate "Partial VM removed")"
|
||||
else
|
||||
|
||||
@@ -33,6 +33,9 @@ VENV_PATH="/opt/googletrans-env"
|
||||
if [[ -f "$UTILS_FILE" ]]; then
|
||||
source "$UTILS_FILE"
|
||||
fi
|
||||
if [[ -f "$BASE_DIR/scripts/global/pmx_journal.sh" ]]; then
|
||||
source "$BASE_DIR/scripts/global/pmx_journal.sh"
|
||||
fi
|
||||
|
||||
load_language
|
||||
initialize_cache
|
||||
@@ -125,7 +128,14 @@ function run_uupdump_creator() {
|
||||
msg_info "$(translate "Installing dependencies: ${MISSING[*]}")"
|
||||
apt-get update -qq >/dev/null 2>&1
|
||||
msg_ok "$(translate "All dependencies installed and verified.")"
|
||||
if ! apt-get install -y "${MISSING[@]}" >/dev/null 2>&1; then
|
||||
# Build dependencies land on the host, so they are recorded;
|
||||
# building the ISO is an operation and is not.
|
||||
if declare -F pmx_install_pkg >/dev/null 2>&1; then
|
||||
if ! PMX_JOURNAL_SOURCE="uup_dump_iso_creator.sh" pmx_install_pkg "${MISSING[@]}"; then
|
||||
msg_error "$(translate "Failed to install: ${MISSING[*]}")"
|
||||
exit 1
|
||||
fi
|
||||
elif ! apt-get install -y "${MISSING[@]}" >/dev/null 2>&1; then
|
||||
msg_error "$(translate "Failed to install: ${MISSING[*]}")"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user