def __init__(self): self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__)) self.env = StackEnvironment()
class SyslinuxHelper: def __init__(self): self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__)) self.env = StackEnvironment() def create_syslinux_stub(self, image_name, cmdline, kernel_filename, ramdisk_filename): """ @param cmdline: kernel command line @param kernel_filename: path to kernel file @param ramdisk_filename: path to ramdisk file @return glance image id """ raw_fs_image = NamedTemporaryFile(delete=False) raw_image_name = raw_fs_image.name tmp_content_dir = None glance_image_id = None try: qcow2_image_name = "%s.qcow2" % raw_image_name # 200 MB sparse file self.log.debug("Creating sparse 200 MB file") outsize = 1024 * 1024 * 200 raw_fs_image.truncate(outsize) raw_fs_image.close() # Partition, format and add DOS MBR g = guestfs.GuestFS() g.add_drive(raw_image_name) g.launch() g.part_disk("/dev/sda","msdos") g.part_set_mbr_id("/dev/sda",1,0xb) g.mkfs("vfat", "/dev/sda1") g.part_set_bootable("/dev/sda", 1, 1) dosmbr = open("/usr/share/syslinux/mbr.bin").read() ws = g.pwrite_device("/dev/sda", dosmbr, 0) if ws != len(dosmbr): raise Exception("Failed to write entire MBR") # Install syslinux g.syslinux("/dev/sda1") #Insert kernel, ramdisk and syslinux.cfg file tmp_content_dir = mkdtemp() kernel_dest = os.path.join(tmp_content_dir,"vmlinuz") shutil.copy(kernel_filename, kernel_dest) initrd_dest = os.path.join(tmp_content_dir,"initrd.img") shutil.copy(ramdisk_filename, initrd_dest) syslinux_conf="""default customhd timeout 30 prompt 1 label customhd kernel vmlinuz append initrd=initrd.img %s """ % (cmdline) f = open(os.path.join(tmp_content_dir, "syslinux.cfg"),"w") f.write(syslinux_conf) f.close() # copy the tmp content to the image g.mount_options ("", "/dev/sda1", "/") for filename in os.listdir(tmp_content_dir): g.upload(os.path.join(tmp_content_dir,filename),"/" + filename) g.sync() g.close() try: self.log.debug("Converting syslinux stub image from raw to qcow2") self._subprocess_check_output(["qemu-img","convert","-c","-O","qcow2",raw_image_name, qcow2_image_name]) self.log.debug("Uploading syslinux qcow2 image to glance") glance_image_id = self.env.upload_image_to_glance(image_name, local_path=qcow2_image_name, format='qcow2') except Exception, e: self.log.debug("Exception while converting syslinux image to qcow2: %s" % e) self.log.debug("Uploading syslinux raw image to glance.") glance_image_id = self.env.upload_image_to_glance(image_name, local_path=raw_image_name, format='raw') finally: self.log.debug("Removing temporary file.") if os.path.exists(raw_image_name): os.remove(raw_image_name) if os.path.exists(qcow2_image_name): os.remove(qcow2_image_name) if tmp_content_dir: shutil.rmtree(tmp_content_dir) return glance_image_id ### Utility functions borrowed from Oz and lightly modified def _executable_exists(self, program): """ Function to find out whether an executable exists in the PATH of the user. If so, the absolute path to the executable is returned. If not, an exception is raised. """ def is_exe(fpath): """ Helper method to check if a file exists and is executable """ return os.path.exists(fpath) and os.access(fpath, os.X_OK) if program is None: raise Exception("Invalid program name passed") fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file raise Exception("Could not find %s" % (program)) def _subprocess_check_output(self, *popenargs, **kwargs): """ Function to call a subprocess and gather the output. Addresses a lack of check_output() prior to Python 2.7 """ if 'stdout' in kwargs: raise ValueError('stdout argument not allowed, it will be overridden.') if 'stderr' in kwargs: raise ValueError('stderr argument not allowed, it will be overridden.') self._executable_exists(popenargs[0][0]) # NOTE: it is very, very important that we use temporary files for # collecting stdout and stderr here. There is a nasty bug in python # subprocess; if your process produces more than 64k of data on an fd that # is using subprocess.PIPE, the whole thing will hang. To avoid this, we # use temporary fds to capture the data stdouttmp = TemporaryFile() stderrtmp = TemporaryFile() process = subprocess.Popen(stdout=stdouttmp, stderr=stderrtmp, *popenargs, **kwargs) process.communicate() retcode = process.poll() stdouttmp.seek(0, 0) stdout = stdouttmp.read() stdouttmp.close() stderrtmp.seek(0, 0) stderr = stderrtmp.read() stderrtmp.close() if retcode: cmd = ' '.join(*popenargs) raise Exception("'%s' failed(%d): %s" % (cmd, retcode, stderr), retcode) return (stdout, stderr, retcode)