merge Luke's branch with the trunk


git-svn-id: https://svn.apache.org/repos/asf/incubator/tashi/branches/luke-zoni-staging@1351880 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/etc/ZoniDefaults.cfg b/etc/ZoniDefaults.cfg
index 6650ceb..93f36d2 100644
--- a/etc/ZoniDefaults.cfg
+++ b/etc/ZoniDefaults.cfg
@@ -30,6 +30,7 @@
 #  Specify data store
 INFO_STORE = sql
 USER_MANAGEMENT = ldap
+PICKLE_FILE = pickled
 
 #  DB host
 [dbConnection]
@@ -58,6 +59,10 @@
 #  Must be relative to TFTP_ROOT_DIR
 INITRD_ROOT = builds/initrd
 KERNEL_ROOT = builds/kernel
+# Extensions from MIMOS
+# put the IP address of your NTP server here
+NTPSVR = 127.0.0.1
+CUSTOM_TEMPLATES_DIR = /var/lib/tftpboot/templates
 
 [www]
 WWW_DOCUMENT_ROOT = /var/www
@@ -96,13 +101,6 @@
 dhcpKeyName = xx_dhcpservername_xx
 dhcpSecretKey = xx_secretkey_xx
 
-#  Domain Config
-[domain]
-domainDescription = "/usr/local/tashi/etc/ZoniDomains.xml"
-ZONI_HOME_DOMAIN = 1  #  Default domain for most switches
-ZONI_HOME_NETWORK = 10.10.0.0/20
-ZONI_IPMI_NETWORK = 10.10.16.0/20
-
 #  Logging
 [loggers]
 keys=root
diff --git a/src/zoni/client/zoni-cli.py b/src/zoni/client/zoni-cli.py
index df6cfd8..9ddf52f 100755
--- a/src/zoni/client/zoni-cli.py
+++ b/src/zoni/client/zoni-cli.py
@@ -53,6 +53,9 @@
 #import zoni.data.usermanagement 
 #from usermanagement import UserManagement
 
+# Extensions from MIMOS
+from zoni.extensions.m_extensions import *
+
 def parseTable():
 	pass
 
@@ -92,6 +95,8 @@
 	group.add_option("--powerOn", "--poweron", dest="POWERON", help="Power on node", action="store_true", default=False)
 	group.add_option("--powerReset", "--powerreset", dest="POWERRESET", help="Power reset node", action="store_true", default=False)
 	group.add_option("--console", dest="CONSOLE", help="Console mode", action="store_true", default=False)
+	# Extensions from MIMOS - specific only for HP Blades and HP c7000 Blade Enclosures
+	group.add_option("--powerOnNet", "--poweronnet", dest="POWERONENET", help="Power on Node into PXE (Currently support on HP Blades through HP c7000 Blade Enclosure)", action="store_true", default=False)
 	parser.add_option_group(group)
 
 	#  Query Interface
@@ -188,6 +193,18 @@
 	group.add_option("--removeDhcp", dest="removeDhcp", help="Remove a DHCP entry", action="store_true", default=False)
 	parser.add_option_group(group)
 
+	# Extensions from MIMOS
+	group = optparse.OptionGroup(parser, "Zoni MIMOS Extensions", "Special Functions created by MIMOS Lab:")
+	group.add_option("--addRole", "--addrole", dest="addRole", help="Create a disk based installation default file for a node based on its role or function, e.g. one|oned|cc|clc|walrus|sc|nc|preseed|kickstart", default=None, action="store")
+	group.add_option("--removeRole", "--removerole", dest="removeRole", help="Remove the default file of a node", action="store_true", default=False)
+	group.add_option("--showRoleMap", dest="showRoleMap", help="Show Role to Host Mapping", action="store_true", default=False)
+	group.add_option("--showKernel", dest="showKernelInfo", help="Show Kernel Info", action="store_true", default=False)
+	group.add_option("--showInitrd", dest="showInitrdInfo", help="Show Initrd Info", action="store_true", default=False)
+	group.add_option("--registerKernelInitrd", dest="registerKernelInitrd", help="Register Kernel and Initrd - vmlinuz:vmlinuz-ver:vmlinuz-arch:initrd:initrd-arch:imagename")
+	group.add_option("--getKernelInitrdID", dest="getKernelInitrdID", help="Get corresponding Kernel and Initrd Info - vmlinuz:initrd:arch")
+	group.add_option("--getConfig", dest="getConfig", help="Get a value from ZoniDefault.cfg - e.g. tftpRootDir, initrdRoot, kernelRoot, fsImagesBaseDir, etc.", default=None, action="store")
+	parser.add_option_group(group)
+
 	(options, args) = parser.parse_args()
 
 	
@@ -201,6 +218,8 @@
 	data = instantiateImplementation("zoni.data.resourcequerysql.ResourceQuerySql", configs, options.verbosity)
 	reservation = instantiateImplementation("zoni.data.reservation.reservationMysql", configs, data, options.verbosity)
 	#query = zoni.data.resourcequerysql.ResourceQuerySql(configs, options.verbosity)
+	# Extensions from MIMOS
+	mimos = instantiateImplementation("zoni.extensions.m_extensions.mimos",configs)
 
 	#  Get host info
 	host=None
@@ -224,12 +243,21 @@
 			if "drac_name" in host:
 				hw= dellDrac(configs, options.nodeName, host)
 			else:
-				mesg = "Host (" + options.nodeName + ") does not have a DRAC card!!\n"
+				mesg = "Host (%s) does not have a DRAC card!!\n" % options.nodeName
 				sys.stdout.write(mesg)
 				exit(1)
+
+		## Extensions from MIMOS - For Dell Blades - calling Dell Blades via the Blade Enclosure, some DRAC commands are slightly different from the ones in blade enclosure when compared to those in the actual blade, this allow a bit more flexiblity and standard calls to the blades
+		if options.hardwareType == "dracblade":
+			hw = dellBlade(configs, options.nodeName, host)
+
+		## Extensions from MIMOS - For HP Blades - calling HP Blades via the HP c7000 Blade Enclosure instead of direct to the blade server itself, this allow a bit more flexiblity and standard calls to the blades
+		if options.hardwareType == "hpilo":
+			hw = hpILO(configs, options.nodeName, host)
+
 		if (options.REBOOTNODE or options.POWERCYCLE  or options.POWEROFF or options.POWEROFFSOFT or \
 			options.POWERON or options.POWERSTATUS or options.CONSOLE or \
-			options.POWERRESET) and options.nodeName:
+			options.POWERONNET or options.POWERRESET) and options.nodeName: # Extensions from MIMOS - added POWERONNET
 
 			if options.verbosity:
 				hw.setVerbose(True)
@@ -258,6 +286,10 @@
 			if options.CONSOLE:
 				hw.activateConsole()
 				exit()
+			## Extensions from MIMOS - For HP Blade via c7000 Blade Enclosure
+			if options.POWERONNET:
+				hw.powerOnNet()
+				exit()
 			hw.getPowerStatus()
 			exit()
 	else:
@@ -817,5 +849,29 @@
 				mesg = "[SUCCESS]\n"
 				sys.stdout.write(mesg) 
 
+	## Extensions from MIMOS - functions are defined in m_extensions.py
+	if ( options.addRole and options.nodeName ) or ( options.removeRole and options.nodeName ):
+		if options.addRole:
+			mimos.assignRoletoHost(host,options.addRole)
+			mimos.addRoletoNode(configs,host,options.nodeName,options.addRole)
+		if options.removeRole:
+			mimos.unassignRolefromHost(host)
+			mimos.removeRolefromNode(configs,host,options.nodeName)
+	if ( options.addRole and not options.nodeName ) or ( options.removeRole and not options.nodeName ):
+		mesg = "Roles: Missing Parameter(s)!"
+		log.error(mesg)
+	if options.showRoleMap:
+		mimos.showRoletoHost(configs)
+	if options.showKernelInfo:
+		mimos.showKernelInfo()
+	if options.showInitrdInfo:
+		mimos.showInitrdInfo()
+	if options.registerKernelInitrd:
+		mimos.registerKernelInitrd(configs,options.registerKernelInitrd)
+	if options.getKernelInitrdID:
+		mimos.getKernelInitrdID(options.getKernelInitrdID)
+	if options.getConfig:
+		mimos.getConfig(configs,options.getConfig)
+
 if __name__ == "__main__":
 	main()
diff --git a/src/zoni/data/resourcequerysql.py b/src/zoni/data/resourcequerysql.py
index 236b926..4ea3ed3 100644
--- a/src/zoni/data/resourcequerysql.py
+++ b/src/zoni/data/resourcequerysql.py
@@ -298,6 +298,11 @@
 		query = "select " + defaultFields + "from sysinfo " + queryopt
 		result = self.selectDb(query)	
 
+		# Extensions from MIMOS - allow showResources to fail gracefully if the Zoni DB is not populated yet
+		if result.rowcount < 1:
+			print "Zoni Hardware/System Database is empty."
+			exit(1)
+
 		line = ""
 		for i in defaultFields.split(","):
 			#line += string.strip(str(i)) + "\t"
@@ -732,7 +737,7 @@
 			host['hw_port'] = int(i[6])
 
 		#  Get drac info
-		query = "select h.hw_id, h.hw_name, h.hw_model, h.hw_ipaddr, h.hw_userid, h.hw_password, p.port_num from hardwareinfo h, portmap p where p.hw_id = h.hw_id and hw_type = 'drac' and sys_id = " +  str(host['sys_id'])
+		query = "select h.hw_id, h.hw_name, h.hw_model, h.hw_ipaddr, h.hw_userid, h.hw_password, h.hw_blenc, p.port_num from hardwareinfo h, portmap p where p.hw_id = h.hw_id and hw_type = 'drac' and sys_id = " +  str(host['sys_id'])
 		result = self.selectDb(query)
 		if result.rowcount > 0:
 			for i in result.fetchall():
@@ -742,7 +747,9 @@
 				host['drac_ipaddr'] = i[3]
 				host['drac_userid'] = i[4]
 				host['drac_password'] = i[5]
-				host['drac_port'] = int(i[6])
+				# Extensions from MIMOS - for Dell Blade
+				host['drac_enclosure'] = i[6]
+				host['drac_port'] = int(i[7])
 
 		#  Get PDU info
 		query = "select h.hw_id, h.hw_name, h.hw_model, h.hw_ipaddr, h.hw_userid, h.hw_password, p.port_num from hardwareinfo h, portmap p where p.hw_id = h.hw_id and h.hw_type = 'pdu' and p.sys_id = " +  str(host['sys_id'])
@@ -756,6 +763,18 @@
 			host['pdu_password'] = i[5]
 			host['pdu_port'] = int(i[6])
 
+		# Extensions from MIMOS - for HP Blade iLO
+		query = "select h.hw_id, h.hw_name, h.hw_model, h.hw_ipaddr, h.hw_userid, h.hw_password, h.hw_blenc, p.port_num from hardwareinfo h, portmap p where p.hw_id = h.hw_id and hw_type = 'hpilo' and sys_id = " +  str(host['sys_id'])
+		result = self.selectDb(query)
+		for i in result.fetchall():
+			host['ilo_id'] = int(i[0])
+			host['ilo_name'] = i[1]
+			host['ilo_model'] = i[2]
+			host['ilo_ipaddr'] = i[3]
+			host['ilo_userid'] = i[4]
+			host['ilo_password'] = i[5]
+			host['ilo_enclosure'] = i[6]
+			host['ilo_port'] = int(i[7])
 
 		#print "host is ", host
 		return host
@@ -1088,8 +1107,14 @@
 			name = imageName.split(":")[0]
 		if len(imageName.split(":")) > 2:
 			dist = imageName.split(":")[1]
-		if len(imageName.split(":")) >= 3:
+		# Extensions from MIMOS - allow adding 2 more pieces of info - kernel_id and initrd_id
+		#if len(imageName.split(":")) >= 3:
+		if len(imageName.split(":")) > 3:
 			dist_ver = imageName.split(":")[2]
+		if len(imageName.split(":")) > 4:
+			kernel_id = imageName.split(":")[3]
+		if len(imageName.split(":")) >= 5:
+			initrd_id = imageName.split(":")[4]
 
 		query = "select * from imageinfo where image_name = \"" + name + "\""
 		result = self.selectDb(query)
@@ -1106,7 +1131,9 @@
 			sys.stderr.write(mesg)
 			return 
 
-		query = "insert into imageinfo (image_name, dist, dist_ver) values(\"" + name + "\", \"" + dist + "\", \"" + dist_ver + "\")"
+		# Extensions from MIMOS - to take care of the addition of kernel_id and initrd_id
+		#query = "insert into imageinfo (image_name, dist, dist_ver) values(\"" + name + "\", \"" + dist + "\", \"" + dist_ver + "\")"
+		query = "insert into imageinfo (image_name, dist, dist_ver, kernel_id, initrd_id) values ('%s', '%s', '%s', '%s', '%s')" % (name, dist, dist_ver, kernel_id, initrd_id)
 		self.insertDb(query)
 
 
diff --git a/src/zoni/extensions/convertz-src/Makefile b/src/zoni/extensions/convertz-src/Makefile
new file mode 100644
index 0000000..1674864
--- /dev/null
+++ b/src/zoni/extensions/convertz-src/Makefile
@@ -0,0 +1,25 @@
+default: install
+	@echo Done
+
+install: checkroot theconvertz manpage livesupportdebs
+
+theconvertz:
+	@echo Install convertz...
+	@if [ ! -e /usr/local/sbin/convertz ]; then echo No file, installing...; cp convertz /usr/local/sbin; chmod 700 /usr/local/sbin/convertz; else echo Got old file, removing old file then install a new one...; rm /usr/local/sbin/convertz; cp convertz /usr/local/sbin; chmod 700 /usr/local/sbin/convertz; fi
+
+uninstall: checkroot
+	@echo Removing convertz and its companions...
+	@if [ -f /usr/local/sbin/convertz ]; then echo Removing convertz; rm /usr/local/sbin/convertz; else echo No file found; fi
+	@if [ -f /usr/local/man/man8/convertz.8.gz ]; then echo Removing convertz manual; rm /usr/local/man/man8/convertz.8.gz; else echo No manual found; fi
+	@if [ -d /var/www/live-boot-support ]; then echo Removing Debian Live Packages; rm -rf /var/www/live-boot-support; else echo No Debian Live Packages found; fi
+
+manpage:
+	@echo Install convertz manual...
+	@if [ ! -d /usr/local/man/man8 ]; then echo No man8 folder, creating man8 folder then install manual...; mkdir -p /usr/local/man/man8; gzip -c convertz.8 > /usr/local/man/man8/convertz.8.gz; elif [ -f /usr/local/man/man8/convertz.8.gz ]; then echo Got old manual, removing old manual then install a new one...; rm /usr/local/man/man8/convertz.8.gz; gzip -c convertz.8 > /usr/local/man/man8/convertz.8.gz; else echo No manual; echo Installing a manual...; gzip -c convertz.8 > /usr/local/man/man8/convertz.8.gz; fi; fi
+
+livesupportdebs:
+	@echo Install Debian Live Packages...
+	@if [ ! -d /var/www/live-boot-support ]; then echo No live-boot-support, copying with folder...; cp -r ./live-boot-support /var/www; else echo Copying debs over...; cp ./live-boot-support/*.deb /var/www/live-boot-support/; fi
+
+checkroot:
+	@if [ `id -u` -eq 0 ]; then echo OK to proceed...; else echo You have to be root to run this; exit 1; fi
diff --git a/src/zoni/extensions/convertz-src/changelog.txt b/src/zoni/extensions/convertz-src/changelog.txt
new file mode 100644
index 0000000..9e9551c
--- /dev/null
+++ b/src/zoni/extensions/convertz-src/changelog.txt
@@ -0,0 +1,17 @@
+convertz - simple vm to live image conversion for zoni
+
+Version 1.0:
+Initial version, some self check for dependent tools/files, supports only Ubuntu
+images with standard non-LVM 2 partitions (root and swap).
+
+To Dos:
+- possible bug in treating raw (.img) image as we work on the original image
+  and not a copy of it thus lossing the original state after injecting live-*
+  packages
+- make self check independent or to run it during the installation/make process,
+  possible even make necessary changes to the /etc/default/grub if necessary
+- make use of nbd/qemu-nbd to skip conversion but possibly need to consider
+  preserving the original image (in case user want it back)
+- sync some of the variables in the script with those in the ZoniDefaults.cfg,
+  will require some additional codes to be added to zoni
+- probably need to port this to python
diff --git a/src/zoni/extensions/convertz-src/convertz b/src/zoni/extensions/convertz-src/convertz
new file mode 100644
index 0000000..2849946
--- /dev/null
+++ b/src/zoni/extensions/convertz-src/convertz
@@ -0,0 +1,466 @@
+#!/bin/bash
+
+# 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.
+
+#This is a quick prototype to convert VM images to a barebone/live image.
+#Several steps/guidelines need to be followed in preparation of the VM image.
+#The assumption is that the VM image is running Ubuntu would have live-boot and
+#live-config installed; consists of only a root (/) partition and a swap
+#partition where the root is the first partition.
+#
+#Few other adjustment required to the kernel in order to get this working:
+#add max_loop=x and loop.max_part=y to the /etc/default/grub and update-grub.
+#Version $thisver: Written 2011 by Jing-Yuan Luke at MIMOS
+
+#export PYTHONPATH=/opt/tashi/tashi/branches/luke-zoni/src
+export PATH=$PATH:$PYTHONPATH/zoni/extra
+thisver="1.0"
+
+usage()
+{
+cat << EOF
+usage: $0 options
+
+This script converts an VM image to a live boot image and registers it to Zoni.
+Currently it only support Ubuntu/Debian based VM images using the live-boot,
+live-config and live-tools packages.
+
+It consists of 2 stages:
+- 1st stage to check and if necessary converts the VM image from any formats to
+  raw, insert live-* packages if missing and finally create a squashfs image.
+- 2nd stage (still work in progress), the script will check the version of
+  kernel and initrd with Zoni's database before registering the new image to Zoni
+  and move it to the appropriate folder.
+
+OPTIONS:
+   -h                   Show this message
+   -i <input image>     Your input VM image
+   -n <image name>      Name for the live image to be registered in Zoni
+   -u                   Update live image
+   -p <partition #>     The / or root partition of the input VM Image (optional)
+   -v                   Print version and Exit
+
+EOF
+}
+
+# Self Check routine, should run just once when convertz is triggered the first time.
+self_check ()
+{
+	if [ -f $WHEREISGRUB ]
+	then
+		if [ ! "`grep -E "max_loop=.*loop\.max_part=" $WHEREISGRUB`" ]
+		then
+        		echo "Missing max_loop and loop.max_part in ${WHEREISGRUB}, please check and correct then reboot."
+			exit 1
+		else
+			echo "grub and loop OK!"
+		fi
+	else
+		echo "Grub missing! Please check!"
+		exit 1
+	fi 
+	if [ -z "${MYQEMUIMG}" -o ! -f "${MYQEMUIMG}" ]
+	then
+		echo "Missing qemu-img, please install the package."
+		exit 1
+	else
+		echo "qemu-img OK!"
+	fi
+	if [ -z "${MYMKSQUASHFS}" -o ! -f "${MYMKSQUASHFS}" ]
+	then
+		echo "Missing mksquashfs, please install the package."
+		exit 1
+	else
+		echo "mksquashfs OK!"
+	fi
+	if [ -z "${MYUUIDGEN}" -o ! -f "${MYUUIDGEN}" ]
+	then
+		echo "Missing uuidgen, please install the package."
+		exit 1
+	else
+		echo "uuidgen OK!"
+	fi
+	if [ -z "${MYPARTED}" -o ! -f "${MYPARTED}" ]
+	then
+		echo "Missing parted, please install the package."
+		exit 1
+	else
+		echo "parted OK!"
+	fi
+	if [ `ls /var/www/live-boot-support/live-*.deb 2> /dev/null | wc -l` -ge 5 ]
+	then
+		echo "live boot and live config debs OK!"
+	else
+		echo "Missing necessary debs, please build and copy to /var/www/live-boot-support."
+		exit 1
+	fi
+
+	# Create a dummy self-checked file
+	touch $HOME/.convertz-selfchecked
+}
+
+# Add live packages to the mounted image but first check and if necessary remove casper package
+add_live_package ()
+{
+	echo "Checking for casper..."
+	if [ -f $MYTEMPDIR/var/lib/dpkg/info/casper.list ]
+	then
+		echo "chroot remove casper pacakge..."
+		chroot $MYTEMPDIR dpkg --purge casper
+	fi
+	echo "Checking for live-* packages..."
+	if [ -f $MYTEMPDIR/var/lib/dpkg/info/live-boot.list -a -f $MYTEMPDIR/var/lib/dpkg/info/live-config.list -a -f $MYTEMPDIR/var/lib/dpkg/info/live-config-upstart.list -a -f $MYTEMPDIR/var/lib/dpkg/info/live-tools.list ]
+	then
+		echo "debian live packages installed"
+	else
+		echo "chroot adding live packages..."
+		cp /var/www/live-boot-support/live-* $MYTEMPDIR
+		index=0
+		for i in `ls /var/www/live-boot-support/live-* | cut -f5 -d"/"`
+		do
+			LIVEDEBS[index]=$i
+			let index=index+1
+		done
+		chroot $MYTEMPDIR dpkg -i ${LIVEDEBS[@]}
+		rm $MYTEMPDIR/live-*
+	fi
+}
+
+# Clean up temporary file and folder before unmounting
+clean_tmp ()
+{
+	if [ -e $MYTEMPIMG ]
+	then
+		echo "Cleaning ${MYTEMPIMG}..."
+		rm $MYTEMPIMG
+	fi
+	if [ -d $MYTEMPDIR ]
+	then
+		if mount | grep $MYTEMPDIR | grep $MYFREELOOP &> /dev/null
+		then
+			echo "Unmounting ${MYTEMPDIR}..."
+			umount $MYTEMPDIR
+		fi
+		echo "Removing ${MYTEMPDIR}..."
+		rmdir $MYTEMPDIR
+	fi
+	echo "Cleaning done."
+}
+
+# Check the loop device partitions
+check_loop_part ()
+{
+	echo "Checking Image Partitions..."
+	if [ `parted $MYFREELOOP unit s p | tail -n +7 | head -n -1 | grep -v extended | wc -l` -gt 2 ]
+	then
+		echo "You got more than 2 partitions, please use the \"-p <partition #>\" option."
+		umnt_loop
+		exit 1
+	else
+		echo "Just 2 partitions."
+		MYFREELOOPPART=${MYFREELOOP}p`parted $MYFREELOOP unit s p | tail -n +7 | head -n -1 | grep -v extended | grep -v linux-swap | awk '{ print $1 }'`
+	fi
+}
+
+# Detach the loop device but first clean temp file and folder
+umnt_loop ()
+{
+	# Got to clean and umount the temp dir first before detach loop
+	clean_tmp
+	echo "Detaching loop..."
+	losetup -d $MYFREELOOP &> /dev/null
+	if [ ! $? == "0" ]
+	then
+		echo "Error detaching ${MYFREELOOP}, you may need to manually do it"
+		exit 1
+	else
+		echo "losetup detach success."
+	fi
+}
+
+# Convert image to raw format
+convert_fmt ()
+{
+	echo "Converting from ${MYIMGFMT} to raw..."
+	$MYQEMUIMG convert -O raw $MYIMGFILE $MYTEMPIMG &> /dev/null
+}
+
+# Check image type and if required convert it
+check_img_info ()
+{
+	echo "Checking Your Image Format..."
+	MYIMGFMT=`qemu-img info $MYIMGFILE | grep "file format" | cut -f3 -d" "`
+	echo "Your image is in ${MYIMGFMT} format."
+	if [ ! $MYIMGFMT == "raw" ]
+	then
+		convert_fmt
+		FORLOOPMNT=$MYTEMPIMG
+	else
+		FORLOOPMNT=$MYIMGFILE
+	fi 
+}
+
+# Get info on vmlinuz, initrd.img, architecture, distribution's name and version as well as actual kernel version
+retrieve_img_internals ()
+{
+	# Find the distro name (e.g. Ubuntu, Debian, etc.) and version here (e.g. Lucid, Maverick, etc.)
+	if [ -f $MYTEMPDIR/etc/lsb-release ]
+	then
+		DIST=`grep DISTRIB_ID $MYTEMPDIR/etc/lsb-release | cut -f2 -d"="`
+		echo $DIST
+		DIST_VER=`grep DISTRIB_CODENAME $MYTEMPDIR/etc/lsb-release | cut -f2 -d"="`
+		echo $DIST_VER
+	else
+		echo "Not Ubuntu/Debian! Only Ubuntu/Debian is currently supported."
+		umnt_loop
+		exit 1
+	fi
+
+	# Get the vmlinuz and initrd then get their version
+	cd $MYTEMPDIR/boot
+	if [ `ls vmlinuz* | wc -l` -gt 1 ]
+	then
+		echo "You have more than 1 kernel installed"
+		MYVMLINUZ=`ls -t vmlinuz* | head -n 1`
+		MYINITRD=`ls -t initrd* | head -n 1`
+		echo "Your latest vmlinuz is ${MYVMLINUZ} and initrd is ${MYINITRD}"
+	else
+		MYVMLINUZ=`ls vmlinuz*`
+		MYINITRD=`ls initrd*`
+		echo "Your vmlinuz is ${MYVMLINUZ} and initrd is ${MYINITRD}"
+	fi
+	MYVMLINUZ_VER=`echo $MYVMLINUZ | sed 's/vmlinuz-//'`
+	MYINITRD_VER=`echo $MYINITRD | sed 's/initrd.img-//'`
+
+	# Get the actual kernel version (e.g. 2.x.y-a.b instead of 2.x.y-a-generic)
+	KERN=`zcat /usr/share/doc/linux-image-${KERN_UNAME}/changelog.Debian.gz | head -n 1 | awk '{ print $2 }'`
+	KERN_VERSION=${KERN:1:(-1)}
+	echo "Your actual kernel version is ${KERN_VERSION}"
+
+	# Get bitness/arch type (e.g. i386 or x86_64)
+	if grep "elf64-x86-64" config-${MYVMLINUZ_VER} &> /dev/null && grep "CONFIG_X86_64=y" config-${MYVMLINUZ_VER} &> /dev/null
+	then
+		MYARCHNESS="x86_64"
+	elif grep "elf32-i386" config-${MYVMLINUZ_VER} &> /dev/null && grep "CONFIG_X86_32=y" config-${MYVMLINUZ_VER} &> /dev/null
+	then
+		MYARCHNESS="i386"
+	else
+		echo "Can't determine your image's OS Architecture!"
+		umnt_loop
+		exit 1
+	fi
+	echo "Your have a ${MYARCHNESS} OS"
+	cd $WORKDIR
+}
+
+# Main starts here. First declare a few variables that is required for self check, more declaration after the self check.
+
+WHEREISGRUB="/boot/grub/grub.cfg"
+WORKDIR=$PWD
+MYQEMUIMG=`which qemu-img`
+MYMKSQUASHFS=`which mksquashfs`
+MYUUIDGEN=`which uuidgen`
+MYPARTED=`which parted`
+INPUTIMAGE=
+IMAGENAME=
+PARTNUM=
+
+while getopts "hi:n:p:vu" OPTION
+do
+	case $OPTION in
+	h)
+		usage
+		exit 0
+		;;
+	i)
+		INPUTIMAGE=$OPTARG
+		;;
+	n)
+		IMAGENAME=$OPTARG
+		;;
+	p)
+		PARTNUM=$OPTARG
+		;;
+	v)
+		echo
+		echo "$0: Version ${thisver}"
+		echo "By Jing-Yuan Luke, Written 2011 at MIMOS"
+		echo 
+		exit 0
+		;;
+	u)
+		UPDATE=1
+		;;
+	?)
+		usage
+		exit 1
+		;;
+	esac
+done
+
+if [[ -z $IMAGENAME ]] || [[ -z $INPUTIMAGE ]] 
+then
+     usage
+     exit 1
+fi
+
+MYIMGFILE=$INPUTIMAGE
+if [ ! -f $MYIMGFILE ]
+then
+	echo "Input Image File does not exist!"
+	exit 1
+fi
+
+if zoni -I | grep ${IMAGENAME} &> /dev/null
+then
+	if [[ -n $UPDATE ]]
+	then
+		echo "Image will be updated."
+	else
+		echo "Image is already registered in Zoni! Use -u if you intend to update/refresh the same Image."
+		exit 1
+	fi
+else
+	echo "Image Name OK!"
+fi
+
+echo "Start of Phase 1: Preparing the VM image to squashfs image..."
+echo "Working from ${WORKDIR}..."
+
+# Check for key tools and files, should only run once so check for dummy convertz-selfchecked file first.
+if [ ! -f $HOME/.convertz-selfchecked ]
+then
+	echo "Running Self Check for the first time."
+	self_check
+else
+	echo "Self Check not needed, bypassing it."
+fi
+
+# More variables for the rest of the work
+KIIDS=
+MYVMLINUZ=
+MYINITRD=
+MYVMLINUZ_VER=
+MYINITRD_VER=
+KERN_VERSION=
+MYARCHNESS=
+DIST=
+DIST_VER=
+MYFREELOOPPART=
+MYPID="`echo $$`-`uuidgen -t`"
+MYTEMPDIR="/tmp/convertz-${MYPID}"
+MYTEMPIMG="/tmp/convertz-${MYPID}.img"
+MYDESTFILE="${IMAGENAME}.squashfs"
+LIVEIMAGEDIR="/var/www/liveboot/"
+TFTPBOOTDIR="/var/lib/tftpboot/liveboot/"
+
+# Check image file info and if necessary convert it to raw
+check_img_info
+
+# Check for free loop device and then attach image to the free loop device
+MYFREELOOP=`losetup -f`
+if [ -z $MYFREELOOP ]
+then
+	echo "No more loop devices available."
+	exit 1
+else
+	echo "loop device available: $MYFREELOOP"
+fi
+
+losetup $MYFREELOOP $FORLOOPMNT &> /dev/null
+if [ ! $? == "0" ]
+then
+	echo "Error attaching ${FORLOOPMNT} to ${MYFREELOOP}"
+	clean_tmp
+	exit 1
+else
+	echo "losetup attached successfully."
+fi
+
+# Mount the loop device partition assuming image is created with only 2 partitions else user need to determine themselves but first create a temp dir
+if [ ! -d $MYTEMPDIR ]
+then
+	echo "Create temp folder..."
+	mkdir -p $MYTEMPDIR
+fi
+
+if [ -z $PARTNUM ]
+then
+	check_loop_part
+else
+	MYFREELOOPPART=${MYFREELOOP}p${PARTNUM}
+fi 
+
+if mount "${MYFREELOOPPART}" $MYTEMPDIR &> /dev/null
+then
+	echo "mount ${MYFREELOOPPART} to ${MYTEMPDIR} success."
+else
+	echo "Can't mount ${MYFREELOOPPART} to ${MYTEMPDIR}, please check/recreate your image."
+	umnt_loop
+	exit 1
+fi
+
+# Get some internal info out from the mounted image first, is it ubuntu/debian or something else, check versions of the vmlinuz and initrd as well as OS architecture
+retrieve_img_internals
+
+# Add live packages if necessary
+add_live_package
+
+# Squash the mounted image now, but first clean up /etc/hosts and /etc/hostname
+rm $MYTEMPDIR/etc/hosts &> /dev/null
+rm $MYTEMPDIR/etc/hostname &> /dev/null
+echo "Creating ${MYDESTFILE}, squashing..."
+mksquashfs $MYTEMPDIR $MYDESTFILE -e boot &> /dev/null
+if [ $? == "0" ]
+then
+	echo "mksquashfs done, your ${MYDESTFILE} is ready."
+else
+	echo "Error while squashing, please check and redo."
+	umnt_loop
+	exit 1
+fi
+
+echo "End of Phase 1!"
+echo "Start of Phase 2: Registering to Zoni..."
+KIIDS=`zoni --getKernelInitrdID ${MYVMLINUZ}:${MYINITRD}:${MYARCHNESS}` &> /dev/null
+if [ ! -z $KIIDS ]
+then
+	echo "The kernel and initrd are already registered in Zoni."
+	# To add update feature - need to check the kernel version
+else
+	echo "Registering new kernel and initrd into Zoni..."
+	KIIDS=`zoni --registerKernelInitrd "${MYVMLINUZ}:${KERN_VERSION}:${MYARCHNESS}:${MYINITRD}:${MYARCHNESS}:${MYDESTFILE}"` &> /dev/null
+	echo "Copying new kernel and initrd to tftpboot..."
+	cp $MYTEMPDIR/boot/$MYVMLINUZ $TFTPBOOTDIR
+	cp $MYTEMPDIR/boot/$MYINITRD $TFTPBOOTDIR
+fi
+if [[ -n $UPDATE ]]
+then
+	echo "Updating/Refreshing Image, no registration needed."
+else
+	echo "Registering new live image to Zoni Database..."
+	zoni --addImage "${IMAGENAME}:${DIST}:${DIST_VER}:${KIIDS}"
+fi
+echo "Updating/Moving ${MYDESTFILE} to live image folder..."
+mv $MYDESTFILE $LIVEIMAGEDIR
+#create template for this new image?
+#zoni addpxe here?
+echo "End of Phase 2: unmount, clean temp file/folder and remove loop device..."
+umnt_loop
+echo "All Done!"
+exit 0
diff --git a/src/zoni/extensions/convertz-src/convertz.8 b/src/zoni/extensions/convertz-src/convertz.8
new file mode 100644
index 0000000..99dc2ef
--- /dev/null
+++ b/src/zoni/extensions/convertz-src/convertz.8
@@ -0,0 +1,71 @@
+.\" Process this file with
+.\" groff -man -Tascii convertz.8
+.\"
+.TH convertz 8 "December 2011" convertz "convertz admin manual"
+.SH NAME
+convertz \- A Simple Tool for Converting VM image to Live Image for Zoni
+.SH SYNOPSIS
+.B zoni [-i 
+.I input VM image
+.B ] [-n
+.I live image name
+.B ] [-u
+.I update image
+.B ] [-p
+.I partition number (optional)
+.B ] [-h] [-v]
+.SH DESCRIPTION
+.BI convertz
+is a simple tool that will convert your VM image to a Live Image for Zoni.
+It accepts any VM image formats such as raw, vdi, qcow, etc.
+(generally formats supported by qemu-img), converts it to raw format and
+make all necessary adjustments before converting it a squashfs image. It
+also obtains other information of the image such as the Linux Kernel
+(vmlinuz) and initial ramdisk (initrd.img) before making necessary steps
+to register the information into Zoni and move the necessary files to their
+respective folders.
+.PP
+Currently
+.BI convertz
+only supports full Ubuntu or Debian based VM images (with vmlinuz and initrd.img in
+/boot folder) and it assumes that the VM images file system in Non LVM
+based and only contains a / or root partition and a swap partition.
+.SH OPTIONS
+.IP "-i input VM image"
+The input is the actual VM image that a user wants to convert to live image.
+.IP "-n live image name"
+This is the live image name that will be register into Zoni as well as the 
+name that the converted live image be named (with a .squashfs extension).
+.IP "-u"
+Use this option to update existing Image.
+.IP "-p partition number"
+This is the partition number of the / or root of the VM image. This parameter
+is optional as
+.BI convertz
+will try to detect the partition itself. It is usefull only if the VM image
+has more than 2 partitions during creation of the VM image.
+.IP -h
+Print usage/help information and exit.
+.IP -v
+Print version and exit.
+.SH FILES
+.I convertz
+depends on several other tools in order to perform its task. They are:
+.RS
+zoni, qemu-img, parted, mksquashfs and uuidgen.
+.RE
+.PP
+In addition, it expects the Debian Live Project deb files are compiled
+and prepared. They are:
+.RS
+live-boot, live-config and live-tools
+.RE
+Information on preparing these files are available at http://live.debian.net
+.SH BUGS
+This is still a work in progress. As mentioned earlier,
+.BI convertz
+only supports Ubuntu or Debian based VM images only. A fair amount of steps had been
+added to try to capture any errors as early as possible, any bugs please
+contact the author. Thanks.
+.SH AUTHOR
+Jing-Yuan Luke (jyluke(alias)gmail.com)
diff --git a/src/zoni/extensions/convertz-src/live-boot-support/README b/src/zoni/extensions/convertz-src/live-boot-support/README
new file mode 100644
index 0000000..abe923c
--- /dev/null
+++ b/src/zoni/extensions/convertz-src/live-boot-support/README
@@ -0,0 +1,31 @@
+The files in this folders are Debian Live Packages to support live boot.
+convertz will require these files to be in /var/www/live-boot-support in order
+to inject them into live the image during conversion from VM image.
+
+Debian Live Packages can be found at http://live.debian.net. The necessary
+pakcages are live-boot, live-config and live-tools. As of the preparation of
+this README (21-Feb-2012), the respective version and date for each package is:
+
+- live-boot	3.0~a25-1	17-Feb-2012
+- live-config	3.0~a32-1	17-Feb-2012
+- live-tools	3.0~a6-1	17-Feb-2012
+
+Generally to the deb files are available to download but you can choose to
+rebuild from source (instructions are available from the url listed above).
+
+If you choose to download the deb files instead, here are the ones that you
+will need:
+
+- live-boot
+	- live-boot_<version>_all.deb
+	- live-boot-initramfs-tools_<version>_all.deb
+-live-config
+	- live-config_<version>_all.deb
+	- live-config-upstart_<version>_all.deb
+-live-tools
+	- live-tools_<version>_all.deb
+
+If you decide to try new versions of the deb files, please remember to
+move the ones in this folder to a safe place before downloading the new
+ones here.
+
diff --git a/src/zoni/extensions/install/db/m_extendDbSetup.py b/src/zoni/extensions/install/db/m_extendDbSetup.py
new file mode 100644
index 0000000..c7ab259
--- /dev/null
+++ b/src/zoni/extensions/install/db/m_extendDbSetup.py
@@ -0,0 +1,176 @@
+# 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 os 
+import sys
+import string
+import re
+try:   
+	import MySQLdb
+	import traceback
+	import optparse
+	import getpass
+except ImportError, e:
+	print "Module not installed : %s" % e
+	exit()
+
+import MySQLdb
+import traceback
+import optparse
+import getpass
+
+a = os.path.join("../")
+sys.path.append(a)
+a = os.path.join("../../")
+sys.path.append(a)
+a = os.path.join("../../..")
+sys.path.append(a)
+a = os.path.join("../../../..")
+sys.path.append(a)
+
+from zoni.version import *
+from zoni.extra.util import *
+
+def main():
+	''' This file extends the database for Zoni '''
+
+	ver = version.split(" ")[0]
+	rev = revision
+
+	parser = optparse.OptionParser(usage="prog -u username ", version="prog %s %s" % (ver, rev))
+	parser.add_option("-u", "--userName", "--username", dest="userName", help="Mysql username")
+	parser.add_option("-p", "--password", dest="password", help="Admin mysql password")
+	(options, args) = parser.parse_args()
+
+#	if not options.userName:
+#		parser.print_help()
+#		exit(1)
+
+#	password = options.password
+#	if not options.password:
+#		password = getpass.getpass()
+
+	(configs, configFiles) = getConfig()
+
+#	extendZoniDb(configs, options.userName, password)
+	extendZoniDb(configs)
+	entryExists(configs)
+
+#def extendZoniDb(config, adminUser, adminPassword):
+def extendZoniDb(config):
+	config = config
+	host = config['dbHost']
+	user = config['dbUser']
+#	adminUser = adminUser
+#	adminPassword = adminPassword
+	passwd = config['dbPassword']
+	db = config['dbInst']
+
+	if config['dbPort'] == "":
+		config['dbPort'] = 3306
+
+	port = config['dbPort']
+
+	conn = connectDb(host, port, user, passwd, db)
+	extendTables(conn)
+	conn.commit()
+	conn.close()
+	sys.stdout.write("Finished\n")
+
+def connectDb (host, port, user, passwd, db=None):
+	#  Connect to DB
+	try:
+		if db:
+			conn = MySQLdb.connect(host = host, port = port, user = user , passwd = passwd, db = db)
+		else:
+			conn = MySQLdb.connect(host = host, port = port, user = user , passwd = passwd)
+
+	except MySQLdb.OperationalError, e:
+		if e[0] == 2005:
+			print "ERROR: %s" % str(e[1])
+			exit(1)
+		else:
+			print "Connection Error : ", e
+			exit(1)
+	return conn
+
+def extendTables(conn):
+	sys.stdout.write("    Extend Zoni Database Schema...\n")
+	'''  Create Tables  '''
+	#  Add a new field to hardwareinfo 
+	sys.stdout.write("    Adding new field to hardwareinfo...")
+	execQuery(conn, "ALTER TABLE `hardwareinfo` ADD `hw_blenc` TEXT NULL DEFAULT NULL AFTER `hw_password`")
+	sys.stdout.write("Success\n")
+
+	#  Create rolemap
+	sys.stdout.write("    Creating rolemap...")
+	execQuery(conn, "CREATE TABLE IF NOT EXISTS `rolemap` ( `sys_id` int(11) unsigned NOT NULL, `image_id` int(11) unsigned NOT NULL )") 
+	sys.stdout.write("Success\n")
+
+def execQuery(conn, query):
+	cursor = conn.cursor()
+	try:
+		cursor.execute (query)
+		conn.commit()
+	except MySQLdb.OperationalError, e:
+		sys.stdout.write("Fail\n")
+		msg = "ERROR: %s" % e[1]
+		sys.stderr.write(msg)
+		exit()
+	return cursor
+
+def entryExists(config):
+	config = config
+	host = config['dbHost']
+	user = config['dbUser']
+	passwd = config['dbPassword']
+	db = config['dbInst']
+
+	if config['dbPort'] == "":
+		config['dbPort'] = 3306
+
+	port = config['dbPort']
+
+	conn = connectDb(host, port, user, passwd, db)
+
+	sys.stdout.write("    Checking if hardwareinfo's hw_notes is populated...\n\n")
+	query = "select hw_notes from hardwareinfo where hw_notes is not NULL"
+ 	r = execQuery(conn, query)
+	res = r.fetchall()
+	if len(res) > 0:
+		sys.stdout.write("    Found %d record(s) in hw_notes...\n" % len(res))
+		for i in range(len(res)):
+			print "    %(#)05d\t%(theres)s" % { "#":i+1, "theres":res[i][0] }
+		sys.stdout.write("\n    Please review if the record(s) refer(s) to blade enclosure info. Do you want sync to hw_blenc?\n")
+		ans = raw_input("    Yes? (Any other responce will cancel the sync) ")
+		if re.match(r"[Yy][Ee][Ss]",ans) or re.match(r"[Yy]",ans):
+			sys.stdout.write("\n    I am syncing now...\n")
+			query = "UPDATE hardwareinfo set hw_blenc = hw_notes"
+			r = execQuery(conn, query)
+			for repl in res:
+				query="update hardwareinfo set hw_notes = NULL where hw_notes = '%s'" % repl[0]
+
+				execQuery(conn, query)
+			sys.stdout.write("    Sync and Update Success\n\n")
+		else:
+			sys.stdout.write("\n    Not syncing...\n\n")
+	return 0
+
+
+if __name__ == "__main__":
+    main()
+
diff --git a/src/zoni/extensions/install/pxe/templates/README b/src/zoni/extensions/install/pxe/templates/README
new file mode 100644
index 0000000..0f4ebb6
--- /dev/null
+++ b/src/zoni/extensions/install/pxe/templates/README
@@ -0,0 +1,7 @@
+Files in this folder serve as template for an alternative way of using zoni
+to provision OS into local disk instead of booting of live images.
+
+They are used in conjuction with several additional functions added by MIMOS to
+support OS provisioning and should be if possible copy to
+/var/lib/tfpboot/templates folder or if this is changed then you need to change
+the CUSTOM_TEMPLATES_DIR in the ZoniDefaults.cfg file.
diff --git a/src/zoni/extensions/install/pxe/templates/kickstart b/src/zoni/extensions/install/pxe/templates/kickstart
new file mode 100644
index 0000000..d26c71f
--- /dev/null
+++ b/src/zoni/extensions/install/pxe/templates/kickstart
@@ -0,0 +1,8 @@
+prompt 0
+timeout 1
+default centos_generic
+
+label centos_generic
+	menu label ^CentOS Generic
+	kernel centos-installer/amd64/linux
+	append initrd=centos-installer/amd64/initrd.gz ksdevice=eth0 ks=http://$IMAGEHOST/cgi-bin/bootnode.py?IMGSVR=$IMAGEHOST&NTPSVR=$NTPSVRIP&BOOTTYPE=$ROLE&HDDTYPE=$USEHDDTYPE
diff --git a/src/zoni/extensions/install/pxe/templates/preseed b/src/zoni/extensions/install/pxe/templates/preseed
new file mode 100644
index 0000000..2a36fab
--- /dev/null
+++ b/src/zoni/extensions/install/pxe/templates/preseed
@@ -0,0 +1,8 @@
+prompt 0
+timeout 1
+default ubuntu_generic
+
+label ubuntu_generic
+	menu label ^Ubuntu Generic
+	kernel ubuntu-installer/amd64/linux
+	append vga=normal locale=en_US setup/layoutcode=en_US console-setup/layoutcode=us initrd=ubuntu-installer/amd64/initrd.gz preseed/url=http://$IMAGEHOST/cgi-bin/bootnode.py?IMGSVR=$IMAGEHOST&NTPSVR=$NTPSVRIP&BOOTTYPE=$ROLE&HDDTYPE=$USEHDDTYPE netcfg/choose_interface=eth0 netcfg/get_hostname="" -- quiet
diff --git a/src/zoni/extensions/install/www/README b/src/zoni/extensions/install/www/README
new file mode 100644
index 0000000..0c99a5d
--- /dev/null
+++ b/src/zoni/extensions/install/www/README
@@ -0,0 +1,12 @@
+The files in here are to demo using zoni (with some additional
+changes/extensions) to support direct OS provisioning into local disk
+as suppose to using live images that zoni is doing now.
+
+The files bootnode.py, getnpass.py, kickstart and preseed are to be
+copied to /usr/lib/cgi-bin/ assuming we are dealing with Apache 
+running in Ubuntu. The preseed and kickstart as just samples and would
+need to be tweaked.
+
+It is also necessary that a proper Ubuntu and/or CentOS repositor is
+setup and served via Apache as the preseed and kickstart are setup
+to install the OS via HTTP.
diff --git a/src/zoni/extensions/install/www/bootnode.py b/src/zoni/extensions/install/www/bootnode.py
new file mode 100644
index 0000000..f21ff12
--- /dev/null
+++ b/src/zoni/extensions/install/www/bootnode.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+
+# 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 os
+import sys
+import cgi, cgitb
+import getnpass
+
+#sys.path.append('/opt/tashi/tashi/branches/zoni-dev/trunk/src')
+#from zoni.extra.util import *
+#(configs, configFiles) = getConfig()
+
+inputpara = cgi.FieldStorage()
+
+imgsvrip = inputpara.getvalue('IMGSVR')
+ntpsvrip = inputpara.getvalue('NTPSVR')
+starttemplate = inputpara.getvalue('BOOTTYPE')
+hddtype = inputpara.getvalue('HDDTYPE')
+
+print "Content-type: text/plain\r\n"
+
+getnpass.parse_n_print(imgsvrip,ntpsvrip,starttemplate,hddtype)
+
diff --git a/src/zoni/extensions/install/www/getnpass.py b/src/zoni/extensions/install/www/getnpass.py
new file mode 100644
index 0000000..3274294
--- /dev/null
+++ b/src/zoni/extensions/install/www/getnpass.py
@@ -0,0 +1,31 @@
+# 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 os
+
+def parse_n_print(imgsvrip,ntpsvrip,starttype,hddtype):
+    sfile = open(starttype,'r')
+    if (hddtype == "cciss"):
+        hdd = "/dev/cciss/c0d0"
+    elif (hddtype == "normal"):
+        hdd = "/dev/sda"
+    for lines in sfile.readlines():
+        lines = lines.replace("$IMGSVR",imgsvrip)
+        lines = lines.replace("$NTPSVR",ntpsvrip)
+        lines = lines.replace("$HARDDISKTYPE",hdd)
+        print lines,
+    sfile.close()
diff --git a/src/zoni/extensions/install/www/kickstart b/src/zoni/extensions/install/www/kickstart
new file mode 100644
index 0000000..c2e496d
--- /dev/null
+++ b/src/zoni/extensions/install/www/kickstart
@@ -0,0 +1,45 @@
+# Kickstart file automatically generated by anaconda.
+
+install
+url --url=http://$IMGSVR/centos6/
+lang en_US.UTF-8
+keyboard us
+#xconfig --startxonboot --resolution=800x600
+network --device eth0 --bootproto dhcp
+rootpw --iscrypted $6$Pkyc0snA$59/9Iy8DcYuXdWbmBb7SkQLzy0YXmgc3IEaA4Qqh/cC2YqEKUyllkuCHQZ1X8/w5tWPxopMUb7ZYqmysYtu6l1
+firewall --enabled --port=22:tcp
+authconfig --enableshadow --enablemd5
+selinux --permissive
+timezone --utc Asia/Kuala_Lumpur
+bootloader --location=mbr --driveorder=hda,sda --append="rhgb quiet"
+# The following is the partition information you requested
+# Note that any partitions you deleted are not expressed
+# here so unless you clear all partitions first, this is
+# not guaranteed to work
+clearpart --all
+part /boot --fstype ext3 --size=100
+part swap --size=512
+part / --fstype ext3 --size=100 --grow
+
+%packages
+@Base
+@Core
+@text-internet
+#dhcp
+#virt-manager
+python
+libvirt
+libvirt-devel
+curl
+curl-devel
+kvm
+ruby
+
+%post --log=/root/post-log
+/bin/mkdir /srv
+/bin/mkdir /srv/cloud
+#/bin/mkdir /srv/cloud/one
+#/bin/mkdir /srv/cloud/images
+/usr/sbin/groupadd cloud
+/usr/sbin/useradd -d /srv/cloud/one -g cloud -m oneadmin
+reboot
diff --git a/src/zoni/extensions/install/www/preseed b/src/zoni/extensions/install/www/preseed
new file mode 100644
index 0000000..1babd02
--- /dev/null
+++ b/src/zoni/extensions/install/www/preseed
@@ -0,0 +1,56 @@
+d-i debian-installer/locale string en_US
+#d-i console-tools/archs skip-config
+#d-i console-setup/ask_detect boolean false
+#d-i console-setup/layoutcode string us
+#d-i console-keymaps-at/keymap select us
+d-i clock-setup/utc boolean true
+d-i clock-setup/ntp-server string $NTPSVR
+d-i time/zone string US/Eastern
+
+d-i clock-setup/ntp boolean true
+
+d-i netcfg/choose_interface select eth0
+
+d-i mirror/country string manual
+d-i mirror/http/hostname string $IMGSVR
+d-i mirror/http/directory string /ubuntu/
+d-i mirror/http/proxy string
+
+d-i partman-lvm/device_remove_lvm boolean true
+d-i partman-md/device_remove_md boolean true
+d-i partman-lvm/confirm boolean true
+
+d-i partman-auto/disk string $HARDDISKTYPE
+d-i partman-auto/method string regular 
+
+d-i partman-auto/expert_recipe string                        \
+      boot-root ::                                           \
+             1024 100000 1000000000 ext4                     \
+                      $primary{ } $bootable{ }               \
+                      method{ format } format{ }             \
+                      use_filesystem{ } filesystem{ ext4 }   \
+                      mountpoint{ / }                        \
+             .                                               \
+             512 1024 200% linux-swap                        \
+                      method{ swap } format{ }               \
+             .
+
+d-i partman/confirm_write_new_label boolean true
+d-i partman/choose_partition select finish
+d-i partman/confirm boolean true
+
+d-i passwd/root-login boolean false
+d-i passwd/make-user boolean true
+
+d-i passwd/user-fullname string Open Nebula Admin
+d-i passwd/username string oneadmin
+d-i passwd/user-password-crypted password $6$iHvfQ5lt$TfCxCSnAvjtYGofvKRy1c07Fe/kZ8dHhqU14AMDiEky5AFEa3lG33jsWQGSGWaf9GdwWsEuw37DaXGuxxQmCP0
+d-i user-setup/encrypt-home boolean false
+
+tasksel tasksel/first multiselect openssh-server
+d-i pkgsel/install-language-support boolean false
+d-i pkgsel/update-policy select none
+
+d-i grub-installer/only_debian boolean true
+d-i grub-installer/with_other_os boolean true
+d-i finish-install/reboot_in_progress note
diff --git a/src/zoni/extensions/m_extensions.py b/src/zoni/extensions/m_extensions.py
new file mode 100644
index 0000000..de5c578
--- /dev/null
+++ b/src/zoni/extensions/m_extensions.py
@@ -0,0 +1,256 @@
+# 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 os
+import sys
+import string
+import re
+import logging
+import string
+import MySQLdb
+
+# m_extensions - This file is created to cater for a different kind of 
+# requirement in MIMOS Lab. Instead of PXE boot images, MIMOS Lab customize
+# Zoni to PXE boot the servers to install a functional OS and relevant packages
+# into their respective local storage using preseed (Ubuntu/Debian) or 
+# kickstart (Centos/Redhat). It is also serve as a file for testing additional
+# codes for the convertz script.
+# Revised Version: 20111202
+
+from zoni.data.infostore import InfoStore
+
+class mimos(InfoStore):
+	def __init__(self, config):
+		self.config = config
+		self.host = config['dbHost']
+		self.user = config['dbUser']
+		self.passwd = config['dbPassword']
+		self.db = config['dbInst']
+		self.port = config['dbPort']
+		self._isDb = 1
+		if self.port == "":
+			self.port = 3306
+		self.log = logging.getLogger(__name__)
+
+		self.conn = self.createConn()
+
+	def createConn(self):
+		try:
+			return MySQLdb.connect(host = self.host, port = self.port, user = self.user, passwd = self.passwd, db = self.db)
+		except MySQLdb.OperationalError, e:
+			msg = "Error: %s" % str(e[1])
+			self.log.error(msg)
+			return
+
+	def keepAlive(self):
+		while True:
+			if not self.conn.open:
+				msg = "Reinitializing DB connection"
+				self.log.info(msg)
+				self.conn - self.createConn()
+			time.sleep(10)
+		return
+
+	def getConfig(self, configs, theconfig):
+		print configs[theconfig]
+		return
+
+	def getDestFile(self, configs, host):
+		therole = ("%s/01-%s" % (configs['tftpImageDir'], (host['mac_addr']).replace(":", "-").lower())
+		return therole
+
+	def addRoletoNode(self, configs, host, thenode, roletemplate):
+		therole = ("%s/01-%s" % (configs['tftpImageDir'], (host['mac_addr']).replace(":", "-").lower())
+		self.log.info("Roles: addRole for %s" % thenode)
+		srctpl = "%s/%s" % (configs['tftpTemplateDir'], roletemplate)
+		if os.path.isfile(therole):
+			mesg = "Roles: Role file exists! Exiting!"
+			self.log.error(mesg)
+			exit()
+		if not os.path.isfile(srctpl):
+			mesg = "Roles: Role template missing! Exiting!"
+			self.log.error(mesg)
+			exit()
+		#shutil.copy(srctpl,therole) #this is direct copy approach, template is not customized, retained here just in case we still need it
+		#read and parse srctpl and write to therole, trying to be a bit more flexible from here on
+		infile = open(srctpl,'r')
+		outfile = open(therole,'w')
+		# Use sys_vendor to determine HDD Type, HP servers use the /dev/cciss/c0d0 form for their storage device
+		if (host['sys_vendor'] == "HP"):
+			hddtype = "cciss"
+		else: # Most other vendors just use standard /dev/sdxy form for storage device
+			hddtype = "normal"
+		for line in infile.readlines():
+			line = line.replace("$IMAGEHOST",configs['imageServerIP'])
+			line = line.replace("$NTPSVRIP",configs['ntpsvrIP'])
+			line = line.replace("$ROLE",roletemplate)
+			line = line.replace("$USEHDDTYPE",hddtype)
+			outfile.write(line)
+		infile.close()
+		outfile.close()
+		self.log.info("Roles: %s created" % therole)
+		return 0
+
+	def removeRolefromNode(self, configs, host, thenode):
+		therole = ("%s/01-%s" % (configs['tftpImageDir'], (host['mac_addr']).replace(":", "-").lower())
+		self.log.info("Roles: removeRole for %s" % thenode)
+		if not os.path.isfile(therole):
+			mesg = "No Role File for %s! Exiting!" % thenode
+			log.error(mesg)
+			exit()
+		os.remove(therole)
+		self.log.info("Roles: %s removed" % therole)
+		return 0
+
+	# This is a temp workaround instead of using assignImagetoHost
+	# A new temp table rolemap added to support this but should merge back to imagemap
+	def assignRoletoHost(self, host, image):
+		cur_image = host['pxe_image_name']
+		query = "select image_id from imageinfo where image_name = '%s'" % image
+		row = self.queryDb(query)
+		if len(row) < 1:
+			mesg = "assignRoletoHost: Image \"%s\" does not exist in db" % image
+			self.log.error(mesg)
+			return 1
+		new_image_id = str(row[0][0])
+		query = "select * from rolemap where sys_id = '%s'" % host['sys_id']
+		result = self.selectDb(query)
+		if result.rowcount > 0:
+			mesg = "assignRoletoHost: detected assigned role - removing from db first"
+			self.log.info(mesg)
+			query = "delete from rolemap where sys_id = '%s'" % host['sys_id']
+			self.delDb(query)
+		query = "insert into rolemap (sys_id, image_id) values ('%s', %s)" % (host['sys_id'], new_image_id)
+		self.insertDb(connection,query)
+		return 0
+
+	def unassignRolefromHost(self, host):
+		query="delete from rolemap where sys_id = '%s'" % str(host['sys_id'])
+		self.delDb(query)
+		return 0
+
+	def showRoletoHost(self):
+		query="select s.location, s.mac_addr, i.image_name from sysinfo s, imageinfo i, rolemap r where r.image_id=i.image_id and r.sys_id=s.sys_id order by s.location"
+		rows = self.queryDb(connection,query)
+		print "Node                 MAC Address       Image Name"
+		for row in rows:
+			print "%-20s %-17s %-30s" % (row[0],row[1],row[2])
+		return 0
+
+	def showKernelInfo(self):
+		query="select k.kernel_id, k.kernel_name, k.kernel_release, k.kernel_arch from kernelinfo k"
+		rows = self.queryDb(query)
+		print "Available Kernels"
+		print "ID  Name                           Release           Arch"
+		for row in rows:
+			kid=row[0]
+			kname=row[1]
+			krelease=row[2]
+			karch=row[3]
+			print "%-3s %-30s %-17s %-6s" % (kid, kname, krelease, karch)
+		return 0
+
+	def showInitrdInfo(self):
+		query="select i.initrd_id, i.initrd_name, i.initrd_arch from initrdinfo i"
+		rows = self.queryDb(query)
+		print 
+		print "Available Initial Ramdisks"
+		print "ID  Name                           Arch"
+		for row in rows:
+			iid=row[0]
+			iname=row[1]
+			iarch=row[2]
+			print "%-3s %-30s %-6s" % (iid, iname, iarch)
+		print
+		return 0
+
+	def getKernelInitrdID(self, info):
+		kernel_name = info.split(":")[0]
+		initrd_name = info.split(":")[1]
+		kernel_arch = info.split(":")[2]
+
+		query = "select k.kernel_id, i.initrd_id from kernelinfo k, initrdinfo i where k.kernel_name='%s' and i.initrd_name='%s' and k.kernel_arch='%s' and i.initrd_arch='%s'" % (kernel_name, initrd_name, kernel_arch, kernel_arch)
+		rows=self.queryDb(query)
+		if len(rows) > 0:
+			for row in rows:
+				kid=str(row[0])
+				iid=str(row[1])
+				print "%s:%s" % (kid, iid)
+		return 0
+
+	def registerKernelInitrd(self, configs, info):
+		foo = info.split(":")
+		kernel_name = foo[0]
+		kernel_release = foo[1]
+		kernel_arch = foo[2]
+		initrd_name = foo[3]
+		initrd_arch = foo[4]
+		kernel_something = foo[5]
+
+		initrd_options = "boot=live toram nopersistent fetch=http://%s/%s/%s initrd=%s/%s" % (configs['imageServerIP'], configs['fsImagesBaseDir'], kernel_something, configs['initrdRoot'], initrd_name)
+
+		query = "insert into kernelinfo (kernel_name, kernel_release, kernel_arch) values ('%s', '%s', '%s)" % (kernel_name, kernel_release, kernel_arch)
+		k_id=self.insertDb(query)
+		query = "insert into initrdinfo (initrd_name, initrd_arch, initrd_options) values ('%s', '%s', '%s')" % (initrd_name, initrd_arch, initrd_options)
+		i_id=self.insertDb(query)
+		print "%s:%s" % (k_id, i_id)
+		return 0
+
+	def queryDb(self, thequery):
+		self.conn.ping(True)
+		cursor=self.conn.cursor()
+		try:
+			cursor.execute(thequery)
+			self.conn.commit()
+			row=cursor.fetchall()
+		except MySQLdb.OperationalError, e:
+			self.log.error("queryDb - %s", e)
+			return -1
+		return row
+
+	def selectDb(self, thequery):
+		self.conn.ping(True)
+		cursor=self.conn.cursor()
+		try:
+			cursor.execute(thequery)
+			self.conn.commit()
+		except MySQLdb.OperationalError, e:
+			self.log.error("selectDb - %s", e)
+			return -1
+		return cursor
+
+	def insertDb(self, thequery):
+		self.conn.ping(True)
+		cursor=self.conn.cursor()
+		try:
+			cursor.execute(thequery)
+			self.conn.commit()
+		except MySQLdb.OperationalError, e:
+			self.log.error("insertDb - %s", e)
+			return -1
+		return cursor.lastrowid
+
+	def delDb(self, thequery):
+		self.conn.ping(True)
+		cursor=self.conn.cursor()
+		try:
+			cursor.execute(thequery)
+			self.conn.commit()
+		except MySQLdb.OperationalError, e:
+			self.log.error("delDb - %s", e)
+			return -1
+		return cursor
diff --git a/src/zoni/extra/util.py b/src/zoni/extra/util.py
index a824a54..0381823 100644
--- a/src/zoni/extra/util.py
+++ b/src/zoni/extra/util.py
@@ -63,6 +63,10 @@
 	config['initrdRoot'] = parser.get("pxe", "INITRD_ROOT").split()[0]
 	config['kernelRoot'] = parser.get("pxe", "KERNEL_ROOT").split()[0]
 
+	# Extensions from MIMOS
+	config['ntpsvrIP'] = parser.get("pxe", "NTPSVR").split()[0] # NTP Server IP Address Support
+	config['tftpTemplateDir'] = parser.get("pxe", "CUSTOM_TEMPLATES_DIR") # Custom Templates for Disk Image
+
 	#  Image store
 	config['imageServerIP'] = parser.get("imageStore", "IMAGE_SERVER_IP").split()[0]
 	config['fsImagesBaseDir'] = parser.get("imageStore", "FS_IMAGES_BASE_DIR").split()[0]
@@ -107,7 +111,8 @@
 	"""Creates many permutations of a list of locations to look for config 
 	   files and then loads them"""
 	config = ConfigParser.ConfigParser()
-	baseLocations = ['./etc/', '/usr/share/zoni/', '/etc/zoni/', os.path.expanduser('~/.zoni/')]
+	# added /usr/local/tashi/etc - MIMOS
+	baseLocations = ['./etc/', '/usr/share/zoni/', '/usr/local/tashi/etc/', '/etc/zoni/', os.path.expanduser('~/.zoni/')]
 	names = ['Zoni'] + additionalNames
 	names = reduce(lambda x, y: x + [y+"Defaults", y], names, [])
 	allLocations = reduce(lambda x, y: x + reduce(lambda z, a: z + [y + a + ".cfg"], names, []), baseLocations, []) + additionalFiles
diff --git a/src/zoni/hardware/hpilo.py b/src/zoni/hardware/hpilo.py
index d6c87f0..b02a1ec 100644
--- a/src/zoni/hardware/hpilo.py
+++ b/src/zoni/hardware/hpilo.py
@@ -23,13 +23,10 @@
 import time
 
 from systemmanagementinterface import SystemManagementInterface
-
-
-#class systemmagement():
-	#def __init__(self, proto):
-		#self.proto = proto
+from zoni.extra.util import timeF, log
 
 #XXX  Need to add more error checking!
+#XXX  Need to consider difference in responses between a rackmount server and a blade server - MIMOS
 
 def log(f):
 	def myF(*args, **kw):
@@ -52,15 +49,19 @@
 
 
 class hpILo(SystemManagementInterface):
-	def __init__(self, host):
-		self.hostname = host['location']
-		self.host = host['ilo_name']
+	def __init__(self, config, nodeName, hostInfo):
+		self.config = config
+		self.nodename = nodeName
+		self.hostname = hostInfo['location']
+		## Need to add in checking to differentiate between rackmount and blade server
+		#self.host = host['ilo_name']
+		self.host = hostInfo['ilo_enclosure']
 		self.user = host['ilo_userid']
 		self.password = host['ilo_password']
 		self.port = host['ilo_port']
 		self.powerStatus = None
 		self.verbose = 0
-		#self.server = "Server-" + str(self.port)
+		self.log = logging.getLogger(__name__)
 
 	def setVerbose(self, verbose):
 		self.verbose = verbose
@@ -83,7 +84,7 @@
 			i=child.expect(['>', 'please try again.', pexpect.EOF, pexpect.TIMEOUT])
 		else:
 			mesg = "Error"
-			sys.stderr.write(mesg)
+			self.log.error(mesg)
 			exit(1)
 
 		if i == 1:
@@ -99,7 +100,6 @@
 
 
 	@timeF
-	@log
 	def getPowerStatus(self):
 		child = self.__login()
 		cmd = "show server status " + str(self.port)
@@ -115,7 +115,7 @@
 			mesg = self.hostname + " Power is off\n\n"
 			self.powerStatus = 0
 
-		sys.stdout.write(mesg)
+		self.log.info(mesg)
 
 		child.close()
 		child.terminate()
@@ -128,7 +128,6 @@
 			return 1;
 		if not self.powerStatus:
 			return 0;
-	
 
 	@timeF
 	def powerOn(self):
@@ -148,7 +147,28 @@
 			mesg = self.hostname + " Power On\n\n"
 		else:
 			mesg = self.hostname + " Power On Fail\n\n"
-		sys.stdout.write(mesg)
+		self.log.info(mesg)
+		child.sendline("quit")
+		child.terminate()
+
+	@timeF
+	def powerOnNet(self):
+		if self.powerStatus == 1:
+			mesg = self.hostname + " Power On\n\n"
+			exit(1)
+
+		child = self.__login()
+		cmd = "poweron server " + str(self.port) + " PXE"
+		child.sendline(cmd)
+		val = child.readline()
+		while "Powering" not in val and "powered" not in val:
+			val = child.readline()
+
+		if "Powering" in val or "already" in val:
+			mesg = self.hostname + " Power On\n\n"
+		else:
+			mesg = self.hostname + " Power On Fail\n\n"
+		self.log.info(mesg)
 		child.sendline("quit")
 		child.terminate()
 
@@ -166,7 +186,7 @@
 		else:
 			mesg = self.hostname + " Power Off Fail\n\n"
 
-		sys.stdout.write(mesg)
+		self.log.info(mesg)
 		child.sendline("quit")
 		child.terminate()
 
@@ -186,7 +206,7 @@
 		mesg = self.hostname + " Power Reset\n\n"
 		#else:
 			#mesg = self.hostname + " Power Reset Fail\n\n"
-		sys.stdout.write(mesg)
+		self.log.info(mesg)
 		child.sendline("quit")
 		child.terminate()
 		
diff --git a/src/zoni/hardware/systemmanagementinterface.py b/src/zoni/hardware/systemmanagementinterface.py
index 3d24361..0d7901b 100644
--- a/src/zoni/hardware/systemmanagementinterface.py
+++ b/src/zoni/hardware/systemmanagementinterface.py
@@ -63,7 +63,8 @@
 		'''  register hardware to zoni'''
 		raise NotImplementedError
 
-
-
-
+	# Extensions from MIMOS - specific to HP Blade via c7000 Blade Enclosure
+	def powerOnNet(self):
+		''' Power HP Blade Server directly from PXE '''
+		raise NotImplementedError