From f88b64a3ee114bf003bcf5e9a691df14dc64e959 Mon Sep 17 00:00:00 2001 From: asamoukin Date: Mon, 17 Aug 2009 04:50:44 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20?= =?UTF-8?q?DNS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.calculate.ru/calculate2/calculate-server/trunk@2466 c91db197-33c1-4113-bf15-f8a5c547ca64 --- pym/cl_fill_server.py | 14 +- pym/cl_ldap.py | 1877 ++++++++++++++++++++++++++++++++++++++++- scripts/cl-dnsrecadd | 12 +- scripts/cl-dnsrecdel | 12 +- scripts/cl-dnsrecmod | 15 +- scripts/cl-dnszoneadd | 12 +- scripts/cl-dnszonedel | 12 +- scripts/cl-dnszonemod | 2 +- 8 files changed, 1911 insertions(+), 45 deletions(-) diff --git a/pym/cl_fill_server.py b/pym/cl_fill_server.py index 2e6b488..3c1db0c 100644 --- a/pym/cl_fill_server.py +++ b/pym/cl_fill_server.py @@ -575,7 +575,7 @@ class fillVars(object, cl_base.glob_attr): def get_sr_dns_net_allow_pass(self): """Текст в named.conf - доступные сети""" - def getNetAllow(): + def getNetAllow(netAllow): netAllow = netAllow.split(",") foundLoc = False for net in netAllow: @@ -584,13 +584,13 @@ class fillVars(object, cl_base.glob_attr): break if not foundLoc: netAllow.append("127.0.0.1") - netAllow = map(lambda x: "\t\t%s;"%x,netAllow) - netAllow = "\n".join(netAllow) - return "\tlisten-on {\n%s\n\t};"%netAllow + netAllow = map(lambda x: "%s;"%x,netAllow) + netAllow = " ".join(netAllow) + return "listen-on { %s };"%netAllow netAllow = self.Get("sr_dns_net_allow") if netAllow: - return getNetAllow() + return getNetAllow(netAllow) netAllow = self.Get("os_net_allow") if netAllow: - return getNetAllow() - return "\tlisten-on { 127.0.0.1; };" \ No newline at end of file + return getNetAllow(netAllow) + return "listen-on { 127.0.0.1; };" \ No newline at end of file diff --git a/pym/cl_ldap.py b/pym/cl_ldap.py index 4ae2c82..30b94fb 100644 --- a/pym/cl_ldap.py +++ b/pym/cl_ldap.py @@ -41,6 +41,10 @@ import datetime import tempfile # Вывод в строку ввода import readline +# Пути в XML документе +from xml import xpath +# Для 32 битного целого (генерация серийного номера DNS зоны) +import ctypes Version = "calculate-server 2.1.4" @@ -711,7 +715,7 @@ in a sambaDomainName', Также прописывает в автозагрузку Входные даннные - список названий сервисов """ - if 'ldap' in servInstalled: + if 'ldap' in servInstalled or 'unix' in servInstalled: if not self.startDaemons('ldap',['slapd'], printSuccess): return False # Устанавливаем автозапуск демона @@ -765,6 +769,14 @@ in a sambaDomainName', if not self.setDaemonAutostart("squid"): flagError = True break + elif service == "dns": + if not self.startDaemons('dns',['named'], printSuccess): + flagError = True + break + # Устанавливаем автозапуск демона + if not self.setDaemonAutostart("named"): + flagError = True + break else: if not self.startDaemons(service,[service], printSuccess): flagError = True @@ -1227,13 +1239,18 @@ in a sambaDomainName', readline.set_pre_input_hook(None) return strInput - def isCorrectStringNet(self, strNetworks): + def isCorrectStringNet(self, strNetworks, checkNet=True): """Проверяет на корректность строку доверительных сетей Выводит cписок сетей """ splNet = strNetworks.replace(","," ").split(" ") - res=re.compile("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?(\/\d\d)?$") + if checkNet: + checkIP = False + res=re.compile("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?(\/\d\d?)?$") + else: + checkIP = True + res=re.compile("^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$") flagError = False networks = [] for i in splNet: @@ -1247,8 +1264,27 @@ in a sambaDomainName', else: splIP = map(lambda x: 255>=int(x.split("/")[0]) and\ x.split("/")[0], find.group().split(".")) - if splIP[0] and int(splIP[0]) == 0 or\ - splIP[0] and int(splIP[3]) == 255: + if not splIP[0] or splIP[0] and int(splIP[0]) == 0: + flagError = True + break + if not splIP[3] or splIP[3] and int(splIP[3]) == 255: + flagError = True + break + if checkNet: + checkIP = False + netList = r.split("/") + if netList and len(netList)>1: + if len(netList)==2: + netMaskInt = int(netList[1]) + if netMaskInt>31 or netMaskInt<4: + flagError = True + break + else: + flagError = True + break + else: + checkIP = True + if checkIP and splIP[3] and int(splIP[3]) == 0: flagError = True break for t in splIP: @@ -1338,6 +1374,17 @@ if you want to continue to run the program again")) os.chown(destDir, uid,gid) return True + @adminConnectLdap + def addEntry(self, DN, entry, errorMessage): + """Добавление узла в LDAP""" + try: + self.conLdap.add_s(DN, entry) + except ldap.LDAPError, e: + self.printERROR(_("LDAP Error") + ": " + e[0]['desc'].strip()) + self.printERROR(errorMessage) + return False + return True + def addDN(self, *arg): """Складывает текстовые элементы DN""" DNs = [] @@ -1595,7 +1642,7 @@ This command is not allowed.")) lines = FD.readlines() FD.close() for line in lines: - if not line in ":": + if not ':' in line: continue num = int(line.split(":")[numEl]) if num<=numMax and num>=numMin: @@ -7249,6 +7296,8 @@ outdated. If the backup is obsolete, use cl-backup.")) verbose = False if options.has_key("v"): verbose = True + # Cервисы которые рестартуют + servicesRestart = [] # Флаг почтового релея flagMailRelay = False if not flagError: @@ -7342,23 +7391,28 @@ outdated. If the backup is obsolete, use cl-backup.")) %service.capitalize() + " ...") if flagMailRelay: service = "mail_relay" + servicesRestart.append(service) + # Перезапускаем ldap + if not flagError: + service = "ldap" + if not self.restartLdapServer(): + return False + self.printOK(_("Restarting service %s")%"LDAP" + " ...") + # Перезапускаем остальные сервисы + if not flagError: + for service in servicesRestart: + if service in "ldap": + continue if not self.stopServices([service]): flagError = True break if not self.startServices([service], False): flagError = True break - if flagMailRelay: + if service == "mail_relay": service = "mail" self.printOK(_("Restarting service %s")%service.capitalize()+\ " ...") - # Перезапускаем ldap - if not flagError: - service = "ldap" - if not self.restartLdapServer(): - return False - self.printOK(_("Restarting service %s")%"LDAP" + " ...") - if not flagError and "samba" in servInstalled and\ serviceUpdate in ["all","samba"]: # Добавляем статические Samba группы и изменяем настройки @@ -8452,6 +8506,12 @@ class cl_ldap(shareLdap): 'replcron':13, 'cl-info':14, 'proxy':15, + 'cl-dnsrecadd':16, + 'cl-dnsrecdel':17, + 'cl-dnsrecmod':18, + 'cl-dnszoneadd':19, + 'cl-dnszonedel':20, + 'cl-dnszonemod':21, } # Cвязь сервисов и действующих опций self.relServices = {"samba":[_("Common options"), @@ -9685,6 +9745,184 @@ the password will be changed only for Samba account") 'helpChapter':_("Common options"), 'help':_("password for distinguished name (dn) - service Proxy from \ file") + }, + {'progAccess':(16,), + 'longOption':"autoptr", + 'optVal':"CONDITION", + 'helpChapter':_("Common options"), + 'help':_("When create a A record will be automatically created \ +PTR record (on/off, on - default)") + }, + {'progAccess':(16,), + 'shortOption':"t", + 'longOption':"type", + 'optVal':"TYPE", + 'helpChapter':_("Common options"), + 'help':_("type record 'a' - forward record (default), 'ptr' - reverse \ +record, 'cname' - canonical name record") + }, + {'progAccess':(16,), + 'longOption':"host", + 'optVal':"HOST", + 'helpChapter':_("Common options"), + 'help':_("fully qualified host name (includes host name and domain \ +name)") + }, + {'progAccess':(16,), + 'longOption':"cnhost", + 'optVal':"CNHOST", + 'helpChapter':_("Common options"), + 'help':_("canonical name (fully qualified host name) for CNAME record") + }, + {'progAccess':(16,), + 'longOption':"ip", + 'optVal':"IP_ADDRESS", + 'helpChapter':_("Common options"), + 'help':_("ip address") + }, + {'progAccess':(16,), + 'longOption':"mx", + 'optVal':"MAIL_SERVERS", + 'helpChapter':_("Common options"), + 'help':_("host names mail servers for mail exchanger (comma \ +delimited)") + }, + {'progAccess':(17,), + 'longOption':"host", + 'optVal':"HOST", + 'helpChapter':_("Common options"), + 'help':_("fully qualified host name (includes host name and domain \ +name), delete forward record") + }, + {'progAccess':(17,), + 'longOption':"ip", + 'optVal':"IP_ADDRESS", + 'helpChapter':_("Common options"), + 'help':_("ip address, delete revese record") + }, + {'progAccess':(18,), + 'longOption':"automod", + 'optVal':"CONDITION", + 'helpChapter':_("Common options"), + 'help':_("When modify a A record will be automatically modified \ +PTR record or when modify a PTR record will be automatically modified \ +A record (on/off, on - default)") + }, + {'progAccess':(18,), + 'shortOption':"t", + 'longOption':"type", + 'optVal':"TYPE", + 'helpChapter':_("Common options"), + 'help':_("type record 'a' - forward record (default), 'ptr' - reverse \ +record, 'cname' - canonical name record") + }, + {'progAccess':(18,), + 'longOption':"host", + 'optVal':"HOST", + 'helpChapter':_("Common options"), + 'help':_("new fully qualified host name (includes host name and \ +domain name)") + }, + {'progAccess':(18,), + 'longOption':"ip", + 'optVal':"IP", + 'helpChapter':_("Common options"), + 'help':_("new ip address") + }, + {'progAccess':(18,), + 'longOption':"mxhosts", + 'optVal':"MAIL_SERVERS", + 'helpChapter':_("Common options"), + 'help':_("new hostnames mail servers for mail exchanger (comma \ +delimited)") + }, + {'progAccess':(18,), + 'longOption':"mxhost", + 'optVal':"MAIL_SERVERS", + 'helpChapter':_("Common options"), + 'help':_("rename old hostname mail server to new hostname mail server \ +for mail exchanger (comma delimited)") + }, + {'progAccess':(18,), + 'longOption':"cname", + 'optVal':"CNAME", + 'helpChapter':_("Common options"), + 'help':_("new canonical name (CNAME record)") + }, + {'progAccess':(19,), + 'shortOption':"t", + 'longOption':"type", + 'optVal':"TYPE", + 'helpChapter':_("Common options"), + 'help':_("zone type (master/slave)") + }, + {'progAccess':(19,), + 'shortOption':"n", + 'longOption':"name", + 'optVal':"NAME", + 'helpChapter':_("Common options"), + 'help':_("zone name, 'domain name' for forward zone or 'net name' for \ +reverse zone") + }, + {'progAccess':(19,), + 'longOption':"server", + 'optVal':"SERVER", + 'helpChapter':_("Common options"), + 'help':_("master autoritative DNS server for zone (hostname server)") + }, + {'progAccess':(19,), + 'longOption':"ipserver", + 'optVal':"IPSERVER", + 'helpChapter':_("Common options"), + 'help':_("ip for master autoritative DNS server for zone") + }, + {'progAccess':(19,), + 'longOption':"email", + 'optVal':"email", + 'helpChapter':_("Common options"), + 'help':_("email administrator zone") + }, + {'progAccess':(19,), + 'longOption':"servers", + 'optVal':"SERVERS", + 'helpChapter':_("Common options"), + 'help':_("All autoritative DNS servers for zone (comma delimited)") + }, + {'progAccess':(19,), + 'longOption':"refresh", + 'optVal':"REFRESH", + 'helpChapter':_("Common options"), + 'help':_("time interval for updating zone, default - 8H (8 hours)") + }, + {'progAccess':(19,), + 'longOption':"update", + 'optVal':"UPDATE", + 'helpChapter':_("Common options"), + 'help':_("time interval for updating zone after an unsuccessful \ +update zone, default - 2H (2 hours)") + }, + {'progAccess':(19,), + 'longOption':"expiry", + 'optVal':"EXPIRY", + 'helpChapter':_("Common options"), + 'help':_("time interval, if during this time interval slave DNS \ +server can not update zone, zone is outdated in slave DNS server, \ +default - 2W (2 weeks)") + }, + {'progAccess':(19,), + 'longOption':"minimum", + 'optVal':"MINIMUM", + 'helpChapter':_("Common options"), + 'help':_("time interval stored in cache failed DNS queries to the \ +zone, default - 2H (2 hours)") + }, + {'progAccess':(20,), + 'shortOption':"n", + 'longOption':"name", + 'optVal':"NAME", + 'helpChapter':_("Common options"), + 'help':_("zone name, 'domain name' for forward zone or 'net name' for \ +reverse zone") }, #{'progAccess':(0,1,2,4,5,6), #'shortOption':"s", @@ -9799,7 +10037,7 @@ file") " " + _("service") }, { - 'progAccess':(8,11,15), + 'progAccess':(8,11,15,16,17,19,20,21), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "]" }, @@ -9813,6 +10051,12 @@ file") 'helpChapter':_("Usage"), 'help': cmdName }, + { + 'progAccess':(18,), + 'helpChapter':_("Usage"), + 'help': cmdName + " [" + _("options") + "]" + " <" +\ + _("hostname or ip") + ">" + }, # Function { 'progAccess':(0,), @@ -9898,6 +10142,36 @@ removed from the LDAP using replication") 'help':_("Checks the users access to the Internet using a Proxy \ service") }, + { + 'progAccess':(16,), + 'helpChapter':"Function", + 'help':_("Add DNS record in LDAP") + }, + { + 'progAccess':(17,), + 'helpChapter':"Function", + 'help':_("Delete DNS record in LDAP") + }, + { + 'progAccess':(18,), + 'helpChapter':"Function", + 'help':_("Modify DNS record in LDAP") + }, + { + 'progAccess':(19,), + 'helpChapter':"Function", + 'help':_("Add DNS zone") + }, + { + 'progAccess':(20,), + 'helpChapter':"Function", + 'help':_("Delete DNS zone") + }, + { + 'progAccess':(21,), + 'helpChapter':"Function", + 'help':_("Modify DNS zone") + }, # Примеры { 'progAccess':(0,), @@ -13065,7 +13339,7 @@ or '-P')")) notFindGroup=filter(lambda x: not self.searchGroupToName(x), groupNames) if notFindGroup: self.printERROR(_("Groups %s is not found in Proxy service")\ - %" ,".join(notFindGroup)) + %", ".join(notFindGroup)) return False else: return True @@ -13698,6 +13972,196 @@ group'), self.printOK(_("Proxy service configured") + " ...") return True +class dnsZoneTxt(cl_profile.bind, cl_profile._error, cl_utils2.cl_smartcon): + """Класс для работы с DNS зонами в тексте конфиг. файла""" + # Имя конфигурационного файла + nameConfigFile = "/etc/bind/named.conf" + def __init__(self): + try: + FD = open(self.nameConfigFile) + text = FD.read() + FD.close() + except: + errMessage = _("Can not open %s") %self.nameConfigFile + self.printERROR(errMessage) + self.setError(errMessage) + if not self.getError(): + cl_profile.bind.__init__(self, text) + + def getTextZone(self, clVars, zoneName, zoneType, zoneMasters=[]): + """Создание текста DNS зоны""" + if zoneType == "master": + dnsBaseDN = clVars.Get("ld_dns_dn") + dnsCommaSplDN = dnsBaseDN.replace(",","%2c") + dnsBasePw = clVars.Get("ld_dns_pw") + if ".in-addr.arpa" in zoneName: + dnsDN = "ou=Reverse,%s"%dnsBaseDN + # реверсивная зона + else: + # прямая зона + dnsDN = "ou=Forward,%s"%dnsBaseDN + template = 'zone "%s" in {\n\ +\ttype %s;\n\ +\tdatabase "ldap ldap://127.0.0.1/zoneName=%s,%s????\ +!bindname=%s,!x-bindpw=%s 178600";\n\ +};' %(zoneName,zoneType,zoneName,dnsDN,dnsCommaSplDN,dnsBasePw) + return template + elif zoneType == "slave": + if not zoneMasters: + self.printERROR(\ + _('Can not found master DNS server in the DNS zone "%s"')%zoneName) + return False + zoneFile = "%s.zone" %zoneName.split(".in-addr.arpa")[0] + template = 'zone "%s" {\n\ +\ttype %s;\n\ +\tfile "sec/%s";\n\ +\tmasters { %s; };\n\ +};' %(zoneName,zoneType,zoneFile, "; ".join(zoneMasters)) + return template + else: + self.printERROR(_('DNS zone type %s unsupported')%zoneType) + return False + + def _geAllXMLZonesNames(self): + """Получаем все XML ноды названий DNS зон""" + if self.getError(): + return False + xmlNodeBody = self.docObj.getNodeBody() + namesArea = xpath.Evaluate(\ + "child::area/child::caption/child::name", xmlNodeBody) + if not namesArea: + return [] + return filter(lambda x: x.firstChild and x.firstChild.nodeValue and\ + 'zone"' in x.firstChild.nodeValue, namesArea) + + def getXMLZoneToName(self, nameZone): + """Получить XML ноду DNS зоны по ее имени""" + if self.getError(): + return False + if nameZone in [".", "localhost", "127.in-addr.arpa"]: + return [] + # Получаем ноды зон + xmlZonesNames = self._geAllXMLZonesNames() + if not xmlZonesNames: + return [] + slpNameZone =\ + 'zone"%s"' %nameZone.replace(" ","").replace("\t","").lower() + return map(lambda x: x.parentNode.parentNode, filter(lambda x:\ + slpNameZone in x.firstChild.nodeValue.lower(), xmlZonesNames)) + + def getAllNamesZones(self): + """Полчить все имена нод областей (кроме служебных)""" + if self.getError(): + return False + retNodesNames = [] + # Получаем ноды зон + xmlZonesNames = self._geAllXMLZonesNames() + if not xmlZonesNames: + return retNodesNames + for nodeZone in xmlZonesNames: + if '"."' in nodeZone.firstChild.nodeValue.lower(): + continue + elif '"localhost"' in nodeZone.firstChild.nodeValue.lower(): + continue + elif '"127.in-addr.arpa"' in nodeZone.firstChild.nodeValue.lower(): + continue + retNodesNames.append(\ + nodeZone.firstChild.nodeValue.rpartition('"')[0].partition('"')[2]) + retNodesNames = filter(lambda x: x, retNodesNames) + return retNodesNames + + def writeInConfig(self, text): + """Запись текста в конфигурационный файл""" + try: + FD = open(self.nameConfigFile,"r+") + FD.truncate(0) + FD.seek(0) + FD.write(text) + FD.close() + except: + errMessage = _("Can not write in file %s") %self.nameConfigFile + self.printERROR(errMessage) + self.setError(errMessage) + return False + return True + + def deleteZone(self, zoneName): + """Удаляет зону из конфигурационного файла bind""" + if self.getError(): + return False + deletesNodes = self.getXMLZoneToName(zoneName) + if not deletesNodes: + self.printERROR(_('Can not found DNS zone "%s"')%zoneName) + return False + # Удаление областей + xmlNodeBody = self.docObj.getNodeBody() + nextNode = lambda x: x.nextSibling + prevNode = lambda x: x.previousSibling + delNodesNext = [] + delNodesPrev = [] + for node in deletesNodes: + nNode = node + nNode = nextNode(nNode) + while nNode and self.docObj.getTypeField(nNode)=="br": + delNodesNext.append(nNode) + nNode = nextNode(nNode) + pNode = node + pNode = prevNode(pNode) + while pNode and self.docObj.getTypeField(pNode)=="br": + delNodesPrev.append(pNode) + pNode = prevNode(pNode) + + # Оставляем два перевода строки сверху + if delNodesPrev and len(delNodesPrev)>=2: + delNodesPrev.pop() + delNodesPrev.pop() + elif delNodesNext and len(delNodesNext)>=2: + delNodesNext.pop() + delNodesNext.pop() + elif delNodesPrev and len(delNodesPrev)==1: + delNodesPrev.pop() + if delNodesNext and len(delNodesNext)==1: + delNodesNext.pop() + elif delNodesNext and len(delNodesNext)==1: + delNodesNext.pop() + delNodes = delNodesPrev + delNodesNext + # Удаляем переводы строк + map(lambda x: xmlNodeBody.removeChild(x), delNodes) + #print xmlNodeBody.toprettyxml().encode("UTF-8") + # Удаляем области + for term in map(lambda x: xmlNodeBody.removeChild(x), deletesNodes): + if not term: + self.printERROR(_('Can not remove DNS zone "%s"')%zoneName+\ + " " + _("in config file %s")%self.nameConfigFile) + return False + # Запись файла + text = self.getConfig().encode("UTF-8") + return self.writeInConfig(text) + + def createZone(self, clVars, zoneName, zoneType, zoneMasters=[]): + """Создает зону в файле конфигурации bind""" + if self.getError(): + return False + textZone = self.getTextZone(clVars, zoneName, zoneType, + zoneMasters) + if not textZone: + return False + bindObj = cl_profile.bind(textZone) + xmlNodeBodyNewZone = bindObj.docObj.getNodeBody() + namesAreaNew = xpath.Evaluate(\ + "child::area/child::caption/child::name", xmlNodeBodyNewZone) + splNameNewNode =\ + namesAreaNew[0].firstChild.nodeValue.replace("{","").split('"') + splNameNewNode = splNameNewNode[1] + if self.getXMLZoneToName(splNameNewNode): + self.printERROR(_('DNS zone "%s" exists')%splNameNewNode) + return False + # Объединение конфигураций + self.join(bindObj) + # Запись файла + text = self.getConfig().encode("UTF-8") + return self.writeInConfig(text) + class servDNS(shareLdap): """Методы сервиса DNS""" # Прямые зоны @@ -13706,6 +14170,17 @@ class servDNS(shareLdap): relRevDN = 'ou=Reverse' relServDN = 'ou=DNS' ldifFileBase = "/usr/lib/calculate/calculate-server/ldif/dns_base.ldif" + # интервал времени для обновления зоны в секундах или + # число + (M - минуты, H - часы, D - дни, W - недели) + zoneRefresh = "8H" + # интервал времени после неудачного обновления зоны + zoneUpdateRetry = "2H" + # интервал времени устаревания данных зоны на вторичных + # DNS серверах в случае невозможности соединения с главны сервером + zoneExpiry = "2W" + # интервал времени хранения данных неудачных запросов к другим + # DNS серверам + zoneMinimum = "2H" def __init__(self): shareLdap.__init__(self) @@ -13716,6 +14191,1339 @@ class servDNS(shareLdap): # DN обратных зон, относительно базового DN self.relReverseDN = self.addDN(self.relRevDN, self.relDN) + @adminConnectLdap + def _searchLdapDNSub(self, name, relDN, attr, retAttr=None): + """Находит DN в LDAP ишет во всех ветках""" + DN = self.addDN(relDN,self.baseDN) + searchScope = ldap.SCOPE_SUBTREE + searchFilter = "%s=%s" %(attr,name) + retrieveAttributes = retAttr + resSearch = self.ldapObj.ldapSearch(DN, searchScope, + searchFilter, retrieveAttributes) + return resSearch + + def _getRelZoneBaseDN(self, zoneName, opt="ZonesDN"): + """Выдает + + opt='ZonesDN' - DN хранения зон + opt='ouZonesDN' - ('ou=Forvard' или 'ou=Reverse') + opt='ZonesDN' - DN зоны + opt='isFwdZone' - (прямая зона - True, обратная зона - False) + выдаваемые DN хранения зон и DN зоны относительно базового DN + """ + if opt=="ZonesDN" or opt=="ZoneDN": + listRelZones = (self.relForwardDN, self.relReverseDN) + elif opt=="ouZonesDN": + listRelZones = (self.relFwdDN, self.relRevDN) + elif opt=="isFwdZone": + listRelZones = (True, False) + if ".in-addr.arpa" in zoneName: + # реверсивная зона + relZoneDN = listRelZones[1] + else: + # прямая зона + relZoneDN = listRelZones[0] + if opt=="ZonesDN" or opt=="ouZonesDN" or opt=="isFwdZone": + return relZoneDN + elif opt=="ZoneDN": + return "zoneName=%s,%s" %(zoneName, relZoneDN) + return False + + def isForwardZone(self, zoneName): + """Прямая зона - True, обратная False""" + return self._getRelZoneBaseDN(zoneName, "isFwdZone") + + def getRelZonesDN(self, zoneName): + """Относительный DN хранения зон""" + return self._getRelZoneBaseDN(zoneName) + + def getRelZoneDN(self, zoneName): + """Относительный DN хранения зоны""" + return self._getRelZoneBaseDN(zoneName, "ZoneDN") + + def getOUZonesDN(self, zoneName): + """ou хранения зон ou=Forvard или ou=Reverse""" + return self._getRelZoneBaseDN(zoneName, "ouZonesDN") + + def searchZoneInLDAP(self, zoneName): + """Находим DNS зону в LDAP""" + relZonesDN = self.getRelZonesDN(zoneName) + resSearch = self.searchLdapDN(zoneName, relZonesDN, "zoneName") + return resSearch + + def searchAllDomainNamesinLDAP(self, domainName): + """Находит узел описания домена (если домен @ - это описание зоны) + + Ищет в LDAP, выдает все записи + """ + hostName, spl, zoneName = domainName.partition(".") + relZoneDN = self.getRelZoneDN(zoneName) + resSearch = self.searchLdapDN(hostName, relZoneDN, "relativeDomainName") + return resSearch + + def searchDomainNameinLDAP(self, domainName): + """Находит узел описания домена (если домен @ - это описание зоны) + + Ищет в LDAP, выдает все записи кроме CNAME + """ + resSearch = self.searchAllDomainNamesinLDAP(domainName) + if resSearch: + resSearch=filter(lambda x: not x[0][1].has_key("cNAMERecord"),\ + resSearch) + return resSearch + + def searchCNameInLDAP(self, domainName): + """Находит узел CNAME + + Ищет в LDAP + """ + resSearch = self.searchAllDomainNamesinLDAP(domainName) + if resSearch: + resSearch=filter(lambda x: x[0][1].has_key("cNAMERecord"),\ + resSearch) + return resSearch + + def searchIPinForward(self, ip): + """Находит узлы с данным ip в прямых зонах + + Ищет в LDAP + """ + resSearch = self._searchLdapDNSub(ip, self.relForwardDN, "aRecord") + return resSearch + + def searchHostsForIPinForward(self, ip): + """Находит имена хостов на основании ip в прямой зоне""" + hostNames = [] + foundNames = self.searchIPinForward(ip) + if foundNames: + for aRecord in foundNames: + relDomainNames = aRecord[0][1]['relativeDomainName'] + zoneName = aRecord[0][1]['zoneName'][0] + domainNames = map(lambda x:"%s.%s"%(x,zoneName),relDomainNames) + hostNames += domainNames + return hostNames + + def searchHostinReverse(self, host): + """Находит узлы с данным именем хоста в обратных зонах + + Ищет в LDAP + """ + hostDot = "%s."%host + resSearch = self._searchLdapDNSub(hostDot,self.relReverseDN,"pTRRecord") + return resSearch + + def searchIPForHostInReverse(self, host): + """Находит ip на основании имени хоста в обратной зоне""" + IPs = [] + foundIPs = self.searchHostinReverse(host) + if foundIPs: + for ptrRecord in foundIPs: + lastOctIPs = ptrRecord[0][1]['relativeDomainName'] + zoneName = ptrRecord[0][1]['zoneName'][0] + domainNames = map(lambda x:"%s.%s"%(x,zoneName),lastOctIPs) + for name in domainNames: + listOctRev = name.rpartition(".in-addr.arpa")[0].split(".") + listOctRev.reverse() + IPs.append(".".join(listOctRev)) + return IPs + + def createSlaveZone(self, zoneName, zoneMasters): + """Создание подчинненной DNS зоны в конфигурационном файле + + zoneName - имя зоны + zoneMasters - ip адреса мастер DNS серверов (список) + """ + if not self.stopServices(['dns']): + return False + objTxtZone = dnsZoneTxt() + if not objTxtZone.createZone(False, zoneName, "slave", zoneMasters): + return False + if not self.startServices(['dns'],False): + return False + self.printOK(_("Append DNS slave zone %s")%zoneName) + return True + + def createMasterZone(self, zoneName, + nameServer="", + emailAddr="", + namesServers = [], + serialNumber="1", + refresh=zoneRefresh, + updateRetry=zoneUpdateRetry, + expiry=zoneExpiry, + minimum=zoneMinimum): + """Создание первичной DNS зоны в конфигурационном файле и в LDAP + Параметры: + nameServer - имя первичного мастер сервера DNS зоны + emailAddr - адрес электронной почты человека управляющего зоной + serialNumber - порядковый номер от 0 до 4.294.967.295 + refresh - интервал времени для обновления зоны в секундах или + число + (M - минуты, H - часы, D - дни, W - недели) + updateRetry - интервал времени после неудачного обновления зоны + expiry - интервал времени устаревания данных зоны на вторичных + DNS серверах в случае невозможности соединения с главным + сервером + minimum - интервал времени хранения данных неудачных запросов к другим + DNS серверам + namesServers - авторитативные DNS-серверы для данного домена. + Количество записей типа NS должно точно + соответствовать количеству DNS-серверов, обслуживающих + домен и включать все DNS-серверы, указанные в домене + """ + # Добавление зоны в конфигурационный файл + ldapParser = iniLdapParser() + part = "dns" + self.clVars.Set("ld_dns_dn",ldapParser.getVar(part,"DN"),True) + self.clVars.Set("ld_dns_pw",ldapParser.getVar(part,"PASS"),True) + if not self.stopServices(['dns']): + return False + objTxtZone = dnsZoneTxt() + if not objTxtZone.createZone(self.clVars, zoneName, "master"): + return False + # Создание зоны в LDAP (создается объект переменных и соединение с LDAP) + if not self.createZoneInLDAP(zoneName, nameServer, emailAddr, + serialNumber, refresh, updateRetry, + expiry, minimum, namesServers): + return False + + if not self.startServices(['dns'],False): + return False + self.printOK(_("Append DNS master zone %s")%zoneName) + return True + + def deleteZone(self, zoneName): + """Удаление DNS зоны из конфигурационного файла и LDAP""" + if not self.stopServices(['dns']): + return False + objTxtZone = dnsZoneTxt() + if not objTxtZone.deleteZone(zoneName): + return False + # Если зона найдена в LDAP удаляем ее + if self.searchZoneInLDAP(zoneName): + # Удаление зоны из LDAP + if not self.deleteZoneInLDAP(zoneName): + return False + if not self.startServices(['dns'],False): + return False + self.printOK(_("Deleted DNS zone %s")%zoneName) + return True + + def createZoneInLDAP(self, zoneName, + nameServer, + emailAddr, + serialNumber, + refresh, + updateRetry, + expiry, + minimum, + namesServers): + """Создание DNS зоны в LDAP + Параметры: + nameServer - имя первичного мастер сервера DNS зоны + emailAddr - адрес электронной почты человека управляющего зоной + serialNumber - порядковый номер от 0 до 4.294.967.295 + refresh - интервал времени для обновления зоны в секундах или + число + (M - минуты, H - часы, D - дни, W - недели) + updateRetry - интервал времени после неудачного обновления зоны + expiry - интервал времени устаревания данных зоны на вторичных + DNS серверах в случае невозможности соединения с главным + сервером + minimum - интервал времени хранения данных неудачных запросов к другим + DNS серверам + namesServers - авторитативные DNS-серверы для данного домена. + Количество записей типа NS должно точно + соответствовать количеству DNS-серверов, обслуживающих + домен и включать все DNS-серверы, указанные в домене + """ + if not nameServer: + self.printERROR(_("Empty name server in sOA Record in zone %s")\ + %zoneName) + return False + if not namesServers: + self.printERROR(_("Empty autoritative names servers in sOA Record\ + in zone %s")%zoneName) + return False + # Метод добавляющий в конце текста точку если ее нет + addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x + # Имя первичного DNS сервера + nameServerDot = addDot(nameServer) + if not emailAddr: + self.printERROR(_("Empty email address in sOA Record in zone %s")\ + %zoneName) + return False + # Почтовый адрес администратора зоны + emailAddrDot = ".".join(addDot(emailAddr).split("@")) + # Регулярное выражение для проверки интервалов времени на корректность + regTime = re.compile("^\d+[smhdwSMHDW]?$") + sOATimeParams = [refresh,updateRetry,expiry,minimum] + # Проверка корректности значений интервалов времени + incorrectTimeValues = filter(lambda x: not regTime.search(x),\ + sOATimeParams) + if incorrectTimeValues: + self.printERROR(_("Values %s incorrect in sOA Record")\ + %", ".join(incorrectTimeValues)) + return False + # Добавление точки если необходимо в каждое имя DNS сервера + # Имена авторитативных DNS серверов для зоны + namesServersDot = map(lambda x: addDot(x), namesServers) + # Получение текста sOA записи + sOARecord = " ".join([nameServerDot,emailAddrDot,serialNumber] +\ + sOATimeParams) + # Ищем зону в LDAP (создается соединение и объект переменных) + if self.searchZoneInLDAP(zoneName): + self.printERROR(_("DNS zone %s exists in LDAP")%zoneName) + return False + baseDN = self.clVars.Get("ld_dns_dn") + if ".in-addr.arpa" in zoneName: + # реверсивная зона + zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, self.relRevDN, + baseDN) + else: + # прямая зона + zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, self.relFwdDN, + baseDN) + zoneBaseEntry = [('objectclass', ['top','dNSZone']), + ('relativeDomainName', [zoneName]), + ('zoneName',[zoneName])] + zoneBaseErrorMessage = _("Can not add in LDAP DNS zone %s") %zoneName + if not self.addEntry(zoneBaseDN, zoneBaseEntry, zoneBaseErrorMessage): + return False + zoneDomainDN = self.addDN("relativeDomainName=@",zoneBaseDN) + zoneDomainErrorMessage = _("Can not add sOA Record in zone %s")%zoneName + zoneDomainEntry = [('objectclass', ['top','dNSZone']), + ('relativeDomainName', ["@"]), + ('zoneName',[zoneName]), + ('sOARecord',[sOARecord]), + ('nSRecord',namesServersDot)] + + if not self.addEntry(zoneDomainDN, zoneDomainEntry, + zoneDomainErrorMessage): + return False + return True + + def deleteZoneInLDAP(self, zoneName): + """Удаление зоны из LDAP""" + # При поиске зоны создается объект переменных и соединение LDAP + if not self.searchZoneInLDAP(zoneName): + self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) + return False + relDelDN = self.getRelZoneDN(zoneName) + # Удаление зоны + ret = self.deleteDN(relDelDN) + if not ret: + return False + return True + + def delRecordDnsServer(self, options): + """Удаляет запись в DNS""" + # Проверим установлен ли сервис dns + if not self.isServiceSetup("dns"): + return False + optKeys = options.keys() + incompKeys = ["host","ip"] + if set(incompKeys)<=set(optKeys): + self.printERROR(_('Command line options "--host" (A record) \ +incompatible with options "--ip" (PTR record)')) + return False + # Удаляет лишние точки в названии + delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) + domainName = "" + ip = "" + typeRec = "" + if options.has_key('host'): + # Доменное имя (имя включающее домен) + typeRec = "a" + domainName = delDot(options['host'].lower()) + # Имя хоста, имя зоны + hostName, spl, zoneName = domainName.partition(".") + if not zoneName: + self.printERROR(_("Domain name %s incorrectly")%domainName) + return False + elif options.has_key('ip'): + # ip адрес + typeRec = "ptr" + ip = options['ip'] + if "/" in ip or "," in ip or not self.isCorrectStringNet(ip): + self.printERROR(_("IP address %s incorrectly")%ip) + return False + ret = False + if typeRec == "a": + foundDomain = self.searchDomainNameinLDAP(domainName) + foundDomainCName = self.searchCNameInLDAP(domainName) + if not foundDomainCName and not foundDomain: + self.printERROR(_("Record %s not exists in LDAP")%domainName) + return False + if foundDomain: + foundIP = foundDomain[0][0][1]['aRecord'][0] + elif foundDomainCName: + foundCName = foundDomainCName[0][0][1]['cNAMERecord'][0] + typeRec = "cname" + # Удаляем A запись или CNAME запись + ret = self.deleteDNSRecord(domainName) + elif typeRec == "ptr": + ipSpl = ip.split(".") + ipSpl.reverse() + # Имя домена обратной зоны + domainNamePTR = "%s.in-addr.arpa" %".".join(ipSpl) + foundDomain = self.searchDomainNameinLDAP(domainNamePTR) + if not foundDomain: + self.printERROR(_("PTR record %s not exists in LDAP")%domainName) + return False + foundDomainName = foundDomain[0][0][1]['pTRRecord'][0] + # Удаляем PTR запись + ret = self.deleteDNSRecord(domainNamePTR) + if not ret: + return False + if typeRec == "a": + # ip имещюиеся в обратной зоне для этого хоста + IPWithHosts = self.searchIPForHostInReverse(domainName) + self.printSUCCESS(_("Deleted A record in LDAP")) + self.printSUCCESS("%s --> %s"%(domainName,foundIP)) + self.printSUCCESS("") + if IPWithHosts: + self.printWARNING(_("DNS has the following PTR records")) + for ip in IPWithHosts: + self.printWARNING("%s --> %s"%(ip,domainName)) + self.printWARNING("") + elif typeRec == "ptr": + # Хосты имеющие этот IP в прямой зоне + hostsWithIP = self.searchHostsForIPinForward(ip) + self.printSUCCESS(_("Deleted PTR record in LDAP")) + self.printSUCCESS("%s --> %s"%(ip, delDot(foundDomainName))) + self.printSUCCESS("") + if hostsWithIP: + self.printWARNING(_("DNS has the following A records")) + for host in hostsWithIP: + self.printWARNING("%s --> %s"%(host,ip)) + self.printWARNING("") + elif typeRec == "cname": + self.printSUCCESS(_("Deleted CNAME record in LDAP")) + self.printSUCCESS("%s --> %s"%(domainName,foundCName)) + self.printSUCCESS("") + return True + + def isForwardName(self, name): + """Проверка может ли имя являтся именем в прямой зоне""" + forward = True + # Проверка на сеть + splName = name.split(".") + for octet in splName: + flagInt = True + try: + int(octet) + except: + flagInt = False + if flagInt: + forward = False + break + return forward + + def delZoneDnsServer(self, options): + """Удаляет зону из DNS""" + # Проверим установлен ли сервис dns + if not self.isServiceSetup("dns"): + return False + # Удаляет лишние точки в названии + delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) + # Имя зоны + zoneName = "" + if options.has_key('n'): + zoneName = delDot(options["n"].lower()) + if not zoneName: + self.printERROR(_('Incorrect zone name')) + self.printERROR(_('Error in command line options "-n"')) + return False + net = zoneName + # Проверка на прямую зону + forwardZone = self.isForwardName(zoneName) + # Обратная зона + if not forwardZone: + network, spl, netmask = net.rpartition("/") + if not netmask == "24" or \ + not self.isCorrectStringNet(net): + self.printERROR(_('Incorrect network %s for reverse zone')\ + %zoneName) + self.printWARNING(_("Example network for reverse zone") +\ + " :") + self.printWARNING(_('"-n 192.168.0.0/24"')) + return False + dataIP = self.getDomainAndZoneFromIP(network) + if not dataIP: + self.printERROR(_("IP address %s incorrectly")%network) + return False + hostName, domainName, zoneName = dataIP + if not zoneName: + self.printERROR(_("Not enough command line option %s")%"-n") + return False + return self.deleteZone(zoneName) + + def addZoneDnsServer(self, options): + """Добавляет зону в DNS""" + # Проверим установлен ли сервис dns + if not self.isServiceSetup("dns"): + return False + optKeys = options.keys() + minKeys = [] + zoneType = "" + # Флаг указывающий - мастер зона + flagZoneMaster = True + # Тип зоны + if "t" in optKeys: + # Тип зоны (master/slave) + zoneType = options["t"] + if zoneType == "master": + minKeys = ["t", "n", "server", "email", "servers"] + flagZoneMaster = True + elif zoneType == "slave": + minKeys = ["t", "n","servers"] + flagZoneMaster = False + else: + self.printERROR(_("Zone type %s unsupported")%zoneType) + self.printWARNING(_("Supported zone types: %s")\ + %", ".join(["master","slave"])) + return False + else: + self.printERROR(_("Not enough command line options: %s")\ + %", ".join("--type")) + return False + if not set(minKeys)<=set(optKeys): + notFoundKeys = list(set(minKeys)-set(optKeys)) + notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ + notFoundKeys) + self.printERROR(_("Not enough command line options: %s")\ + %", ".join(notFoundKeys)) + return False + # Удаляет лишние точки в названии + delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) + # Имя зоны + zoneName = "" + if options.has_key('n'): + forwardZone = True + zoneName = delDot(options["n"].lower()) + if not zoneName: + self.printERROR(_('Incorrect zone name')) + self.printERROR(_('Error in command line options "-n"')) + return False + net = zoneName + # Проверка на сеть + splNet = net.split(".") + for octet in splNet: + flagIntOctet = True + try: + int(octet) + except: + flagIntOctet = False + if flagIntOctet: + forwardZone = False + break + network, spl, netmask = net.rpartition("/") + if not netmask == "24" or \ + not self.isCorrectStringNet(net): + if not forwardZone: + self.printERROR(_('Incorrect network %s for reverse zone')\ + %zoneName) + self.printWARNING(_("Example network for reverse zone") +\ + " :") + self.printWARNING(_('"-n 192.168.0.0/24"')) + return False + # Обратная зона + if not forwardZone: + netSpl = network.split(".") + netSpl.pop() + netSpl.reverse() + # Имя обратной зоны + zoneName = "%s.in-addr.arpa" %".".join(netSpl) + + # Все авторитативные сервера зоны, в случае slаve зоны + # ip авторитативных серверов хранения зоны + namesServers = "" + if options.has_key('servers'): + namesServers = options['servers'].split(",") + # Проверка на ip + if not flagZoneMaster: + if not self.isCorrectStringNet(options['servers'], False): + self.printERROR(_('Incorrect autoritatives servers IP')) + self.printERROR(_('Error in command line options \ +"--servers"')) + self.printWARNING(_('Example:')) + self.printWARNING('--servers 192.168.0.1,192.168.0.2') + return False + else: + flagErrorNs = False + for ns in namesServers: + if self.isCorrectStringNet(ns, False): + flagErrorNs = True + break + if flagErrorNs: + self.printERROR(_('Incorrect autoritatives servers names')) + self.printERROR(_('Error in command line options \ +"--servers"')) + self.printWARNING(_('Example:')) + self.printWARNING('--servers ns.domain.ru,ns1.domain.ru') + return False + + # Мастер зона + if flagZoneMaster: + # Авторитативный сервер + nameServer = "" + if options.has_key('server'): + nameServer = delDot(options["server"].lower()) + if self.isCorrectStringNet(nameServer, False): + self.printERROR(_('Incorrect autoritative server')) + self.printERROR(_('Error in command line options \ +"--server"')) + self.printWARNING(_('Example:')) + self.printWARNING('--server ns.domain.com') + return False + if not nameServer: + self.printERROR(_('Incorrect autoritative server name')) + self.printERROR(_('Error in command line options \ +"--server"')) + return False + # Добавляем мастер сервер в имена авторитативаных серверов + if not nameServer in namesServers: + namesServers.insert(0, nameServer) + # Имя хоста, имя зоны + nsHostName, spl, nsZoneName = nameServer.partition(".") + # ip авторитативного сервера + ipserver = "" + if nsZoneName == zoneName or (self.searchZoneInLDAP(nsZoneName) and\ + not self.searchDomainNameinLDAP(nameServer)): + if not options.has_key('ipserver'): + self.printERROR(_('Not found A-record for "%s" \ +(master server DNS)')%nameServer) + self.printERROR(_('Not enough command line option \ +"--ipserver"')) + return False + else: + ipserver = options["ipserver"] + if "," in ipserver or \ + not self.isCorrectStringNet(ipserver, False): + self.printERROR(_("IP address %s incorrectly")%ipserver) + return False + else: + if options.has_key('ipserver'): + if self.searchZoneInLDAP(nsZoneName) and\ + self.searchDomainNameinLDAP(nameServer): + self.printERROR(_('Command line option "--ipserver" \ +is not needed, as the host name "%s" found in the DNS server')%nameServer) + else: + self.printERROR(_('Command line option "--ipserver" \ +is not needed, as the host name "%s" does not belong to the existing zones on \ +this DNS server')%nameServer) + return False + # Почтовый адрес администратора зоны + email = "" + if options.has_key('email'): + email = options['email'] + # интервал времени для обновления зоны + refresh = self.zoneRefresh + if options.has_key('refresh'): + refresh = options['refresh'] + # интервал времени после неудачного обновления зоны + update = self.zoneUpdateRetry + if options.has_key('update'): + update = options['update'] + # интервал времени устаревания данных зоны + expiry = self.zoneExpiry + if options.has_key('expiry'): + expiry = options['expiry'] + # интервал времени хранения данных неудачных запросов + minimum = self.zoneMinimum + if options.has_key('minimum'): + minimum = options['minimum'] + if not self.createMasterZone(zoneName, nameServer, email, + namesServers, "1", refresh, update, + expiry, minimum): + return False + # Добавление localhost.имя_зоны + if forwardZone: + optionsLocalhost = {"autoptr":"off","t":"a", + "host":"localhost.%s"%zoneName, + "ip":"127.0.0.1"} + if not self.addRecordDnsServer(optionsLocalhost): + return False + # Создание обратной зоны в случае необходимости + if ipserver: + network = ipserver + netSpl = network.split(".") + netSpl.pop() + netSpl.reverse() + # Имя обратной зоны + zoneNameReverse = "%s.in-addr.arpa" %".".join(netSpl) + if not self.searchZoneInLDAP(zoneNameReverse): + # Добавляем обратную зону + if not self.createMasterZone(zoneNameReverse, nameServer, + email,namesServers, "1", + refresh, update, expiry, + minimum): + return False + # Добавление A записи для первичного DNS сервера + optionsR = {"autoptr":"off","t":"a","host":nameServer, + "ip":ipserver} + if not self.addRecordDnsServer(optionsR): + return False + ipSpl = network.split(".") + ipSpl.reverse() + # Имя домена обратной зоны + domainNamePTR = "%s.in-addr.arpa" %".".join(ipSpl) + foundReverseDomain =self.searchDomainNameinLDAP(domainNamePTR) + if foundReverseDomain: + zoneName = foundReverseDomain[0][0][1]['zoneName'][0] + relativeDomainName = \ + foundReverseDomain[0][0][1]['relativeDomainName'][0] + pTRRecord = foundReverseDomain[0][0][1]['pTRRecord'][0] + # Удаляет лишние точки в названии + delDot = lambda y: ".".join(filter(lambda x: x,\ + y.split("."))) + reverseHost = delDot(pTRRecord) + listOctRev = \ + zoneName.rpartition(".in-addr.arpa")[0].split(".") + listOctRev.reverse() + reverseIp = ".".join(listOctRev) + self.printWARNING(_("Can not add PTR record in LDAP")) + self.printWARNING(_("PTR record exists")) + self.printWARNING("%s --> %s"%(reverseIp,reverseHost)) + self.printWARNING("") + else: + # Добавление PTR записи для первичного DNS сервера + optionsR = {"t":"ptr", "host":nameServer, "ip":ipserver} + if not self.addRecordDnsServer(optionsR): + return False + # Slave зона + else: + if not self.createSlaveZone(zoneName, namesServers): + return False + return True + + def modRecordDnsServer(self, options, hostOrIP): + """Модифицирует запись в DNS""" + # Проверим установлен ли сервис dns + if not self.isServiceSetup("dns"): + return False + # Удаляет лишние точки в названии + delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) + # модификация другой записи A -> PTR, PTR -> A + modOther = True + if options.has_key('automod'): + autoMod = options['automod'] + if autoMod == "on": + modOther = True + elif autoMod == "off": + modOther = False + else: + self.printERROR(_('Command line options "--automod %s" \ +incorrect, use "--automod on" or "--automod off"')%autoMod) + return False + # По умолчанию прямой тип записи + typeRec = "a" + if options.has_key('t'): + # Тип модифицируемой записи + typeRec = options['t'].lower() + supportTypes = ("a","ptr","cname") + if not typeRec in supportTypes: + self.printERROR(_("Record type %s unsupported")%typeRec) + self.printWARNING(_("Supported record types: %s")\ + %", ".join(supportTypes)) + return False + + mxServers = [] + if options.has_key('mxhosts'): + # Оключаем модификацию обратной зоны + modOther = False + # Почтовые серверы для доменного имени + if typeRec == "ptr": + self.printERROR(_('Command line options "--mxhosts" \ +incompatible with PTR record (options "-t")')) + return False + if typeRec == "cname": + self.printERROR(_('Command line options "--mxhosts" \ +incompatible with CNAME record (options "-t")')) + return False + mxServers=map(lambda x: delDot(x.lower()), + options['mxhosts'].split(",")) + # Переименование mx записи + # modMxServers[0] - cтарая запись + # modMxServers[1] - новая запись + modMxServers = [] + if options.has_key('mxhost'): + # Оключаем модификацию обратной зоны + modOther = False + # Почтовые серверы для доменного имени + if typeRec == "ptr": + self.printERROR(_('Command line options "--mxhost" \ +incompatible with PTR record (options "-t")')) + return False + if typeRec == "cname": + self.printERROR(_('Command line options "--mxhost" \ +incompatible with CNAME record (options "-t")')) + return False + modMxServers=map(lambda x: delDot(x.lower()),\ + options['mxhost'].split(",")) + if len(modMxServers)!=2: + self.printERROR(_('Incorrect command line options "--mxhost"')) + self.printWARNING(_("Example") + ":") + self.printWARNING("--mxhost old.mail.host,new.mail.host") + return False + cnameServer = "" + if options.has_key('cname'): + # Оключаем модификацию обратной зоны + modOther = False + # Доменное имя (имя включающее домен) + cnameServer = delDot(options['cname'].lower()) + # Имя хоста, имя зоны + tmpHostName, spl, tmpZoneName = cnameServer.partition(".") + if not tmpZoneName or not self.isForwardName(cnameServer): + self.printERROR(_("Domain name %s incorrectly")%cnameServer) + return False + # Флаг True - hostOrIP является хостом + hostInForwardZone = self.isForwardName(hostOrIP) + ip = "" + domainName = "" + hostName = "" + zoneName = "" + domainNamePTR = "" + hostNamePTR = "" + zoneNamePTR = "" + # hostOrIP является именем хоста + if hostInForwardZone: + domainName = delDot(hostOrIP.lower()) + # Имя хоста, имя зоны + hostName, spl, zoneName = domainName.partition(".") + if not zoneName: + self.printERROR(_("Domain name %s incorrectly")%domainName) + return False + # Поиск модифицируемой записи в DNS + # Поиск основной записи + if typeRec == "a": + # найдена CNAME запись? + foundCnameRecord = False + foundMain = self.searchDomainNameinLDAP(domainName) + if not foundMain: + foundMain = self.searchCNameInLDAP(domainName) + foundCnameRecord = True + if not foundMain: + self.printERROR(_("Record %s not exists in LDAP")\ + %domainName) + return False + # Поиcк в обратной зоне в случае необходимости + if modOther and not foundCnameRecord: + otherIP = delDot(foundMain[0][0][1]['aRecord'][0]) + dataIP = self.getDomainAndZoneFromIP(otherIP) + if not dataIP: + self.printERROR(_("IP address %s incorrectly")%otherIP) + return False + hostNameTmp, otherDomain, zoneNameTmp = dataIP + foundOther = self.searchAllDomainNamesinLDAP(otherDomain) + if not foundOther: + self.printERROR(_("PTR record %s not exists in LDAP")\ + %otherDomain) + return False + # Проверка на соответствие имени хоста + if domainName != foundOther[0][0][1]['pTRRecord'][0]: + modOther = False + elif typeRec == "ptr": + IPs = self.searchIPForHostInReverse(domainName) + if len(IPs)>1: + self.printERROR(_("Found multiple records in reverse zone")) + for IP in IPs: + self.printERROR("%s --> %s"%(IP,domainName)) + self.printERROR("") + return False + ip = IPs[0] + dataIP = self.getDomainAndZoneFromIP(ip) + if not dataIP: + self.printERROR(_("IP address %s incorrectly")%ip) + return False + hostNamePTR, domainNamePTR, zoneNamePTR = dataIP + foundMain = self.searchAllDomainNamesinLDAP(domainNamePTR) + if not foundMain: + self.printERROR(_("PTR record %s not exists in LDAP")\ + %domainNamePTR) + return False + # Поиcк в обратной зоне в случае необходимости + if modOther: + otherDomain = delDot(foundMain[0][0][1]['pTRRecord'][0]) + foundOther = self.searchAllDomainNamesinLDAP(otherDomain) + if not foundOther: + self.printERROR(_("A record %s not exists in LDAP")\ + %otherDomain) + return False + # Проверка на соответствие ip хоста + if ip != foundOther[0][0][1]['aRecord'][0]: + modOther = False + # hostOrIP является ip + else: + if "," in hostOrIP or not self.isCorrectStringNet(hostOrIP, False): + self.printERROR(_("IP address %s incorrectly")%hostOrIP) + return False + ip = hostOrIP + if typeRec == "cname": + self.printERROR(_('IP address %s')%ip + " " +\ + _('incompatible with CNAME record (options "-t")')) + return False + # Поиск модифицируемой записи в DNS + # Поиск основной записи + if typeRec == "ptr": + dataIP = self.getDomainAndZoneFromIP(ip) + if not dataIP: + self.printERROR(_("IP address %s incorrectly")%ip) + return False + hostNamePTR, domainNamePTR, zoneNamePTR = dataIP + foundMain = self.searchAllDomainNamesinLDAP(domainNamePTR) + if not foundMain: + self.printERROR(_("PTR record %s not exists in LDAP")\ + %domainNamePTR) + return False + # Поиcк в обратной зоне в случае необходимости + if modOther: + otherDomain = delDot(foundMain[0][0][1]['pTRRecord'][0]) + foundOther = self.searchAllDomainNamesinLDAP(otherDomain) + if not foundOther: + self.printERROR(_("A record %s not exists in LDAP")\ + %otherDomain) + return False + # Проверка на соответствие ip хоста + if ip != foundOther[0][0][1]['aRecord'][0]: + modOther = False + elif typeRec == "a": + domainNames = self.searchHostsForIPinForward(ip) + if len(domainNames)>1: + self.printERROR(_("Found multiple records in forward zone")) + for host in domainNames: + self.printERROR("%s --> %s"%(host,ip)) + self.printERROR("") + return False + domainName = domainNames[0] + hostName, spl, zoneName = domainName.partition(".") + # найдена CNAME запись? + foundCnameRecord = False + foundMain = self.searchDomainNameinLDAP(domainName) + if not foundMain: + foundMain = self.searchCNameInLDAP(domainName) + foundCnameRecord = True + if not foundMain: + self.printERROR(_("Record %s not exists in LDAP")\ + %domainName) + return False + # Поиcк в обратной зоне в случае необходимости + if modOther and not foundCnameRecord: + otherIP = delDot(foundMain[0][0][1]['aRecord'][0]) + dataIP = self.getDomainAndZoneFromIP(otherIP) + if not dataIP: + self.printERROR(_("IP address %s incorrectly")%otherIP) + return False + hostNameTmp, otherDomain, zoneNameTmp = dataIP + foundOther = self.searchAllDomainNamesinLDAP(otherDomain) + if not foundOther: + self.printERROR(_("PTR record %s not exists in LDAP")\ + %otherDomain) + return False + # Проверка на соответствие имени хоста + if domainName != foundOther[0][0][1]['pTRRecord'][0]: + modOther = False + + + + + newDomainName = "" + newHostName = "" + newZoneName = "" + if options.has_key('host'): + # Доменное имя (имя включающее домен) + newDomainName = delDot(options['host'].lower()) + # Имя хоста, имя зоны + newHostName, spl, newZoneName = newDomainName.partition(".") + if not newZoneName or not self.isForwardName(newDomainName): + self.printERROR(_("Domain name %s incorrectly")%newDomainName) + return False + newIP = "" + if options.has_key('ip'): + # newIP адрес + newIP = options['ip'] + if "," in newIP or not self.isCorrectStringNet(newIP, False): + self.printERROR(_("IP address %s incorrectly")%newIP) + return False + self.printSUCCESS("OK") + return True + + + + def getDomainAndZoneFromIP(self, ip): + """Получение имени хоста, домена, зоны из ip""" + ipSpl = ip.split(".") + ipSpl.reverse() + # Имя обратного домена + domainName = "%s.in-addr.arpa" %".".join(ipSpl) + hostName, spl, zoneName = domainName.partition(".") + if zoneName: + return (hostName, domainName, zoneName) + else: + return False + + def moveDNSReverseRecord(self, oldIP, newIP): + """Переносит запись c oldIP в запись с newIP (в обратной зоне)""" + dataOldIP = self.getDomainAndZoneFromIP(oldIP) + if not dataOldIP: + self.printERROR(_("IP address %s incorrectly")%oldIP) + return False + oldHostName, oldDomainName, oldZoneName = dataOldIP + dataNewIP = self.getDomainAndZoneFromIP(newIP) + if not dataNewIP: + self.printERROR(_("IP address %s incorrectly")%newIP) + return False + newHostName, newDomainName, newZoneName = dataNewIP + return self.moveDNSForwardRecord(oldDomainName, newDomainName) + + def moveDNSForwardRecord(self, oldDomainName, newDomainName): + """Переносит запись oldDomainName в newDomainName (в прямой зоне)""" + # Имя нового хоста, имя новой зоны + newHostName, spl, newZoneName = newDomainName.partition(".") + # Ищем новую зону + if not self.searchZoneInLDAP(newZoneName): + self.printERROR(_("Can not found DNS zone %s in LDAP")%newZoneName) + return False + # Ищем старый хост + foundOld = self.searchAllDomainNamesinLDAP(oldDomainName) + if not foundOld: + self.printERROR(_("Record %s not exists in LDAP")%oldDomainName) + return False + # Данные + data = foundOld[0][0][1] + data["zoneName"] = [newZoneName] + data["relativeDomainName"] = [newHostName] + domainEntry = data.items() + # Добавляем новую запись + baseDN = self.clVars.Get("ld_dns_dn") + ouZonesDN = self.getOUZonesDN(newZoneName) + zoneBaseDN = "zoneName=%s,%s,%s"%(newZoneName, ouZonesDN, baseDN) + domainDN = self.addDN("relativeDomainName=%s" %newHostName,zoneBaseDN) + # Сообщение в случае ошибки + errorMessage = _('Can not add record "%s" in LDAP'%newDomainName) + # Добавляем запись + if not self.addEntry(domainDN, domainEntry, errorMessage): + return False + # Удаляем предыдущую запись + if not self.deleteDNSRecord(oldDomainName): + return False + # Имя cтарого хоста, имя старой зоны + oldHostName, spl, oldZoneName = oldDomainName.partition(".") + namesZones = [oldZoneName, newZoneName] + if namesZones[0] == namesZones[1]: + namesZones.pop() + flagError = False + for nameZone in namesZones: + # Увеличиваем на 1 серийный номер зоны + if not self.incrementSerialNumberZone(nameZone): + flagError = True + break + if flagError: + return False + return True + + def addRecordDnsServer(self, options): + """Добавляет запись в DNS""" + # Проверим установлен ли сервис dns + if not self.isServiceSetup("dns"): + return False + optKeys = options.keys() + # По умолчанию прямой тип записи + typeRec = "a" + if options.has_key('t'): + # Тип добавлямой записи + typeRec = options['t'].lower() + supportTypes = ("a","ptr","cname") + if not typeRec in supportTypes: + self.printERROR(_("Record type %s unsupported")%typeRec) + self.printWARNING(_("Supported record types: %s")\ + %", ".join(supportTypes)) + return False + if typeRec == "cname": + minKeys = ["cnhost","host"] + else: + minKeys = ["host","ip"] + if not set(minKeys)<=set(optKeys): + notFoundKeys = list(set(minKeys)-set(optKeys)) + notFoundKeys = map(lambda x: len(x)>1 and '"--%s"'%x or '"-%s"'%x,\ + notFoundKeys) + self.printERROR(_("Not enough command line options: %s")\ + %", ".join(notFoundKeys)) + return False + # Флаг автоматического создания PTR записи + createPtr = True + if options.has_key('autoptr'): + if typeRec == "ptr": + self.printERROR(_('Command line options "--autoptr" \ +incompatible with type DNS record PTR (options "-t")')) + return False + if typeRec == "cname": + self.printERROR(_('Command line options "--autoptr" \ +incompatible with type DNS record CNAME (options "-t")')) + return False + autoPtr = options['autoptr'] + if autoPtr == "on": + createPtr = True + elif autoPtr == "off": + createPtr = False + else: + self.printERROR(_('Command line options "--autoptr %s" \ +incorrect, use "--autoptr on" or "--autoptr off"')%autoPtr) + return False + # Удаляет лишние точки в названии + delDot = lambda y: ".".join(filter(lambda x: x, y.split("."))) + domainName = "" + hostName = "" + zoneName = "" + if options.has_key('host'): + # Доменное имя (имя включающее домен) + domainName = delDot(options['host'].lower()) + # Имя хоста, имя зоны + hostName, spl, zoneName = domainName.partition(".") + if not zoneName: + self.printERROR(_("Domain name %s incorrectly")%domainName) + return False + cnDomainName = "" + cnHostName = "" + cnZoneName = "" + if options.has_key('cnhost'): + if options.has_key('ip'): + self.printERROR(_('Command line options "--ip" incompatible \ +with type DNS record CNAME (options "-t")')) + return False + if options.has_key('mx'): + self.printERROR(_('Command line options "--mx" incompatible \ +with type DNS record CNAME (options "-t")')) + return False + # Доменное каноническое имя (имя включающее домен) для CNAME + cnDomainName = delDot(options['cnhost'].lower()) + # Имя хоста, имя зоны + cnHostName, spl, cnZoneName = cnDomainName.partition(".") + if not cnZoneName: + self.printERROR(_("Domain name %s incorrectly")%cnDomainName) + return False + ip = "" + if options.has_key('ip'): + # ip адрес + ip = options['ip'] + if "," in ip or not self.isCorrectStringNet(ip, False): + self.printERROR(_("IP address %s incorrectly")%ip) + return False + mxServers = [] + if options.has_key('mx'): + # Почтовые серверы для доменного имени + if typeRec == "ptr": + self.printERROR(_('Command line options "--mx" incompatible \ +with type DNS record PTR (options "-t")')) + return False + mxServers = map(lambda x: delDot(x.lower()),\ + options['mx'].split(",")) + ret = False + # Флаг создания A записи + flagCreateARecord = False + # Прямая запись DNS + if typeRec == "a": + ret = self.addDNSRecord(domainName, ip, mxServers) + flagCreateARecord = ret + if ret and createPtr: + typeRec = "ptr" + if typeRec == "ptr": + ipSpl = ip.split(".") + ipSpl.reverse() + # Имя домена обратной зоны + domainNamePTR = "%s.in-addr.arpa" %".".join(ipSpl) + ret = self.addDNSRecord(domainNamePTR, domainName) + if typeRec == "cname": + ret = self.addCNameDNSRecord(domainName, cnDomainName) + if not ret: + if flagCreateARecord: + # Удаляем A запись + self.deleteDNSRecord(domainName) + return False + if typeRec == "a" or flagCreateARecord: + self.printSUCCESS(_("Added A record in LDAP")) + self.printSUCCESS("%s --> %s"%(domainName,ip)) + self.printSUCCESS("") + if mxServers: + self.printSUCCESS(_("Added MX records in LDAP")) + for mailServer in mxServers: + self.printSUCCESS("%s --> %s"%(domainName, mailServer)) + if typeRec == "ptr": + self.printSUCCESS(_("Added PTR record in LDAP")) + self.printSUCCESS("%s --> %s"%(ip,domainName)) + self.printSUCCESS("") + if typeRec == "cname": + self.printSUCCESS(_("Added CNAME record in LDAP")) + self.printSUCCESS("%s --> %s"%(domainName,cnDomainName)) + self.printSUCCESS("") + return True + + + def addCNameDNSRecord(self, domainName, cnDomainName): + """Добавляем CNAME DNS запись в LDAP + domainName -> cnDomainName + """ + hostName, spl, zoneName = domainName.partition(".") + cnHostName, spl, cnZoneName = cnDomainName.partition(".") + # Поиск зоны + if self.searchZoneInLDAP(cnZoneName): + # Поиск имени хоста + if not self.searchDomainNameinLDAP(cnDomainName): + self.printERROR(_("Can not found A record %s in LDAP")\ + %cnDomainName) + return False + # Поиск зоны + if not self.searchZoneInLDAP(zoneName): + self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) + return False + # Поиск CNAME записи + findCName = self.searchCNameInLDAP(domainName) + if findCName: + self.printERROR(_("CNAME record %s exists in LDAP")\ + %domainName) + cnameHosts = findCName[0][0][1]['cNAMERecord'] + for cnameHost in cnameHosts: + self.printERROR("%s --> %s"%(domainName,cnameHost)) + self.printERROR("") + return False + # Метод добавляющий в конце текста точку если ее нет + addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x + domainEntry = [('objectclass', ['top','dNSZone']), + ('relativeDomainName', [hostName]), + ('dNSClass', ['IN']), + ('zoneName',[zoneName]), + ('cNAMERecord',[addDot(cnDomainName)])] + baseDN = self.clVars.Get("ld_dns_dn") + ouZonesDN = self.getOUZonesDN(zoneName) + zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, ouZonesDN, baseDN) + domainDN = self.addDN("relativeDomainName=%s"%hostName,zoneBaseDN) + errorMessage = _("Can not add CNAME record in LDAP") + # Добавляем запись для хоста + if not self.addEntry(domainDN, domainEntry,errorMessage): + return False + # Увеличиваем на 1 серийный номер зоны + if not self.incrementSerialNumberZone(zoneName): + return False + return True + + + def addDNSRecord(self, domainName, ipAddrOrHost, namesMailServers=[]): + """Добавляем DNS запись в LDAP прямую или обратную""" + hostName, spl, zoneName = domainName.partition(".") + # При поиске зоны создается объект переменных и соединение LDAP + if not self.searchZoneInLDAP(zoneName): + self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) + return False + if self.searchDomainNameinLDAP(domainName): + self.printERROR(_("Record %s exists in LDAP")\ + %domainName) + return False + # Поиск CNAME записи + if self.searchCNameInLDAP(domainName): + self.printERROR(_("CNAME record %s exists in LDAP")\ + %domainName) + return False + flagForward = self.isForwardZone(zoneName) + # Метод добавляющий в конце текста точку если ее нет + addDot = lambda x: (len(x)>0 and x[-1]!="." and "%s."%x) or x + if flagForward: + # MX записи для которых нужны A записи + mailServersInZones = filter(lambda x:\ + self.searchZoneInLDAP(x.partition(".")[2]),\ + namesMailServers) + notFoundMailServers = filter(lambda x:\ + not self.searchDomainNameinLDAP(x),\ + mailServersInZones) + if notFoundMailServers: + self.printERROR(\ + _("Can not found A records for MX records - %s")\ + %", ".join(notFoundMailServers)) + self.printWARNING(\ + _("First, add the A records required for MX records")) + return False + namesMailServersDot = map(lambda x: addDot(x), namesMailServers) + domainEntry = [('objectclass', ['top','dNSZone']), + ('relativeDomainName', [hostName]), + ('dNSClass', ['IN']), + ('zoneName',[zoneName]), + ('aRecord',[ipAddrOrHost])] + mxValues =map(lambda x: "%s %s" %(x*10+10, namesMailServersDot[x]),\ + range(len(namesMailServersDot))) + if mxValues: + # Добавляем MX записи + domainEntry.append(('mXRecord', mxValues)) + else: + domainEntry = [('objectclass', ['top','dNSZone']), + ('relativeDomainName', [hostName]), + ('zoneName',[zoneName]), + ('pTRRecord',[addDot(ipAddrOrHost)])] + baseDN = self.clVars.Get("ld_dns_dn") + ouZonesDN = self.getOUZonesDN(zoneName) + zoneBaseDN = "zoneName=%s,%s,%s" %(zoneName, ouZonesDN, baseDN) + domainDN = self.addDN("relativeDomainName=%s"%hostName,zoneBaseDN) + if flagForward: + errorMessage = _("Can not add A record in LDAP") + else: + errorMessage = _("Can not add RTR record in LDAP") + # Добавляем запись для хоста + if not self.addEntry(domainDN, domainEntry,errorMessage): + return False + # Увеличиваем на 1 серийный номер зоны + if not self.incrementSerialNumberZone(zoneName): + return False + return True + + def deleteDNSRecord(self, domainName): + """Удаляем DNS запись из LDAP""" + hostName, spl, zoneName = domainName.partition(".") + if not self.searchZoneInLDAP(zoneName): + self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) + return False + if not self.searchAllDomainNamesinLDAP(domainName): + self.printERROR(_("Record %s not exists in LDAP")%domainName) + return False + relZoneDN = self.getRelZoneDN(zoneName) + relDelDN = self.addDN("relativeDomainName=%s"%hostName,relZoneDN) + # Удаление DNS записи + ret = self.delDN(relDelDN) + if not ret: + return False + # Увеличиваем на 1 серийный номер зоны + if not self.incrementSerialNumberZone(zoneName): + return False + return True + + def incrementSerialNumberZone(self, zoneName): + """Увеличение на единицу серийного номера зоны""" + if not self.searchZoneInLDAP(zoneName): + self.printERROR(_("Can not found DNS zone %s in LDAP")%zoneName) + return False + foundNames = self.searchDomainNameinLDAP("@.%s"%zoneName) + if not foundNames: + self.printERROR(_("Can not found SOA Record in DNS zone %s")\ + %zoneName) + return False + sOARecord = foundNames[0][0][1]['sOARecord'][0] + sOAList = sOARecord.split(" ") + if len(sOAList)!=7: + self.printERROR(_("Incorrect SOA Record in DNS zone %s")%zoneName) + return False + try: + serialNumer = str(ctypes.c_uint32(int(sOAList[2])).value + 1) + except: + self.printERROR(_("Incorrect SOA Record in DNS zone %s")%zoneName) + self.printERROR(_("Incorrect serial number %s in SOA Record")\ + %str(sOAList[2])) + return False + sOAList[2] = serialNumer + sOARecord = " ".join(sOAList) + relZoneDN = self.getRelZoneDN(zoneName) + modAttrs = [(ldap.MOD_REPLACE, 'sOARecord', sOARecord)] + DN = self.addDN("relativeDomainName=@", relZoneDN) + if not self.modAttrsDN(DN, modAttrs): + self.printERROR(_("Can not write new serial number for zone %s\ +in LDAP")%zoneName) + return False + return True def getAllowNet(self): """Получаем от пользователя доверительные сети @@ -13812,6 +15620,26 @@ class servDNS(shareLdap): # файлов профилей if not self.applyProfilesFromService('dns'): return False + # Удаляем ненужные текстовые зоны + objTxtZone = dnsZoneTxt() + delZonesNames = objTxtZone.getAllNamesZones() + relList = map(lambda x: objTxtZone.deleteZone(x), delZonesNames) + flagDelError = False + i = 0 + for ret in relList: + if not ret: + flagDelError = True + break + i += 1 + if flagDelError: + self.printERROR(\ + _('Can not delete DNS zone "%s"')%delZonesNames[i] + " " +\ + _("in file %s")%objTxtZone.nameConfigFile) + return False + map(lambda x :\ + self.printOK(_('Deleted DNS zone "%s"')%x + " " +\ + _("in file %s")%objTxtZone.nameConfigFile)\ + ,delZonesNames) # Проверим запущен ли ldap if not self.getRunService("ldap"): # Запускаем LDAP сервер @@ -13880,9 +15708,10 @@ class tsOpt(cl_base.opt): сервисом. (например "group" или "user") optService проверять хвост командной строки на наличие сервиса notOptError выдавать ошибку при отсутствии опций командной строки + lastOpt одно произвольное значение в хвосте командной строки """ - def __init__(self, helpObj, parBeforeService,optService=True, - notOptError=False): + def __init__(self, helpObj, parBeforeService, optService=True, + notOptError=False, lastOpt=False): # последний параметр является сервисом service = sys.argv[-1:][0].rstrip() # от cl_help получаем короткие и длинные опции @@ -13916,16 +15745,22 @@ class tsOpt(cl_base.opt): self.flagHelp = True #Если нет хвостов elif not self.params: - if optService: + if optService or lastOpt: print helpObj.getHelp(helpObj.relOptions['h']) self.flagHelp = True else: if self.params.has_key('service'): - if not (self.params['service'] in helpObj.allServ) or\ - len(self.nameParams) != self.__iter: + if lastOpt: + pass + elif not (self.params['service'] in helpObj.allServ): self.handlerErrOpt() + self.flagHelp = True + if len(self.nameParams) != self.__iter: + self.handlerErrOpt() + self.flagHelp = True else: self.handlerErrOpt() + self.flagHelp = True # В случае отсутствия опций командной строки if notOptError and not self.opt and self.params.has_key('service'): self.printErrorNotOpt() diff --git a/scripts/cl-dnsrecadd b/scripts/cl-dnsrecadd index 25af874..b9496c8 100644 --- a/scripts/cl-dnsrecadd +++ b/scripts/cl-dnsrecadd @@ -26,13 +26,19 @@ tr.setLanguage(sys.modules[__name__]) import cl_ldap if __name__ == "__main__": - ldapObj = cl_ldap.cl_ldap("cl-dns") + ldapObj = cl_ldap.cl_ldap("cl-dnsrecadd") optObj = cl_ldap.tsOpt(ldapObj,[],False) flagError = False + # Вывод помощи если нет параметров командной строки + if not optObj.opt: + print ldapObj.getHelp(ldapObj.relOptions['h']) + optObj.flagHelp = True if not optObj.flagHelp: + # Добавление записи в DNS + flagError = True obj = cl_ldap.servDNS() - #if obj.addUserReplServer(optObj.opt, logObj): - #flagError = False + if obj.addRecordDnsServer(optObj.opt): + flagError = False if flagError: sys.exit(1) else: diff --git a/scripts/cl-dnsrecdel b/scripts/cl-dnsrecdel index 25af874..eff2b43 100644 --- a/scripts/cl-dnsrecdel +++ b/scripts/cl-dnsrecdel @@ -26,13 +26,19 @@ tr.setLanguage(sys.modules[__name__]) import cl_ldap if __name__ == "__main__": - ldapObj = cl_ldap.cl_ldap("cl-dns") + ldapObj = cl_ldap.cl_ldap("cl-dnsrecdel") optObj = cl_ldap.tsOpt(ldapObj,[],False) flagError = False + # Вывод помощи если нет параметров командной строки + if not optObj.opt: + print ldapObj.getHelp(ldapObj.relOptions['h']) + optObj.flagHelp = True if not optObj.flagHelp: + # Добавление записи в DNS + flagError = True obj = cl_ldap.servDNS() - #if obj.addUserReplServer(optObj.opt, logObj): - #flagError = False + if obj.delRecordDnsServer(optObj.opt): + flagError = False if flagError: sys.exit(1) else: diff --git a/scripts/cl-dnsrecmod b/scripts/cl-dnsrecmod index 25af874..c414a99 100644 --- a/scripts/cl-dnsrecmod +++ b/scripts/cl-dnsrecmod @@ -26,13 +26,20 @@ tr.setLanguage(sys.modules[__name__]) import cl_ldap if __name__ == "__main__": - ldapObj = cl_ldap.cl_ldap("cl-dns") - optObj = cl_ldap.tsOpt(ldapObj,[],False) + ldapObj = cl_ldap.cl_ldap("cl-dnsrecmod") + optObj = cl_ldap.tsOpt(ldapObj,[],False,False,True) flagError = False + # Вывод помощи если нет параметров командной строки + if not optObj.opt and optObj.params.has_key('service'): + print ldapObj.getHelp(ldapObj.relOptions['h']) + optObj.flagHelp = True if not optObj.flagHelp: + # Добавление записи в DNS + flagError = True obj = cl_ldap.servDNS() - #if obj.addUserReplServer(optObj.opt, logObj): - #flagError = False + hostnameOrIP = optObj.params['service'] + if obj.modRecordDnsServer(optObj.opt, hostnameOrIP): + flagError = False if flagError: sys.exit(1) else: diff --git a/scripts/cl-dnszoneadd b/scripts/cl-dnszoneadd index 25af874..291add6 100644 --- a/scripts/cl-dnszoneadd +++ b/scripts/cl-dnszoneadd @@ -26,13 +26,19 @@ tr.setLanguage(sys.modules[__name__]) import cl_ldap if __name__ == "__main__": - ldapObj = cl_ldap.cl_ldap("cl-dns") + ldapObj = cl_ldap.cl_ldap("cl-dnszoneadd") optObj = cl_ldap.tsOpt(ldapObj,[],False) flagError = False + # Вывод помощи если нет параметров командной строки + if not optObj.opt: + print ldapObj.getHelp(ldapObj.relOptions['h']) + optObj.flagHelp = True if not optObj.flagHelp: + # Добавление записи в DNS + flagError = True obj = cl_ldap.servDNS() - #if obj.addUserReplServer(optObj.opt, logObj): - #flagError = False + if obj.addZoneDnsServer(optObj.opt): + flagError = False if flagError: sys.exit(1) else: diff --git a/scripts/cl-dnszonedel b/scripts/cl-dnszonedel index 25af874..4f190f9 100644 --- a/scripts/cl-dnszonedel +++ b/scripts/cl-dnszonedel @@ -26,13 +26,19 @@ tr.setLanguage(sys.modules[__name__]) import cl_ldap if __name__ == "__main__": - ldapObj = cl_ldap.cl_ldap("cl-dns") + ldapObj = cl_ldap.cl_ldap("cl-dnszonedel") optObj = cl_ldap.tsOpt(ldapObj,[],False) flagError = False + # Вывод помощи если нет параметров командной строки + if not optObj.opt: + print ldapObj.getHelp(ldapObj.relOptions['h']) + optObj.flagHelp = True if not optObj.flagHelp: + # Добавление записи в DNS + flagError = True obj = cl_ldap.servDNS() - #if obj.addUserReplServer(optObj.opt, logObj): - #flagError = False + if obj.delZoneDnsServer(optObj.opt): + flagError = False if flagError: sys.exit(1) else: diff --git a/scripts/cl-dnszonemod b/scripts/cl-dnszonemod index 25af874..7b4da48 100644 --- a/scripts/cl-dnszonemod +++ b/scripts/cl-dnszonemod @@ -26,7 +26,7 @@ tr.setLanguage(sys.modules[__name__]) import cl_ldap if __name__ == "__main__": - ldapObj = cl_ldap.cl_ldap("cl-dns") + ldapObj = cl_ldap.cl_ldap("cl-dnszonemod") optObj = cl_ldap.tsOpt(ldapObj,[],False) flagError = False if not optObj.flagHelp: