in Paramiko werden die SSH-Hostkeys leider nur aus einer Datei gelesen (ist nur leider blöd, wenn man das ganze nicht unbedingt in einer Datei stehen hat. (Ich möchte in meinem Fall den Key aus dem Putty-Eintrag in der Windows-Registry ins Open-SSH-Format konvertieren und dann anschließend laden, aber ohne das ganze auf die Festplatte zu speichern)). Ich würde dies gerne so umschreiben, dass auch ein StringIO benutzt werden kann.
Die relevante Funktion ist folgendermaßen:
Code: Alles auswählen
def load(self, filename):
"""
Read a file of known SSH host keys, in the format used by OpenSSH.
This type of file unfortunately doesn't exist on Windows, but on
posix, it will usually be stored in
``os.path.expanduser("~/.ssh/known_hosts")``.
If this method is called multiple times, the host keys are merged,
not cleared. So multiple calls to `load` will just call `add`,
replacing any existing entries and adding new ones.
:param str filename: name of the file to read host keys from
:raises IOError: if there was an error reading the file
"""
with open(filename, 'r') as f:
for lineno, line in enumerate(f):
line = line.strip()
if (len(line) == 0) or (line[0] == '#'):
continue
e = HostKeyEntry.from_line(line, lineno)
if e is not None:
_hostnames = e.hostnames
for h in _hostnames:
if self.check(h, e.key):
e.hostnames.remove(h)
if len(e.hostnames):
self._entries.append(e)
Das ganze geht einfach und funktioniert gut, wenn ich die Zeile „with open(filename, 'r') as f:“ entferne und das f direkt als StringIO übergebe. Nur dann kann man natürlich nicht mehr aus Dateien lesen.
Da in Python ja oft eigentlich beides gehen sollte (Duck Typing, oder nicht?), soll der eben je nachdem beides lesen können. Wenn ich der Methode einfach ein StringIO übergebe, bekomme ich ein TypeError: invalid file: <_io.StringIO object at 0x00000000043515E8>.
Wie soll man sowas nun implementieren? Das einfachste wäre einfach
Code: Alles auswählen
def load(self, filename):
try:
with open(filename, 'r') as f:
for lineno, line in enumerate(f):
line = line.strip()
if (len(line) == 0) or (line[0] == '#'):
continue
e = HostKeyEntry.from_line(line, lineno)
if e is not None:
_hostnames = e.hostnames
for h in _hostnames:
if self.check(h, e.key):
e.hostnames.remove(h)
if len(e.hostnames):
self._entries.append(e)
except TypeError:
for lineno, line in enumerate(filename):
line = line.strip()
if (len(line) == 0) or (line[0] == '#'):
continue
e = HostKeyEntry.from_line(line, lineno)
if e is not None:
_hostnames = e.hostnames
for h in _hostnames:
if self.check(h, e.key):
e.hostnames.remove(h)
if len(e.hostnames):
self._entries.append(e)
Danke!