#!/usr/bin/env python

"""
Copyright (C) 2006-2009 Citrix Systems Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; version 2.1 only. with the special
exception on linking described in file 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 Lesser General Public License for more details.
"""

import sys
import os
import commands
import time
from optparse import OptionParser
#import XenAPI

pool_conf = '/etc/xensource/pool.conf'
interface_reconfigure = "@BASE_PATH@/libexec/interface-reconfigure"
inventory_file = '/etc/xensource-inventory'
management_conf = '/etc/firstboot.d/data/management.conf'
network_reset = '/tmp/network-reset'

def read_dict_file(fname):
	f = open(fname, 'r')
	d = {}
	for l in f.readlines():
		kv = l.split('=')
		d[kv[0]] = kv[1][1:-2]
	return d

def read_inventory():
	return read_dict_file(inventory_file)

def read_management_conf():
	return read_dict_file(management_conf)

def write_inventory(inventory):
	f = open(inventory_file, 'w')
	for k in inventory:
		f.write(k + "='" + inventory[k] + "'\n")
	f.close()

if __name__ == "__main__":
	parser = OptionParser()
	parser.add_option("-m", "--master", help="Master's address", dest="address", default=None)
	parser.add_option("--device", help="Device name of new management interface", dest="device", default=None)
	parser.add_option("--mode", help='IP configuration mode for new management interface: "dhcp" or "static" (default is dhcp)', dest="mode", default="dhcp")
	parser.add_option("--ip", help="IP address for new management interface", dest="ip", default='')
	parser.add_option("--netmask", help="Netmask for new management interface", dest="netmask", default='')
	parser.add_option("--gateway", help="Gateway for new management interface", dest="gateway", default='')
	parser.add_option("--dns", help="DNS server for new management interface", dest="dns", default='')
	(options, args) = parser.parse_args()
	
	# Determine pool role
	try:
		f = open(pool_conf, 'r')
		try:
			l = f.readline()
			ls = l.split(':')
			if ls[0] == 'master':
				master = True
				address = 'localhost'
			else:
				master = False
				address = ls[1]
		finally:
			f.close()
	except:
		pass
	
	# Get the management device from the firstboot data if not specified by the user
	if options.device == None:
		try:
			conf = read_management_conf()
			device = conf['LABEL']
		except:
			print "Could not figure out which interface should become the management interface. \
				Please specify one using the --device option."
			sys.exit(1)
	else:
		device = options.device
	print "The management interface will be", device

	# Determine IP configuration for management interface
	options.mode = options.mode.lower()
	if options.mode not in ["dhcp", "static"]:
		parser.error('mode should be either "dhcp" or "static"')
		sys.exit(1)
		
	if options.mode == 'static' and (options.ip == '' or options.netmask == ''):
		parser.error("if static IP mode is selected, an IP address and netmask need to be specified")
		sys.exit(1)
	
	# Warn user
	if not os.access('/tmp/fist_network_reset_no_warning', os.F_OK):
		warning = """!! WARNING !!

This command will reboot the host and reset its network configuration.
Before completing this command:
- Shut down all VMs running on this host.
- Disable HA if this host is part of a resource pool with HA enabled.

Type 'yes' to continue.
"""
		res = raw_input(warning)
		if res <> 'yes':
			sys.exit(1)
	
	# Update master's IP, if needed and given
	if master == True and options.address != None:
		address = options.address
		print "Setting master's ip (" + address + ")..."
		try:
			f = open(pool_conf, 'w')
			f.write('slave:' + address)
		finally:
			f.close()
	
	# Stop networking subsystem to ensure bonds etc are down
	os.system('service network stop')
		
	# Construct bridge name for management interface based on convention
	if device[:3] == 'eth':
		bridge = 'xenbr' + device[3:]
	else:
		bridge = 'br' + device
	
	# Ensure xapi is not running
	print "Stopping xapi..."
	os.system('service xapi stop >/dev/null 2>/dev/null')
	
	# Reconfigure new management interface
	print "Reconfiguring " + device + "..."
	if_args = ' --force ' + bridge + ' rewrite --mac=x --device=' + device + ' --mode=' + options.mode
	if options.mode == 'static':
		if_args += ' --ip=' + options.ip + ' --netmask=' + options.netmask
		if options.gateway != '':
			if_args += ' --gateway=' + options.gateway
	os.system(interface_reconfigure + if_args + ' >/dev/null 2>/dev/null')

	# Update interfaces in inventory file
	print 'Updating inventory file...'
	inventory = read_inventory()
	inventory['MANAGEMENT_INTERFACE'] = bridge
	inventory['CURRENT_INTERFACES'] = ''
	write_inventory(inventory)
	
	# Write trigger file for XAPI to continue the network reset on startup
	try:
		f = file(network_reset, 'w')
		f.write('DEVICE=' + device + '\n')
		f.write('MODE=' + options.mode + '\n')
		if options.mode == 'static':
			f.write('IP=' + options.ip + '\n')
			f.write('NETMASK=' + options.netmask + '\n')
			if options.gateway != '':
				f.write('GATEWAY=' + options.gateway + '\n')
			if options.dns != '':
				f.write('DNS=' + options.dns + '\n')
	finally:
		f.close()

	# Reset the domain 0 network interface naming configuration
	# back to a fresh-install state for the currently-installed
	# hardware.
	os.system("/etc/sysconfig/network-scripts/interface-rename.py --reset-to-install")

	# Reboot
	os.system("/sbin/reboot")

