Joey Boggs
2009-Sep-14 21:43 UTC
[Ovirt-devel] [PATCH node-image] add livecd-iso-to-iscsi script to support iscsi root booting setup
This enables the ability to take the ovirt-node-image iso and deploy it to an iscsi disk. It also provides a sample pxe configuration for booting based on the iscsi root device. Includes support for user/password as well as reverse chap user/password. --- Makefile.am | 1 + livecd-iso-to-iscsi | 201 ++++++++++++++++++++++++++++++++++++++++++++++ ovirt-node-image.spec.in | 2 + 3 files changed, 204 insertions(+), 0 deletions(-) create mode 100755 livecd-iso-to-iscsi diff --git a/Makefile.am b/Makefile.am index a44ae49..d920813 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,7 @@ EXTRA_DIST = \ $(PACKAGE).ks \ create-ovirt-iso-nodes \ edit-livecd \ + livecdiso-to-iscsi \ livecd-setauth \ livecd-rpms \ README diff --git a/livecd-iso-to-iscsi b/livecd-iso-to-iscsi new file mode 100755 index 0000000..fd3934d --- /dev/null +++ b/livecd-iso-to-iscsi @@ -0,0 +1,201 @@ +#!/usr/bin/python +# Convert a live CD iso into iscsi root bootable format +# iSCSI lun must be accessible via this script +# Copyright 2009 Red Hat, Inc. +# Written by Joey boggs <jboggs at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from optparse import OptionParser +from tempfile import mkdtemp +import dbus +import dbus.glib +import sys +import os +import subprocess +import shutil + +parser = OptionParser() +parser.add_option("--iso", dest="iso", help="LiveCD iso filename") +parser.add_option("--target", dest="target", help="iSCSI target ip address") +parser.add_option("--targetname", dest="targetname", help="iSCSI target lun") +parser.add_option("--targetport", dest="targetport", default="3260", help="iSCSI port number, defaults to 3260") +parser.add_option("--user", dest="user", help="Target username(optional)") +parser.add_option("--password", dest="password", help="Target password") +parser.add_option("--reverse_user", dest="reverse_user", help="Reverse CHAP username(optional)") +parser.add_option("--reverse_password", dest="reverse_password", help="Reverse CHAP password(optional)") +parser.add_option("--disk", dest="disk", help="iSCSI disk device name") +parser.add_option("--disk-label", dest="disk_label", default="ovirt-node-root", help="file system label") + +(options, args) = parser.parse_args() + +def fail(msg): + print(msg) + sys.exit(1) + +if os.geteuid () != 0: + fail("You must run as root") + +if options.iso is None: + fail("ERROR: iso file must be defined") +else: + options.iso = os.path.abspath(options.iso) + +if options.target is None: + fail("ERROR: iscsi target must be defined") + +if options.targetname is None: + fail("ERROR: iscsi targetname must be defined") + +if len(options.disk_label.strip()) > 15: + fail("ERROR: disk label must be 14 characters or less") + +try: + file = os.mkdir("tftpboot") +except OSError, e: + tftp_remove = raw_input("tftpboot directory exists, overwrite? (y/N)? ") + if tftp_remove.lower() == "y": + shutil.rmtree("tftpboot") + os.mkdir("tftpboot") + else: + print "Aborting" + sys.exit(1) + +if options.disk is None: + print "Below are the detected disks, if the iscsi disk is not shown, please ensure you are logged into the correct target\n" + bus = dbus.SystemBus () + hal_obj = bus.get_object ('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager') + hal = dbus.Interface (hal_obj, 'org.freedesktop.Hal.Manager') + udis = hal.FindDeviceByCapability ('storage') + dev_dict = {} + dev_count = 1 + for udi in udis: + dev_obj = bus.get_object ('org.freedesktop.Hal', udi) + dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device') + dev_bus=dev.GetProperty ('storage.bus') + dev_name=dev.GetProperty ('block.device') + dev_size=dev.GetProperty ('storage.size') + dev_size=(dev_size/1024/1024) + basename=os.path.basename(udi) + if dev_bus == "scsi": + print "%s. %s %sM %s \n" % (dev_count,dev_name,dev_size,basename) + dev_dict[str(dev_count)] = dev_name + dev_count = dev_count + 1 + print "Enter Q to Quit" + dev_choice = raw_input("Which device? ") + while not dev_dict.has_key(dev_choice): + if dev_choice.lower() == "q": + print "Aborting" + sys.exit(1) + else: + print "%s is an invalid choice" % dev_choice + dev_choice = raw_input("Which device? ") + options.disk = dev_dict[dev_choice] + +cont = raw_input("Creating file system on %s, do you wish to continue (y/N) " % options.disk) +if cont.lower() != "y": + print "Aborting" + sys.exit(1) + +isomount = mkdtemp() +isomount_ret = subprocess.call(["mount", "-o", "loop", options.iso, isomount]) +if isomount_ret != 0: + fail("Error mounting %s" % options.iso) + +kernel="%s/isolinux/vmlinuz0" % isomount +initrd="%s/isolinux/initrd0.img" % isomount +squashfs="%s/LiveOS/squashfs.img" % isomount +ext3fs="tftpboot/squashfs-root/LiveOS/ext3fs.img" +shutil.copy(kernel,"tftpboot") +shutil.copy(initrd,"tftpboot") + +unsquash = subprocess.call(["unsquashfs", squashfs]) + +# workaround until bug is fixed with squashfs -d option +shutil.move("squashfs-root","tftpboot/squashfs-root") + +print "Placing embedded file system on %s" % options.disk +dd_cmd="dd if=%s of=%s" % (ext3fs,options.disk) +copy_iscsi_ret = subprocess.call(dd_cmd, shell=True) +if copy_iscsi_ret != 0: + fail("Error copying to %s" % options.disk) + +umount_ret = subprocess.call(["umount", isomount]) +if umount_ret != 0: + fail("Error unmounting %s, continuing" % isomount) +else: + os.rmdir(isomount) +shutil.rmtree("tftpboot/squashfs-root") + +pxe_template = """ + +# pxelinux configuration. +DEFAULT pxeboot +TIMEOUT 20 +PROMPT 0 +LABEL ovirt-node-iscsi + KERNEL /vmlinuz0 + APPEND initrd=/initrd0.img ro root=LABEL=%(disk_label)s netroot=iscsi:%(user)s%(password)s@%(target)s::%(target_port)s::%(target_name)s ip=eth0:dhcp + ipappend 2 +ONERROR LOCALBOOT 0 +""" + +# insert empty values for unneeded variables in the pxe template +if not options.user is None: + options.user = options.user + ":" +else: + options.user = "" + +if not options.password is None: + options.password = options.password + ":" +else: + options.password = "" + +if not options.reverse_user is None: + options.reverse_user = options.reverse_user + ":" +else: + options.reverse_user = "" + +if not options.reverse_password is None: + options.reverse_password = options.reverse_password + ":" +else: + options.reverse_password = "" + +os.mkdir("tftpboot/pxelinux.cfg") +pxe_cfg = pxe_template % { + "disk_label": options.disk_label, + "target": options.target, + "target_port": options.targetport, + "target_name": options.targetname, + "user": options.user, + "password": options.password, + "reverse_user": options.reverse_user, + "reverse_password": options.reverse_password + } + +pxe_conf = open("tftpboot/pxelinux.cfg/default", 'w') +pxe_conf.write(pxe_cfg) +pxe_conf.close() + +if os.path.exists("/usr/share/syslinux/pxelinux.0"): + shutil.copy("/usr/share/syslinux/pxelinux.0","tftpboot") +elif os.path.exists("/usr/lib/syslinux/pxelinux.0"): + shutil.copy("/usr/lib/syslinux/pxelinux.0","tftpboot") +else: + print "Warning: You need to add pxelinux.0 to tftpboot/ subdirectory" + +print "Your iscsiroot has been setup on %s" % options.disk +print "" +print "Copy the tftpboot/ subdirectory to your tftpserver root directory" +print "Set up your DHCP, TFTP and PXE server to serve /tftpboot/.../pxeboot.0" diff --git a/ovirt-node-image.spec.in b/ovirt-node-image.spec.in index e64f4de..1f8c31b 100644 --- a/ovirt-node-image.spec.in +++ b/ovirt-node-image.spec.in @@ -65,6 +65,7 @@ mkdir %{buildroot} %{__install} -d -m0755 %{buildroot}%{_sbindir} %{__install} -p -m0755 create-ovirt-iso-nodes %{buildroot}%{_sbindir} %{__install} -p -m0755 edit-livecd %{buildroot}%{_sbindir} +%{__install} -p -m0755 livecd-iso-to-iscsi %{buildroot}%{_sbindir} %{__install} -p -m0755 livecd-setauth %{buildroot}%{_sbindir} %{__install} -p -m0755 livecd-rpms %{buildroot}%{_sbindir} %{__tar} -xf %{image_manifests} -C %{buildroot}%{app_root} @@ -94,6 +95,7 @@ cobbler sync > /dev/null 2>&1 || : %defattr(0755,root,root,0755) %{_sbindir}/create-ovirt-iso-nodes %{_sbindir}/edit-livecd +%{_sbindir}/livecd-iso-to-iscsi %{_sbindir}/livecd-setauth %{_sbindir}/livecd-rpms -- 1.6.2.5
Joey Boggs
2009-Sep-15 02:34 UTC
[Ovirt-devel] Re: [PATCH node-image] add livecd-iso-to-iscsi script to support iscsi root booting setup
ignore this version, theres a typo in Makefile.am causing the build to fail
Joey Boggs
2009-Sep-15 02:35 UTC
[Ovirt-devel] [PATCH node-image] add livecd-iso-to-iscsi script to support iscsi root booting setup
This enables the ability to take the ovirt-node-image iso and deploy it to an iscsi disk. It also provides a sample pxe configuration for booting based on the iscsi root device. Includes support for user/password as well as reverse chap user/password. --- Makefile.am | 1 + livecd-iso-to-iscsi | 201 ++++++++++++++++++++++++++++++++++++++++++++++ ovirt-node-image.spec.in | 2 + 3 files changed, 204 insertions(+), 0 deletions(-) create mode 100755 livecd-iso-to-iscsi diff --git a/Makefile.am b/Makefile.am index a44ae49..306f49f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,7 @@ EXTRA_DIST = \ $(PACKAGE).ks \ create-ovirt-iso-nodes \ edit-livecd \ + livecd-iso-to-iscsi \ livecd-setauth \ livecd-rpms \ README diff --git a/livecd-iso-to-iscsi b/livecd-iso-to-iscsi new file mode 100755 index 0000000..fd3934d --- /dev/null +++ b/livecd-iso-to-iscsi @@ -0,0 +1,201 @@ +#!/usr/bin/python +# Convert a live CD iso into iscsi root bootable format +# iSCSI lun must be accessible via this script +# Copyright 2009 Red Hat, Inc. +# Written by Joey boggs <jboggs at redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from optparse import OptionParser +from tempfile import mkdtemp +import dbus +import dbus.glib +import sys +import os +import subprocess +import shutil + +parser = OptionParser() +parser.add_option("--iso", dest="iso", help="LiveCD iso filename") +parser.add_option("--target", dest="target", help="iSCSI target ip address") +parser.add_option("--targetname", dest="targetname", help="iSCSI target lun") +parser.add_option("--targetport", dest="targetport", default="3260", help="iSCSI port number, defaults to 3260") +parser.add_option("--user", dest="user", help="Target username(optional)") +parser.add_option("--password", dest="password", help="Target password") +parser.add_option("--reverse_user", dest="reverse_user", help="Reverse CHAP username(optional)") +parser.add_option("--reverse_password", dest="reverse_password", help="Reverse CHAP password(optional)") +parser.add_option("--disk", dest="disk", help="iSCSI disk device name") +parser.add_option("--disk-label", dest="disk_label", default="ovirt-node-root", help="file system label") + +(options, args) = parser.parse_args() + +def fail(msg): + print(msg) + sys.exit(1) + +if os.geteuid () != 0: + fail("You must run as root") + +if options.iso is None: + fail("ERROR: iso file must be defined") +else: + options.iso = os.path.abspath(options.iso) + +if options.target is None: + fail("ERROR: iscsi target must be defined") + +if options.targetname is None: + fail("ERROR: iscsi targetname must be defined") + +if len(options.disk_label.strip()) > 15: + fail("ERROR: disk label must be 14 characters or less") + +try: + file = os.mkdir("tftpboot") +except OSError, e: + tftp_remove = raw_input("tftpboot directory exists, overwrite? (y/N)? ") + if tftp_remove.lower() == "y": + shutil.rmtree("tftpboot") + os.mkdir("tftpboot") + else: + print "Aborting" + sys.exit(1) + +if options.disk is None: + print "Below are the detected disks, if the iscsi disk is not shown, please ensure you are logged into the correct target\n" + bus = dbus.SystemBus () + hal_obj = bus.get_object ('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager') + hal = dbus.Interface (hal_obj, 'org.freedesktop.Hal.Manager') + udis = hal.FindDeviceByCapability ('storage') + dev_dict = {} + dev_count = 1 + for udi in udis: + dev_obj = bus.get_object ('org.freedesktop.Hal', udi) + dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device') + dev_bus=dev.GetProperty ('storage.bus') + dev_name=dev.GetProperty ('block.device') + dev_size=dev.GetProperty ('storage.size') + dev_size=(dev_size/1024/1024) + basename=os.path.basename(udi) + if dev_bus == "scsi": + print "%s. %s %sM %s \n" % (dev_count,dev_name,dev_size,basename) + dev_dict[str(dev_count)] = dev_name + dev_count = dev_count + 1 + print "Enter Q to Quit" + dev_choice = raw_input("Which device? ") + while not dev_dict.has_key(dev_choice): + if dev_choice.lower() == "q": + print "Aborting" + sys.exit(1) + else: + print "%s is an invalid choice" % dev_choice + dev_choice = raw_input("Which device? ") + options.disk = dev_dict[dev_choice] + +cont = raw_input("Creating file system on %s, do you wish to continue (y/N) " % options.disk) +if cont.lower() != "y": + print "Aborting" + sys.exit(1) + +isomount = mkdtemp() +isomount_ret = subprocess.call(["mount", "-o", "loop", options.iso, isomount]) +if isomount_ret != 0: + fail("Error mounting %s" % options.iso) + +kernel="%s/isolinux/vmlinuz0" % isomount +initrd="%s/isolinux/initrd0.img" % isomount +squashfs="%s/LiveOS/squashfs.img" % isomount +ext3fs="tftpboot/squashfs-root/LiveOS/ext3fs.img" +shutil.copy(kernel,"tftpboot") +shutil.copy(initrd,"tftpboot") + +unsquash = subprocess.call(["unsquashfs", squashfs]) + +# workaround until bug is fixed with squashfs -d option +shutil.move("squashfs-root","tftpboot/squashfs-root") + +print "Placing embedded file system on %s" % options.disk +dd_cmd="dd if=%s of=%s" % (ext3fs,options.disk) +copy_iscsi_ret = subprocess.call(dd_cmd, shell=True) +if copy_iscsi_ret != 0: + fail("Error copying to %s" % options.disk) + +umount_ret = subprocess.call(["umount", isomount]) +if umount_ret != 0: + fail("Error unmounting %s, continuing" % isomount) +else: + os.rmdir(isomount) +shutil.rmtree("tftpboot/squashfs-root") + +pxe_template = """ + +# pxelinux configuration. +DEFAULT pxeboot +TIMEOUT 20 +PROMPT 0 +LABEL ovirt-node-iscsi + KERNEL /vmlinuz0 + APPEND initrd=/initrd0.img ro root=LABEL=%(disk_label)s netroot=iscsi:%(user)s%(password)s@%(target)s::%(target_port)s::%(target_name)s ip=eth0:dhcp + ipappend 2 +ONERROR LOCALBOOT 0 +""" + +# insert empty values for unneeded variables in the pxe template +if not options.user is None: + options.user = options.user + ":" +else: + options.user = "" + +if not options.password is None: + options.password = options.password + ":" +else: + options.password = "" + +if not options.reverse_user is None: + options.reverse_user = options.reverse_user + ":" +else: + options.reverse_user = "" + +if not options.reverse_password is None: + options.reverse_password = options.reverse_password + ":" +else: + options.reverse_password = "" + +os.mkdir("tftpboot/pxelinux.cfg") +pxe_cfg = pxe_template % { + "disk_label": options.disk_label, + "target": options.target, + "target_port": options.targetport, + "target_name": options.targetname, + "user": options.user, + "password": options.password, + "reverse_user": options.reverse_user, + "reverse_password": options.reverse_password + } + +pxe_conf = open("tftpboot/pxelinux.cfg/default", 'w') +pxe_conf.write(pxe_cfg) +pxe_conf.close() + +if os.path.exists("/usr/share/syslinux/pxelinux.0"): + shutil.copy("/usr/share/syslinux/pxelinux.0","tftpboot") +elif os.path.exists("/usr/lib/syslinux/pxelinux.0"): + shutil.copy("/usr/lib/syslinux/pxelinux.0","tftpboot") +else: + print "Warning: You need to add pxelinux.0 to tftpboot/ subdirectory" + +print "Your iscsiroot has been setup on %s" % options.disk +print "" +print "Copy the tftpboot/ subdirectory to your tftpserver root directory" +print "Set up your DHCP, TFTP and PXE server to serve /tftpboot/.../pxeboot.0" diff --git a/ovirt-node-image.spec.in b/ovirt-node-image.spec.in index e64f4de..1f8c31b 100644 --- a/ovirt-node-image.spec.in +++ b/ovirt-node-image.spec.in @@ -65,6 +65,7 @@ mkdir %{buildroot} %{__install} -d -m0755 %{buildroot}%{_sbindir} %{__install} -p -m0755 create-ovirt-iso-nodes %{buildroot}%{_sbindir} %{__install} -p -m0755 edit-livecd %{buildroot}%{_sbindir} +%{__install} -p -m0755 livecd-iso-to-iscsi %{buildroot}%{_sbindir} %{__install} -p -m0755 livecd-setauth %{buildroot}%{_sbindir} %{__install} -p -m0755 livecd-rpms %{buildroot}%{_sbindir} %{__tar} -xf %{image_manifests} -C %{buildroot}%{app_root} @@ -94,6 +95,7 @@ cobbler sync > /dev/null 2>&1 || : %defattr(0755,root,root,0755) %{_sbindir}/create-ovirt-iso-nodes %{_sbindir}/edit-livecd +%{_sbindir}/livecd-iso-to-iscsi %{_sbindir}/livecd-setauth %{_sbindir}/livecd-rpms -- 1.6.2.5