#!/usr/bin/python -tt # # Copyright(c) FUJITSU Limited 2007. # # Script to set up an cloning guest configuration and kick off an cloning # # 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; either version 2 of the License, or # (at your option) any later version. # # 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. import os, sys, string from optparse import OptionParser, OptionValueError import subprocess import libxml2 import logging import virtinst import virtinst.CloneManager as clmgr ### Utility functions def prompt_for_input(prompt = "", val = None): if val is not None: return val print prompt + " ", return sys.stdin.readline().strip() ### General input gathering functions def get_clone_name(new_name, design): while 1: new_name = prompt_for_input("What is the new name for the clone virtual machine?", new_name) try: design.clone_name = new_name break except (ValueError, RuntimeError), e: print "ERROR: ", e new_name = None def get_original_guest(guest, design): while 1: guest = prompt_for_input("What is the original name or uuid of your virtual machine?", guest) try: design.original_guest = guest break except (ValueError, RuntimeError), e: print "ERROR: ", e guest = None def get_clone_macaddr(new_mac, design): if new_mac is None: pass elif new_mac[0] == "RANDOM": new_mac = None else: for i in new_mac: design.set_clone_mac(i) def get_clone_uuid(new_uuid, design): if new_uuid is not None: design.set_clone_uuid(new_uuid) def get_clone_diskfile(new_diskfile, design): if new_diskfile is None: raise ValueError, "The new disk image files for the clone guest must be needed" for i in new_diskfile: design.set_clone_devices(i) def get_hyper_connect(uri, design): if uri is not None: design.set_hyper_connect(uri) ### Option parsing def check_before_store(option, opt_str, value, parser): if len(value) == 0: raise OptionValueError, "%s option requires an argument" %opt_str setattr(parser.values, option.dest, value) def check_before_append(option, opt_str, value, parser): if len(value) == 0: raise OptionValueError, "%s option requires an argument" %opt_str parser.values.ensure_value(option.dest, []).append(value) def parse_args(): parser = OptionParser() # original name parser.add_option("-o", "--original", type="string", dest="original_guest", action="callback", callback=check_before_store, help="Name or uuid for the original guest; The status must be shut off") # clone new name parser.add_option("-n", "--name", type="string", dest="new_name", action="callback", callback=check_before_store, help="New name for the clone guest") # clone new uuid parser.add_option("-u", "--uuid", type="string", dest="new_uuid", action="callback", callback=check_before_store, help="New UUID for the clone guest; if none is given a random UUID will be generated") # clone new macs parser.add_option("-m", "--mac", type="string", dest="new_mac", action="callback", callback=check_before_append, help="New fixed MAC address for the clone guest; if none or RANDOM is given a random address will be used") # clone new disks parser.add_option("-f", "--file", type="string", dest="new_diskfile", action="callback", callback=check_before_append, help="New file to use as the disk image for the clone guest") # connect parser.add_option("-c", "--connect", type="string", dest="connect", action="callback", callback=check_before_store, help="Connect to hypervisor with URI") # Misc options parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Print debugging information") (options,args) = parser.parse_args() return options ### Let's do it! def main(): if os.geteuid() != 0: print >> sys.stderr, "Must be root to clone guests" sys.exit(1) options = parse_args() if options.debug: logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%a, %d %b %Y %H:%M:%S", stream=sys.stderr) else: logging.basicConfig(level=logging.ERROR, format="%(asctime)s %(levelname)-8s %(message)s", datefmt="%a, %d %b %Y %H:%M:%S", stream=sys.stderr) logging.debug("start clone") design = clmgr.CloneDesign() try: get_clone_diskfile(options.new_diskfile, design) get_clone_macaddr(options.new_mac, design) get_original_guest(options.original_guest, design) get_clone_name(options.new_name, design) get_clone_uuid(options.new_uuid, design) get_hyper_connect(options.connect, design) # setup design object design.setup() # start cloning clmgr.start_duplicate(design) logging.debug("end clone") except Exception, e: print "ERROR: ", e sys.exit(1) if __name__ == "__main__": main()