Request for tashi to support subdomains.

Adding support for tashi to support subdomains within the cluster.
You can pass the --hint subDomain=mydomain 



git-svn-id: https://svn.apache.org/repos/asf/incubator/tashi/trunk@1430233 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/tashi/agents/dhcpdns.py b/src/tashi/agents/dhcpdns.py
index 9e95843..48a35b3 100644
--- a/src/tashi/agents/dhcpdns.py
+++ b/src/tashi/agents/dhcpdns.py
@@ -5,15 +5,15 @@
 # to you under the Apache License, Version 2.0 (the
 # "License"); you may not use this file except in compliance
 # with the License.  You may obtain a copy of the License at
-# 
+#
 #   http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing,
 # software distributed under the License is distributed on an
 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
-# under the License.    
+# under the License.
 
 import logging
 import os
@@ -25,6 +25,7 @@
 from tashi.rpycservices.rpyctypes import Instance
 from tashi import boolean
 
+
 class DhcpDns(InstanceHook):
 	def __init__(self, config, client, post=False):
 		InstanceHook.__init__(self, config, client, post)
@@ -48,7 +49,7 @@
 					network = int(network)
 				except:
 					continue
-				self.ipRange[network] = value	
+				self.ipRange[network] = value
 		self.reverseDns = boolean(self.config.get('DhcpDns', 'reverseDns'))
 		self.log = logging.getLogger(__file__)
 		self.ipMin = {}
@@ -62,7 +63,7 @@
 		self.usedIPs = {}
 		for network in self.ipRange:
 			ipRange = self.ipRange[network]
-			(ipMin, ipMax) = ipRange.split("-")	
+			(ipMin, ipMax) = ipRange.split("-")
 			ipMin = ipMin.strip()
 			ipMax = ipMax.strip()
 			ipNum = self.strToIp(ipMin)
@@ -80,7 +81,7 @@
 					self.usedIPs[ipNum] = ip
 				except Exception:
 					pass
-		
+
 	def strToIp(self, s):
 		ipNum = -1
 		try:
@@ -88,10 +89,10 @@
 		except:
 			pass
 		return ipNum
-	
+
 	def ipToStr(self, ip):
 		return "%d.%d.%d.%d" % ((ip>>24)&0xff, (ip>>16)&0xff, (ip>>8)&0xff, ip&0xff)
-	
+
 	def allocateIP(self, nic):
 		# XXXstroucki: if the network is not defined having an ip
 		# range, this will throw a KeyError. Should be logged.
@@ -99,7 +100,10 @@
 		allocatedIP = None
 		requestedIP = self.strToIp(nic.ip)
 		wrapToMinAlready = False
-		if (requestedIP <= self.ipMax[network] and requestedIP >= self.ipMin[network] and (requestedIP not in self.usedIPs)):
+		if (requestedIP <= self.ipMax[network] and
+			requestedIP >= self.ipMin[network] and
+			(requestedIP not in self.usedIPs)):
+
 			allocatedIP = requestedIP
 
 		# nic.ip will be updated later in preCreate if chosen
@@ -117,7 +121,7 @@
 		ipString = self.ipToStr(allocatedIP)
 		self.usedIPs[allocatedIP] = ipString
 		return ipString
-	
+
 	def addDhcp(self, name, ipaddr, hwaddr):
 		try:
 			self.removeDhcp(name)
@@ -159,25 +163,29 @@
 		stdin.close()
 		__output = stdout.read()
 		stdout.close()
-	
+
 	def addDns(self, name, ip):
 		try:
 			self.removeDns(name)
 		except:
 			pass
 		cmd = "nsupdate"
-		child = subprocess.Popen(args=cmd.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+		child = subprocess.Popen(args=cmd.split(),
+					stdin=subprocess.PIPE,
+					stdout=subprocess.PIPE)
 		try:
 			(stdin, stdout) = (child.stdin, child.stdout)
 			stdin.write("server %s\n" % (self.dnsServer))
 			stdin.write("key %s %s\n" % (self.dnsKeyName, self.dnsSecretKey))
-			stdin.write("update add %s.%s %d A %s\n" % (name, self.dnsDomain, self.dnsExpire, ip))
+			stdin.write("update add %s %d A %s\n" % (name, self.dnsExpire, ip))
 			stdin.write("\n")
 			if (self.reverseDns):
 				ipSegments = map(int, ip.split("."))
 				ipSegments.reverse()
-				reverseIpStr = ("%d.%d.%d.%d.in-addr.arpa" % (ipSegments[0], ipSegments[1], ipSegments[2], ipSegments[3]))
-				stdin.write("update add %s %d IN PTR %s.%s.\n" % (reverseIpStr, self.dnsExpire, name, self.dnsDomain))
+				reverseIpStr = ("%d.%d.%d.%d.in-addr.arpa" % (ipSegments[0],
+						ipSegments[1], ipSegments[2], ipSegments[3]))
+				stdin.write("update add %s %d IN PTR %s.\n" % (reverseIpStr,
+						self.dnsExpire, name))
 				stdin.write("\n")
 			stdin.close()
 			__output = stdout.read()
@@ -185,14 +193,15 @@
 		finally:
 			os.kill(child.pid, signal.SIGTERM)
 			(pid, __status) = os.waitpid(child.pid, os.WNOHANG)
-			while (pid == 0): 
+			while (pid == 0):
 				time.sleep(0.5)
 				os.kill(child.pid, signal.SIGTERM)
 				(pid, __status) = os.waitpid(child.pid, os.WNOHANG)
-	
+
 	def removeDns(self, name):
 		cmd = "nsupdate"
-		child = subprocess.Popen(args=cmd.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+		child = subprocess.Popen(args=cmd.split(), stdin=subprocess.PIPE,
+					stdout=subprocess.PIPE)
 		try:
 			(stdin, stdout) = (child.stdin, child.stdout)
 			stdin.write("server %s\n" % (self.dnsServer))
@@ -201,10 +210,11 @@
 				ip = socket.gethostbyname(name)
 				ipSegments = map(int, ip.split("."))
 				ipSegments.reverse()
-				reverseIpStr = ("%d.%d.%d.%d.in-addr.arpa" % (ipSegments[0], ipSegments[1], ipSegments[2], ipSegments[3]))
+				reverseIpStr = ("%d.%d.%d.%d.in-addr.arpa" % (ipSegments[0],
+						ipSegments[1], ipSegments[2], ipSegments[3]))
 				stdin.write("update delete %s IN PTR\n" % (reverseIpStr))
 				stdin.write("\n")
-			stdin.write("update delete %s.%s A\n" % (name, self.dnsDomain))
+			stdin.write("update delete %s A\n" % (name))
 			stdin.write("\n")
 			stdin.close()
 			__output = stdout.read()
@@ -212,17 +222,27 @@
 		finally:
 			os.kill(child.pid, signal.SIGTERM)
 			(pid, __status) = os.waitpid(child.pid, os.WNOHANG)
-			while (pid == 0): 
+			while (pid == 0):
 				time.sleep(0.5)
 				os.kill(child.pid, signal.SIGTERM)
 				(pid, __status) = os.waitpid(child.pid, os.WNOHANG)
-	
+
 	def doUpdate(self, instance):
 		newInstance = Instance()
 		newInstance.id = instance.id
 		newInstance.nics = instance.nics
 		self.client.vmUpdate(instance.id, newInstance, None)
 
+	def getFqdn(self, instance):
+		domainName = self.dnsDomain
+		subDomain = instance.hints.get("subDomain", None)
+		if subDomain != None:
+			domainName = "%s.%s" % (subDomain, self.dnsDomain)
+
+		fqdn = "%s.%s" % (instance.name, domainName)
+
+		return fqdn
+
 	def preCreate(self, instance):
 		if (len(instance.nics) < 1):
 			return
@@ -232,8 +252,9 @@
 			nic.ip = ip
 			try:
 				if (i == 0):
-					self.log.info("Adding %s:{%s->%s} to DNS" % (instance.name, instance.name, ip))
-					self.addDns(instance.name, ip)
+					self.log.info("Adding %s:{%s->%s} to DNS" % (instance.name,
+					self.getFqdn(instance), ip))
+					self.addDns(self.getFqdn(instance), ip)
 				if (i == 0):
 					dhcpName = instance.name
 				else:
@@ -258,7 +279,8 @@
 				# address. How does this happen?
 				del self.usedIPs[ipNum]
 			except Exception:
-				self.log.exception("Failed to remove host %s, ip %s from pool of usedIPs" % (instance.name, ip))
+				self.log.exception("Failed to remove host %s, ip %s from pool of usedIPs" %
+						(instance.name, ip))
 			try:
 				if (i == 0):
 					dhcpName = instance.name
@@ -272,6 +294,6 @@
 			# resolve the dns server name (line 190). Perhaps
 			# the hostname should be then pushed onto a list
 			# to try again next time.
-			self.removeDns(instance.name)
+			self.removeDns(self.getFqdn(instance))
 		except Exception:
 			self.log.exception("Failed to remove host %s from DNS" % (instance.name))
diff --git a/src/tashi/client/tashi-client.py b/src/tashi/client/tashi-client.py
index 5171b83..640342e 100755
--- a/src/tashi/client/tashi-client.py
+++ b/src/tashi/client/tashi-client.py
@@ -340,7 +340,7 @@
 
 # Example use strings
 examples = {
-'createVm': ['--name vmname --disks i386-hardy.qcow2', '--userId 3 --name vmname --cores 8 --memory 7168 --disks mpi-hardy.qcow2:True,scratch.qcow2:False --nics :1.2.3.4,1::52:54:00:00:56:78 --hints enableDisplay=True'],
+'createVm': ['--name vmname --disks i386-hardy.qcow2', '--userId 3 --name vmname --cores 8 --memory 7168 --disks mpi-hardy.qcow2:True,scratch.qcow2:False --nics :1.2.3.4,1::52:54:00:00:56:78 --hints enableDisplay=True --hints subDomain=mysubdomain'],
 'createMany': ['--basename vmname --disks i386-hardy.qcow2 --count 4'],
 'shutdownVm': ['--instance 12345', '--instance vmname'],
 'destroyVm': ['--instance 12345', '--instance vmname'],