import type { Metadata } from "next" import { getTranslations, getMessages, setRequestLocale } from "next-intl/server" import { Link } from "@/i18n/navigation" import Image from "next/image" import { DocHeader } from "@/components/ui/doc-header" import { Callout } from "@/components/ui/callout" import CopyableCode from "@/components/CopyableCode" export async function generateMetadata({ params, }: { params: Promise<{ locale: string }> }): Promise { const { locale } = await params const t = await getTranslations({ locale, namespace: "docs.storageShare.hostIscsi.meta" }) return { title: t("title"), description: t("description"), openGraph: { title: t("ogTitle"), description: t("ogDescription"), type: "article", url: "https://macrimi.github.io/ProxMenux/docs/storage-share/host-iscsi", }, } } type VocabRow = { term: string; meaningRich: string } type StringItem = string type RelatedItem = { href: string; label: string; tail?: string } export default async function HostIscsiPage({ params, }: { params: Promise<{ locale: string }> }) { const { locale } = await params setRequestLocale(locale) const t = await getTranslations({ locale, namespace: "docs.storageShare.hostIscsi" }) const messages = (await getMessages({ locale })) as unknown as { docs: { storageShare: { hostIscsi: { vocab: { rows: VocabRow[] } add: { items: StringItem[] } troubleshoot: { discoverItems: StringItem[] } related: { items: RelatedItem[] } } } } } const vocabRows = messages.docs.storageShare.hostIscsi.vocab.rows const addItems = messages.docs.storageShare.hostIscsi.add.items const discoverItems = messages.docs.storageShare.hostIscsi.troubleshoot.discoverItems const relatedItems = messages.docs.storageShare.hostIscsi.related.items const code = (chunks: React.ReactNode) => {chunks} const strong = (chunks: React.ReactNode) => {chunks} const em = (chunks: React.ReactNode) => {chunks} return (
{t.rich("intro.body", { code })}

{t("vocab.heading")}

{vocabRows.map((row, idx) => ( ))}
{t("vocab.headerTerm")} {t("vocab.headerMeaning")}
{row.term} {t.rich(`vocab.rows.${idx}.meaningRich`, { code, em })}

{t("opening.heading")}

{t.rich("opening.body", { strong })}

{t("opening.imageAlt")}

{t("howRuns.heading")}

{t("howRuns.body")}

{`┌─────────────────────────────────────────────┐
│  PHASE 1 — Prepare initiator, discover      │
│  (nothing touched yet in storage.cfg)       │
└──────────────────┬──────────────────────────┘
                   ▼
      Dependency check
      └─ iscsiadm present? (open-iscsi package)
         If missing → apt-get install open-iscsi
                     + systemctl enable --now iscsid
                   │
                   ▼
      Portal entry (manual only)
      └─ user types    or  :
         If no ':' → ProxMenux appends ":3260"
                   │
                   ▼
      Reachability validation
      ├─ ping -c 1 -W 3           ── fail → abort
      └─ nc -z -w 3         ── warn but continue
         (iSCSI over alternative ports may block nc)
                   │
                   ▼
      Target discovery
      iscsiadm --mode discovery --type sendtargets \\
               --portal 
      Extracts IQNs from stdout (lines matching ^iqn\\.)
                   │
                   ▼
      Target selection
      ├─ 1 target found → auto-selected
      └─ 2+ targets    → menu
                   │
                   ▼
      Storage ID
      (default derived from last ':' segment of the IQN:
         "iscsi-")
                   │
                   ▼
      Content type (fixed — not a checklist)
      └─ images        iSCSI exposes block devices, so
                       only 'images' makes sense. No
                       backup/iso/vztmpl/rootdir/snippets.
                   │
   ┌──────── Cancel   OR   Confirm ────┐
   ▼                                   ▼
Exit, nothing        ┌─────────────────┴─────────────────┐
was changed          │  PHASE 2 — Register in Proxmox     │
                     └─────────────────┬─────────────────┘
                                       ▼
                       If storage ID already exists:
                       └─ ask "remove and recreate?"
                          └─ yes → pvesm remove 
                          └─ no  → abort
                                       ▼
                       pvesm add iscsi  \\
                           --portal  \\
                           --target  \\
                           --content images
                                       │
                                       ▼
                       iscsid opens a persistent session to
                       the target; LUNs appear in /dev/disk/
                       by-path/ip-:-iscsi--lun-N
                                       │
                                       ▼
                       Proxmox auto-connects on every boot
                       via the node.startup=automatic flag
                       written by pvesm`}
      

{t("add.heading")}

    {addItems.map((_, idx) => (
  1. {t.rich(`add.items.${idx}`, { strong, code })}
  2. ))}
{t("add.authBody1")}
cat /etc/iscsi/initiatorname.iscsi
{t.rich("add.authBody2", { em, code })}

{t("manual.heading")}

{t("manual.body")}

{t("view.heading")}

{t.rich("view.body", { code })}

{t("remove.heading")}

{t.rich("remove.body", { code, strong })}

{t("remove.warnBody")}

{t("test.heading")}

{t.rich("test.body", { code })}

{t("troubleshoot.heading")}

{t.rich("troubleshoot.portalBody", { em })} {t("troubleshoot.discoverIntro")}
    {discoverItems.map((_, idx) => (
  • {t.rich(`troubleshoot.discoverItems.${idx}`, { strong })}
  • ))}
{t("troubleshoot.noTargetBody")} {t.rich("troubleshoot.noLunBody", { code })} {t.rich("troubleshoot.chapBody", { code })}

{t("related.heading")}

    {relatedItems.map((item) => (
  • {item.label} {item.tail}
  • ))}
) }