Seite 1 von 3
Serverliste importieren und abarbeiten
Verfasst: Mittwoch 16. September 2009, 09:22
von morytox
hallo ich habe ein tool geschrieben welches mir Daten auf einem Server sichert.
Dazu habe ich in den Funktionen systembefehle in denen Daten zum server sind (bsp: ip adresse , username und pfad auf server)
Nun habe ich das Programm erst auf einen Server Speziell angepasst.
Mein vorhaben ist es Eine datei mit den Einträgen der Server zu haben welche Das Programm so ausliest dass man dann eine Liste hat in welcher vllt separiert Die 3 Serverspeziefischen angaben stehen(und das dann für Mehrere Server) und dass das Script dann in einer for schleife läuft und mit jedem Durchgang den nächsten server hat.
Also im ersten durchgang auf 3 Variablen die 3 Daten hat und im nächsten die vom nächsten server und das alles so lange wie server in der datei / liste sind
um das mal visuell zu machen...
Datei mit :
Serverip1 Username1 pfad1
Serverip2 Username2 pfad2
Serverip3 Username3 pfad3
Das dann in ne Liste packen und dann im for loop
for server in liste
funktion1() <-- führt befehle mit den 3 variablen aus und dass für jeden server einmal
[/code]
Verfasst: Mittwoch 16. September 2009, 09:29
von Hyperion
Was genau ist nun Deine Frage? Ich habe das Problem so ehrlich gesagt nicht verstanden! (Und kann mir vorstellen, dass das anderen genauso geht

)
Verfasst: Mittwoch 16. September 2009, 09:39
von morytox
naja wie kann ich mein vorhaben konkret realisieren ? bin noch relativ frisch in der programmsprache und ich hab keine ahnung wie ich die datei so improtieren kann dass die sortierung klar ist etc ... also wie kann ich das konkret umsetzen ? gibt es da beispiele oder so ?
z.B. auch wie ich ne forschleife sinnvoll mit ner liste anstatt des in range() befehls machen kann
Verfasst: Mittwoch 16. September 2009, 09:45
von cofi
Zuerst mal solltest du deine ``funktion1`` aendern und die Konfiguration zu Parametern machen, dann reicht das hier:
Code: Alles auswählen
with open(config_fname) as config:
for line in config:
ip, user, path = config.strip().split()
magic(ip, user, path)
Edit: Wenn du natuerlich Leerzeichen in den Angaben brauchst, dann solltest du dir einen anderen Trenner als " " suchen.
Verfasst: Mittwoch 16. September 2009, 09:58
von morytox
das heißt ich öffne die Datei mit dem namen "config_fname" als config (ist das eine art die datei zu lesen in python ?) und öffne dann die for schleife in der jede zeile (mit 3 einheiten) auf die variablen ip, user, path gelegt wird (reicht das wenn ich in der datei die elemente nur mit leerzeichen getrennt habe oder sollte man da was erkennbares wie arg1:arg2:arg3 nehmen ? und wenn ja wie wirkt sich dann die änderung heir aus ? muss die datei ne bestimmte endung haben ?
Verfasst: Mittwoch 16. September 2009, 10:08
von sma
Deine Schlussfolgerungen sind richtig und die Datei muss keine bestimmte Endung haben. Das ":" statt " " als Trenner macht es ja auch nicht besser, denn jetzt darf dann eben dieses Zeichen nicht in Pfad, Namen und Adresse vorkommen. Sind es IPv6-Adressen, so haben die z.B: ":".
Nachtrag: Ich würde `split(" ", 2)` empfehlen, da dies einen String in maximal drei Teile teilt. Wenn Adresse und User garantiert kein Leerzeichen enthalten, dann kann der dritte Teil, der Pfad, auch Leerzeichen haben und es funktioniert trotzdem.
Stefan
Verfasst: Mittwoch 16. September 2009, 10:18
von cofi
sma hat geschrieben:Deine Schlussfolgerungen sind richtig
Bis auf den Dateinnamen. Hier wird eine Variable namens ``config_fname`` erwartet, die den Pfad zur Datei enthaelt.
Du kannst auch eine Zeichenkombination als Trenner verwenden um ganz sicher zu gehen, zb. ``/-\`` und splittest dann mit ``split(r"/-")`` (das r steht fuer einen Rawstring, wg dem Backslash)
Das ``with`` oeffnet die Datei per Kontextmanager, d.h. es wird der Block abgearbeitet und dann die Datei geschlossen.
Verfasst: Mittwoch 16. September 2009, 10:38
von morytox
okay danke erstmal für eure hilfe aber jetzt hat sich etwas meine aufgabenstellung verändert. in der liste befinden sich jetzt verschiedene server .. jetzt heißt es dass je nach anforderung verschiedene server abgearbeitet werden sollen ... kann man das erste element durch ne art index ersetzen bsp
xy serverip1 usrname1 pfad1
xy serverip2 usrname2 pfad2
yz serverip1 usrname1 pfad1
yz serverip2 usrname2 pfad2
und dann bei ner bestimmten angabe nur die linien mit dem bestimmten index abgearbeitet werden ?
achso und wenn config_fname eine variable ist auf der der pfad liegt, wie ordne ich dann den pfad zu ? ganz einfach mit bsp:
config_fname=/home/usr/ordner/serverconfig , wobei serverconfig dann die datei ist ?
Verfasst: Mittwoch 16. September 2009, 10:46
von Hyperion
Ich würde anstatt mit split() zu experimentieren einfach auf ein anderes Format setzen. INI, JSON, (XML,) ... es gibt doch so viele einfach zu schreibende Formate, für die es fertige Parser gibt. Damit erspart man sich Grübeleien über mögliche Trennzeichen oder das Escaping von Steuerzeichen.
In der Doku findest Du da einige Module: csv, ConfigParser, json und für xml ElementTree.
Verfasst: Mittwoch 16. September 2009, 10:48
von Hyperion
morytox hat geschrieben:okay danke erstmal für eure hilfe aber jetzt hat sich etwas meine aufgabenstellung verändert. in der liste befinden sich jetzt verschiedene server .. jetzt heißt es dass je nach anforderung verschiedene server abgearbeitet werden sollen ... kann man das erste element durch ne art index ersetzen bsp
xy serverip1 usrname1 pfad1
xy serverip2 usrname2 pfad2
yz serverip1 usrname1 pfad1
yz serverip2 usrname2 pfad2
"xy" und "yz" sind also Anforderungen, die in jeweils einer passenden Funktion ausgeführt werden?
Ist jetzt immer noch die Frage, wie das Dateiformat aufgebaut sein soll, oder wie man diese "Liste" abarbeitet?
Verfasst: Mittwoch 16. September 2009, 11:03
von sma
Das ist jetzt nicht unbedingt ideomatisch widerspruchsfreies Python aber...
Code: Alles auswählen
class Line:
def process(self, line):
func, self.ip, self.name, self.path = line.split(" ", 3)
return getattr(self, func)()
def xy(self):
return "XY"
def yz(self):
return "YZ"
print Line().process("xy ip1 user1 path1")
Stefan
Verfasst: Mittwoch 16. September 2009, 11:05
von morytox
@Stefan Das versteh ich jetzt nich ganz. was genau macht der prog auszug den du mir geschrieben hast und wo muss ich ihn einbaun um was zu erreichen ?
jes schau ich echt wie n schein ins uhrwerk ^^ angenommen ich würde mir son ding in xml zusammenschustern wie müsste diese Datei aufgebaut sein ? und wie implementiere ich das dann in die schleife?
Und das script soll dafür da sein dateipakete je nach produktionsstatus/fortschrit (xy oder yz oder weiß ich was) auf die dazu zuständigen server zu schieben / kopieren die funktionen für den vorgang hab ich geschrieben und will da via variablen nurnoch die daten einsetzen wohin der weg nun gehen soll. das will ich anhand einer serverliste realisieren.
Das heißt man gibt zum anfang an welcher produktionsstatus erreicht ist und anhand der angabe werden die zuständigen server aus der liste ausgelesen und und das programm arbeitet die server dann ab
Verfasst: Mittwoch 16. September 2009, 11:22
von Rebecca
Wenn du noch auf der Suche fuer ein Dateiformat bist, wuerde ich csv empfehlen, Python hat sogar ein [mod]csv[/mod]-Modul.

XML waere hier wirklich mit Kanonen auf Spatzen geschossen...
Verfasst: Mittwoch 16. September 2009, 11:25
von Hyperion
Noch mal zum Verständnis: Wozu sind "xy" und "yz" nun gut?
Verfasst: Mittwoch 16. September 2009, 11:26
von morytox
Also wenn der Scriptnutzer xy oder yz eingibt werden je nach eingabe andere Server in der liste abgearbeitet
ich geb ma n auszug:
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
import subprocess
import os
import logging
logging.basicConfig(filename = "/home/mory/svndeploy/data/log/Deploymentlog.log", filemode = "a", level = logging.DEBUG, format = "%(asctime)s [%(levelname)-8s] %(message)s")
serverconfig=/home/mory/svndeploy/bin/serverconfig
stand=" ist auf dem aktuellen Stand"
standn=" ist auf neuem Stand"
pfadex=" /home/mory/svndeploy/data/exports"
pfadco=" /home/mory/svndeploy/data/checkout"
logging.info("Subversion wird auf Updates geprüft.")
uppng = subprocess.Popen([r"svn", "up", "/home/mory/svndeploy/data/checkout/symbole"], stdout=subprocess.PIPE).communicate()[0]
upjs = subprocess.Popen([r"svn", "up", "/home/mory/svndeploy/data/checkout/WebApp_JS_Skripts"], stdout=subprocess.PIPE).communicate()[0]
upcss = subprocess.Popen([r"svn", "up", "/home/mory/svndeploy/data/checkout/trunk"], stdout=subprocess.PIPE).communicate()[0]
# Funktionen für JS Skripte
def exportjs():
os.system("svn export -q"+pfadco+"/WebApp_JS_Skripts"+pfadex+"/WebApp_JS_Skripts")
logging.info("Skripts sind exportiert.")
def cleanupjs():
os.system("rm -f"+pfadex+"/WebApp_JS_Skripts.tgz")
os.system("rm -rf"+pfadex+"/WebApp_JS_Skripts")
logging.info("Alte Skripte sind gelöscht.")
def packenjs():
os.system("cd"+pfadex+" && tar czf"+pfadex+"/WebApp_JS_Skripts.tgz WebApp_JS_Skripts")
logging.info("Skripte sind gepackt.")
def uploadjs():
os.system("scp"+pfadex+"/WebApp_JS_Skripts.tgz "+server+":"+path)
logging.info("Skripte wurden transferiert.")
def detarjs():
os.system("ssh "+server+" \"cd "+path+" && tar xzf "+path+"/WebApp_JS_Skripts.tgz > /dev/null\"")
logging.info("Skripte entpackt.")
def cleanupwsjs():
os.system("ssh "+server+" \"rm -f "+path+"/WebApp_JS_Skripts.tgz\"")
os.system("ssh "+server+" \"mv "+path+"/WebApp_JS_Skripts "+path+"/`date +'%Y%m%d%H%M%S'`WebApp_JS_Skripts\"")
logging.info("Webserver bereinigt.")
with open(serverconfig) as config:
for line in config:
ip, usr, path = config.strip().split(r"/-\")
server=usr+"@"+ip
if "zu" in upjs:
cleanupjs()
cleanupwsjs(server, path)
exportjs()
packenjs()
uploadjs(server, path)
detarjs(server, path)
logging.info("WebApp_JS_Skripts"+standn)
else:
logging.info("WebApp_JS_Skripts"+stand)
logging.info("Deployment durchgeführt")
logging.shutdown()
Verfasst: Mittwoch 16. September 2009, 11:36
von Hyperion
Ok, dann schlage ich mal folgende JSON-Datei vor:
Code: Alles auswählen
{
"yz": [
{
"ip": "noch ne ip",
"user": "noche einer",
"path": "wieder einer"
}
],
"xy": [
{
"ip": "ip-adresse",
"user": "user1",
"path": "path1"
},
{
"ip": "noch ne ip",
"user": "user99",
"path": "path56"
}
]
}
Letztlich hast Du ein Dict, in welchem nach den Stati ("xy" und "yz") unterschiedliche Listen zugerodnet sind. Innerhalb der Listen habe ich hier wieder ein Dict gewählt, wenn es wirklich immer nur "ip", "user" und "path" in einer festen Reiehnfolge sind, kann man da auch eine Liste nehmen.
Das ganze könnte man so abarbeiten:
Code: Alles auswählen
import json
# Exception Handling überlasse ich mal Dir ;-)
with open("jobs.json", "r") as in_file:
jobs = json.load(in_file)
try:
for job in jobs[user_eingabe]:
print "Job: {ip}, {user}, {path}".format(**job)
process(job)
except KeyError, e:
print "Ungültiger / Undefinierter Status"
Verfasst: Mittwoch 16. September 2009, 11:42
von Hyperion
Zu Deinem Code:
- Zeilen > 80 Zeichen ([wiki]Lange Zeilen im Sourcecode)[/wiki]
- Wieso verwendest Du os.system, wo Du doch weiter oben subprocess nutzt?
- Code auf Modulebene ist nicht wirklich toll
- Strings besser nicht mit "+" zusammensetzen
- für das Zusammensetzen von Pfaden gibt es os.join
Verfasst: Mittwoch 16. September 2009, 11:51
von morytox
- was bedeutet code auf modulebene ?
- subprocess fand ich nciht so gut , ich hatte es anfangs mit subprocess versucht hab aber nur fehler bekommen weil da so viele ergänzungeen und alles war , hab einfahc nicht durchgesehn und os.system sieht verdammt einfach aus bzw. war für mich sehr einfach anzuwenden
-zeiln kannsch kürzen da hast recht
-wieso nicht + ? soll ich in dem fall dann os.system(os.join("string", var, "string")) schreiben ?
*edit*
wo kommen jetzt eigentlich die Auszuführenden Funktionen hin und was muss ich als parameter übergeben ...
*hmz* klar bei process ^^
print "Job: {ip}, {user}, {path}".format(**job) wofür ist das noch gleich gut ?
und wenn man jetzt den prozess mit dem parameter ausführt hat man in der funktion die 3 variablen ip usr und path mit den zugehörigen daten belegt ja ?
Verfasst: Mittwoch 16. September 2009, 12:22
von Hyperion
morytox hat geschrieben:- was bedeutet code auf modulebene ?
Beispiel:
Code: Alles auswählen
print "Hallo Welt"
def func():
#mache etwas
def func2():
# mache was anderes
...
Das print steht hier auf Modulebene. Wenn Du nun dieses Script (wir nennen es mal foo.py) in ein anderes Python-Script einbinden willst, würdest Du folgendes schreiben:
Du willst also in der Funktion bar die Funktion func2 aus dem Script (Modul) "foo.py" nutzen. Nun passiert nach dem import aber folgendes: Es werden alle Befehle abgearbeitet in foo, die sich auf Modulebene (sprich außerhalb von Funktionen und Klassen) befinden. Du würdest also die Ausgabe des print Befehls sehen. Das ist aber in diesem Falle vermutlich nicht erwünscht.
Also nutzt man folgenden Trick:
Code: Alles auswählen
import irgendwas
def func1():
pass
def funcx():
pass
def main():
# hier ist der Einstiegspunkt in die Abarbeitung des Scriptes
print "Hallo Welt!"
func1()
...
if __name__ == "__main__":
main()
Startest Du dieses Script, so "merkt" der Interpreter, dass Du dieses Script ausfürehn möchtest und verzweigt in die main()-Funktion (Kann auch anders heißen oder direkt unterhalb des if __name__-Hooks stehen).
Importierst Du nun dieses Script in einem anderen, so weiß der Interpreter, dass er eben nicht in dieses main()-Funktion reinrutschen soll. Genau das erwartet man eben bei dieser Benutzung.
Ein weiterer Grund ist die Vermeidung von unnötigen globalen Variablen. Schreibst Du alles "planlos" auf Modulebene, so sind natürlich alle Namen in allen Funktionen verfügbar. Das ist idR gefährlich und unnötig. So kannst Du Dir überlegen, was Du ggf. in der main()-Funktion definierst und was nicht.
- subprocess fand ich nciht so gut , ich hatte es anfangs mit subprocess versucht hab aber nur fehler bekommen weil da so viele ergänzungeen und alles war , hab einfahc nicht durchgesehn und os.system sieht verdammt einfach aus bzw. war für mich sehr einfach anzuwenden
Was genau hat denn da nicht funktioniert? Man wird Dir hier immer aus guten Gründen zu subprocess raten. Es ersetzt eben das alte Sammelsurium an verschiedenen Funktionen (popen, popen2, usw) durch eine Abstraktion. Also: Auf subprocess umstellen lohnt sich.
-wieso nicht + ? soll ich in dem fall dann os.system(os.join("string", var, "string")) schreiben ?
Strings sind immutable in Python, d.h. man kann diese Zeichenketten nicht verändern. "foo" + "bar" erzeugt in Wirklichkeit also eine neue Zeichenkette. Das ist für Laufzeit und Ressourcen nicht förderlich. Man kann einzelne Zeichenketten z.B. durch "".join() zusammenfügen.
Man beachte die "[" und "]". join() verlangt als Parameter eine Sequenz.
Und ja, genauso sollte man os.join() verwenden. Damit hast Du einen garantiert fehlerfreien Pfad.
Verfasst: Mittwoch 16. September 2009, 12:30
von Hyperion
Ich habe mein Snippet mal überarbeitet und kommentiert.
Code: Alles auswählen
import json
# Exception Handling überlasse ich mal Dir ;-)
with open("jobs.json", "r") as in_file:
jobs = json.load(in_file)
try:
for job in jobs[user_eingabe]:
# dient nur zur Ausgabe des Jobs
print "Job: {ip}, {user}, {path}".format(**job)
# hier rufst Du eben die Funktion(en) auf, die mit diesen Parametern
# abgearbeitet werden sollen.
# das "**" vor job erkläre ich unten, Du kannst aber auch direkt die
# Parameter übergeben, also job["ip"] z.B.
process(**job)
except KeyError, e:
print "Ungültiger / Undefinierter Status"
Das "**job" ist eine gute Idee, wenn die Funktion eben genau diese Parameter erwartet, oder beliebige Parameter annehmen soll. Damit wird das Dict quasi direkt als Parameter in die Funktion übergeben.
Code: Alles auswählen
In [23]: foo(**jobs)
{'ip': '192.168.0.1', 'user': 'chris'}
In [24]: def foo(**kwargs):
....: print kwargs
....:
....:
In [25]: jobs = {"ip": "192.168.0.1", "user": "chris"}
In [26]: foo(**jobs)
{'ip': '192.168.0.1', 'user': 'chris'}
In [31]: def bar(user, ip):
....: print user, ip
....:
....:
In [32]: bar(**jobs)
chris 192.168.0.1