diff --git a/XSConsoleData.py b/XSConsoleData.py index 22925f7..5a96df0 100644 --- a/XSConsoleData.py +++ b/XSConsoleData.py @@ -26,6 +26,23 @@ from XSConsoleState import * from XSConsoleUtils import * +# PR #22: Add py3-compatible wrapper for commands.getstatusoutput() to keep the code base functional: +if sys.version_info >= (3, 0): + getoutput = subprocess.getoutput + getstatusoutput = subprocess.getstatusoutput + +else: + import commands + + getoutput = commands.getoutput + + def getstatusoutput(command): + """getstatusoutput with status = exit code, compatible with Python3 getstatusoutput()""" + + status, output = commands.getstatusoutput(command) + return os.WEXITSTATUS(status), output # https://github.com/benjaminp/six/issues/207 + + class DataMethod: def __init__(self, inSend, inName): self.send = inSend @@ -98,31 +115,31 @@ def Create(self): self.ReadTimezones() self.ReadKeymaps() - (status, output) = subprocess.getstatusoutput("dmidecode") + (status, output) = getstatusoutput("dmidecode") if status != 0: # Use test dmidecode file if there's no real output - (status, output) = subprocess.getstatusoutput("/bin/cat ./dmidecode.txt") + (status, output) = getstatusoutput("/bin/cat ./dmidecode.txt") if status == 0: self.ScanDmiDecode(output.split("\n")) - (status, output) = subprocess.getstatusoutput("/sbin/lspci -m") + (status, output) = getstatusoutput("/sbin/lspci -m") if status != 0: - (status, output) = subprocess.getstatusoutput("/usr/bin/lspci -m") + (status, output) = getstatusoutput("/usr/bin/lspci -m") if status == 0: self.ScanLspci(output.split("\n")) if os.path.isfile("/usr/bin/ipmitool"): - (status, output) = subprocess.getstatusoutput("/usr/bin/ipmitool mc info") + (status, output) = getstatusoutput("/usr/bin/ipmitool mc info") if status == 0: self.ScanIpmiMcInfo(output.split("\n")) - (status, output) = subprocess.getstatusoutput("/bin/cat /etc/xensource-inventory") + (status, output) = getstatusoutput("/bin/cat /etc/xensource-inventory") if status == 0: self.ScanInventory(output.split("\n")) - (status, output) = subprocess.getstatusoutput("/usr/bin/openssl x509 -in %s/xapi-ssl.pem -fingerprint -noout" % (Config.Inst().XCPConfigDir())) + (status, output) = getstatusoutput("/usr/bin/openssl x509 -in %s/xapi-ssl.pem -fingerprint -noout" % (Config.Inst().XCPConfigDir())) if status == 0: fp = output.split("=") if len(fp) >= 2: @@ -454,22 +471,22 @@ def LoggingDestinationSet(self, inDestination): self.session.xenapi.host.syslog_reconfigure(self.host.opaqueref()) def UpdateFromResolveConf(self): - (status, output) = subprocess.getstatusoutput("/usr/bin/grep -v \"^;\" /etc/resolv.conf") + (status, output) = getstatusoutput("/usr/bin/grep -v \"^;\" /etc/resolv.conf") if status == 0: self.ScanResolvConf(output.split("\n")) def UpdateFromSysconfig(self): - (status, output) = subprocess.getstatusoutput("/bin/cat /etc/sysconfig/network") + (status, output) = getstatusoutput("/bin/cat /etc/sysconfig/network") if status == 0: self.ScanSysconfigNetwork(output.split("\n")) def UpdateFromHostname(self): - (status, output) = subprocess.getstatusoutput("/bin/cat /etc/hostname") + (status, output) = getstatusoutput("/bin/cat /etc/hostname") if status == 0: self.ScanHostname(output.split("\n")) def UpdateFromNTPConf(self): - (status, output) = subprocess.getstatusoutput("/bin/cat /etc/chrony.conf") + (status, output) = getstatusoutput("/bin/cat /etc/chrony.conf") if status == 0: self.ScanNTPConf(output.split("\n")) @@ -477,7 +494,7 @@ def StringToBool(self, inString): return inString.lower().startswith('true') def RootLabel(self): - output = subprocess.getoutput('/bin/cat /proc/cmdline') + output = getoutput('/bin/cat /proc/cmdline') match = re.search(r'root=\s*LABEL\s*=\s*(\S+)', output) if match: retVal = match.group(1) @@ -675,7 +692,7 @@ def ScanIpmiMcInfo(self, inLines): self.data['bmc']['version'] = match.group(1) def ScanService(self, service): - (status, output) = subprocess.getstatusoutput("systemctl is-enabled %s" % (service,)) + (status, output) = getstatusoutput("systemctl is-enabled %s" % (service,)) self.data['chkconfig'][service] = status == 0 def ScanResolvConf(self, inLines): @@ -779,7 +796,7 @@ def TimezoneSet(self, inTimezone): cfg.write('/etc/sysconfig/clock') def CurrentTimeString(self): - return subprocess.getoutput('/bin/date -R') + return getoutput('/bin/date -R') def ReadKeymaps(self): self.data['keyboard'] = { @@ -811,7 +828,7 @@ def KeymapSet(self, inKeymap): keymapParam = ShellUtils.MakeSafeParam(inKeymap) # Load the keymap now - status, output = subprocess.getstatusoutput('/bin/loadkeys "'+keymapParam+'"') + status, output = getstatusoutput('/bin/loadkeys "'+keymapParam+'"') if status != 0: raise Exception(output) @@ -914,7 +931,7 @@ def ReconfigureManagement(self, inPIF, inMode, inIP, inNetmask, inGateway, in self.RequireSession() self.session.xenapi.PIF.reconfigure_ip(inPIF['opaqueref'], inMode, inIP, inNetmask, inGateway, FirstValue(inDNS, '')) self.session.xenapi.host.management_reconfigure(inPIF['opaqueref']) - status, output = subprocess.getstatusoutput('%s host-signal-networking-change' % (Config.Inst().XECLIPath())) + status, output = getstatusoutput('%s host-signal-networking-change' % (Config.Inst().XECLIPath())) if status != 0: raise Exception(output) finally: @@ -1090,32 +1107,32 @@ def StartXAPI(self): State.Inst().SaveIfRequired() def EnableService(self, service): - status, output = subprocess.getstatusoutput("systemctl enable %s" % (service,)) + status, output = getstatusoutput("systemctl enable %s" % (service,)) if status != 0: raise Exception(output) def DisableService(self, service): - status, output = subprocess.getstatusoutput("systemctl disable %s" % (service,)) + status, output = getstatusoutput("systemctl disable %s" % (service,)) if status != 0: raise Exception(output) def RestartService(self, service): - status, output = subprocess.getstatusoutput("systemctl restart %s" % (service,)) + status, output = getstatusoutput("systemctl restart %s" % (service,)) if status != 0: raise Exception(output) def StartService(self, service): - status, output = subprocess.getstatusoutput("systemctl start %s" % (service,)) + status, output = getstatusoutput("systemctl start %s" % (service,)) if status != 0: raise Exception(output) def StopService(self, service): - status, output = subprocess.getstatusoutput("systemctl stop %s" % (service,)) + status, output = getstatusoutput("systemctl stop %s" % (service,)) if status != 0: raise Exception(output) def NTPStatus(self): - status, output = subprocess.getstatusoutput("/usr/bin/ntpstat") + status, output = getstatusoutput("/usr/bin/ntpstat") return output def SetVerboseBoot(self, inVerbose): @@ -1124,7 +1141,7 @@ def SetVerboseBoot(self, inVerbose): else: name = 'quiet' - status, output = subprocess.getstatusoutput( + status, output = getstatusoutput( "(export TERM=xterm && /opt/xensource/libexec/set-boot " + name + ")") if status != 0: raise Exception(output) diff --git a/XSConsoleDataUtils.py b/XSConsoleDataUtils.py index 76d60b0..92d6aaf 100644 --- a/XSConsoleDataUtils.py +++ b/XSConsoleDataUtils.py @@ -80,7 +80,7 @@ def DeviceList(cls, inWritableOnly): @classmethod def SRDeviceList(self): retVal= [] - status, output = subprocess.getstatusoutput("/opt/xensource/libexec/list_local_disks") + status, output = getstatusoutput("/opt/xensource/libexec/list_local_disks") if status == 0: regExp = re.compile(r"\s*\(\s*'([^']*)'\s*,\s*'([^']*)'\s*,\s*'([^']*)'\s*,\s*'([^']*)'\s*,\s*'([^']*)'\s*\)") for line in output.split("\n"): @@ -168,18 +168,18 @@ def USBFormat(self, inVDI): if e.errno != errno.EINTR: # Loop if EINTR raise - status, output = subprocess.getstatusoutput('/bin/sync') + status, output = getstatusoutput('/bin/sync') if status != 0: raise Exception(output) # Format the new partition with VFAT - status, output = subprocess.getstatusoutput("/sbin/mkfs.vfat -n 'XenServer Backup' -F 32 '" +partitionName + "' 2>&1") + status, output = getstatusoutput("/sbin/mkfs.vfat -n 'XenServer Backup' -F 32 '" +partitionName + "' 2>&1") if status != 0: raise Exception(output) - status, output = subprocess.getstatusoutput('/bin/sync') + status, output = getstatusoutput('/bin/sync') if status != 0: raise Exception(output) @@ -237,7 +237,7 @@ def __init__(self, inVDI, inMode = None): FileUtils.AssertSafePath(self.mountDev) self.mountPoint = tempfile.mkdtemp(".xsconsole") - status, output = subprocess.getstatusoutput("/bin/mount -t auto -o " + self.mode + ' ' +self.mountDev+" "+self.mountPoint + " 2>&1") + status, output = getstatusoutput("/bin/mount -t auto -o " + self.mode + ' ' +self.mountDev+" "+self.mountPoint + " 2>&1") if status != 0: try: self.Unmount() @@ -276,7 +276,7 @@ def HandleMountFailure(self, inOutput): raise Exception(inOutput) realDevice = FileUtils.DeviceFromVDI(self.vdi) - status, output = subprocess.getstatusoutput("/sbin/fdisk -l '" +realDevice+"'") + status, output = getstatusoutput("/sbin/fdisk -l '" +realDevice+"'") if status != 0: raise Exception(output) @@ -313,7 +313,7 @@ def Scan(self, inRegExp = None, inNumToReturn = None): def Unmount(self): status = 0 if self.mountedVBD: - status, output = subprocess.getstatusoutput("/bin/umount '"+self.mountPoint + "' 2>&1") + status, output = getstatusoutput("/bin/umount '"+self.mountPoint + "' 2>&1") os.rmdir(self.mountPoint) self.mountedVBD = False if self.pluggedVBD: @@ -360,7 +360,7 @@ def __init__(self, inVDI, inMode = None): FileUtils.AssertSafePath(self.mountDev) self.mountPoint = tempfile.mkdtemp(".xsconsole") - status, output = subprocess.getstatusoutput("/bin/mount -t auto -o " + self.mode + ' ' +self.mountDev+" "+self.mountPoint + " 2>&1") + status, output = getstatusoutput("/bin/mount -t auto -o " + self.mode + ' ' +self.mountDev+" "+self.mountPoint + " 2>&1") if status != 0: try: self.Unmount() @@ -382,7 +382,7 @@ def HandleMountFailure(self, inStatus, inOutput): # Entered after self.Unmount has run if self.vdi['SR']['type'] != 'udev' or self.vdi['SR']['content_type'] != 'disk': # Take special action for USB devices only, i.e. don't reformat SCSI disks, etc. - if inStatus == 8192: # Return code for empty CD drive + if inStatus == 32: # 32 is the mount(8) return code for mount failure, assuming empty CD drive raise Exception(Lang("Drive is empty")) raise Exception(inOutput) @@ -400,7 +400,7 @@ def HandleMountFailure(self, inStatus, inOutput): raise Exception(inOutput) realDevice = FileUtils.DeviceFromVDI(self.vdi) - status, output = subprocess.getstatusoutput("/sbin/fdisk -l '" +realDevice+"'") + status, output = getstatusoutput("/sbin/fdisk -l '" +realDevice+"'") if status != 0: raise Exception(output) @@ -437,7 +437,7 @@ def Scan(self, inRegExp = None, inNumToReturn = None): def Unmount(self): status = 0 if self.mountedVDI: - status, output = subprocess.getstatusoutput("/bin/umount '"+self.mountPoint + "' 2>&1") + status, output = getstatusoutput("/bin/umount '"+self.mountPoint + "' 2>&1") os.rmdir(self.mountPoint) self.mountedVDI = False XSLog('Unmounted '+self.mountPoint) diff --git a/plugins-base/XSFeatureDRBackup.py b/plugins-base/XSFeatureDRBackup.py index e9350c6..55b2f2c 100644 --- a/plugins-base/XSFeatureDRBackup.py +++ b/plugins-base/XSFeatureDRBackup.py @@ -16,8 +16,6 @@ if __name__ == "__main__": raise Exception("This script is a plugin for xsconsole and cannot run independently") -import subprocess - from XSConsoleStandard import * class DRBackupDialogue(SRDialogue): @@ -38,8 +36,7 @@ def DoAction(self, inSR): sr_uuid = inSR['uuid'] command = "%s/xe-backup-metadata -n -u %s" % (Config.Inst().HelperPath(), sr_uuid) - status, output = subprocess.getstatusoutput(command) - status = os.WEXITSTATUS(status) + status, output = getstatusoutput(command) initalize_vdi = "" if status == 3: initalize_vdi = "-c" @@ -48,7 +45,7 @@ def DoAction(self, inSR): Layout.Inst().TransientBanner(Lang("Backing up metadata... This may take several minutes.")) command = "%s/xe-backup-metadata %s -u %s" % (Config.Inst().HelperPath(), initalize_vdi, sr_uuid) - status, output = subprocess.getstatusoutput(command) + status, output = getstatusoutput(command) if status == 0: Layout.Inst().PushDialogue(InfoDialogue(Lang("Backup Successful"), output)) else: diff --git a/plugins-base/XSFeatureDRRestore.py b/plugins-base/XSFeatureDRRestore.py index a8aedb6..2fa6b8e 100644 --- a/plugins-base/XSFeatureDRRestore.py +++ b/plugins-base/XSFeatureDRRestore.py @@ -92,8 +92,7 @@ def HandleMethodChoice(self, inChoice, dryRun): dry_flag="" Layout.Inst().TransientBanner(Lang("Restoring VM Metadata. This may take a few minutes...")) command = "%s/xe-restore-metadata -y %s -u %s -x %s -d %s -m %s" % (Config.Inst().HelperPath(), dry_flag, self.sr_uuid, self.vdi_uuid, self.chosen_date, chosen_mode) - status, output = subprocess.getstatusoutput(command) - status = os.WEXITSTATUS(status) + status, output = getstatusoutput(command) Layout.Inst().PopDialogue() if status == 0: Layout.Inst().PushDialogue(InfoDialogue(Lang("Metadata Restore Succeeded: ") + output)) diff --git a/plugins-base/XSFeatureSRCreate.py b/plugins-base/XSFeatureSRCreate.py index c29d258..f8c1a13 100644 --- a/plugins-base/XSFeatureSRCreate.py +++ b/plugins-base/XSFeatureSRCreate.py @@ -16,8 +16,6 @@ if __name__ == "__main__": raise Exception("This script is a plugin for xsconsole and cannot run independently") -import subprocess - from XSConsoleStandard import * import xml.dom.minidom @@ -1288,7 +1286,7 @@ def CommitNFS_ATTACH(self): 'user') def CommitNFS_ISO_ATTACH(self): - self.srParams['uuid'] = subprocess.getoutput('/usr/bin/uuidgen') + self.srParams['uuid'] = getoutput('/usr/bin/uuidgen') self.CommitAttach(self.srTypes['NFS_ISO'], { # device_config 'location':self.srParams['server']+':'+self.srParams['serverpath'], 'options':self.srParams['options'] @@ -1300,7 +1298,7 @@ def CommitNFS_ISO_ATTACH(self): ) def CommitCIFS_ISO_ATTACH(self): - self.srParams['uuid'] = subprocess.getoutput('/usr/bin/uuidgen') + self.srParams['uuid'] = getoutput('/usr/bin/uuidgen') deviceConfig = { 'location':'//'+self.srParams['server']+'/'+self.srParams['serverpath'], 'type':'cifs', diff --git a/plugins-base/XSFeatureSaveBugReport.py b/plugins-base/XSFeatureSaveBugReport.py index cc9e3dc..06a7c4c 100644 --- a/plugins-base/XSFeatureSaveBugReport.py +++ b/plugins-base/XSFeatureSaveBugReport.py @@ -16,8 +16,6 @@ if __name__ == "__main__": raise Exception("This script is a plugin for xsconsole and cannot run independently") -import subprocess - from XSConsoleStandard import * class SaveBugReportDialogue(FileDialogue): @@ -52,7 +50,7 @@ def DoAction(self): file = open(filename, "w") # xen-bugtool requires a value for $USER command = "( export USER=root && /usr/sbin/xen-bugtool --yestoall --silent --output=tar --outfd="+str(file.fileno()) + ' )' - status, output = subprocess.getstatusoutput(command) + status, output = getstatusoutput(command) file.close() if status != 0: diff --git a/plugins-base/XSFeatureUploadBugReport.py b/plugins-base/XSFeatureUploadBugReport.py index 6d3b8f5..d243f95 100644 --- a/plugins-base/XSFeatureUploadBugReport.py +++ b/plugins-base/XSFeatureUploadBugReport.py @@ -16,8 +16,6 @@ if __name__ == "__main__": raise Exception("This script is a plugin for xsconsole and cannot run independently") -import subprocess - from XSConsoleStandard import * class UploadBugReportDialogue(InputDialogue): @@ -48,7 +46,7 @@ def HandleCommit(self, inValues): if proxy != '': command += " http_proxy='"+proxy+"'" - status, output = subprocess.getstatusoutput(command) + status, output = getstatusoutput(command) if status != 0: XSLogError('Upload bugreport failed', output) # Error output can be verbose, so syslog only diff --git a/plugins-oem/XSFeatureOEMBackup.py b/plugins-oem/XSFeatureOEMBackup.py index 800a6ae..334181c 100644 --- a/plugins-oem/XSFeatureOEMBackup.py +++ b/plugins-oem/XSFeatureOEMBackup.py @@ -16,8 +16,6 @@ if __name__ == "__main__": raise Exception("This script is a plugin for xsconsole and cannot run independently") -import subprocess - from XSConsoleStandard import * class OEMBackupDialogue(FileDialogue): @@ -70,7 +68,7 @@ def DoCommit(self): filename = self.vdiMount.MountedPath(self.filename) FileUtils.AssertSafePath(filename) command = "/opt/xensource/bin/xe host-backup file-name='"+filename+"' host="+hostRef - status, output = subprocess.getstatusoutput(command) + status, output = getstatusoutput(command) if status != 0: raise Exception(output) diff --git a/plugins-oem/XSFeatureOEMRestore.py b/plugins-oem/XSFeatureOEMRestore.py index 68a44b6..39770d2 100644 --- a/plugins-oem/XSFeatureOEMRestore.py +++ b/plugins-oem/XSFeatureOEMRestore.py @@ -16,8 +16,6 @@ if __name__ == "__main__": raise Exception("This script is a plugin for xsconsole and cannot run independently") -import subprocess - from XSConsoleStandard import * class OEMRestoreDialogue(FileDialogue): @@ -60,7 +58,7 @@ def DoAction(self): filename = self.vdiMount.MountedPath(self.filename) FileUtils.AssertSafePath(filename) command = "/opt/xensource/bin/xe host-restore file-name='"+filename+"' host="+hostRef - status, output = subprocess.getstatusoutput(command) + status, output = getstatusoutput(command) if status != 0: raise Exception(output) diff --git a/plugins-oem/XSFeatureUpdate.py b/plugins-oem/XSFeatureUpdate.py index b820ea1..538c1f6 100644 --- a/plugins-oem/XSFeatureUpdate.py +++ b/plugins-oem/XSFeatureUpdate.py @@ -16,8 +16,6 @@ if __name__ == "__main__": raise Exception("This script is a plugin for xsconsole and cannot run independently") -import subprocess - from XSConsoleStandard import * class UpdateDialogue(FileDialogue): @@ -60,7 +58,7 @@ def DoAction(self): filename = self.vdiMount.MountedPath(self.filename) FileUtils.AssertSafePath(filename) command = "/opt/xensource/bin/xe update-upload file-name='"+filename+"' host-uuid="+hostRef - status, output = subprocess.getstatusoutput(command) + status, output = getstatusoutput(command) if status != 0: raise Exception(output)