#!/usr/bin/python
# Copyright (c) 2006-2007 XenSource Inc.
# Author: Vincent Hanquez <vincent@xensource.com>
#
# storage manager backend: qcow operations
#

import os
import sys
import xml.dom.minidom
import re

########################### operation specific ###########################
class operations_qcow:
	def sr_create(self, dconf, sr_uuid):
		print "sr_create"

	def sr_scan(self, dconf, sr_uuid):
		location = dconf["location"]
		ls = os.listdir(location)
		regex = re.compile("^[0-9a-f]{8}-(([0-9a-f]{4})-){3}[0-9a-f]{12}$")
		def match_uuid(s): return regex.search(s, 0)
		ls = filter(match_uuid, ls)
		return ls

	def sr_content_type(self, dconf, sr_uuid):
		return "qcow"

	def sr_attach(self, dconf, sr_uuid):
		if dconf.has_key("server"):
			src = "%s:%s" % (dconf["server"], dconf["serverpath"])
			dst = dconf["dest"]
			cmd = [ "mount", "-t", "nfs", src, dst ];
			os.spawnvp(os.P_WAIT, cmd[0], cmd)
		return

	def sr_detach(self, dconf, sr_uuid):
		if dconf.has_key("server"):
			dst = dconf["dest"]
			cmd = [ "umount", dst ];
			os.spawnvp(os.P_WAIT, cmd[0], cmd)
		return

	def __vdi_location(self, dconf, vdi_uuid):
		location = dconf["location"]
		return "%s/%s" % (location, vdi_uuid)

	def __base_location(self, dconf, vdi_uuid):
		location = dconf["location"]
		return "%s/base-%s" % (location, vdi_uuid)

	def vdi_create(self, dconf, sr_uuid, vdi_uuid, size):
		file = self.__vdi_location(dconf, vdi_uuid)
		if os.path.exists(file):
			sys.exit(3)
		size_mb = int(size) / (1024 * 1024)
		print "creating qcow with size: %d Mb" % (size_mb)
		cmd = [ "qcow-create", str(size_mb) + "M", file ]
		os.spawnvp(os.P_WAIT, cmd[0], cmd)

	def vdi_delete(self, dconf, sr_uuid, vdi_uuid):
		file = self.__vdi_location(dconf, vdi_uuid)
		# FIXME check if it's a qcow file
		cmd = [ "rm", file ]
		os.spawnvp(os.P_WAIT, cmd[0], cmd)

	def vdi_attach(self, dconf, sr_uuid, vdi_uuid):
		file = self.__vdi_location(dconf, vdi_uuid)
		if not os.path.exists(file):
			sys.exit(4)
		return file

	def vdi_detach(self, dconf, sr_uuid, vdi_uuid):
		file = self.__vdi_location(dconf, vdi_uuid)
		if not os.path.exists(file):
			sys.exit(4)
		return

	def vdi_clone(self, dconf, sr_uuid, vdi_uuid, dvdi_uuid):
		# make some sanity check to not overwrite anything
		file = self.__vdi_location(dconf, vdi_uuid)
		if not os.path.exists(file):
			sys.exit(3)
		newfile = self.__vdi_location(dconf, dvdi_uuid)
		if os.path.exists(newfile):
			sys.exit(4)
		basefile = self.__base_location(dconf, vdi_uuid)
		if os.path.exists(basefile):
			sys.exit(4)

		# move the file, create a base file and clone current vdi from it
		cmd = [ "mv", file, basefile ]
		os.spawnvp(os.P_WAIT, cmd[0], cmd)
		cmd = [ "qcow-create", "0G", file, basefile ]
		os.spawnvp(os.P_WAIT, cmd[0], cmd)

		# create a clone
		cmd = [ "qcow-create", "0G", newfile, basefile ]
		os.spawnvp(os.P_WAIT, cmd[0], cmd)
		return

	def vdi_snapshot(self, dconf, sr_uuid, vdi_uuid, new_uuid):
		file = self.__vdi_location(dconf, vdi_uuid)
		file2 = self.__vdi_location(dconf, new_uuid)
		if not os.path.exists(file):
			sys.exit(3)
		cmd = [ "cp", file, file2 ]
		os.spawnvp(os.P_WAIT, cmd[0], cmd)
		return

	def vdi_lock(self, dconf, sr_uuid, vdi_uuid, host_uuid, force):
		# nop
		return

	def vdi_unlock(self, dconf, sr_uuid, vdi_uuid, host_uuid):
		# nop
		return

########################### common part ##################################
def get_data(nodelist):
	rc = ""
	for node in nodelist:
		if node.nodeType == node.TEXT_NODE:
			rc = rc + node.data
	return rc

def dconf_of_xml(xml_string):
	dom = xml.dom.minidom.parseString(xml_string)
	smconfig = dom.getElementsByTagName("dconf")[0]
	dconf = {}
	for node in smconfig.childNodes:
		dconf[node.nodeName] = get_data(node.childNodes)
	return dconf

def __create_answer():
	dom = xml.dom.minidom.Document()
	element = dom.createElement("sr")
	dom.appendChild(element)
	return (dom, element)

def append_text_node(dom, parent, tag, data):
	node = dom.createElement(tag)
	parent.appendChild(node)
	datanode = dom.createTextNode(data)
	node.appendChild(datanode)

def output_sr_scan(vdis):
	(dom, element) = __create_answer()
	for vdi in vdis:
		vdinode = dom.createElement("vdi")
		element.appendChild(vdinode)

		append_text_node(dom, vdinode, "uuid", vdi)
		append_text_node(dom, vdinode, "locked", "false")
	print (dom.toprettyxml())

def output_sr_content_type(type):
	dom, element = __create_answer()
	pathnode = dom.createElement("type")
	element.appendChild(pathnode)
	# fixme hacky to keep spaces
	textnode = dom.createTextNode("\"%s\"" % type)
	pathnode.appendChild(textnode)
	print (dom.toprettyxml())

def output_vdi_attach(path):
	dom, element = __create_answer()
	pathnode = dom.createElement("path")
	element.appendChild(pathnode)
	# fixme hacky to keep spaces
	textnode = dom.createTextNode("\"%s\"" % path)
	pathnode.appendChild(textnode)
	print (dom.toprettyxml())

def main():
	if len (sys.argv) < 3:
		print "usage: %s <dconf_xml_string> <cmd> [parameters]" % (sys.argv[0])
		sys.exit(1)

	dconfstr = sys.argv[1]
	cmd = sys.argv[2]
	params = sys.argv[3:]

	dconf = dconf_of_xml(dconfstr)
	ops = operations_qcow()

	if cmd == "sr_create":
		ops.sr_create(dconf, params[0])
	elif cmd == "sr_scan":
		output_sr_scan(ops.sr_scan(dconf, params[0]))
	elif cmd == "sr_content_type":
		output_sr_content_type(ops.sr_content_type(dconf, params[0]))
	elif cmd == "sr_attach":
		ops.sr_attach(dconf, params[0])
	elif cmd == "sr_detach":
		ops.sr_detach(dconf, params[0])
	elif cmd == "vdi_create":
		ops.vdi_create(dconf, params[0], params[1], params[2])
	elif cmd == "vdi_delete":
		ops.vdi_delete(dconf, params[0], params[1])
	elif cmd == "vdi_attach":
		output_vdi_attach(ops.vdi_attach(dconf, params[0], params[1]))
	elif cmd == "vdi_detach":
		ops.vdi_detach(dconf, params[0], params[1])
	elif cmd == "vdi_clone":
		ops.vdi_clone(dconf, params[0], params[1], params[2])
	elif cmd == "vdi_snapshot":
		ops.vdi_snapshot(dconf, params[0], params[1], params[2])
	elif cmd == "vdi_lock":
		ops.vdi_lock(dconf, params[0], params[1], params[2], params[3])
	elif cmd == "vdi_unlock":
		ops.vdi_unlock(dconf, params[0], param[1], params[2])
	else:
		print "command \"%s\" doesn't exist" % (cmd)
		sys.exit(2)
	sys.exit(0)

if __name__ == "__main__":
	main()
