#!/usr/bin/python
#
#    uec.py - a basic cgi-bin script for triggering UEC installations
#
#    Copyright (C) 2010 Canonical Ltd.
#
#    Authors: Thierry Carrez <thierry.carrez@canonical.com>
#             Dustin Kirkland <kirkland@canonical.com>
#             Chris Cheney <chris.cheney@canonical.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published by
#    the Free Software Foundation, version 3 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import os, shutil
import subprocess
import cgi, yaml

# Send out headers
print "Content-Type: text/html\n\n"
print "<html>"
print "<body>"

# Redirect errors to HTML doc
sys.stderr = sys.stdout

# Load CGI fields and configuration
f = cgi.FieldStorage()
hosts_cfg = yaml.load(open("/etc/uec-provisioning/hosts.cfg", "r"))
mirrors_cfg = yaml.load(open("/etc/uec-provisioning/mirrors.cfg", "r"))
webui_cfg = yaml.load(open("/etc/uec-provisioning/webui.cfg", "r"))

mac = {}
try:
	for h in hosts_cfg['hosts']:
		mac[h['ip']] = h['mac']
except:
	print("<b>ERROR</b>: No hosts configured in <code>/etc/uec-provisioning/hosts.cfg</code>")
	sys.exit(0)

#----

# If called with done, unlink file
if f.getfirst('done'):
	try:
		print("Finishing install for %s" % mac[os.environ["REMOTE_ADDR"]])
		os.unlink(os.path.join(webui_cfg['tftp_dir'],"pxelinux.cfg","01-"+mac[os.environ["REMOTE_ADDR"]].replace(":","-")))
	except KeyError:
		print("Unknown IP")
	sys.exit(0)

#----

# If no ip given, send out form
# TODO: Autoselect UDEB based on local repo contents
if f.getfirst('ip') is None:
	print "<form>"
	print "<h2>Host</h2>"
	print "<select name=ip>"
	for i in hosts_cfg["hosts"]:
		print("<option value=\""+i['ip']+"\">"+i['hostname']+"</option>")
	print "</select>"

	print """
<h2>Services</h2>
<input type="checkbox" name="clc" value="1">CLC<br>
<input type="checkbox" name="wc"  value="1">WC<br>
<input type="checkbox" name="cc"  value="1">CC<br>
<input type="checkbox" name="sc"  value="1">SC<br>
<input type="checkbox" name="nc"  value="1">NC<br>
<input type="checkbox" name="manual"  value="1">Manual Installation<br>
"""

	cluster_name = "cluster1"
	if webui_cfg.has_key('cluster_name'):
		cluster_name = webui_cfg['cluster_name']

	if webui_cfg.has_key('ip_range'):
		ip_range = webui_cfg['ip_range']
	else:
		p1 = subprocess.Popen("/usr/lib/uec-provisioning/ip_helper range", shell=True, stdout=subprocess.PIPE)
		output = p1.communicate()[0]
		ip_range = output.rstrip("\n\r")

	print "<h2>Eucalyptus Configuration</h2>"
	print "IP Range: <input name=\"ip_range\" value=\"" + ip_range + "\"<br>"
	print "Cluster Name: <input name=\"cluster_name\" value=\"" + cluster_name + "\"><br>"

	# need to know how to have this fail properly if there are no mirrors defined in file...
	print """
<h2>Mirror Selection</h2>
<select name=mirror>
"""
	print("<option value=\"default\">default</option>")
	if mirrors_cfg.has_key('mirrors'):
		for i in mirrors_cfg["mirrors"]:
			sel=""
			if i.has_key('default') and i['default']:
				sel=" selected "
			print("<option value=\""+i['name']+ "\"" + 
			      sel +">"+i['name']+"</option>")
	print "</select>"

	print """
<h2>Partition Setup</h2>
<input type="checkbox" name="lvm-full-disk" value="1" checked>Erase disk - Use LVM for full disk<br>
"""

	print """
<h2>Account Setup</h2>
User Fullname: <input name="user-fullname" value="Ubuntu User"><br>
Username: <input name="username" value="ubuntu"><br>
Password: <input name="user-password" value="ubuntu"><br>
<input type="checkbox" name="allow-password-weak" value="true" checked>Allow Weak Password<br>
"""

	if webui_cfg.has_key('developer') and webui_cfg['developer'] == 1:
		print """
<h2>Version</h2>
<input type="checkbox" name="localdeb" value="1">Enable local repository<br>
<input name="euca_udeb" value="1.6.2~bzr1189-0ubuntu2~ppa2"><br>
"""

	print """
<h2>Additional Packages</h2>
<input type="text" name="packages" value="openssh-server">
"""

	print """
<h2>Install</h2>
<input type="submit" name="submit" value="Begin installation">
"""

	print """
</form>
</body>
</html>
"""
	sys.exit(0)

#----

# If we are here, we were called with ip
ip = f.getfirst('ip')
print ("Booting %s(%s) with the following preseed:<br>" % (ip, mac[ip]))

# Write pxelinux config
pxe = open(os.path.join(webui_cfg['tftp_dir'],"pxelinux.cfg","01-%s" % mac[ip].replace(":","-")), "w")
pxe.write("default linux\n")
pxe.write("prompt 1\n")
pxe.write("timeout 20\n")
pxe.write("label linux\n")
pxe.write("\tkernel ubuntu-installer/amd64/linux\n")
pxe.write("\tappend priority=critical %s url=http://%s/preseed/preseed-%s initrd=ubuntu-installer/amd64/initrd.gz root=/dev/rd/0 rw DEBCONF_DEBUG=developer --\n" % (webui_cfg['extra_kern_opt'],webui_cfg['preseed_host'], mac[ip]))
pxe.close()

# Copy preseed model
preseed = os.path.join(webui_cfg['preseed_dir'],"preseed-"+mac[ip])
shutil.copyfile(os.path.join(webui_cfg['preseed_dir'],"preseed"),preseed)
preseed_file = open(preseed, "a")

# Mirror to use
if (f.getfirst('mirror') != "default"):
	for i in mirrors_cfg['mirrors']:
		if i['name'] == f.getfirst('mirror'):
			preseed_file.write("d-i mirror/country string manual\n")
			preseed_file.write("d-i mirror/http/directory string %s\n" % i['ubuntu-dir'])
			preseed_file.write("d-i mirror/http/hostname string %s\n" % i['ubuntu-host'])
			preseed_file.write("d-i mirror/http/proxy string\n")
			preseed_file.write("d-i apt-setup/services-select multiselect security\n")
			preseed_file.write("d-i apt-setup/security_host string %s\n" % i['security-host'])
			preseed_file.write("d-i apt-setup/security_path string %s\n" % i['security-dir'])
else:
	print("<b>Using default (non-local) mirror.</b><br>")

# Partition the disk
if (f.getfirst('lvm-full-disk')):
	print("<b>Erase disk - Use LVM for full disk</b><br>")
	preseed_file.write("d-i partman/default_filesystem string ext3\n")
	preseed_file.write("d-i partman/choose_partition select finish\n")
	preseed_file.write("d-i partman/confirm boolean true\n")
	preseed_file.write("d-i partman/confirm_nooverwrite boolean true\n")
	preseed_file.write("d-i partman/confirm_write_new_label boolean true\n")
	preseed_file.write("d-i partman-auto/disk string\n")
	preseed_file.write("d-i partman-auto/method string lvm\n")
	preseed_file.write("d-i partman-lvm/device_remove_lvm boolean true\n")
	preseed_file.write("d-i partman-lvm/confirm boolean true\n")
	preseed_file.write("d-i partman-md/device_remove_md boolean true\n")
else:
	print("<b>No paritioning scheme selected. You must provide your own partitioning preseed data.</b><br>")

# User account setup
if (f.getfirst('user-fullname')):
	preseed_file.write("d-i passwd/user-fullname string %s\n" % f.getfirst('user-fullname'))
if (f.getfirst('user-password')):
	preseed_file.write("d-i passwd/user-password password %s\n" % f.getfirst('user-password'))
	preseed_file.write("d-i passwd/user-password-again password %s\n" % f.getfirst('user-password'))
if (f.getfirst('username')):
	preseed_file.write("d-i passwd/username string %s\n" % f.getfirst('username'))
if (f.getfirst('allow-password-weak')):
	preseed_file.write("d-i user-setup/allow-password-weak boolean %s\n" % f.getfirst('allow-password-weak'))

# Additional packages
if (f.getfirst('packages')):
	preseed_file.write("d-i pkgsel/include string %s\n" % f.getfirst('packages'))

# UEC specific
preseed_file.write("d-i base-installer/kernel/override-image string linux-server\n")
preseed_file.write("d-i debian-installer/splash boolean false\n")
preseed_file.write("d-i pkgsel/install-language-support boolean false\n")
preseed_file.write("d-i pkgsel/language-pack-patterns string\n")

# Add values for local deb
if webui_cfg.has_key('developer') and webui_cfg['developer'] == 1:
	# Check if localdeb exists
	if (f.getfirst('localdeb')):
		euca_udeb = f.getfirst('euca_udeb')
		location = '%s/%s/eucalyptus-udeb_%s_amd64.udeb' % (webui_cfg['localdeb_dir'], webui_cfg['localdeb_dist'],euca_udeb)
		if (not os.path.exists(location)):
			print "<b>ERROR: %s doesn't exist</b>\n" % euca_udeb
		else:
			preseed_file.write("d-i preseed/early_command string anna net-retriever && wget %s/%s/eucalyptus-udeb_%s_amd64.udeb && udpkg --unpack eucalyptus-udeb_%s_amd64.udeb\n" % (webui_cfg['localdeb'], webui_cfg['localdeb_dist'], euca_udeb, euca_udeb))
			preseed_file.write("d-i apt-setup/local0/repository string %s/ %s/\n" % (webui_cfg['localdeb'], webui_cfg['localdeb_dist']))
			preseed_file.write("d-i apt-setup/local0/comment string Local\n") 
			preseed_file.write("d-i apt-setup/local0/key string %s\n" % webui_cfg['localdeb_key']) 

# Add values for services
services = ""
if (f.getfirst('nc')):
	services += "node, "
	preseed_file.write("d-i anna/choose_modules string eucalyptus-udeb\n")
if (f.getfirst('clc')):
	services += "cloud, "
	preseed_file.write("d-i anna/choose_modules string eucalyptus-udeb\n")
if (f.getfirst('wc')):
	services += "walrus, "
	preseed_file.write("d-i anna/choose_modules string eucalyptus-udeb\n")
if (f.getfirst('cc')):
	services += "cluster, "
	preseed_file.write("d-i anna/choose_modules string eucalyptus-udeb\n")
	preseed_file.write("eucalyptus-udeb eucalyptus/publicips string %s\n" % f.getfirst('ip_range'))
	preseed_file.write("eucalyptus-common eucalyptus/cluster-name string %s\n" % f.getfirst('cluster_name'))
if (f.getfirst('sc')):
	services += "storage, "
	preseed_file.write("d-i anna/choose_modules string eucalyptus-udeb\n")

if services.endswith(", "):
	services = services[:-2]
if (services != ""):
	preseed_file.write("eucalyptus-udeb eucalyptus/install-mode multiselect %s\n" % services)

# Script specific
preseed_file.write("d-i preseed/late_command string wget http://%s%s?done=1\n" % (os.environ["SERVER_NAME"], os.environ["SCRIPT_NAME"]))

# Add extra_preseed from configuration, if any
if webui_cfg.has_key('extra_preseed'):
	for line in webui_cfg['extra_preseed']:
		preseed_file.write(line+"\n")

preseed_file.close()

# Send wake on LAN
# TODO: avoid system call
os.system("powerwake %s" % mac[ip])

# Dump preseed for review
print("<pre>")
preseed_file=open(preseed,"r")
for line in preseed_file:
	print(line[:-1])
preseed_file.close()
print('''
</pre>
</body>
</html>
''')
