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