seit ungefähr zwei Monaten beschäftige ich mich nun mit Python. Derweil habe ich schon verschiedene Scripts geschrieben.
Da ich aber nicht wirklich jemanden habe, der das mal kontrolliert, was ich entwickel, wollte ich mich gerne an das Forum wenden. Hier wurde mir stets immer gut weiter geholfen.
Es soll nicht der ganze Code kontrolliert und verbessert werden. Mir geht es vorrangig eher um die Code-Struktur, und darum, dass andere Entwickler diesen später auch gut verstehen können.
Meine Fragen wären hiernach:
Ist der Aufbau der Klassen und Methoden-Struktur so geeignet?
Ist das Setzen der Instanzvariablen innerhalb von __init__ so korrekt?
Sind die Methoden-Namen korrekt gewählt?
Ist der Inhalt innerhalb der Methoden in Ordnung - oder müsste ich einzelne Abschnitte weiter in kleinere, neue Methoden auslagen?
Sind die privaten Methoden, die innerhalb anderer Methoden aufgerufen werden, so in Ordnung?
Gibt es allgemeine Tipps?
Ich habe ein Script, welches nach Benutzereingabe einen Host aus Text-Dateien entfernt. Die Arbeitsweise ist ungefähr so:
- Es durchsucht die Textdateien nach dem Host-Namen
- Wenn der gesuchte Hostname in der Datei gefunden wurde:
-- dann wird die Textdatei durchlaufen und der Inhalt passend dargestellt, ohne diesen Host, neu abgespeichert
-- zusätzlich wird eine zweite Datei abgeändert, die die Anzahl der Hosts zählt
-- letztendlich wird der Host aus einer JSON-Datei entfernt
Meine eigene Einschätzung:
Mir kommt die Methode __removeFromHostsFile() sehr lang vor. Vllt. liegt es auch an den Kommentaren
Die privaten Methoden, die innerhalb anderer Methoden aufgerufen werden, halte ich dort für ziemlich versteckt. Ich habe das allerdings so gemacht, weil die halt nur dann ausgeführt werden sollen, wenn die überliegende Methode auch ausgeführt wird.
Das Script ist (auch aufgrund der Kommentare) leider sehr lang: ungefähr 200 Zeilen. Verzeiht 's mir.. Ich hoffe jemand hat dennoch wertvolle Tipps auf Lager, wie ich das Coding allgemein verbessern könnte.
Lieben Gruß
Code: Alles auswählen
# class HostRemover
# __init__()
# removeHost()
# __removeFromDiscoveriesJson()
# __removeFromHostsFiles()
# __findContentFromAst()
# __substractNumberOfHosts()
# __cleanHostFile
import os
import sys
import re
import mkFileVisitor
import ast
import json
import fifi
class HostRemover():
def __init__(self, hostname):
self.hostname = hostname
self.ownFile = os.path.basename(__file__)
# public class
# needs a list of files
def removeHost(self, files, discoveriesJson):
for filename in files:
if(self.__removeFromHostsFile(filename)):
break
self.__removeFromDiscoveriesJson(discoveriesJson)
def __removeFromDiscoveriesJson(self, discoveryFile):
if os.path.isfile(discoveryFile):
#load discoveries (json-object) and convert it to a list-object
discoveries = open(discoveryFile).read()
discoveriesDecoded = json.loads(discoveries)
newDiscoveries = dict()
# loop the discoveries-list
# fill new list (without our host)
for host in discoveriesDecoded:
if self.hostname not in host:
newDiscoveries[host] = discoveriesDecoded[host]
#convert our new list to an json-object
newDiscoveries = json.dumps(newDiscoveries)
#save the new discovieres (without our host)
discoveries = open(discoveryFile,"w")
discoveries.write(str(newDiscoveries))
discoveries.close()
else:
print self.ownFile + " couldn't read " + os.path.abspath(discoveryFile)
# such a stupid method to parse the host-files :@@@
def __removeFromHostsFile(self, filename):
with open(filename, "r+") as hostfile:
hostInFile = False
# loop the hosts-file
# and check if it contains our host
for line in hostfile:
if self.hostname in line:
hostInFile = True
break
if hostInFile:
# set fileobject to begin
hostfile.seek(0)
# creating new hosts-descriptions without our hosts:
newContent = ""
newContent += self.__findContentFromAst(filename, "ipaddresses", "update")
newContent += self.__findContentFromAst(filename, "host_attributes", "update")
newContent += self.__findContentFromAst(filename, "explicit_snmp_communities", "update")
# in "hosts.mk"-file are some host-descriptions
# which are not traceable with python's AST-module:
#
# host_contactgroups += [ ..content.. ]
# all_hosts += [ ..content.. ]
# extra_host_conf.setdefault('alias', []).extend( [ ..content.. ] )
# extra_host_conf.setdefault('parents', []).extend( [ ..content.. ] )
#
# so in the following i need to parse it on another way...
contactGroupOrAllHosts = False
extraHostConf = False
for line in hostfile:
# check if the line contains necessary keywords
if "host_contactgroups +=" in line or "all_hosts +=" in line:
contactGroupOrAllHosts = True
elif "extra_host_conf.setdefault('" in line:
extraHostConf = True
if contactGroupOrAllHosts:
if self.hostname not in line:
newContent += line
if "]" in line and len(line) < 3:
contactGroupOrAllHosts=False
newContent += "\n"
elif extraHostConf:
if "[(u'" in line and self.hostname in line:
newContent += "["
if self.hostname in line and ")])" in line:
newContent += "])\n\n"
elif self.hostname not in line:
newContent += line
if ")])" in line:
extraHostConf = False
newContent += "\n"
newContent = self.__cleanHostFile(newContent)
hostfile.seek(0)
hostfile.write(newContent)
hostfile.truncate()
watoFile = filename.split("hosts.mk")[0] + ".wato"
self.__subtractNumberOfHosts(watoFile)
return True
else:
return False
def __cleanHostFile(self, content):
# remove empty entries
content = content.replace("all_hosts += [\n]","")
content = content.replace("extra_host_conf.setdefault('alias', []).extend(\n[])","")
content = content.replace("extra_host_conf.setdefault('parents', []).extend(\n[])","")
content = content.replace("explicit_snmp_communities.update(\n{})","")
content = content.replace("host_contactgroups += [\n]","")
content = content.replace("ipaddresses.update(\n{})","")
content = content.replace("host_attributes.update(\n{})","")
#remove needless line-breaks
for i in range(0,10):
content = content.replace("\n\n\n","\n\n")
return content
# AST = abstract syntax tree
# .mk-files are also written in python-syntax,
# so we can find few content with pythons AST-module
def __findContentFromAst(self, filename, param1, param2):
fileContent = open(filename).read()
# let us visit the file and seek for the passed parameter.
# visitor uses the AST-module for parsing the code
contentVisitor = mkFileVisitor.Visitor(param1, param2)
contentVisitor.visit(ast.parse(fileContent))
newContent = dict()
# loop visitors result
# save result as "newContent" without our host
for host in contentVisitor.result:
for item in host:
if self.hostname not in item:
newContent[item] = host[item]
return param1 + "." + param2 + "(\n" + str(newContent) + ")\n\n"
# This method is written for hidden ".wato"-configuration-files.
# These files just store the number of hosts in a folder.
# In addition these files prsent the foldername.
def __subtractNumberOfHosts(self, filename):
with open(filename, "r+") as watofile:
number = 0
title = ""
for line in watofile:
# takes the number of host while using a regular expression:
number = re.findall('([0-9]+)', line)[0]
# stores the folder-title while using split()
if "'title': u'" in line:
title = line.split("'title': u'")[1].split("'}")[0]
else:
title = line.split("'title': '")[1].split("'}")[0]
if number:
number = int(number)-1
output = "{'attributes': {}, 'num_hosts': " + str(number) + ", 'title': u'" + title + "'}"
watofile.seek(0)
watofile.write(output)
watofile.truncate()
def main():
hostname = sys.argv[1]
try:
finder = fifi.FileFinder("hosts.mk", root="../../../../etc/check_mk/conf.d/wato/")
files = finder.findFiles()
except:
print sys.exc_info()[0]
remover = HostRemover(hostname)
remover.removeHost(files, "../discoveries.json")
if __name__ == '__main__':
main()