def mpath_part_scan(force = False): global use_mpath if not force and not use_mpath: return 0 ret = createMpathPartnodes() if ret == 0: util.runCmd2(util.udevsettleCmd()) return ret
def start_fcoe(interfaces): ''' startFCoE takes dictonary of {interface: dcb config} dcb config could be either True or False and returns a dictonary {interface:result} result could be either OK or error returned from fipvlan ''' ''' modprobe sg (scsi generic) modprobe bnx2fc if required. ''' result = {} start_lldpad() util.runCmd2(['/sbin/modprobe', 'sg']) util.runCmd2(['/sbin/modprobe', 'fcoe']) for interface, dcb in interfaces.iteritems(): if netutil.getDriver(interface) == 'bnx2x': # This will do modprobe multiple times util.runCmd2(['/sbin/modprobe', 'bnx2fc']) if dcb: util.runCmd2(['/sbin/dcbtool', 'sc', interface, 'dcb', 'on']) util.runCmd2(['/sbin/dcbtool', 'sc', interface, 'app:fcoe', 'e:1']) util.runCmd2(['/sbin/dcbtool', 'sc', interface, 'pfc', 'e:1', 'a:1', 'w:1']) else: util.runCmd2(['/sbin/lldptool', '-i', interface, '-L', 'adminStatus=disabled']) for interface in interfaces: xelogging.log("Starting fipvlan on %s"% interface) rc, out, err = util.runCmd2(['/usr/sbin/fipvlan', '-s', '-c', interface], True, True) if rc != 0: result[interface] = err else: result[interface] = "OK" xelogging.log(result) # Wait for block devices to appear. # Without being able to know how long this will take and because LUNs can # appear before the block devices are created, just wait a constant number # of seconds for FCoE to stabilize. time.sleep(30) util.runCmd2(util.udevsettleCmd()) for interface, status in result.iteritems(): if status == 'OK': xelogging.log(get_luns_on_intf(interface)) return result
def attach_rfc4173(iname, rfc4173_spec): """ Attach a disk given an initiator name, and spec in the following format: "iscsi:"<targetip>":"<protocol>":"<port>":"<LUN>":"<targetname> return disk, e.g. "/dev/sdb" """ try: parts = rfc4173_spec.split(':',5) assert(parts[0] == "iscsi") targetip = parts[1] port = parts[3] lun = parts[4] and int(parts[4]) or 0 iqn = parts[5] except: raise IscsiDeviceException, "Cannot parse spec %s" % rfc4173_spec if port: targetip += ':%s' % port # Attach to disk if not os.path.exists("/etc/iscsi/initiatorname.iscsi"): open("/etc/iscsi/initiatorname.iscsi","w").write("InitiatorName=%s" % iname) rv = util.runCmd2([ '/sbin/modprobe', 'iscsi_tcp' ]) if rv: raise RuntimeError, "/sbin/modprobe iscsi_tcp failed" try: if not util.pidof('iscsid'): fd = open("/etc/iscsi/initiatorname.iscsi", "w") fd.write("InitiatorName=%s" % iname) fd.close() rv = util.runCmd2([ '/sbin/iscsiadm', '-m', 'discovery', '-t', 'sendtargets', '-p', targetip]) if rv: raise RuntimeError, "/sbin/iscsiadm -m discovery failed" rv = util.runCmd2([ '/sbin/iscsiadm', '-m', 'node', '-T', iqn, '-p', targetip, '-l']) # login if rv: raise RuntimeError, "/sbin/iscsiadm -m node -l failed" finally: util.runCmd2(util.udevsettleCmd()) # update /dev disk = rfc4173_to_disk(rfc4173_spec) iscsi_disks.append(disk) return disk
def mpath_enable(): global use_mpath assert 0 == util.runCmd2(['modprobe','dm-multipath']) if not os.path.exists('/etc/multipath.conf') and os.path.exists('/etc/multipath.conf.disabled'): os.rename('/etc/multipath.conf.disabled', '/etc/multipath.conf') # launch manually to make possible to wait initialization util.runCmd2(["/sbin/multipath", "-v0", "-B"]) time.sleep(1) util.runCmd2(util.udevsettleCmd()) # This creates maps for all disks at start of day (because -e is ommitted) assert 0 == util.runCmd2('multipathd -d > /var/log/multipathd 2>&1 &') wait_for_multipathd() # CA-48440: Cope with lost udev events util.runCmd2(["multipathd","-k"], inputtext="reconfigure") # Tell DM to create partition nodes for newly created mpath devices assert 0 == mpath_part_scan(True) xelogging.log("created multipath device(s)"); use_mpath = True
def process_ibft(ui, interactive): """Process the iBFT. Bring up any disks that the iBFT says should be attached, and reserve the NICs that it says should be used for iSCSI. """ util.runCmd2(['/sbin/iscsiadm', '-k', '0']) rv = util.runCmd2(['iscsid']) if rv: raise RuntimeError('Failed to start iscsid') nics = set() targets = 0 rv, out = util.runCmd2(['iscsistart', '-f'], with_stdout=True) if rv: xelogging.log("process_ibft: No valid iBFT found.") return for line in out.split('\n'): m = re.match('iface.net_ifacename = (.*)$', line.strip()) if m: nics.add(m.group(1)) m = re.match(r'node.conn\[\d+\].address = ', line.strip()) if m: targets += 1 # Do nothing if the iBFT contains no valid targets if targets == 0: xelogging.log("process_ibft: No valid target configs found in iBFT") return # If interactive, ask user if he wants to proceed if ui and interactive: msg = \ "Found iSCSI Boot Firmware Table\n\nAttach to disks specified in iBFT?\n\n" \ "This will reserve %s for iSCSI disk access. Reserved NICs are not available " \ "for use as the management interface or for use by virtual machines." % " and ".join(sorted(nics)) button = ButtonChoiceWindowEx(ui.screen, "Attach iSCSI disks", msg, ['Yes', 'No'], width=60) if button == 'no': return setup_ibft_nics() # Attach disks rv = util.runCmd2(['iscsistart', '-b']) if rv: raise RuntimeError('Failed to attach iSCSI target disk(s)') util.runCmd2(util.udevsettleCmd()) time.sleep(5) rv, out = util.runCmd2(['iscsiadm', '-m', 'session', '-P', '3'], with_stdout=True) if rv: raise RuntimeError('Failed to find attached disks') for line in out.split('\n'): m = re.match(r'\s*Attached scsi disk (\w+)\s+.*$', line) if m: iscsi_disks.append('/dev/' + m.group(1)) xelogging.log('process_ibft: iSCSI Disks: %s' % (str(iscsi_disks), )) xelogging.log('process_ibft: Reserved NICs: %s' % (str(list(ibft_reserved_nics)), ))
def welcome_screen(answers): driver_answers = {'driver-repos': []} tui.update_help_line([None, "<F9> load driver"]) def load_driver(driver_answers): tui.screen.popHelpLine() tui.update_help_line([None, ' ']) drivers = driver.doInteractiveLoadDriver(tui, driver_answers) xelogging.log(drivers) xelogging.log(driver_answers) if drivers[0]: if 'extra-repos' not in answers: answers['extra-repos'] = [] answers['extra-repos'].append(drivers) return True global loop global popup loop = True def fn9(): global loop global popup loop = True popup = 'driver' return False def fn10(): global loop global popup loop = True popup = 'storage' return False while loop: loop = False popup = None driver_answers['network-hardware'] = answers['network-hardware'] = netutil.scanConfiguration() button = snackutil.ButtonChoiceWindowEx(tui.screen, "Welcome to %s Setup" % MY_PRODUCT_BRAND, """This setup tool can be used to install or upgrade %s on your system or restore your server from backup. Installing %s will erase all data on the disks selected for use. Please make sure you have backed up any data you wish to preserve before proceeding. To load a device driver press <F9>. To setup advanced storage classes press <F10>. """ % (MY_PRODUCT_BRAND, MY_PRODUCT_BRAND), ['Ok', 'Reboot'], width = 60, help = "welcome", hotkeys = {'F9': fn9, 'F10': fn10}) if popup == 'driver': load_driver(driver_answers) tui.update_help_line([None, "<F9> load driver"]) elif popup == 'storage': tui.fcoe.select_fcoe_ifaces(answers) tui.update_help_line([None, "<F9> load driver"]) tui.screen.popHelpLine() if button == 'reboot': return EXIT xelogging.log("Waiting for partitions to appear...") util.runCmd2(util.udevsettleCmd()) time.sleep(1) diskutil.mpath_part_scan() # ensure partitions/disks are not locked by LVM lvm = LVMTool() lvm.deactivateAll() del lvm tui.progress.showMessageDialog("Please wait", "Checking for existing products...") answers['installed-products'] = product.find_installed_products() answers['upgradeable-products'] = upgrade.filter_for_upgradeable_products(answers['installed-products']) answers['backups'] = product.findXenSourceBackups() tui.progress.clearModelessDialog() diskutil.log_available_disks() # CA-41142, ensure we have at least one network interface and one disk before proceeding label = None if len(diskutil.getDiskList()) == 0: label = "No Disks" text = "hard disks" text_short = "disks" if len(answers['network-hardware'].keys()) == 0: label = "No Network Interfaces" text = "network interfaces" text_short = "interfaces" if label: text = """This host does not appear to have any %s. If %s are present you may need to load a device driver on the previous screen for them to be detected.""" % (text, text_short) ButtonChoiceWindow(tui.screen, label, text, ["Back"], width = 48) return REPEAT_STEP return RIGHT_FORWARDS
def go(ui, args, answerfile_address, answerfile_script): extra_repo_defs = [] results = { 'keymap': None, 'serial-console': None, 'operation': init_constants.OPERATION_INSTALL, 'boot-serial': False, 'extra-repos': [], 'network-backend': constants.NETWORK_BACKEND_DEFAULT, 'root-password': ('pwdhash', '!!'), 'create-new-partitions': True, # FALSE = DOS | TRUE = GPT set via command line only with --disable-gpt 'new-partition-layout': False, # TRUE = GPT with LOG,BACKUP,ROOT,BOOT,SWAP,SR automatically set during install/upgrade 'services': {s: None for s in constants.SERVICES }, # default state for services, example {'sshd': None} } suppress_extra_cd_dialog = False serial_console = None boot_console = None boot_serial = False if not xen_control_domain() or '--virtual' in args: hardware.useVMHardwareFunctions() for (opt, val) in args.items(): if opt == "--boot-console": # takes precedence over --console if hardware.is_serialConsole(val): boot_console = hardware.getSerialConfig() elif opt == "--console": for console in val: if hardware.is_serialConsole(console): serial_console = hardware.getSerialConfig() if hardware.is_serialConsole(val[-1]): boot_serial = True elif opt == "--keymap": results["keymap"] = val logger.log("Keymap specified on command-line: %s" % val) elif opt == "--extrarepo": extra_repo_defs += val elif opt == "--onecd": suppress_extra_cd_dialog = True elif opt == "--disable-gpt": constants.GPT_SUPPORT = False results["create-new-partitions"] = False logger.log( "Forcing DOS partition table and old partition layout via command-line" ) elif opt == "--legacy-partitions": results["create-new-partitions"] = False logger.log("Forcing old partition layout via command-line") elif opt == "--cc-preparations": constants.CC_PREPARATIONS = True results['network-backend'] = constants.NETWORK_BACKEND_BRIDGE if boot_console and not serial_console: serial_console = boot_console boot_serial = True if serial_console: try: results['serial-console'] = hardware.SerialPort.from_string( serial_console) results['boot-serial'] = boot_serial logger.log( "Serial console specified on command-line: %s, default boot: %s" % (serial_console, boot_serial)) except: pass interactive = True try: if os.path.isfile(constants.defaults_data_file): data_file = open(constants.defaults_data_file) try: defaults = json.load(data_file) finally: data_file.close() results.update(defaults) # loading an answerfile? assert ui is not None or answerfile_address is not None or answerfile_script is not None if answerfile_address and answerfile_script: raise RuntimeError( "Both answerfile and answerfile generator passed on command line." ) a = None parsing_except = None if answerfile_address: a = answerfile.Answerfile.fetch(answerfile_address) elif answerfile_script: a = answerfile.Answerfile.generate(answerfile_script) if a: interactive = False results['network-hardware'] = netutil.scanConfiguration() try: results.update(a.parseScripts()) results.update(a.processAnswerfileSetup()) if ui and results.get('ui-confirmation-prompt', False): if not ui.init.confirm_proceed(): logger.log("User did not confirm installation. Reboot") return constants.EXIT_USER_CANCEL if 'extra-repos' in results: # load drivers now for media, address in results['extra-repos']: for r in repository.repositoriesFromDefinition( media, address, drivers=True): r.installPackages(lambda x: (), {'root': '/'}) if 'fcoe-interfaces' in results: fcoeutil.start_fcoe(results['fcoe-interfaces']) util.runCmd2(util.udevsettleCmd()) time.sleep(1) diskutil.mpath_part_scan() # ensure partitions/disks are not locked by LVM lvm = disktools.LVMTool() lvm.deactivateAll() del lvm diskutil.log_available_disks() results.update(a.processAnswerfile()) results = fixMpathResults(results) except Exception as e: logger.logException(e) parsing_except = e results['extra-repos'] += extra_repo_defs logger.log("Driver repos: %s" % str(results['extra-repos'])) scripts.run_scripts('installation-start') if parsing_except: raise parsing_except # log the modules that we loaded: logger.log("All needed modules should now be loaded. We have loaded:") util.runCmd2(["lsmod"]) status = constants.EXIT_OK # how much RAM do we have? ram_found_mb = hardware.getHostTotalMemoryKB() / 1024 ram_warning = ram_found_mb < constants.MIN_SYSTEM_RAM_MB vt_warning = not hardware.VTSupportEnabled() # Generate the UI sequence and populate some default # values in backend input. Note that not all these screens # will be displayed as they have conditional to skip them at # the start of each function. In future these conditionals will # be moved into the sequence definition and evaluated by the # UI dispatcher. aborted = False if ui and interactive: uiexit = ui.installer.runMainSequence(results, ram_warning, vt_warning, suppress_extra_cd_dialog) if uiexit == uicontroller.EXIT: aborted = True if not aborted: if results['install-type'] == constants.INSTALL_TYPE_RESTORE: logger.log('INPUT ANSWER DICTIONARY') backend.prettyLogAnswers(results) logger.log("SCRIPTS DICTIONARY:") backend.prettyLogAnswers(scripts.script_dict) logger.log("Starting actual restore") backup = results['backup-to-restore'] if ui: pd = tui.progress.initProgressDialog( "Restoring %s" % backup, "Restoring data - this may take a while...", 100) def progress(x): if ui and pd: tui.progress.displayProgressDialog(x, pd) restore.restoreFromBackup(backup, progress) if ui: tui.progress.clearModelessDialog() tui.progress.OKDialog( "Restore", "The restore operation completed successfully.") else: logger.log("Starting actual installation") backend.performInstallation(results, ui, interactive) if ui and interactive: ui.installer.screens.installation_complete() logger.log("The installation completed successfully.") else: logger.log( "The user aborted the installation from within the user interface." ) status = constants.EXIT_USER_CANCEL except Exception as e: try: # first thing to do is to get the traceback and log it: ex = sys.exc_info() err = str.join("", traceback.format_exception(*ex)) logger.log("INSTALL FAILED.") logger.log("A fatal exception occurred:") logger.log(err) # run the user's scripts - an arg of "1" indicates failure scripts.run_scripts('installation-complete', '1') # collect logs where possible xelogging.collectLogs("/tmp") # now display a friendly error dialog: if ui: ui.exn_error_dialog("install-log", True, interactive) else: txt = constants.error_string(str(e), 'install-log', True) logger.log(txt) # and now on the disk if possible: if 'primary-disk' in results and 'primary-partnum' in results and 'logs-partnum' in results: backend.writeLog(results['primary-disk'], results['primary-partnum'], results['logs-partnum']) elif 'primary-disk' in results and 'primary-partnum' in results: backend.writeLog(results['primary-disk'], results['primary-partnum'], None) logger.log(results) except Exception as e: # Don't let logging exceptions prevent subsequent actions print 'Logging failed: ' + str(e) # exit with failure status: status = constants.EXIT_ERROR else: # run the user's scripts - an arg of "0" indicates success try: scripts.run_scripts('installation-complete', '0') except: pass # put the log in /tmp: xelogging.collectLogs('/tmp') # and now on the disk if possible: if 'primary-disk' in results and 'primary-partnum' in results and 'logs-partnum' in results: backend.writeLog(results['primary-disk'], results['primary-partnum'], results['logs-partnum']) elif 'primary-disk' in results and 'primary-partnum' in results: backend.writeLog(results['primary-disk'], results['primary-partnum'], None) assert (status == constants.EXIT_OK or status == constants.EXIT_USER_CANCEL) return status
def go(ui, args, answerfile_address, answerfile_script): extra_repo_defs = [] results = { 'keymap': None, 'serial-console': None, 'operation': init_constants.OPERATION_INSTALL, 'boot-serial': False, 'extra-repos': [], 'network-backend': constants.NETWORK_BACKEND_DEFAULT, 'root-password': ('pwdhash', '!!'), 'create-new-partitions': True, # FALSE = DOS | TRUE = GPT set via command line only with --disable-gpt 'new-partition-layout': False, # TRUE = GPT with LOG,BACKUP,ROOT,BOOT,SWAP,SR automatically set during install/upgrade } suppress_extra_cd_dialog = False serial_console = None boot_console = None boot_serial = False if not xen_control_domain() or args.has_key('--virtual'): hardware.useVMHardwareFunctions() for (opt, val) in args.items(): if opt == "--boot-console": # takes precedence over --console if hardware.is_serialConsole(val): boot_console = hardware.getSerialConfig() elif opt == "--console": for console in val: if hardware.is_serialConsole(console): serial_console = hardware.getSerialConfig() if hardware.is_serialConsole(val[-1]): boot_serial = True elif opt == "--keymap": results["keymap"] = val xelogging.log("Keymap specified on command-line: %s" % val) elif opt == "--extrarepo": extra_repo_defs += val elif opt == "--onecd": suppress_extra_cd_dialog = True elif opt == "--disable-gpt": constants.GPT_SUPPORT = False results["create-new-partitions"] = False xelogging.log("Forcing old partition layout via command-line") if boot_console and not serial_console: serial_console = boot_console boot_serial = True if serial_console: try: results['serial-console'] = hardware.SerialPort.from_string( serial_console) results['boot-serial'] = boot_serial xelogging.log( "Serial console specified on command-line: %s, default boot: %s" % (serial_console, boot_serial)) except: pass interactive = True try: if os.path.isfile(constants.defaults_data_file): data_file = open(constants.defaults_data_file) try: defaults = json.load(data_file) finally: data_file.close() results.update(defaults) # loading an answerfile? assert ui != None or answerfile_address != None or answerfile_script != None if answerfile_address and answerfile_script: raise RuntimeError, "Both answerfile and answerfile generator passed on command line." a = None parsing_except = None if answerfile_address: a = answerfile.Answerfile.fetch(answerfile_address) elif answerfile_script: a = answerfile.Answerfile.generate(answerfile_script) if a: interactive = False results['network-hardware'] = netutil.scanConfiguration() try: results.update(a.parseScripts()) results.update(a.processAnswerfileSetup()) if ui and results.get('ui-confirmation-prompt', False): if not ui.init.confirm_proceed(): xelogging.log( "User did not confirm installation. Reboot") return constants.EXIT_USER_CANCEL if results.has_key('extra-repos'): # load drivers now for media, address in results['extra-repos']: for r in repository.repositoriesFromDefinition( media, address, drivers=True): r.installPackages(lambda x: (), {'root': '/'}) if 'fcoe-interfaces' in results: fcoeutil.start_fcoe(results['fcoe-interfaces']) util.runCmd2(util.udevsettleCmd()) time.sleep(1) diskutil.mpath_part_scan() # ensure partitions/disks are not locked by LVM lvm = disktools.LVMTool() lvm.deactivateAll() del lvm diskutil.log_available_disks() results.update(a.processAnswerfile()) results = fixMpathResults(results) except Exception, e: xelogging.logException(e) parsing_except = e results['extra-repos'] += extra_repo_defs xelogging.log("Driver repos: %s" % str(results['extra-repos'])) scripts.run_scripts('installation-start') if parsing_except: raise parsing_except # log the modules that we loaded: xelogging.log( "All needed modules should now be loaded. We have loaded:") util.runCmd2(["lsmod"]) status = constants.EXIT_OK # how much RAM do we have? ram_found_mb = hardware.getHostTotalMemoryKB() / 1024 ram_warning = ram_found_mb < constants.MIN_SYSTEM_RAM_MB vt_warning = not hardware.VTSupportEnabled() # Generate the UI sequence and populate some default # values in backend input. Note that not all these screens # will be displayed as they have conditional to skip them at # the start of each function. In future these conditionals will # be moved into the sequence definition and evaluated by the # UI dispatcher. aborted = False if ui and interactive: uiexit = ui.installer.runMainSequence(results, ram_warning, vt_warning, suppress_extra_cd_dialog) if uiexit == uicontroller.EXIT: aborted = True if not aborted: if results['install-type'] == constants.INSTALL_TYPE_RESTORE: xelogging.log('INPUT ANSWER DICTIONARY') backend.prettyLogAnswers(results) xelogging.log("SCRIPTS DICTIONARY:") backend.prettyLogAnswers(scripts.script_dict) xelogging.log("Starting actual restore") backup = results['backup-to-restore'] if ui: pd = tui.progress.initProgressDialog( "Restoring %s" % backup, "Restoring data - this may take a while...", 100) def progress(x): if ui and pd: tui.progress.displayProgressDialog(x, pd) restore.restoreFromBackup(backup, progress) if ui: tui.progress.clearModelessDialog() tui.progress.OKDialog( "Restore", "The restore operation completed successfully.") else: xelogging.log("Starting actual installation") backend.performInstallation(results, ui, interactive) if ui and interactive: ui.installer.screens.installation_complete() xelogging.log("The installation completed successfully.") else: xelogging.log( "The user aborted the installation from within the user interface." ) status = constants.EXIT_USER_CANCEL
def start_fcoe(interfaces): ''' startFCoE takes a list of interfaces and returns a dictonary {interface:result} result could be either OK or error returned from fipvlan ''' ''' modprobe sg (scsi generic) modprobe bnx2fc if required. ''' dcb_wait = True result = {} start_lldpad() util.runCmd2(['/sbin/modprobe', 'sg']) util.runCmd2(['/sbin/modprobe', 'libfc']) util.runCmd2(['/sbin/modprobe', 'fcoe']) util.runCmd2(['/sbin/modprobe', 'bnx2fc']) for interface in interfaces: if hw_lldp_capable(interface): if dcb_wait: # Wait for hardware to do dcb negotiation dcb_wait = False time.sleep(15) util.runCmd2([ '/sbin/lldptool', '-i', interface, '-L', 'adminStatus=disabled' ]) else: # Ideally this would use fcoemon to start FCoE but this doesn't # fit the host-installer use case because it is possible to start # one interface at a time. util.runCmd2(['/sbin/dcbtool', 'sc', interface, 'dcb', 'on']) util.runCmd2(['/sbin/dcbtool', 'sc', interface, 'app:fcoe', 'e:1']) util.runCmd2( ['/sbin/dcbtool', 'sc', interface, 'pfc', 'e:1', 'a:1', 'w:1']) # wait for dcbtool changes to take effect time.sleep(1) logger.log('Starting fipvlan on %s' % interface) rc, err = util.runCmd2(['/usr/sbin/fipvlan', '-s', '-c', interface], with_stderr=True) if rc != 0: result[interface] = err else: result[interface] = 'OK' logger.log(result) # Wait for block devices to appear. # Without being able to know how long this will take and because LUNs can # appear before the block devices are created, just wait a constant number # of seconds for FCoE to stabilize. time.sleep(30) util.runCmd2(util.udevsettleCmd()) for interface, status in result.iteritems(): if status == 'OK': logger.log(get_luns_on_intf(interface)) return result