#! /usr/bin/python3
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# 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.





import web
import socket, struct
import cloud_utils
from cloud_utils import Command
urls = ("/ipallocator", "ipallocator")
app = web.application(urls, globals())

augtool = Command("augtool")
service = Command("service")
class dhcp:
	_instance = None
	def __init__(self):
		self.availIP=[]
		self.router=None
		self.netmask=None
		self.initialized=False

		options = augtool.match("/files/etc/dnsmasq.conf/dhcp-option").stdout.decode('utf-8').strip()
		for option in options.splitlines():
			if option.find("option:router") != -1:
				self.router = option.split("=")[1].strip().split(",")[1]
				print(self.router)

		dhcp_range = augtool.get("/files/etc/dnsmasq.conf/dhcp-range").stdout.decode('utf-8').strip()
		dhcp_start = dhcp_range.split("=")[1].strip().split(",")[0]
		dhcp_end = dhcp_range.split("=")[1].strip().split(",")[1]
		self.netmask = dhcp_range.split("=")[1].strip().split(",")[2]
		print(dhcp_start, dhcp_end, self.netmask)

 		start_ip_num = self.ipToNum(dhcp_start);
		end_ip_num =  self.ipToNum(dhcp_end)
		print(start_ip_num, end_ip_num)

		for ip in range(start_ip_num, end_ip_num + 1):
			self.availIP.append(ip)
		print(self.availIP[0], self.availIP[len(self.availIP) - 1])

		#load the ip already allocated
		self.reloadAllocatedIP()

	def ipToNum(self, ip):
		return struct.unpack("!I", socket.inet_aton(ip))[0]

	def numToIp(self, num):
		return socket.inet_ntoa(struct.pack('!I', num))

	def getFreeIP(self):
		if len(self.availIP) > 0:
			ip = self.numToIp(self.availIP[0])
			self.availIP.remove(self.availIP[0])
			return ip
		else:
			return None

	def getNetmask(self):
		return self.netmask

	def getRouter(self):
		return self.router

	def getInstance():
		if not dhcp._instance:
			dhcp._instance = dhcp()
		return dhcp._instance
	getInstance = staticmethod(getInstance)

	def reloadAllocatedIP(self):
		dhcp_hosts = augtool.match("/files/etc/dnsmasq.conf/dhcp-host").stdout.decode('utf-8').strip().splitlines()

		for host in dhcp_hosts:
			if host.find("dhcp-host") != -1:
				allocatedIP = self.ipToNum(host.split("=")[1].strip().split(",")[1])
				if allocatedIP in self.availIP:
					self.availIP.remove(allocatedIP)

	def allocateIP(self, mac):
		newIP = self.getFreeIP()
		dhcp_host = augtool.match("/files/etc/dnsmasq.conf/dhcp-host").stdout.decode('utf-8').strip()
		cnt = len(dhcp_host.splitlines()) + 1
		script = """set %s %s
			    save"""%("/files/etc/dnsmasq.conf/dhcp-host[" + str(cnt) + "]", str(mac) + "," + newIP)
		augtool < script
		#reset dnsmasq
		service("dnsmasq", "restart", stdout=None, stderr=None)
		return newIP

	def releaseIP(self, ip):
		dhcp_host = augtool.match("/files/etc/dnsmasq.conf/dhcp-host").stdout.decode('utf-8').strip()
		path = None
		for host in dhcp_host.splitlines():
			if host.find(ip) != -1:
				path = host.split("=")[0].strip()

		if path == None:
			print("Can't find " + str(ip) + " in conf file")
			return None

		print(path)
		script = """rm %s
			    save"""%(path)
		augtool < script

		self.availIP.remove(ip)

		#reset dnsmasq
		service("dnsmasq", "restart", stdout=None, stderr=None)

class ipallocator:
	def GET(self):
		try:
			user_data = web.input()
			command = user_data.command
			print("Processing: " + command)

			dhcpInit = dhcp.getInstance()

			if command == "getIpAddr":
				mac = user_data.mac
				zone_id = user_data.dc
				pod_id = user_data.pod
				print(mac, zone_id, pod_id)
				freeIP = dhcpInit.allocateIP(mac)
				if not freeIP:
					return "0,0,0"
				print("Find an available IP: " + freeIP)

				return freeIP + "," + dhcpInit.getNetmask() + "," + dhcpInit.getRouter()
			elif command == "releaseIpAddr":
				ip = user_data.ip
				zone_id = user_data.dc
				pod_id = user_data.pod
				dhcpInit.releaseIP(ip)
		except:
			return None

if __name__ == "__main__":
	app.run()
