#!/usr/bin/python

"""SUSENebula Node Registration Service."""

# Author: Robert Schweikert
# License: GPL v2
# Copyright: SUSE

import SocketServer
import os
import re
import signal
import sys
import syslog

ipPattern = r'\d{1,3}?\.\d{1,3}?\.\d{1,3}?\.\d{1,3}?'
ipPat = re.compile(ipPattern)

base = r'\d{0,2}?[A-F]{0,2}?:'
macPattern = 5*base + r'\d{0,2}?[A-F]{0,2}?'
macPat = re.compile(macPattern)

#------------------------------------------------------------------------------
class RegistrationHandler(SocketServer.BaseRequestHandler):
	"""Cloud head node registration request handler."""
	def handle(self):
		syslog.openlog('[NOD_REG]',syslog.LOG_PID, syslog.LOG_DAEMON)
		syslog.syslog(syslog.LOG_INFO, 'Cloud node registration\n')
		# self.request is the TCP socket connected to the client
		macAddr, ipAddr, name = self.request.recv(1024).strip().split(';')
		# Verify proper MAC Address format
		if not macPat.match(macAddr):
			msg = 'Received improper data for MAC Address '
			msg += macAddr
			msg += ' -> skip registration\n'
			syslog.syslog(syslog.LOG_ERR, msg)
			syslog.closelog()
			return
		# Verify the IP address format
		if not ipPat.match(ipAddr):
			msg = 'Received improper data for IP Adress '
			msg += ipAddr
			msg += ' -> skip registration\n'
			syslog.syslog(syslog.LOG_ERR, msg)
			syslog.closelog()
			return
		syslog.syslog(syslog.LOG_INFO, 'MAC Address: %s\n' %macAddr)
		syslog.syslog(syslog.LOG_INFO, 'IP Address: %s\n' %ipAddr)
		syslog.syslog(syslog.LOG_INFO, 'Node name: %s\n' %name)
		# Setup the dhcp server to make sure the node being registered
		# always gets the same IP address
		lines = open('/etc/dhcpd.conf', 'r').readlines()
		processBlock = None
		for ln in lines:
			if ln.find(name) != -1:
				processBlock = 1
				continue
			if processBlock and ln.find('fixed-address') != -1:
				setIP = ln.split()[-1].strip()[:-1]
				if setIP != ipAddr:
					msg = 'Host with name "%s" already registered with ' %name
					msg += 'IP "%s". Cannot register node.\n' %ipAddr
					syslog.syslog(syslog.LOG_INFO, msg)
					syslog.closelog()
					return
		dhconf = open('/etc/dhcpd.conf', 'a')
		dhconf.write('\n')
		dhconf.write('host %s {\n' %name)
		dhconf.write('    hardware ethernet %s;\n' %macAddr)
		dhconf.write('    fixed-address %s;\n' %ipAddr)
		dhconf.write('}\n')
		dhconf.close()
		# Restart the dhcp server as we just change the config
		os.system('/etc/init.d/dhcpd restart  >& /dev/null')
		# Create hosts entry
		hosts = open('/etc/hosts', 'a')
		hosts.write('%s    %s\n' %(ipAddr, name))
		hosts.close()
		# Register node with Nebula infrastructure
		cmd = '/usr/bin/sudo env ONE_AUTH=/var/lib/one/.one/one_auth '
		cmd += '/usr/bin/onehost create %s -i im_kvm -v vmm_kvm ' %ipAddr
		cmd += '-n vnm_kvm'
		res = os.system(cmd)
		if res:
			msg = 'Registration failed, onehost command with non zero status\n'
			syslog.syslog(syslog.LOG_ERR, msg)
			syslog.closelog()
			return
		syslog.syslog(syslog.LOG_ERR, 'Node registration succesful.\n')
		syslog.closelog()

#------------------------------------------------------------------------------
def sigHandler(signum, frame):
	"""Signal handler for termination"""
	syslog.openlog('[NOD_REG]',syslog.LOG_PID,syslog.LOG_DAEMON)
	syslog.syslog(syslog.LOG_INFO, 'Terminating server on signal: %d' %signum)
	syslog.closelog()
	os.remove('/var/run/suseNebula/regSrv.pid')
	sys.exit(0)

#------------------------------------------------------------------------------
if __name__ == "__main__":
	syslog.openlog('[NOD_REG]', syslog.LOG_PID, syslog.LOG_DAEMON)
	syslog.syslog(syslog.LOG_INFO, 'Start node registration service\n')
	# Determine the IP address of this host
	inetInfo = os.popen('/sbin/ifconfig').readlines()
	ipAddr = None
	# Use the first IPv4 address found
	for item in inetInfo:
		if item.find('inet addr') != -1:
			# Extract the IP address from line expected in following format
			# inet addr:192.168.1.6  Bcast:192.168.1.255  Mask:255.255.255.0
			ipAddr = item.strip().split()[1].split(':')[-1]
			if ipPat.match(ipAddr):
				break

	if not ipAddr:
		# No IP address found. Print a message to syslog and exit
		syslog.syslog(syslog.LOG_ERR,
					'Could not determine IP address, exiting\n')
		syslog.closelog()
		sys.exit(1)
		
	server = SocketServer.TCPServer((ipAddr, 8445), RegistrationHandler)

	if not server:
		syslog.syslog(syslog.LOG_ERR, 'Could not create server, exiting\n')
		syslog.closelog()
		sys.exit(1)

	# Write pid to a file
	pid = os.getpid()
	if not os.path.exists('/var/run/suseNebula'):
		os.mkdir('/var/run/suseNebula')
	pidFl = open('/var/run/suseNebula/regSrv.pid', 'w');
	pidFl.write('%d\n' %pid)
	pidFl.close()

	# Register signal handler
	signal.signal(signal.SIGHUP, sigHandler)
	signal.signal(signal.SIGTERM, sigHandler)
	signal.signal(signal.SIGINT, sigHandler)

	# No additional message will be printed, close the log
	syslog.syslog(syslog.LOG_INFO, 'Cloud registration service  running\n')
	syslog.closelog()
	server.serve_forever()
		
