Beiträge von darkstar

    Dank Dir terence, das war genau richtig ;)


    Anschließend bekam ich:

    [2026-03-31 11:03:48] [ERROR] API Fehler 400: {"code":"server.patch.oneattribute","message":"Only one attribute at a time is allowed."}

    Was auf die Unmöglichkeit hinweist, sowohl state = OFF als auch stateOption = POWEROFF in einem Patch-Request gleichzeitig zu setzen.


    stateOption = POWEROFF allein hat er nicht gefressen, aber state = OFF hat den erwünschten Effekt erzielt, d.h. der Server mit der übergebenen ServerID war sofort aus und musste über das SCP neu gestartet werden. Über Stateoption denke ich jetzt erstmal nicht mehr nach.

    ---

    def fence_server(token: str, server_id: str):
    url = f"{API_BASE}/servers/{server_id}"
    log("WARNING", f"Sende Fencing-Signal (OFF) an Server {server_id}...")

    try:
    # PATCH Request exakt wie im funktionierenden IP-Skript gestaltet:
    resp = requests.patch(url,
    headers={"Authorization": f"Bearer {token}", "Content-Type": "application/merge-patch+json"},
    json={"state": "OFF"},
    timeout=30)

    if resp.status_code in (200, 202, 204):
    log("SUCCESS", f"Server {server_id} erfolgreich ausgeschaltet (Status: {resp.status_code}).")
    sys.exit(0)
    else:
    log("ERROR", f"API Fehler {resp.status_code}: {resp.text}")
    sys.exit(1)
    except Exception as e:
    log("ERROR", f"Fencing Exception: {e}")
    sys.exit(1)
    ---

    Das kommt jetzt in die pacemaker-Config (Verzeichnisse, serverID und Servernamen sind geändert), in etwa so:

    Definition für v01 um v02 zu fencen…

    pcs stonith create fence_v02 fence_exec \
    executable="/etc/NETCUP/NETCUP_Fence.py" \
    cmdline_options="--fence 654321" \
    monitor_options="--status" \
    pcmk_host_list="v02" \
    shell_timeout=30 \
    op monitor interval=60s

    Definiton für v02 um v01 zu fencen

    pcs stonith create fence_v01 fence_exec \
    executable="/etc/NETCUP/NETCUP_Fence.py" \
    cmdline_options="--fence 123456" \
    monitor_options="--status" \
    pcmk_host_list="v01" \
    shell_timeout=30 \
    op monitor interval=60s


    pcs constraint location fence_v01 avoids v01
    pcs constraint location fence_v02 avoids v02


    Kontrolle

    pcs stonith status

    Aktuell bastel ich auf der gleichen Basis noch an einer Fence-Funktion...
    Soll ein POWEROFF auslösen, nach meinem Verständnis der Doku geht das über /servers/{server_id}, und dann setzen von "state" auf "OFF" und "stateOption" auf "POWEROFF".

    Sieht im Moment so aus:

    ----------------------------------------------------------------
    def fence_server(token: str, server_id: str):
    url = f"{API_BASE}/servers/{server_id}"
    log("WARNING", f"Sende Fencing-Signal (OFF / POWEROFF) an Server {server_id}...")

    try:
    # PATCH Request
    resp = requests.patch(url,
    headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
    json={"state": "OFF", "stateOption": "POWEROFF"},
    timeout=30)

    if resp.status_code in (200, 202, 204):
    log("SUCCESS", f"Server {server_id} erfolgreich ausgeschaltet (Status: {resp.status_code}).")
    sys.exit(0)
    else:
    log("ERROR", f"API Fehler {resp.status_code}: {resp.text}")
    sys.exit(1)
    except Exception as e:
    log("ERROR", f"Fencing Exception: {e}")
    sys.exit(1)
    ---

    Das Token ist da, die server_id ist die interne, auf die ich auch die FailoverIP routen würde.
    Ich bekomme allerdings eine Fehlermeldung:

    [2026-03-30 16:56:24] [WARNING] Sende Fencing-Signal (OFF / POWEROFF) an Server 888888...
    [2026-03-30 16:56:24] [ERROR] API Fehler 415: {"code":"error.not.supported","message":"The HTTP header Content-Type is missing or is invalid"}

    Also es kommt von der REST-API ein Fehler 415 zurück, die Meldung ist "{"code":"error.not.supported","message":"The HTTP header Content-Type is missing or is invalid"}"

    Natürlich habe ich den Content-Type gesetzt...

    Hat irgendwer eine Idee?

    Die Hardware die aktuell läuft kostet nicht mehr... Es ist an der Stelle einfach scheinheilig von Euch.

    Du verwechselst einen Zahlung mit den Kosten bei Investitionsgütern.


    Eine Zahlung bedeutet Liquiditätsverlust, muss irgendwoher finanziert werden (auch die Finanzierung selbst kostet!). Für GuV zählen aber dank AfA nur die anteiligen bilanziellen Kosten pro Monat (AfA sind 3-5 Jahre im Serverbereich).

    Und nach Ende der AfA-Dauer musst Du das Geld wieder im Sack haben, damit Du die abgeschriebene Investition=Hardware voll ersetzen kannst., sonst hast Du Verlust.

    Nun gibt es aber aktuelle Preissignale, dass Du in 3 oder 5 Jahren die Hardware mit den bisherigen Abschreibungen nicht neu kaufen kannst sondern Du erkennst einen Preistrend. Und das muss gedeckt werden. Und das gilt auch für gebrauchte Hardware. Sonst kannst Du nur einen Teil des Vertragsbestandes Wechselangebote zu neuen Verträgen machen (samt Migrationsaufwand für den Kunden) und alles Andere regelmäßig kündigen.

    Für mich ist die Aussage klar:

    Mit Server verschwinden auch die sog. Sonderbuchungen und werden entsprechend endabgerechnet, also bei Sonderkündigung ggf. auch erstattet.

    Zusatz-IP an anderen Standort geht nicht - als nix Standort-„tauschen“. Aber du kannst Dir ja am anderen Standort eine Zusatz-IP bestellen.

    Soooo, jetzt wird bei --list-servers auch der Nickname angezeigt. Der Nickname ist nur zur Info gedacht, kann also bei assign nicht als Referenz genutzt werden, da nicht eineindeutig.

    Bei --list-vips werden jetzt nur noch die VirtualIPs angezeigt, nicht die zusätzlichen IPs (editable: false). Ich denke, man in solchen Fällen auch über das SCP die zusätzliche IP zuordnen und braucht dafür nicht ein Skript, dass eigentlich für Failover-Situationen gedacht ist.

    Man hätte sich solche Workstation auch zum Ausschlachten kaufen können, um dadurch an solcher Hardware vergünstigt ranzukommen.

    Da ist genau nichts dran was Du auch in einem Server verbauen würdest.

    Geht beim redundanten Netzteil los, geht mit Server-Mainboard mit eher 2 als 1 CPU, mit extra viel Steckplätzen für Speicher und iKVM, weiter, dazu reichlich ECC-RAM und sicherlich auch U.3 Enterprise SSDs (sicherlich kein U.2) - gerne NVME (auch dafür braucht es besonders viele CPU-Lanes damit das nicht nur irgendwie sondern mit Geschwindigkeit funktioniert.

    Was nimmt man für diese Marktpreise als Grundlage? Sowas wie ein niederländisches geizhalz.de?

    Bei sowas hat man häufig auch Rückläufer & Einzelstücke im Angebot, die weit unterhalb der echten Marktpreise liegen - wenn man auf einheitlich und Menge hinauswill…

    Ansonsten beziehen sich die Preise vermutlich auf Consumer-Hardware, d.h. kein ECC (reg./unreg.). Das ist sicherlich nett zu wissen, mein Desktop zuhause hat auch 192GB RAM, weil ich auf mal eine ex-produktive VM dort starte (z.B. eine VM mit einem ansonsten nicht mehr benutzten Backup-Server zum Zugriff auf sehr alte Datenbestände). Nur kommt gerade bei großen Virtualisierungs- und großen DB-Servern (ich meine z.B. für SAP/HANA brauchts ab 1 TB) deutlich mehr RAM rein.

    Kommt mir nämlich noch _relativ_ günstig vor, insbesondere wenn es in Richtung für bestimmte Mainboards geprüfte / zertifizierte RAM-Bausteine geht, wie sie gerade bei Servern zum Einsatz kommen…

    Ich komme ja von eigener Hardware im eigenen Rack, 25 Jahre lang. Mehrere 100 Euro pro Monat nur für das Rack, Strom und ein bisschen Traffic. Hardware kommt da noch hinzu, wurde zunächst komplett selbst zusammengestellt und die letzten 15 Jahre auf Basis Asus Server Barebone assembliert. Reisekosten zum RZ kommen auch noch hinzu. Am Anfang war das mit dem RZ noch geradezu familiär, es gab sogar sowas wie Usertreffen mit Grillen, dann wurde einmal weiterverkauft, dann nochmal und nun hat man einen neuen Finanzinvestor.
    Zugegeben, das waren auch schonmal 3 Racks, aber da wurde noch auf Baremetal und nicht auf Virtualisierung gesetzt.

    Nun wäre mal wieder - nachdem die letzte Erneuerung schon eine Weil her ist - dieses Jahr eine Hardwareerneuerung fällig gewesen. Ziel: 3 - 5 neue Server im Proxmox-Cluster. Und bei der Betrachtung der Leistungsstärke heutiger Systeme im Verhältnis zu dem, was darauf läuft (zuletzt waren das Dual-Prozessor 10-core-Xeons) erschien mir das bereits wie Overkill und ich wäre gerne im Bereich 4545P Epyc-Single CPU gelandet. Dann kamen die Preise dazu. Nun bin ich mit erstmal 2 RS 2000 G12 und 1 x RS 1000 G12 sehr glücklich, 1GBit-VLAN, 1 x Virtual IP und die Support-Option für 1,99 Euro/Monat habe ich auch gezogen - wobei mein Support-Bedarf eher sporadisch ist, allerdings sind mir 80 Euro netto für 30 min hands-on-time alle paar Jahre - nur zur Fehlerfeststellung bzw. Resetversuch - nicht fremd.

    Die Preiserhöhung wird mich keine 10 Euro netto kosten…

    Hätte ich jetzt meine 3 Server mit Mehrkosten von etwa 6000 Euro _pro System_ gegenüber Budget gekauft, kann ich mit dem gesparten Geld 1800 Monate Mehrkosten finanzieren, das sind 150 Jahre bezogen auf die 3 Systeme.

    Und so lächele ich nur…

    Ich kann das mit den Zusatzadressen leider nicht prüfen, ich nutze derzeit nur Failover...

    Am ehesten kann man noch so agieren, dass nur die VirtualIPs mit "editable = true" ausgegeben werden - dann sieht man die Zusatzadressen bei --list-vips nicht.

    Was die Nicknames angeht - die kann ich zusätzlich bei --list-servers ausgeben, aber nur als Info.

    Nur der Netcup-Servernamen und die ServerID sind aus meiner Sicht so eindeutlig, dass man sie als eineindeutigen Parameter für das Setzen des Routings verwenden kann, wobei auch der Servername letztlich intern auf die ServerID zurückgeführt wird. Die Nicknames können theoretisch mehrfach existieren oder?

    Sooo, wenn ich hier schon dusselige Fragen stelle und hilfreiche Antworten bekomme kann ich auch mal mit einem Ergebnis um die Ecke kommen...

    Das folgende Skript ändert über die Netcup-REST-API das Routing einer VirtualIP auf den jeweiligen Server.

    Dank an terence, da war dann schonmal ein Lichtschein am Ende des Tunnels.
    Credits gehen auch an den des Autor von GitHub - montilo/NetcupHomeIPUpdater: Updates Netcup Firewall Rules with Home-IP · GitHub für das Beispiel für die Authentifizierung (--setup und --whoami) sowie an Google Gemini für die Untersttützung.

    Ich muss dazu sagen, dass ich zwar schon viel Software geschrieben habe, aber mich noch nie zuvor mit Python-Programmierung beschäftigt habe - letztlich hat es nur ein paar Stunden gedauert.

    Freue mich auf Anregungen und Verbesserungsvorschläge.

    ---

    Bedienungsanleitung


    1. Voraussetzungen installieren

    Das Skript benötigt python3, das Modul requests für die API-Kommunikation und PyYAML für das Einlesen der Konfiguration.

    Bash


    Code
    # Systempakete aktualisieren (optional)
    apt update && apt install python3 python3-pip -y
    
    # Notwendige Bibliotheken installieren
    pip3 install requests pyyaml

    2. Die Datei config.yaml erstellen

    Erstelle im selben Verzeichnis wie dein Skript eine Datei namens config.yaml. Du kannst diesen Inhalt als Vorlage kopieren:

    YAML

    Code
    # Pfad, in dem das dauerhafte Login-Token gespeichert wird
    refresh_token_file: "~/.netcup_refresh_token"
    
    # Deine interne Netcup User-ID (sollte durch --setup automatisch befüllt werden, sonst --whoami)
    user_id: 0
    
    # Standard-Werte für den schnellen Wechsel mit --assign (optional)
    vip_id: "123.123.123.123"   # Deine Failover-IP oder deren interne ID
    server_id: "v....."    # Dein Ziel-Servername oder dessen interne ID

    3. Ersteinrichtung (Authentifizierung)

    Bevor das Skript IPs schalten kann, muss es sich bei Netcup autorisieren.

    1. Führe das Skript mit dem Setup-Flag aus:

      Bash

      Code
      python3 NETCUP_FailOverIPV4.py --setup
    2. Das Skript gibt dir eine URL und einen Code aus.
    3. Öffne die URL im Browser, logge dich in dein Netcup SCP ein und bestätige den Zugriff.
    4. Gehe zurück zum Terminal und drücke Enter.
    5. Wichtig: Das Skript versucht nun automatisch deine user_id aus deinen letzten Tasks zu lesen und in die config.yaml zu schreiben.

    4. Testen der Konfiguration

    Um sicherzugehen, dass alles funktioniert, kannst du deine Daten abfragen:

    • Wer bin ich? (Zeigt User-ID und Name):

      Bash

      Code
      python3 NETCUP_FailOverIPV4.py --whoami
    • Failover-IPs auflisten:

      Bash

      Code
      python3 NETCUP_FailOverIPV4.py --list-vips
    • Server-IDs finden:

      Bash

      Code
      python3 NETCUP_FailOverIPV4.py --list-servers

    5. Anwendung im Failover-Fall

    Wenn alles konfiguriert ist, reichen folgende Befehle:

    • Manueller Wechsel (überschreibt Config):

      Bash

      Code
      python3 NETCUP_FailOverIPV4.py --assign 1.2.3.4 MeinZielServer
    • Automatischer Wechsel (nutzt vip_id/server_id aus der Config):

      Bash

      Code
      python3 NETCUP_FailOverIPV4.py --assign

    Sicherheitshinweise:

    • Dateiberechtigungen: Da das Skript ein Authentifizierungs-Token speichert, sollte der Zugriff eingeschränkt sein:

      Bash

      Code
      chmod 600 ~/.netcup_refresh_token
      chmod 600 config.yaml
    • Rate-Limit: Beachte, dass durch die eingebaute Sperre von 301 Sekunden (ca. 5 Minuten) ein "Ping-Pong" zwischen zwei Servern verhindert wird. Sollte ein Wechsel fehlschlagen, musst du diese Zeit abwarten, bevor das Skript die API erneut anspricht.

    ---

    Skript im Anhang...

    Ich saß auch 1996 das erste Mal vor einem Netscape Browser. War aber an der Uni, für zu Hause war ein Internetanschluss viel zu teuer. Da hatten wir nur Datex-J fürs Online-Banking. Vorher war ich noch auf Mailboxen (Fido) unterwegs, das ging ja immer zum Ortstarif für unter 3DM/Stunde :)

    Tatsachlich hatte ich über Fido auch meine erste (Internet) E-Mail Adresse, aber Abruf war immer über die Mailbox per Terminal...

    Hihi, Vor 25 Jahren „Rauchzeichen sind out ISDN ist in“? Eigentlich ging vor 25 Jahren ISDN bei mir schon zu Ende, dann kam DSL im heimischen 19 Zoll-Rack zusammen mit der Eigentumswohnung..,

    Ich war 1994 Fidonet-Node geworden, 1995 kamen die ersten ISDN-Leitungen (4. Anschluss im Vorwahlbereich) - erst auf AVM B1-Karte, dann auch noch mit Courier-I-Modems (mit V.90 Host-Modus-das ging nur damit).

    Telefonrechnung 4stellig mit einer 2 vorne und die Telekom schickte mir Einladungen zu Kundenveranstaltungen… „Da sie zu den Kunden gehören die unsere Leistungen in besonderem Maß in Anspruch nehmen…“.

    Setup war unter OS/2 Warp mit Xenia Mailer (auch deutsche Supportsite), PCBoard for OS/2, Fastecho und eine Menge Kleinzeug…

    Internet über Gateway gab es auch etwa seit 1995… Meine erste E-Mail-Adresse hatte ich 1994… Dagegen gab es den ersten Onlinezugang erst 1996 über die Hochschule und irgendwann was mit 50 MB/Traffic per Modemeinwahl ab 1998… Soweit Geschichten aus dem letzten Jahrtausend.

    Moin zusammen,

    ich bin neu bei Netcup und hab derzeit 2 nagelneue RS 2000 G12 Rootserver sowie ein VLAN mit 1 GBit.

    Beide rootserver sind frisch aus Datenübernahmegründen noch mit einem Debian bookworm installiert worden und haben eine DRBD-Partition, d.h. das wird ein active-passive-Setup.

    Das schwenken der IP und des DRBD samt Filesystem klappt serverseitig schon gut, allerdings muss noch das Routing Netcup-seitig angepasst werden und die Rest API scheint eine solche Funktion zu bieten.

    Gibt es eigentlich schon ein simples Beispiel auf Basis curl, wie man mittels Rest-Api z.B. eine Netcup-failover-IP zuordnet?

    Ich scheitere derzeit schon an der Authentifizierung bzw. bin auch verwirrt bzgl. der zu nutzenden Daten…

    UserID ist nach meinem Verständnis die Kundennummer vom SCP-Login.

    Aber was nimmt man nun als Password?

    Im SCP finde ich noch unter Optionen „REST API“, wo man die IP-Adressen einschränken kann.

    Ansonsten kann man im SCP unter Optionen noch ein Password für einen Webservice setzen, wo ich allerdings fürchte, dass es sich dabei um WDSL handelt.

    Und dann gibt es noch im CCP unter Stammdaten/_Api noch Api-Passwörter und Api-Keys generieren - da denke ich aber, dass das nicht die Rest-API für die Rootserver meint, da von Domainregistrierung gesprochen wird.


    Weiteres Vorgehen wäre nach meinem Verständnis:

    /api/v1/servers zwecks Ermittlung ServerID

    /api/v1/users/{userid}/failoverips/v4 zwecks Ermittlung id Failover-IP

    /api/v1/users/{userid}/failoverips/v4/(id failover-ip) zwecks setzen der Route (im Data dann die ServerID)