コード例 #1
0
ファイル: Collector.py プロジェクト: nerzhul/Z-Eye
	def connectAndCollectConfig(self,deviceName,deviceIP,sshUser,sshPwd,privilegedPwd):
		self.incrThreadNb()

		try:
			sshPwdClear = base64.b64decode(sshPwd)
			privilegedPwdClear = base64.b64decode(privilegedPwd)
			
			ssh = ZEyeSSHBroker(deviceIP,sshUser,sshPwdClear)
			if ssh.connect() == False:
				self.decrThreadNb()
				return
				
			if ssh.setupPrivileges(privilegedPwdClear) == False:
				self.decrThreadNb()
				return
			
			startupCfg = ""
			runningCfg = ""	
			#startupCfg = ssh.sendPrivilegedCmd("show startup-config")
			#runningCfg = ssh.sendPrivilegedCmd("show running-config")
			
			pgsqlCon = PgSQL.connect(host=zConfig.pgHost,user=zConfig.pgUser,password=zConfig.pgPwd,database=zConfig.pgDB)
			pgcursor = pgsqlCon.cursor()
			
			pgcursor.execute("DELETE FROM z_eye_switch_configs WHERE device = '%s'" % deviceName)
			
			if len(startupCfg) > 0:
				pgcursor.execute("INSERT INTO z_eye_switch_configs (device,cfgtype,cfgoutput) VALUES ('%s','1','%s')" % (deviceName,startupCfg))
				
			if len(runningCfg) > 0:
				pgcursor.execute("INSERT INTO z_eye_switch_configs (device,cfgtype,cfgoutput) VALUES ('%s','2','%s')" % (deviceName,runningCfg))
				
			pgsqlCon.commit()
			pgcursor.close()
			pgsqlCon.close()
			
			ssh.disablePrivileges()
		except Exception, e:
			self.logCritical("connectAndCollectConfig: FATAL %s" % e)
コード例 #2
0
ファイル: zDHCP.py プロジェクト: nerzhul/Z-Eye
	def doConfigDHCP(self,addr,user,pwd,reservpath,subnetpath):
		self.incrThreadNb()

		subnetBuf = ""
		reservBuf = ""
		try:
			# One pgsql connection per thread
			pgsqlCon = PgSQL.connect(host=zConfig.pgHost,user=zConfig.pgUser,password=zConfig.pgPwd,database=zConfig.pgDB)
			pgcursor = pgsqlCon.cursor()
			pgcursor.execute("SELECT clustername FROM z_eye_dhcp_cluster WHERE dhcpaddr = '%s'" % addr)
			pgres = pgcursor.fetchall()

			# No cluster, then no action to do
			if pgcursor.rowcount == 0:
				self.decrThreadNb()
				return

			ssh = ZEyeSSHBroker(addr,user,pwd)
			if ssh.connect() == False:
				self.decrThreadNb()
				return

			# We get the remote OS for some commands
			remoteOs = ssh.getRemoteOS()
			if remoteOs != "Linux" and remoteOs != "FreeBSD" and remoteOs != "OpenBSD":
				self.logError("%s OS (on %s) is not supported" % (remoteOs,addr))
				self.decrThreadNb()
				return

			hashCmd = ""
			if remoteOs == "Linux":
				hashCmd = "md5sum"
			elif remoteOs == "FreeBSD" or remoteOs == "OpenBSD":
				hashCmd = "md5 -q"
		
			# We test file existence. If they doesn't exist, we create it. If creation failed, the DHCP manager cannot use this server
			if ssh.isRemoteExists(reservpath) == False:
				ssh.sendCmd("touch %s" % reservpath)

			if ssh.isRemoteWritable(reservpath) == False:
				self.logError("%s (on %s) is not writable" % (reservpath,addr))
				self.decrThreadNb()
				return
		
			if ssh.isRemoteExists(subnetpath) == False:
				ssh.sendCmd("touch %s" % subnetpath)

			if ssh.isRemoteWritable(subnetpath) == False:
				self.logError("%s (on %s) is not writable" % (subnetpath,addr))
				self.decrThreadNb()
				return
		
			if ssh.isRemoteExists("/tmp/dhcprestart") == False:
				ssh.sendCmd("touch %s" % "/tmp/dhcprestart")

			if ssh.isRemoteWritable("/tmp/dhcprestart") == False:
				self.logError("%s (on %s) is not writable" % ("/tmp/dhcprestart",addr))
				self.decrThreadNb()
				return
			
			"""
			This variable enable failover part
			With ISC DHCP failover can be declared only if used
			"""
			showFailover = False
			for idx in pgres:
				if idx[0] in self.clusterList:
					# custom options
					for cOpt in self.customOptsList:
						# Only real custom options are declared
						if self.customOptsList[cOpt][2] == False:
							codeType = ""
							if self.customOptsList[cOpt][1] == "uint8":
								codeType = "unsigned integer 8"
							elif self.customOptsList[cOpt][1] == "uint16":
								codeType = "unsigned integer 16"
							elif self.customOptsList[cOpt][1] == "uint32":
								codeType = "unsigned integer 32"
							elif self.customOptsList[cOpt][1] == "int8":
								codeType = "integer 8"
							elif self.customOptsList[cOpt][1] == "int16":
								codeType = "integer 16"
							elif self.customOptsList[cOpt][1] == "uint32":
								codeType = "integer 32"
							elif self.customOptsList[cOpt][1] == "ip":
								codeType = "ip-address"
							else:
								codeType = self.customOptsList[cOpt][1]
							subnetBuf += "option %s code %s = %s;\n" % (cOpt,self.customOptsList[cOpt][0],codeType)

					if len(subnetBuf) > 0:
						subnetBuf += "\n"

					# Cluster options 
					failoverPeerBuf = ""
					failoverPeerName = ""
					if idx[0] in self.clusterOptions:
						# ISC dhcp clusters
						if self.clusterOptions[idx[0]][0] == 1 or self.clusterOptions[idx[0]][0] == 2:
							peerAddr = ""
							"""
							cluster members has always 2 members on this configuration then,
							peer is the other record
							"""
							for peer in self.clusterMembers[idx[0]]:
								if peer != addr:
									if self.clusterMembers[idx[0]][peer]["clusteraddr"] != None:
										peerAddr = self.clusterMembers[idx[0]][peer]["clusteraddr"]
							
							localAddr = addr
							# If there is a valid clusterAddr, replace localAddr
							if addr in self.clusterMembers[idx[0]] and self.clusterMembers[idx[0]][addr]["clusteraddr"] != None:
								localAddr = self.clusterMembers[idx[0]][addr]["clusteraddr"]

							failoverPeerBuf += "failover peer \"cluster-%s\" {" % idx[0].replace(' ','-')
							failoverPeerName = "cluster-%s" % idx[0].replace(' ','-')
							# This is for cluster master
							if addr == self.clusterOptions[idx[0]][1]:
								failoverPeerBuf += "\n\tprimary;"
							# This is for cluster slave
							else:
								failoverPeerBuf += "\n\tsecondary;"

							failoverPeerBuf += "\n\taddress %s;\n\tport 647;\n\tpeer address %s;\n\tpeer port 647;" % (localAddr,peerAddr)
							failoverPeerBuf += "\n\tmax-response-delay 3;\n\tmax-unacked-updates 2;\n\tload balance max seconds 10;"
							# This is for cluster master
							if (self.clusterOptions[idx[0]][0] == 1 or self.clusterOptions[idx[0]][0] == 2) and self.clusterOptions[idx[0]][1] == addr:
								if self.clusterOptions[idx[0]][0] == 2:
									failoverPeerBuf += "\n\tmclt 1800;\n\tsplit 127;"
								else:
									failoverPeerBuf += "\n\tmclt 1800;\n\tsplit 255;"

							failoverPeerBuf += "\n}\n\n"

					for subnet in self.clusterList[idx[0]]:
						netmask = self.subnetList[subnet][0]
						subnetIpList = self.subnetList[subnet][1]

						# Special case for DNS2
						dns2 = ""
						if len(self.subnetList[subnet][4]) > 0 and self.subnetList[subnet][4] != self.subnetList[subnet][3]:
							dns2 = ",%s" % self.subnetList[subnet][4]

						subnetBuf += "subnet %s netmask %s {\n\toption routers %s;\n\toption domain-name \"%s\";\n" % (subnet,netmask,self.subnetList[subnet][2],self.subnetList[subnet][5])

						# Set options values
						if subnet in self.subnetOptgroupsList:
							for options in self.subnetOptgroupsList[subnet]:
								# Text values must have braces and strip ' " ' char
								if self.customOptsList[options[0]][1] == "text":
									subnetBuf += "\toption %s \"%s\";\n" % (options[0],ZEyeUtil.addslashes(options[1]))
								else:
									if options[0] == "next-server":
										subnetBuf += "\t%s %s;\n" % (options[0],options[1])
									else:
										subnetBuf += "\toption %s %s;\n" % (options[0],options[1])

						if self.subnetList[subnet][6] != "" and self.subnetList[subnet][6] != 0:
							subnetBuf += "\tdefault-lease-time %s;\n" % self.subnetList[subnet][6]

						if self.subnetList[subnet][7] != "" and self.subnetList[subnet][7] != 0:
							subnetBuf += "\tmax-lease-time %s;\n" % self.subnetList[subnet][7]
			
						subnetBuf += "\toption domain-name-servers %s%s;\n\n" % (self.subnetList[subnet][3],dns2)
						
						# Now create pool with failover peer and ranges
						if subnet in self.rangeList:
							# Show this part only if we have rangelist
							if len(self.rangeList[subnet]) > 0:
								# Start pool brace
								subnetBuf += "\tpool {\n"

								# Show failover part and enable showFailover variable
								showFailover = True
								if len(failoverPeerName) > 0:
									subnetBuf += "\t\tfailover peer \"%s\";\n\n" % failoverPeerName

								for range in self.rangeList[subnet]:
									subnetBuf += "\t\trange %s %s;\n" % (range[0],range[1])

								subnetBuf += "\t}\n"
						subnetBuf += "}\n\n"


						for ip in subnetIpList:
							reservBuf += "host %s {\n\thardware ethernet %s;\n\tfixed-address %s;\n" % (self.ipList[ip][1],self.ipList[ip][0],ip)
							if ip in self.IPv4OptgroupsList:
								for options in self.IPv4OptgroupsList[ip]:
									# Text values must have braces and strip ' " ' char
									if self.customOptsList[options[0]][1] == "text":
										reservBuf += "\toption %s \"%s\";\n" % (options[0],ZEyeUtil.addslashes(options[1]))
									else:
										if options[0] == "next-server":
											reservBuf += "\t%s %s;\n" % (options[0],options[1])
										else:
											reservBuf += "\toption %s %s;\n" % (options[0],options[1])
							reservBuf += "}\n"
	
			
			if showFailover == True:
				subnetBuf = "%s%s" % (failoverPeerBuf,subnetBuf)

			# check md5 trace to see if subnet file is different
			tmpmd5 = ssh.sendCmd("cat %s|%s" % (subnetpath,hashCmd))
			tmpmd5 = re.sub("\n", "", tmpmd5)
			tmpmd52 = hashlib.md5("%s\n" % subnetBuf).hexdigest()
			if tmpmd5 != tmpmd52:
				ssh.sendCmd("echo '%s' > %s" % (subnetBuf,subnetpath))
				ssh.sendCmd("echo 1 > /tmp/dhcprestart")
				self.logInfo("subnets modified on %s, asking dhcpd restart" % addr)
			
			# check md5 trace to see if reserv file is different
			tmpmd5 = ssh.sendCmd("cat %s|%s" % (reservpath,hashCmd))
			tmpmd5 = re.sub("\n", "", tmpmd5)
			tmpmd52 = hashlib.md5("%s\n" % reservBuf).hexdigest()
			if tmpmd5 != tmpmd52:
				ssh.sendCmd("echo '%s' > %s" % (reservBuf,reservpath))
				ssh.sendCmd("echo 1 > /tmp/dhcprestart")
				self.logInfo("reservations modified on %s, asking dhcpd restart" % addr)

			ssh.close()
		except Exception, e:
			self.logCritical(e)
コード例 #3
0
ファイル: zDNS.py プロジェクト: nerzhul/Z-Eye
	def doConfigDNS(self,addr,user,pwd,namedpath,chrootpath,mzonepath,szonepath,zeyenamedpath,nsfqdn,tsigtransfer,tsigupdate):
		self.incrThreadNb()

		cfgbuffer = ""
		try:
			# No zone or cluster, stop it
			if len(self.zoneList) == 0 or len(self.clusterList) == 0:
				self.decrThreadNb()
				return

			ssh = ZEyeSSHBroker(addr,user,pwd)
			if ssh.connect() == False:
				self.decrThreadNb()
				return

			# We get the remote OS for some commands
			remoteOs = ssh.getRemoteOS()
			if remoteOs != "Linux" and remoteOs != "FreeBSD" and remoteOs != "OpenBSD":
				self.logError("%s OS (on %s) is not supported" % (remoteOs,addr))
				self.decrThreadNb()
				return

			hashCmd = ""
			if remoteOs == "Linux":
				hashCmd = "md5sum"
			elif remoteOs == "FreeBSD" or remoteOs == "OpenBSD":
				hashCmd = "md5 -q"

			# We test file existence. If they doesn't exist, we create it. If creation failed, the DNS manager cannot use this server
			if ssh.isRemoteExists(zeyenamedpath) == False:
				ssh.sendCmd("touch %s" % zeyenamedpath)

			if ssh.isRemoteWritable(zeyenamedpath) == False:
				self.logError("%s (on %s) is not writable, no DNS configuration will be done on this server" % (zeyenamedpath,addr))
				self.decrThreadNb()
				return
				
			if ssh.isRemoteExists("/tmp/dnsrestart") == False:
				ssh.sendCmd("touch /tmp/dnsrestart")

			if ssh.isRemoteWritable("/tmp/dnsrestart") == False:
				self.logError("/tmp/dnsrestart (on %s) is not writable, no DNS configuration will be done on this server" % addr)
				self.decrThreadNb()
				return
				
			# Write options
			for cluster in self.clusterList:
				if addr in self.clusterList[cluster][0] or addr in self.clusterList[cluster][1] or addr in self.clusterList[cluster][2]:
					tmpcfgbuffer = ""
					if len(self.clusterList[cluster][3]) > 0:
						tmpcfgbuffer += "\tallow-recursion {\n"
						for acl in self.clusterList[cluster][3]:
							if acl == "none" or acl == "any":
								tmpcfgbuffer += "\t\t%s;\n" % acl
							else:
								tmpcfgbuffer += "\t\t\"%s\";\n" % acl
						tmpcfgbuffer += "\t};\n"

					if len(self.clusterList[cluster][4]) > 0:
						tmpcfgbuffer += "\tallow-transfer {\n"
						for acl in self.clusterList[cluster][4]:
							# Only write non if no tsig transfer key
							if acl == "none":
								if tsigtransfer == "":
									tmpcfgbuffer += "\t\t%s;\n" % acl
							elif acl == "any":
								tmpcfgbuffer += "\t\t%s;\n" % acl
							else:
								tmpcfgbuffer += "\t\t\"%s\";\n" % acl
						if tsigtransfer != "":
							tmpcfgbuffer += "\t\tkey \"%s\";\n" % self.tsigList[tsigtransfer][0]
						tmpcfgbuffer += "\t};\n"

					if len(self.clusterList[cluster][5]) > 0:
						tmpcfgbuffer += "\tallow-update {\n"
						for acl in self.clusterList[cluster][5]:
							# Only write non if no tsig update key
							if acl == "none":
								if tsigupdate == "":
									tmpcfgbuffer += "\t\t%s;\n" % acl
							elif acl == "any":
								tmpcfgbuffer += "\t\t%s;\n" % acl
							else:
								tmpcfgbuffer += "\t\t\"%s\";\n" % acl
						if tsigupdate != "":
							tmpcfgbuffer += "\t\tkey \"%s\";\n" % self.tsigList[tsigupdate][0]
						tmpcfgbuffer += "\t};\n"

					if len(self.clusterList[cluster][6]) > 0:
						tmpcfgbuffer += "\tallow-notify {\n"
						for acl in self.clusterList[cluster][6]:
							if acl == "none" or acl == "any":
								tmpcfgbuffer += "\t\t%s;\n" % acl
							else:
								tmpcfgbuffer += "\t\t\"%s\";\n" % acl
						tmpcfgbuffer += "\t};\n"

					if len(self.clusterList[cluster][7]) > 0:
						tmpcfgbuffer += "\tallow-query {\n\t\t127.0.0.1;\n\t\t::1;\n"
						for acl in self.clusterList[cluster][7]:
							# If none ACL is found, don't write it because we must allow localhost
							if acl == "any":
								tmpcfgbuffer += "\t\t%s;\n" % acl
							elif acl != "none":
								tmpcfgbuffer += "\t\t\"%s\";\n" % acl
						tmpcfgbuffer += "\t};\n"
						
					if self.clusterList[cluster][8] == True:
						tmpcfgbuffer += "\tdnssec-enable yes;\n"
					else:
						tmpcfgbuffer += "\tdnssec-enable no;\n"
						
					if self.clusterList[cluster][9] == True:
						tmpcfgbuffer += "\tdnssec-validation yes;\n"
					else:
						tmpcfgbuffer += "\tdnssec-validation no;\n"

					if len(tmpcfgbuffer) > 0:
						cfgbuffer += "options {\n\tversion\"\";\n\tlisten-on { any; };\n\tlisten-on-v6 { any; };\n%s};\n" % tmpcfgbuffer
					
			# Write TSIG keys
			for tsig in self.tsigList:
				algo = ""
				if self.tsigList[tsig][1] == 1:
					algo = "hmac-md5"
				elif self.tsigList[tsig][1] == 2:
					algo = "hmac-sha1"
				elif self.tsigList[tsig][2] == 3:
					algo = "hmac-sha256"
				if algo != "":
					cfgbuffer += "key \"%s\" {\n\talgorithm %s;\n\tsecret \"%s\";\n};\n" % (self.tsigList[tsig][0],algo,self.tsigList[tsig][2])	
					
			# Write ACLS
			for acl in self.aclList:
				tmpcfgbuffer = ""
				for ip in self.aclList[acl][0]:
					tmpcfgbuffer += "\t%s;\n" % ip
				for network in self.aclList[acl][1]:
					tmpcfgbuffer += "\t%s;\n" % network
				for childacl in self.aclList[acl][2]:
					tmpcfgbuffer += "\t\"%s\";\n" % childacl
				for tsig in self.aclList[acl][3]:
					tmpcfgbuffer += "\tkey \"%s\";\n" % tsig
				for dnsname in self.aclList[acl][4]:
					# We need to catch exception. If exception, name not resolvable
					try:
						dnsanswer = dns.resolver.query(dnsname,'A')
						for rdata in dnsanswer:
							tmpcfgbuffer += "\t%s;\n" % rdata.address
					except DNSException, e:
						self.logError("unable to resolve name %s" % dnsname)

				if len(tmpcfgbuffer) > 0:
					cfgbuffer += "acl \"%s\" {\n%s};\n" % (acl,tmpcfgbuffer)

			for zone in self.zoneList:
				srvType = 0 
				clusterCaches = False
				for cluster in self.zoneList[zone][1]:
					# This server must be in the zone clusters
					if addr in self.clusterList[cluster][0]:
						srvType = 1
					elif addr in self.clusterList[cluster][1]:
						srvType = 2
					elif addr in self.clusterList[cluster][2]:
						srvType = 3 
					if len(self.clusterList[cluster][2]) > 0:
						clusterCaches = True
				
				if srvType > 0:
					validZone = False

					masterList = None
					slaveList = None
					cacheList = None

					tmpcfgbuffer = "zone \"%s.\" {\n" % zone
					# Zone in classic mode
					if self.zoneList[zone][0] == 1:
						# Configuration for caches
						if clusterCaches:
							if srvType == 3:
								tmpcfgbuffer += "\ttype forward;\n\tforwarders {\n"
								# Forwarders are master and then slaves
								for cluster in self.zoneList[zone][1]:
									for master in self.clusterList[cluster][0]:
										tmpcfgbuffer += "\t\t%s;\n" % master
									for slave in self.clusterList[cluster][1]:
										tmpcfgbuffer += "\t\t%s;\n" % slave 

								validZone = True
						else:
							# Configuration for masters
							if srvType == 1:
								tmpcfgbuffer += "\ttype master;\n"
								if len(chrootpath) > 0:
									tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (re.sub(ZEyeUtil.addslashes(chrootpath),"",mzonepath),zone)
								else:
									tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (mzonepath,zone)

								transferBuf = ""
								updateBuf = ""
								queryBuf = ""

								"""
								If there is slaves, we must allow transfer and queries
								If there is caches, we must allow queries
								We also load herited rules if herited is selected
								"""
								for cluster in self.zoneList[zone][1]:
									if len(self.clusterList[cluster][1]) > 0:
										slaveList = self.clusterList[cluster][1]
									if len(self.clusterList[cluster][2]) > 0:
										cacheList = self.clusterList[cluster][2]

									if "herited" in self.zoneList[zone][4]:
										for acl in self.clusterList[cluster][4]:
											if acl != "none":
												transferBuf += "\t\t\"%s\";\n" % acl
									if "herited" in self.zoneList[zone][6]:
										for acl in self.clusterList[cluster][5]:
											if acl != "none":
												updateBuf += "\t\t\"%s\";\n" % acl
									if "herited" in self.zoneList[zone][7]:
										for acl in self.clusterList[cluster][7]:
											if acl != "none":
												queryBuf += "\t\t\"%s\";\n" % acl


								if slaveList != None:
									for slave in slaveList:
										transferBuf += "\t\t%s;\n" % slave
										queryBuf += "\t\t%s;\n" % slave 

								if cacheList != None:
									for cache in cacheList:
										queryBuf += "\t\t%s;\n" % cache
										
								"""
								We add Z-Eye TSIG key, if present
								"""
								if tsigtransfer != None and tsigtransfer != "" and tsigtransfer in self.tsigList:
									transferBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0]
									queryBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0]
									updateBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0]

								"""
								Now we load real ACLs
								If any, allow all and simplify output.
								If none or herited, only allow cluster members (needed to have a working cluster)
								Else, allow cluster members + ACLS
								"""
								if "any" in self.zoneList[zone][4]:
									transferBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][4] and "herited" not in self.zoneList[zone][4]:
									for acl in self.zoneList[zone][4]:
										transferBuf += "\t\t\"%s\";\n" % acl

								if "any" in self.zoneList[zone][6]:
									updateBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][6] and "herited" not in self.zoneList[zone][6]:
									for acl in self.zoneList[zone][6]: 
										updateBuf += "\t\t\"%s\";\n" % acl

								if "any" in self.zoneList[zone][7]:
									queryBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][7] and "herited" not in self.zoneList[zone][7]:
									for acl in self.zoneList[zone][7]: 
										queryBuf += "\t\t\"%s\";\n" % acl
								
								# And we write ACLs
								if len(transferBuf) > 0:
									tmpcfgbuffer += "\tallow-transfer {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % transferBuf
								if len(updateBuf) > 0:
									tmpcfgbuffer += "\tallow-update {\n%s\t};\n" % updateBuf 
								if len(queryBuf) > 0:
									tmpcfgbuffer += "\tallow-query {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % queryBuf

								tmpcfgbuffer += "\tnotify yes;\n"

								validZone = True
							# Configuration for slaves
							elif srvType == 2:
								tmpcfgbuffer += "\ttype slave;\n\tmasters {\n"
								# Now we configure masters
								for cluster in self.zoneList[zone][1]:
									for master in self.clusterList[cluster][0]:
										tmpcfgbuffer += "\t\t%s;\n" % master
								tmpcfgbuffer += "\t};\n"

								if len(chrootpath) > 0:
									tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (re.sub(ZEyeUtil.addslashes(chrootpath),"",szonepath),zone)
								else:
									tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (szonepath,zone)

								transferBuf = ""
								notifyBuf = ""
								queryBuf = ""

								"""
								If there is masters, we must allow transfer, queries and notify
								If there is caches, we must allow queries
								We also load herited rules if herited is selected
								"""
								for cluster in self.zoneList[zone][1]:
									if len(self.clusterList[cluster][0]) > 0:
										masterList = self.clusterList[cluster][0]
									if len(self.clusterList[cluster][2]) > 0:
										cacheList = self.clusterList[cluster][2]
										
									if "herited" in self.zoneList[zone][4]:
										for acl in self.clusterList[cluster][4]:
											if acl != "none":
												transferBuf += "\t\t\"%s\";\n" % acl
									if "herited" in self.zoneList[zone][5]:
										for acl in self.clusterList[cluster][6]:
											if acl != "none":
												notifyBuf += "\t\t\"%s\";\n" % acl
									if "herited" in self.zoneList[zone][7]:
										for acl in self.clusterList[cluster][7]:
											if acl != "none":
												queryBuf += "\t\t\"%s\";\n" % acl


								if masterList != None:
									for master in masterList:
										transferBuf += "\t\t%s;\n" % master 
										notifyBuf += "\t\t%s;\n" % master
										queryBuf += "\t\t%s;\n" % master

								if cacheList != None:
									for cache in cacheList:
										queryBuf += "\t\t%s;\n" % cache
								
								"""
								We add Z-Eye TSIG key, if present
								"""
								if tsigtransfer != None and tsigtransfer != "" and tsigtransfer in self.tsigList:
									transferBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0];
									queryBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0];

								"""
								Now we load real ACLs
								If any, allow all and simplify output.
								If none, only allow cluster members
								Else, allow cluster members + ACLS
								"""
								if "any" in self.zoneList[zone][4]:
									transferBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][4] and "herited" not in self.zoneList[zone][4]:
									for acl in self.zoneList[zone][4]:
										transferBuf += "\t\t\"%s\";\n" % acl

								if "any" in self.zoneList[zone][5]:
									notifyBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][5] and "herited" not in self.zoneList[zone][5]:
									for acl in self.zoneList[zone][5]: 
										notifyBuf += "\t\t\"%s\";\n" % acl

								if "any" in self.zoneList[zone][7]:
									queryBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][7] and "herited" not in self.zoneList[zone][7]:
									for acl in self.zoneList[zone][7]: 
										queryBuf += "\t\t\"%s\";\n" % acl
								
								# And we write ACLs
								if len(transferBuf) > 0:
									tmpcfgbuffer += "\tallow-transfer {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % transferBuf
								if len(notifyBuf) > 0:
									tmpcfgbuffer += "\tallow-notify {\n%s\t};\n" % notifyBuf
								if len(queryBuf) > 0:
									tmpcfgbuffer += "\tallow-query {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % queryBuf

								validZone = True
					# Zone in slave mode
					elif self.zoneList[zone][0] == 2:
						# Only if there is masters 
						if len(self.zoneList[zone][2]) > 0:
							# If there is caches, slave is on cache
							if clusterCaches:
								if srvType == 3:
									tmpcfgbuffer += "\ttype slave;\n\tmasters {\n"
									for fwd in self.zoneList[zone][2]:
										tmpcfgbuffer += "\t\t%s;\n" % fwd
									tmpcfgbuffer += "\t};\n"
									validZone = True
							else:
								tmpcfgbuffer += "\ttype slave;\n\tmasters {\n"
								for master in self.zoneList[zone][2]:
									tmpcfgbuffer += "\t\t%s;\n" % master
								tmpcfgbuffer += "\t};\n"

								if len(chrootpath) > 0:
									tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (re.sub(ZEyeUtil.addslashes(chrootpath),"",szonepath),zone)
								else:
									tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (szonepath,zone)

								transferBuf = ""
								notifyBuf = ""
								queryBuf = ""

								"""
								If there is masters, we must allow transfer and notify
								If there is caches, we must allow queries
								We also load herited rules if herited is selected
								"""
								for cluster in self.zoneList[zone][1]:
									if len(self.clusterList[cluster][2]) > 0:
										cacheList = self.clusterList[cluster][2]

									if "herited" in self.zoneList[zone][4]:
										for acl in self.clusterList[cluster][4]:
											transferBuf += "\t\t\"%s\";\n" % acl
									if "herited" in self.zoneList[zone][5]:
										for acl in self.clusterList[cluster][6]:
											notifyBuf += "\t\t\"%s\";\n" % acl
									if "herited" in self.zoneList[zone][7]:
										for acl in self.clusterList[cluster][7]:
											queryBuf += "\t\t\"%s\";\n" % acl

								for master in self.zoneList[zone][2]:
									notifyBuf += "\t\t%s;\n" % master 
									transferBuf += "\t\t%s;\n" % master 

								# If this is a cluster master of slave, we must allow cache to query
								if cacheList != None and srvType != 3:
									for cache in cacheList:
										queryBuf += "\t\t%s;\n" % cache
								
								"""
								We add Z-Eye TSIG key, if present
								"""
								if tsigtransfer != None and tsigtransfer != "" and tsigtransfer in self.tsigList:
									transferBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0];
									queryBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0];

								"""
								Now we load real ACLs
								If any, allow all and simplify output.
								If none or herited, only allow cluster members
								Else, allow cluster members + ACLS
								"""
								if "any" in self.zoneList[zone][4]:
									transferBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][4] and "herited" not in self.zoneList[zone][4]:
									for acl in self.zoneList[zone][4]:
										transferBuf += "\t\t\"%s\";\n" % acl

								if "any" in self.zoneList[zone][5]:
									notifyBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][5] and "herited" not in self.zoneList[zone][5]:
									for acl in self.zoneList[zone][5]: 
										notifyBuf += "\t\t\"%s\";\n" % acl

								if "any" in self.zoneList[zone][7]:
									queryBuf = "\t\tany;\n"
								elif "none" not in self.zoneList[zone][7] and "herited" not in self.zoneList[zone][7]:
									for acl in self.zoneList[zone][7]: 
										queryBuf += "\t\t\"%s\";\n" % acl
								
								# And we write ACLs
								if len(transferBuf) > 0:
									tmpcfgbuffer += "\tallow-transfer {\n%s\t};\n" % transferBuf
								if len(notifyBuf) > 0:
									tmpcfgbuffer += "\tallow-notify {\n%s\t};\n" % notifyBuf
								if len(queryBuf) > 0:
									tmpcfgbuffer += "\tallow-query {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % queryBuf
								validZone = True
					# Zone in forward mode
					elif self.zoneList[zone][0] == 3:
						# Only if there is forwarders
						if len(self.zoneList[zone][3]) > 0:
							# If there is caches, forward is on cache
							if clusterCaches:
								if srvType == 3:
									tmpcfgbuffer += "\ttype forward;\n\tforwarders {\n"
									for fwd in self.zoneList[zone][3]:
										tmpcfgbuffer += "\t\t%s;\n" % fwd
									tmpcfgbuffer += "\t};\n"

									# No ACL in a forward zone

									validZone = True
							else:
								tmpcfgbuffer += "\ttype forward;\n\tforwarders {\n"
								for fwd in self.zoneList[zone][3]:
									tmpcfgbuffer += "\t\t%s;\n" % fwd

								tmpcfgbuffer += "\t};\n"

								# No ACL in a forward zone

								validZone = True
					
					if validZone == True:
						cfgbuffer += "%s};\n" % tmpcfgbuffer
						# Classic zone
						if self.zoneList[zone][0] == 1 and srvType == 1:
							"""
							Verify if zone file exists on master servers. If not exists create a basic file
							Not needed for slaves. Zonefile is created when transfer if not exists on slave servers.
							"""
							if ssh.isRemoteExists("%s/%s/%s" % (chrootpath,mzonepath,zone)) == False:
								# SOA record
								ttlRefresh = self.zoneList[zone][8]
								if ttlRefresh == 0:
									ttlRefresh = 3600
								ttlRetry = self.zoneList[zone][9]
								if ttlRetry == 0:
									ttlRetry = 180
								ttlExpire = self.zoneList[zone][10]
								if ttlExpire == 0:
									ttlExpire = 864000
								ttlMinimum = self.zoneList[zone][11]
								if ttlMinimum == 0:
									ttlMinimum = 3600

								zonefile = "$ORIGIN .\n$TTL 86400\n%s IN SOA %s. hostmaster.%s. (\n\t\t\t1\n\t\t\t%d\n\t\t\t%d\n\t\t\t%d\n\t\t\t%d )\n" % (zone,nsfqdn,zone,ttlRefresh,ttlRetry,ttlExpire,ttlMinimum)

								# If caches, NS are on caches
								if cacheList != None:
									for cache in cacheList:
										zonefile += "\t\t\tNS\t%s.\n" % self.serverList[cache][7]
								else:
									zonefile += "\t\t\tNS\t%s.\n" % nsfqdn
									if slaveList != None:
										for slave in slaveList:
											zonefile += "\t\t\tNS\t%s.\n" % self.serverList[slave][7]
								zonefile += "\n$ORIGIN %s.\n" % zone
								
								
								if ssh.isRemoteWritable("%s/%s/%s" % (chrootpath,mzonepath,zone)) == False:
									self.logError("Unable to write zonefile on server %s. Please ensure %s/%s/%s is writable !" % (addr,chrootpath,mzonepath,zone))
								else:
									ssh.sendCmd("echo '%s' > %s/%s/%s" % (zonefile,chrootpath,mzonepath,zone))
									ssh.sendCmd("echo 1 > /tmp/dnsrestart")
									self.logInfo("file for zone %s created on %s" % (zone,addr))
						elif self.zoneList[zone][0] == 1 and srvType == 2:
							"""
							Verify if zone file exists on slave servers.
							If not exists ask a service restart to load zone
							"""
							if ssh.isRemoteExists("%s/%s/%s" % (chrootpath,szonepath,zone)) == False:
								ssh.sendCmd("echo 1 > /tmp/dnsrestart")
								self.logInfo("file for zone %s inexistant on %s (slave), asking named restart" % (zone,addr))
								
			# check md5 trace to see if subnet file is different
			tmpmd5 = ssh.sendCmd("cat %s|%s" % (zeyenamedpath,hashCmd))
			tmpmd5 = re.sub("\n", "", tmpmd5)
			tmpmd52 = hashlib.md5("%s\n" % cfgbuffer).hexdigest()
			if tmpmd5 != tmpmd52:
				ssh.sendCmd("echo '%s' > %s" % (cfgbuffer,zeyenamedpath))
				ssh.sendCmd("echo 1 > /tmp/dnsrestart")
				self.logInfo("configuration modified on %s" % addr)
			
			ssh.close()