Bitte um Hilfe bei while loop / dictionary

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
jakob83
User
Beiträge: 6
Registriert: Sonntag 14. Juni 2020, 12:41

Hallo,

ich möchte eine script erstellen, mit welchem ich automasierte Befehle vie paramiko mit ssh an diverse clients sendne möchte (später so ca. 20).

Mein Problem ist das ich den Code nicht zu lang werden lassen will, daher die Idee für den Schlüssel die Variable "x" zu nehmen (ansonsten müsste man für
jeden host eine einzelne Zeile ergänzen...

Code: Alles auswählen

ssh.connect(z, port=HOSTS["1"]["ssh_port"], username=HOSTS["1"]["username"], password=HOSTS["1"]["pwd"], allow_agent = False)
    stdin, stdout, stderr = ssh.exec_command(updatehost, get_pty=True)
    stdin.write(HOSTS["1"]["su_pwd"])
    stdin.flush()
Was kann man hier ändern dass es funktioniert?:

Code: Alles auswählen


import paramiko

HOSTS = {
    "1": {"name": "PC1", "ip": "192.168.1.10", "host_name": "Computer1", "ssh_port": "22", "username": "user1", "pwd": "pw1", "su_pwd": "supwd1\n"},
    "2": {"name": "PC2", "ip": "192.168.1.11", "host_name": "Computer2", "ssh_port": "22", "username": "user2", "pwd": "p2w", "su_pwd": "supwd2\n"},
    }


# Counter for Nested  Hosts Dictonary
x = 0

# TH = TotalHosts
TH=len(HOSTS.keys())

updatehost="sudo apt-get update && sudo apt-get upgrade -y && sudo apt-get clean && sudo apt-get autoremove"

ssh = paramiko.SSHClient()

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

while x <= TH:
    x = x+1
    ssh.connect(HOSTS[x]["ip"], port=HOSTS[x]["ssh_port"], username=HOSTS[x]["username"], password=HOSTS[x]["pwd"], allow_agent = False)
    stdin, stdout, stderr = ssh.exec_command(updatehost, get_pty=True)
    stdin.write(HOSTS[x]["su_pwd"])
    stdin.flush()
    for line in iter(stdout.readline, ""):
         print(line, end="")
         
gibt folgende Ausnahme zurück:

Code: Alles auswählen

Traceback (most recent call last):
  File "Z:\Python\ssh_paramiko.py", line 30, in <module>
    ssh.connect(HOSTS[x]["ip"], port=HOSTS[x]["ssh_port"], username=HOSTS[x]["username"], password=HOSTS[x]["pwd"], allow_agent = False)
KeyError: 0
Vielen Dank im Voraus für die Mühe!
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Du hast in deinem Dictionary als Key einen String und versuchst nun über einen Int an den Value zu kommen. Das funktioniert so nicht. Ich würde auch die while Schleife durch eine for-Schleife ersetzen.
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Da die Schlüssel auch keinerlei Bedeutung zu haben scheinen würde man auch kein Wörterbuch für `HOSTS` verwenden, sondern eine Liste.

Warum das `iter()` in der ``for``-Schleife und nicht einfach eine Schleife über `stdout`?
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man Variablen mit Kommentaren versehen muß, dann ist klar, dass der Name schlecht ist: TH -> TOTAL_HOSTS
Die while-Schleife ist eigentlich eine for-Schleife. Über einen Index iteriert man in Python auch nicht, sondern direkt über die Objekte.
Eingerückt wird immer mit 4 Leerzeichen pro Eben, nicht mal 4 und mal 5.

Code: Alles auswählen

import paramiko

HOSTS = [
    {"name": "PC1", "ip": "192.168.1.10", "host_name": "Computer1", "ssh_port": "22", "username": "user1", "pwd": "pw1", "su_pwd": "supwd1"},
    {"name": "PC2", "ip": "192.168.1.11", "host_name": "Computer2", "ssh_port": "22", "username": "user2", "pwd": "p2w", "su_pwd": "supwd2"},
]

UPDATEHOST = "sudo apt-get update && sudo apt-get upgrade -y && sudo apt-get clean && sudo apt-get autoremove"

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for host in HOST:
    ssh.connect(host["ip"], port=host["ssh_port"], username=host["username"], password=host["pwd"], allow_agent=False)
    stdin, stdout, stderr = ssh.exec_command(updatehost, get_pty=True)
    stdin.write(host["su_pwd"] + "\n")
    stdin.flush()
    for line in stdout:
        print(line, end="")
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich verwende bei solchen Sachen noch ganz gerne ein `addict.Dict` um per Punktoperator auf die Werte im Wörterbuch zugreifen zu können.

Und auch bei den Schlüsseln sollte man keine Abkürzungen verwenden, genau wie bei Namen nicht. `su_pwd` ist zum Beispiel irritierend, weil es ja nicht nur ``sudo`` gibt, sondern tatsächlich auch ein ``su``-Kommando was auch nach einem Passwort fragt. Diese Verwirrung sollte man sich ersparen.

Das Programm enthält eine potentielle Verklemmung wenn ``apt-get`` Ausgaben auf der Standardfehlerausgabe macht!

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import paramiko
from addict import Dict

HOSTS = [
    {
        "name": "PC1",
        "ip": "192.168.1.10",
        "host_name": "Computer1",
        "ssh_port": "22",
        "username": "user1",
        "password": "pw1",
        "sudo_password": "supwd1",
    },
    {
        "name": "PC2",
        "ip": "192.168.1.11",
        "host_name": "Computer2",
        "ssh_port": "22",
        "username": "user2",
        "password": "p2w",
        "sudo_password": "supwd2",
    },
]

UPDATEHOST = (
    "sudo apt-get update"
    " && sudo apt-get upgrade -y"
    " && sudo apt-get clean"
    " && sudo apt-get autoremove"
)


def main():
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    for host in map(Dict, HOSTS):
        ssh.connect(
            host.ip,
            port=host.ssh_port,
            username=host.username,
            password=host.password,
            allow_agent=False,
        )
        stdin, stdout, _stderr = ssh.exec_command(UPDATEHOST, get_pty=True)
        stdin.write(host.sudo_password + "\n")
        stdin.flush()
        #
        # FIXME When ``apt-get`` prints stuff to its ``stderr`` this will
        # eventually hang in a deadlock!
        #
        for line in stdout:
            print(line, end="")


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
jakob83
User
Beiträge: 6
Registriert: Sonntag 14. Juni 2020, 12:41

Vielen Dank an alle für die rasche Hilfe und die guten Ratschläge!

Ich schreibe es um und probiere es aus!


LG
Antworten