1   
   2  """ 
   3  This library contains APIs for executing shell commands, for getting the exit status of 
   4  the executed command, and for allowing multiple commands to run conditional on that exit status. 
   5  It is initialized with a Shell Client, and then uses the client to run commands and get the results. 
   6  """ 
   7  from com.hp.ucmdb.discovery.probe.services.dynamic.core import DynamicServiceFrameworkImpl 
   8  from com.hp.ucmdb.discovery.library.communication.downloader.cfgfiles import GeneralSettingsConfigFile 
   9   
  10  import modeling 
  11  import netutils 
  12  import logger 
  13  import errorcodes 
  14  import errorobject 
  15  import shell_interpreter 
  16  import re 
  17  import string 
  18  import sys 
  19  import codecs 
  20   
  21  from java.io import File 
  22  from java.util import Properties, WeakHashMap 
  23  from java.util import Locale 
  24  from java.nio.charset import Charset 
  25  from java.nio import ByteBuffer 
  26  from java.nio.charset import CodingErrorAction 
  27   
  28  from com.hp.ucmdb.discovery.library.common import CollectorsParameters 
  29  from com.hp.ucmdb.discovery.library.clients.agents import NTCmdSessionAgent 
  30  from com.hp.ucmdb.discovery.library.clients.agents.ssh import SSHAgent 
  31  from com.hp.ucmdb.discovery.library.clients.agents import AgentConstants 
  32  from com.hp.ucmdb.discovery.library.clients.agents import PowerShellAgent 
  33  from com.hp.ucmdb.discovery.library.clients.shell import PowerShellClient 
  34  from com.hp.ucmdb.discovery.library.clients.protocols.telnet import StreamReaderThread 
  35   
  36  from java.lang import String 
  37  from java.lang import Boolean 
  38   
  39   
  40  DDM_LINK_SYSTEM32_LOCATION = "%SystemDrive%" 
  41  DDM_LINK_SYSTEM32_NAME = "ddm_link_system32" 
  42   
  43   
  45      'Shell command base class' 
  46 -    def __init__(self, line, output=None, returnCode=None): 
   47          '''@types: str, str, int -> None 
  48          @deprecated 
  49          ''' 
  50          self.cmd = line 
  51   
  52          self.line = line 
  53          self.output = output 
  54          self.outputInBytes = [] 
  55          self.returnCode = returnCode 
  56          self.executionTimeout = 0 
  57          self.waitForTimeout = 0 
  58          self.useSudo = 1 
  59          self.checkErrCode = 1 
  60          self.preserveSudoContext = 0 
   61   
  64   
   67   
  68   
  70      r'''Language describes localized system configuration: locale, character sets, 
  71      code pages etc''' 
  72      DEFAULT_CHARSET_OBJECT = Charset.defaultCharset() 
  73   
  74 -    def __init__(self, locale, bundlePostfix, charsets, wmiCodes=None, codepage=None): 
   75          ''' Default constructor also performs initialization of supported 
  76          character sets on the probe machine 
  77          @types: java.util.Locale, str, str, list(int), int -> None''' 
  78          self.locale = locale 
  79          self.bundlePostfix = bundlePostfix 
  80          self.charsets = charsets 
  81          self.wmiCodes = wmiCodes 
  82          self.charsetNameToObject = {} 
  83          self.__initCharsets() 
  84          self.codepage = codepage 
   85   
  87          'Find supported character sets on the probe machine' 
  88          for charsetName in self.charsets: 
  89              try: 
  90                  charset = Charset.forName(charsetName) 
  91                  self.charsetNameToObject[charsetName] = charset 
  92              except: 
  93                  logger.warn("Charset is not supported: %s." % charsetName) 
    94   
  95  LOCALE_SPANISH = Locale("es", "", "") 
  96  LOCALE_RUSSIAN = Locale("ru", "", "") 
  97  LOCALE_GERMAN = Locale("de", "", "") 
  98  LOCALE_FRENCH = Locale("fr", "", "") 
  99  LOCALE_ITALIAN = Locale("it", "", "") 
 100  LOCALE_PORTUGUESE = Locale("pt", "", "") 
 101  LOCALE_CHINESE = Locale("cn", "", "") 
 102  LOCALE_KOREAN = Locale("kr", "", "") 
 103  LOCALE_DUTCH = Locale("nl", "", "") 
 104   
 105  LANG_ENGLISH = Language(Locale.ENGLISH, 'eng', ('Cp1252',), (1033,), 437) 
 106  LANG_GERMAN = Language(Locale.GERMAN, 'ger', ('Cp1252', 'Cp850'), (1031,), 850) 
 107  LANG_SPANISH = Language(LOCALE_SPANISH, 'spa', ('Cp1252',), (1034, 3082,)) 
 108  LANG_RUSSIAN = Language(LOCALE_RUSSIAN, 'rus', ('Cp866', 'Cp1251'), (1049,), 866) 
 109  LANG_JAPANESE = Language(Locale.JAPANESE, 'jap', ('MS932',), (1041,), 932) 
 110  LANG_FRENCH = Language(Locale.FRENCH, 'fra', ('Cp1252',), (1036,), 850) 
 111  LANG_ITALIAN = Language(Locale.ITALIAN, 'ita', ('Cp1252',), (1040,), 850) 
 112  LANG_DUTCH = Language(LOCALE_DUTCH, 'nld', ('Cp1252',), (1043,), 850) 
 113  LANG_PORTUGUESE = Language(LOCALE_PORTUGUESE, 'prt', ('Cp1252',), (1046,), 850) 
 114  LANG_CHINESE = Language(Locale.CHINESE, 'chn', ('MS936',), (2052,), 936) 
 115  LANG_KOREAN = Language(Locale.KOREAN, 'kor', ('MS949',), (1042,), 949) 
 116   
 117  LANGUAGES = (LANG_ENGLISH, LANG_GERMAN, LANG_SPANISH, LANG_RUSSIAN, 
 118               LANG_JAPANESE, LANG_FRENCH, LANG_ITALIAN, LANG_PORTUGUESE, 
 119               LANG_CHINESE, LANG_KOREAN, LANG_DUTCH) 
 120   
 121   
 122  DEFAULT_LANGUAGE = LANG_ENGLISH 
 123   
 124   
 126      'Discoverer determines language on destination system' 
 128          '@types: Shell -> None' 
 129          self.shell = shell 
  130   
 132          '@types: -> Language' 
 133          raise NotImplementedError() 
   134   
 135   
 137      'Windows specific discoverer' 
 141   
 143          ''' Determine language for Windows system. 
 144          @types: -> Language 
 145          @note: English will be used as default one if fails 
 146                 to determine machine encoding 
 147          ''' 
 148          language = self.getLanguageFromWmi() 
 149          if not language: 
 150              language = self.getLanguageFromChcp() 
 151          if not language: 
 152              logger.warn('Failed to determine machine encoding, using default %s' % DEFAULT_LANGUAGE.locale) 
 153              return DEFAULT_LANGUAGE 
 154          else: 
 155              return language 
  156   
 158          '''@types: -> shellutils.Language or None 
 159          @command: wmic OS Get CodeSet 
 160          ''' 
 161          osLanguageOutput = self.shell.execAlternateCmds('wmic OS Get CodeSet < %SystemRoot%\win.ini', '%WINDIR%\system32\wbem\wmic OS Get CodeSet < %SystemRoot%\win.ini') 
 162          if osLanguageOutput and self.shell.getLastCmdReturnCode() == 0: 
 163              return self.__parseLanguageFromWmi(osLanguageOutput) 
  164   
 166          '''@types: -> shellutils.Language or None 
 167          @command: wmic OS Get OSLanguage 
 168          ''' 
 169          osLanguageOutput = self.shell.execAlternateCmds('wmic OS Get OSLanguage < %SystemRoot%\win.ini', '%WINDIR%\system32\wbem\wmic OS Get OSLanguage < %SystemRoot%\win.ini') 
 170          if osLanguageOutput and self.shell.getLastCmdReturnCode() == 0: 
 171              return self.__parseLanguageFromWmi(osLanguageOutput) 
  172   
 174          '@types: str -> shellutils.Language or None' 
 175          if osLanguageOutput: 
 176              languageResult = None 
 177              matcher = re.search(r"(\d{4})", osLanguageOutput) 
 178              if matcher: 
 179                  osLanguageCodeStr = matcher.group(1) 
 180                  osLanguageCode = int(osLanguageCodeStr) 
 181                  for lang in LANGUAGES: 
 182                      if osLanguageCode in lang.wmiCodes: 
 183                          logger.debug('Bundle postfix %s' % lang.bundlePostfix) 
 184                          languageResult = lang 
 185                          break 
 186              return languageResult 
  187   
 193   
 195          ''' Determine language executing chcp command 
 196          @types: -> Language or None 
 197          @command: chcp 
 198          ''' 
 199          languageResult = None 
 200          codepage = int(self.shell.getCodePage()) 
 201          for lang in LANGUAGES: 
 202              if codepage == lang.codepage: 
 203                  logger.debug('Bundle postfix %s' % lang.bundlePostfix) 
 204                  languageResult = lang 
 205                  break 
 206          return languageResult 
   207   
 208   
 210      'For Unix destination localization is not supported. English language is used' 
 214   
  218   
 219   
 221 -    def match(self, content): 
  222          '@types: str -> bool' 
 223          raise NotImplementedError() 
   224   
 225   
 228          '@types: str -> None' 
 229          self.keyword = keyword 
  230   
 231 -    def match(self, content): 
  232          '@types: str -> bool' 
 233          logger.debug('Matching by keyword: %s' % self.keyword) 
 234           
 235          if self.keyword and content: 
 236              buffer = re.search(self.keyword, content, re.I) 
 237              if buffer: 
 238                  return 1 
   239   
 240   
 242   
 243 -    def __init__(self, bytesArray, language, framework): 
  244          '@types: jarray(byte), Language, Framework' 
 245          self.bytesArray = bytesArray 
 246          self.language = language 
 247          self.framework = framework 
 248          self.outputHandlers = [] 
  249   
 250 -    def addOutputHandler(self, handler): 
  251          '''@types: OutputHandler -> None''' 
 252          self.outputHandlers.append(handler) 
  253   
 254 -    def getDecodedString(self, outputMatcher): 
  255          ''' Select such charset that decoded content using it will match using matcher 
 256          and return decoded content 
 257          @types: OutputMatcher -> tuple(str(decoded output), str(charset name))''' 
 258          charsetObjects = self.language.charsetNameToObject.values() 
 259          if charsetObjects: 
 260              for charset in charsetObjects: 
 261                  decodedContent = self.decodeString(charset) 
 262                  for outputHandler in self.outputHandlers: 
 263                      decodedContent = outputHandler.handle(decodedContent) 
 264   
 265                  decodedContentString = str(String(decodedContent)) 
 266                  if outputMatcher.match(decodedContentString): 
 267                      return (decodedContentString, charset.name()) 
 268   
 269              msg = "Command output verification has failed. Check whether the language is supported." 
 270              errobj = errorobject.createError(errorcodes.COMMAND_OUTPUT_VERIFICATION_FAILED, None, msg) 
 271              logger.reportWarningObject(errobj) 
 272              logger.debug(msg) 
 273   
 274          charset = Language.DEFAULT_CHARSET_OBJECT 
 275          decodedContent = str(String(self.decodeString(charset))) 
 276          return (decodedContent, charset.name()) 
  277   
 278 -    def decodeString(self, charsetObject): 
  279          ''' Decode string with specified charset 
 280          @types: java.nio.charset.Charset -> jarray(char)''' 
 281          decoder = charsetObject.newDecoder() 
 282          decoder.onMalformedInput(CodingErrorAction.REPLACE) 
 283          decoder.onUnmappableCharacter(CodingErrorAction.REPLACE) 
 284          charBuffer = decoder.decode(ByteBuffer.wrap(self.bytesArray)) 
 285          return charBuffer.array() 
   286   
 287   
 290          '@types: jarray(char) -> jarray(char)' 
 291          return contents 
   292   
 293   
 304   
 306          '@types: jarray(char) -> str' 
 307          return SSHAgent.translateBackspace(String(contents)) 
  308   
 310          '@types: str -> str' 
 311          return SSHAgent.removeMarkers(contents) 
   312   
 313   
 315      POWERSHELL_CMD_SUCCESS = 'True' 
 316      POWERSHELL_CMD_FAILED = 'False' 
 317   
 318 -    def __init__(self, command=None, trimWS=None): 
  319          '@types: str, bool' 
 320          self.command = command 
 321          self.trimWS = trimWS 
  322   
 334   
 351   
 352 -    def handle(self, contentChars): 
  353          '''@types: jarray(char) -> jarray(char)''' 
 354          cleanedOutput = PowerShellAgent.cleanupCommandOutput(self.command, String(contentChars), self.trimWS) 
 355          return String(cleanedOutput).toCharArray() 
   356   
 357   
 360          '@types: str, bool' 
 361          self.command = command 
 362          self.trimWS = trimWS 
  363   
 364 -    def handle(self, contentChars): 
  365          '@types: jarray(char) -> jarray(char)' 
 366          cleanedOutput = NTCmdSessionAgent.cleanupCommandOutput(self.command, String(contentChars), self.trimWS) 
 367          return String(cleanedOutput).toCharArray() 
   368   
 369   
 372          '@types: jarray(char) -> jarray(char)' 
 373          return StreamReaderThread.translateBackspace(contents, len(contents)).toCharArray() 
   374   
 375   
 377      ''' Command transaction class. 
 378      Provides possibility to define alternative ways for determining command execution status 
 379      ''' 
 380 -    def __init__(self, cmd, expectedReturnCode=None, sucessString=None, failureString=None): 
  381          '''@types: str, int, str, str''' 
 382          self.cmd = cmd 
 383          self.expectedReturnCode = expectedReturnCode 
 384          self.sucessString = sucessString 
 385          self.failureString = failureString 
   386   
 387   
 388 -def ShellUtils(client, props=None, protocolName=None): 
  389      '''BaseClient or DynamicServiceFrameworkImpl, java.util.Properties, str -> Shell 
 390      This method play role of factory method for backward compatibility and will be removed in further releases 
 391      @deprecated: Use ShellFactory instead 
 392      @raise Exception: failed to detect OS 
 393      ''' 
 394      if isinstance(client, DynamicServiceFrameworkImpl): 
 395          if not props: 
 396              props = Properties() 
 397          Framework = client 
 398          client = Framework.createClient(props) 
 399       
 400      return ShellFactory().createShell(client, protocolName) 
  401   
 402   
 404      '''This class manages shell creation for different shell protocols SSH, Telnet, or NTCMD.''' 
 430   
 432          ''' Check for cygwin shell. In cygwin shell it is possible to launch 
 433          windows command interpreter. 
 434          @types: Client -> bool 
 435          @command: cmd.exe /c ver 
 436          @raise Exception: Failed starting Windows Cmd Shell 
 437          ''' 
 438          winOs = 0 
 439          logger.debug('Check for Cygwin installed on Windows') 
 440          buffer = shellClient.executeCmd('cmd.exe /c ver') 
 441          if self.__isWinDetectInVerOutput(buffer): 
 442              try: 
 443                  logger.debug('Entering Windows CMD shell') 
 444                  shellClient.executeCmd('cmd.exe', 10000, 1) 
 445                  shellClient.getShellCmdSeperator() 
 446              except: 
 447                  raise Exception("Failed starting Windows Cmd Shell") 
 448              winOs = 1 
 449          return winOs 
  450   
 452          ''' Determine windows shell trying to execute 'ver' command 
 453          @command: ver 
 454          @types: BaseClient -> bool 
 455          @raise Exception: Failed detecting OS type 
 456          ''' 
 457          try: 
 458              osBuff = shellClient.executeCmd('ver') 
 459              if osBuff is None: 
 460                  errMsg = 'Failed detecting OS type. command=\'ver\' returned with no output' 
 461                  logger.error(errMsg) 
 462                  raise Exception(errMsg) 
 463               
 464               
 465              winOs = self.__isWinDetectInVerOutput(osBuff) 
 466              return winOs 
 467          except: 
 468              errMsg = 'Failed detecting OS type. Exception received: %s' % (sys.exc_info()[1]) 
 469              logger.error(errMsg) 
 470              raise Exception(errMsg) 
  471   
 473          '''Determine restricted shell of VIO server installed on AIX 
 474          @command: ioscli uname -a 
 475          @types: BaseClient -> bool''' 
 476          logger.debug("Check for IBM VIO Server Shell") 
 477          isVioServer = 0 
 478          try: 
 479              output = shellClient.executeCmd("ioscli uname -a") 
 480              if not output or output.count("ioscli"): 
 481                  logger.debug('Failed detecting IBM VIO Server. %s' % output) 
 482              else: 
 483                  isVioServer = 1 
 484          except: 
 485              logger.warnException('Failed detecting IBM VIO Server') 
 486          return isVioServer 
  487   
 489          try: 
 490              osBuff = shellClient.executeCmd('uname') 
 491              if osBuff and re.match("\s*Darwin", osBuff): 
 492                  return 1 
 493          except: 
 494              logger.warn('Failed checking for MacOS') 
 495              logger.debugException('') 
  496   
 498          '@types: str -> bool' 
 499          return (buffer 
 500                  and (buffer.lower().find('windows') > -1 
 501                       or buffer.find('MS-DOS') > -1)) 
   502   
 503   
 505      'Exception case when command does not exists or cannot be recognized' 
 506      pass 
  507   
 508   
 510      'Exception case when client has no permission to execute command' 
 511      pass 
  512   
 513   
 515      """ 
 516      Class for managing Shell connections via SSH, Telnet, or NTCmd 
 517   
 518      B{Shell is not thread-safe.} Every thread must have its own instance. 
 519      """ 
 520       
 521      NO_CMD_RETURN_CODE_ERR_NUMBER = -9999  
 522   
 524          '@types: Client' 
 525          self.cmdCache = WeakHashMap() 
 526           
 527          self.__client = client                 
 528           
 529          self.osType = None                     
 530           
 531          self.osVer = None                     
 532          self.__lastCmdReturnCode = None        
 533          self.__alternateCmdList = []         
 534          self.__shellCmdSeparator = None 
 535   
 536           
 537          self.winOs = self.isWinOs() 
 538          self.getOsType() 
 539           
 540          self.getLastCommandOutputBytes = None 
 541           
 542          self.lastExecutedCommand = None 
 543           
 544          self.copiedFiles = [] 
 545   
 546          self.osLanguage = None 
 547           
 548          self.charsetName = None 
 549          self.determineOsLanguage() 
 550   
 551          if self.osLanguage.charsets: 
 552              self.useCharset(self.osLanguage.charsets[0]) 
 553           
 554          self.globalSettings = GeneralSettingsConfigFile.getInstance() 
 555          self.__defaultCommandTimeout = None 
 556          self.getDefaultCommandTimeout() 
  557   
 559          ''' Get default command timeout declared in globalSettings.xml 
 560          @types: -> number 
 561          ''' 
 562          if not self.__defaultCommandTimeout: 
 563              self.__defaultCommandTimeout = self.globalSettings.getPropertyIntegerValue('shellGlobalCommandTimeout', 1) 
 564          return self.__defaultCommandTimeout 
  565   
 567          '@deprecated: Unix only dedicated' 
 568          pass 
  569   
 571          '@types: -> bool' 
 572          return NotImplementedError() 
  573   
 575          """Returns the type of the operating system running on the target host to which the shell client is connected 
 576          @types: -> str 
 577          @raise Exception: Failed getting machine OS type 
 578          """ 
 579          if not self.osType: 
 580              try: 
 581                  self.osType = self._getOsType() 
 582              except Exception, e: 
 583                  logger.errorException(str(e)) 
 584                  raise Exception('Failed getting machine OS type') 
 585          return self.osType 
  586   
 588          ''' Template method for each derived class to get properly OS type 
 589          @types: -> str 
 590          @raise Exception: Failed getting machine OS type''' 
 591          return NotImplementedError() 
  592   
 594          ''' Indicates whether running commands in cygwin shell 
 595          @types: -> bool 
 596          @deprecated: will be removed from public access''' 
 597          return 0 
  598   
 600          """ Get version of the OS running on the target host to which the shell 
 601          client is connected 
 602          @types: -> str or None 
 603          @deprecated: should be moved to the OS discoverer (domain layer) 
 604          """ 
 605          if not self.osVer: 
 606              try: 
 607                  self.osVer = self._getOsVersion() 
 608              except Exception, e: 
 609                  logger.warn(str(e)) 
 610          return self.osVer 
  611   
 613          return self.osLanguage 
  614   
 618   
 620          ''' Template method to get OS version for derived shell 
 621          @types: -> str 
 622          @raise Exception: Failed to get OS version 
 623          ''' 
 624          return NotImplemented 
  625   
 627          '@types: -> OsLanguageDiscoverer' 
 628          raise NotImplemented 
  629   
 631          ''' Use specified character set for command encoding and output decoding in raw client 
 632          @types: str 
 633          @raise IllegalCharsetNameException: The given charset name is illegal 
 634          @raise UnsupportedCharsetException: No support for the named charset is available in this instance of the JVM 
 635          ''' 
 636          charset = Charset.forName(charsetName) 
 637          logger.debug('Using charset: %s' % charsetName) 
 638          logger.debug('Can encode: %s' % charset.canEncode()) 
 639          self.__client.setCharset(charset) 
  640   
 642          """ Returns the shell command exit status code 
 643          @types: -> str 
 644          """ 
 645          raise NotImplemented 
  646   
 648          ''' Get command separator depending on OS type 
 649          @types: -> str''' 
 650          return self.getShellCmdSeperator() 
  651   
 653          """ 
 654          Returns the shell command separator character. 
 655          This is the character used between commands when more than one command 
 656          is passed on the same command line. 
 657          @types: -> str 
 658          @deprecated: Use getCommandSeparator instead 
 659          """ 
 660          if (self.__shellCmdSeparator is None): 
 661              self.__shellCmdSeparator = self.__client.getShellCmdSeperator() 
 662          return self.__shellCmdSeparator 
  663   
 664 -    def __addAlternateCmd(self, cmd, expectedReturnCode=None, sucessString=None, failureString=None): 
  665          '''Add alternative command to execute list 
 666          @types: str, int, str, str''' 
 667          self.__alternateCmdList.append(__CmdTransaction(cmd, expectedReturnCode, sucessString, failureString)) 
  668   
 670          if (len(self.__alternateCmdList) > 0): 
 671              self.__alternateCmdList = [] 
  672   
 674          ''' Go over all alternative commands list and execute each until the first successful command termination. 
 675           This method basically executes shell commands and retrieves terminate status of the executed command 
 676           until a command ended successfully. 
 677           command is successful when: 
 678           1. it returned the expected return code. 
 679           2. if no return code is given, the output of the command is compared against sucessString 
 680                to determine command success. 
 681           3. if failureString is given the output of the command is compared against failureString 
 682                to determine command failure 
 683          @types: int -> str 
 684          ''' 
 685          err_output = '' 
 686          for cmdTrans in self.__alternateCmdList: 
 687              try: 
 688                  output = self.execCmd(cmdTrans.cmd, timeout) 
 689                  if (cmdTrans.expectedReturnCode is not None): 
 690                      if (cmdTrans.expectedReturnCode == self.getLastCmdReturnCode()): 
 691                          logger.debug('command=\'%s\' ended successfully' % cmdTrans.cmd) 
 692                          return output 
 693                      else: 
 694                          err_output = '%s\n%s' % (err_output, output) 
 695                          logger.debug('command=%s did not pass return code creteria. got rc=%d expected rc=%d' % (cmdTrans.cmd, self.getLastCmdReturnCode(), cmdTrans.expectedReturnCode)) 
 696                          continue 
 697                  elif(cmdTrans.sucessString is not None): 
 698                      if (output.find(cmdTrans.sucessString) > -1): 
 699                           
 700                          logger.debug('command=\'%s\' ended successfully' % cmdTrans.cmd) 
 701                          return output 
 702                      else: 
 703                          err_output = '%s\n%s' % (err_output, output) 
 704                          logger.debug('command=%s did not pass sucsess string creteria. got output string=%s expected=%s' % (cmdTrans.cmd, output, cmdTrans.sucessString)) 
 705                          continue 
 706                  elif(cmdTrans.failureString is not None): 
 707                      if (output.find(cmdTrans.sucessString) > -1): 
 708                           
 709                          logger.debug('command=\'%s\' did not pass failure string creteria. got output string=%s which contains failure string=%s' % (cmdTrans.cmd, output, cmdTrans.failureString)) 
 710                          err_output = '%s\n%s' % (err_output, output) 
 711                          continue 
 712                      else: 
 713                           
 714                          logger.debug('command=\'%s\' ended successfully' % cmdTrans.cmd) 
 715                          return output 
 716              except: 
 717                  logger.warnException('Failed to execute %s.' % cmdTrans.cmd) 
 718          return err_output 
  719   
 721          """ 
 722          Executes the input list of shell commands until one of them succeeds. 
 723          @types: vararg(str) -> str or None 
 724          @return: output of the first successful command, otherwise None 
 725          """ 
 726          return self.execAlternateCmdsList(commands) 
  727   
 729          """ 
 730          Executes the input list of shell commands until one of them succeeds. 
 731          @types: list(str), int -> str or None 
 732          @param timeout: timeout for each command in milliseconds 
 733          @return: output of the first successesfull command, otherwise None 
 734          """ 
 735          for cmd in commands: 
 736              logger.debug('adding alternate cmd=\'%s\'' % cmd) 
 737              self.__addAlternateCmd(cmd, 0) 
 738          output = self.__execCmdSet(timeout) 
 739          self.__removeAllAlternateCmds() 
 740          return output 
  741   
 743          """ 
 744          Returns the exit status of the last shell command issued by execCmd or execAlternateCmds methods 
 745          @types: -> int 
 746          @return: exit status of the last command issued 
 747          @raise Exception: Cannot get last command return code: no command was issued 
 748          """ 
 749          if (self.__lastCmdReturnCode is None): 
 750              raise Exception('Cannot get last command return code: no command was issued') 
 751          return self.__lastCmdReturnCode 
  752   
 754          """ Checks whether the file or directory exists on the File System 
 755          @types: str -> bool 
 756          @deprecated: Use FileSystem methods instead 
 757          """ 
 758          raise NotImplemented 
  759   
 760 -    def execCmd(self, cmdLine, timeout=0, waitForTimeout=0, useSudo=1, checkErrCode=1, useCache=0, preserveSudoContext=0): 
  761          """ Executes a shell command and sets the exit status of the command. 
 762          @types: str, int, int, bool, bool, bool -> str 
 763          Issue the given command followed by an echo of its return status, in the last line of the output 
 764          The exit status is an integer. 
 765          @param cmdLine: command to execute 
 766          @param timeout: time in ms or if < 1ms treated as coefficient for predefined timeout 
 767          @return: output of the executed shell command 
 768          @raise Exception: Command execution does not produced output nor return code 
 769          """ 
 770           
 771          if useCache and self.cmdCache.containsKey(cmdLine): 
 772              command = self.cmdCache.get(cmdLine) 
 773              self.__lastCmdReturnCode = command.returnCode 
 774              self.getLastCommandOutputBytes = command.outputInBytes 
 775              return command.output 
 776   
 777          if timeout and timeout < 1000: 
 778              timeout = timeout * self.__defaultCommandTimeout 
 779   
 780          command = Command(cmdLine) 
 781          command.executionTimeout = timeout 
 782          command.waitForTimeout = waitForTimeout 
 783          command.useSudo = useSudo 
 784          command.checkErrCode = checkErrCode 
 785          command.preserveSudoContext = preserveSudoContext 
 786   
 787          command = self._execute(command) 
 788   
 789          self.__lastCmdReturnCode = command.returnCode 
 790          self.getLastCommandOutputBytes = command.outputInBytes 
 791   
 792          self.cmdCache.put(cmdLine, command) 
 793          return command.output 
  794   
 796          ''' Template method for derived shells for exact command execution 
 797          @types: Command -> Command 
 798          @raise Exception 
 799          @raise NoPermission 
 800          @raise CommandNotFound 
 801          ''' 
 802          raise NotImplemented 
  803   
 804 -    def execCmdAsBytes(self, cmdLine, timeout=0, waitForTimeout=0, useSudo=1): 
  805          ''' Get raw data as list of bytes. 
 806          @types: str, int, int, bool -> list(byte)''' 
 807          self.execCmd(cmdLine, timeout, waitForTimeout, useSudo) 
 808          return self.getLastCommandOutputBytes 
  809   
 810 -    def resolveHost(self, hostName, nodeClassName='node'): 
  811          """ Create host CI with IP as key resolved by host name 
 812          @types: str -> ObjectStateHolder or None 
 813          @return: IP address or None if IP cannot be resolved or is local 
 814          @deprecated: Will be removed in further version 
 815          """ 
 816          node_ip = None 
 817          dns_name = None 
 818          try: 
 819              node_ip = netutils.getHostAddress(hostName, None) 
 820          except: 
 821              node_ip = None 
 822          if (node_ip is None) or netutils.isLocalIp(node_ip): 
 823              try: 
 824                  logger.debug('Trying to resolve ip for node %s by nslookup command' % hostName) 
 825                  result = self.execCmd('nslookup %s' % hostName) 
 826                  logger.debug('nslookup command returned result:', result) 
 827                  m = re.search('(Name:)\s+(.+)\s+(Address:)\s+(\d+\.\d+\.\d+\.\d+)', result) or re.search('(Name:)\s+(.+)\s+(Addresses:)\s+(?:[0-9a-f:]*)\s+(\d+\.\d+\.\d+\.\d+)', result) 
 828                  if m is not None: 
 829                      node_ip = m.group(4).strip() 
 830                      dns_name = m.group(2).strip() 
 831                  else: 
 832                      node_ip = None 
 833              except: 
 834                  logger.debugException('Failed to resolve ip address of cluster node ', hostName) 
 835                  node_ip = None 
 836          if (node_ip is None) or netutils.isLocalIp(node_ip): 
 837              return None 
 838          nodeHostOSH = modeling.createHostOSH(node_ip, nodeClassName) 
 839          if dns_name: 
 840              nodeHostOSH.setStringAttribute('host_dnsname', dns_name) 
 841          if hostName and not hostName.count('.'): 
 842              nodeHostOSH.setStringAttribute('host_hostname', hostName) 
 843          return nodeHostOSH 
  844   
 846          """ Resolve IP by host name 
 847          @types: str -> str or None 
 848          @return: IP address or None if IP cannot be resolved or is local 
 849          @deprecated: Use netutils.IpResolver instead 
 850          """ 
 851          node_ip = None 
 852          try: 
 853              node_ip = netutils.getHostAddress(hostName, None) 
 854          except: 
 855              node_ip = None 
 856          if (node_ip is None) or (netutils.isLocalIp(node_ip)): 
 857              try: 
 858                  logger.debug('Trying to resolve ip for node %s by nslookup command' % hostName) 
 859                  result = self.execCmd('nslookup %s' % hostName) 
 860                  logger.debug('nslookup command returned result:', result) 
 861                  m = re.search('(Name:)\s+(.+)\s+(Address:)\s+(\d+\.\d+\.\d+\.\d+)', result) or re.search('(Name:)\s+(.+)\s+(Addresses:)\s+(?:[0-9a-f:]*)\s+(\d+\.\d+\.\d+\.\d+)', result) 
 862                  if m is not None: 
 863                      node_ip = m.group(4).strip() 
 864                  else: 
 865                      node_ip = None 
 866              except: 
 867                  logger.debugException('Failed to resolve ip address of cluster node ', hostName) 
 868                  node_ip = None 
 869          if (node_ip is None) or (netutils.isLocalIp(node_ip)): 
 870              return None 
 871          return node_ip 
  872   
 873 -    def getXML(self, path, forceSudo=0): 
  874          ''' Get xml content with proper encoding 
 875          @types: str, bool -> str 
 876          @param forceSudo:if true, always uses sudo, if false first tries to run command without sudo 
 877          @deprecated: Use file system module for such purposes 
 878          ''' 
 879          content = self.safecat(path, forceSudo) 
 880          if content: 
 881              match = re.search(r'encoding="(\S+.)"', content) 
 882              if match: 
 883                  encoding = match.group(1) 
 884                  encodedContent = String(self.getLastCommandOutputBytes, encoding) 
 885                  handler = self.createOutputHandler(self.lastExecutedCommand) 
 886                  output = handler.handle(encodedContent) 
 887                  return str(String(output)) 
 888          return content 
  889   
 890 -    def safecat(self, path, forceSudo=0): 
  891          ''' Get file content by specified path 
 892          @types: str, bool -> str 
 893          @deprecated: Use methods from file system module instead 
 894          @param path:full path (including name) to the desired file 
 895          @param forceSudo:if true, always uses sudo, if false first tries to run command without sudo 
 896          @raise Exception: Redirection symbols used or getting content failed 
 897          ''' 
 898          raise NotImplemented 
  899   
 901          '@types: -> str' 
 902           
 903          return self.__client.getClientType() 
  904   
 906          '@types: -> int' 
 907          return self.__client.getPort() 
  908   
 912   
 914          '''Perform cleaning of temporary data on destination system and close the client''' 
 915          self.__removeCopiedData() 
 916          self.__client and self.__client.close() 
  917   
 919          removeCopiedData = self.globalSettings.getPropertyStringValue('removeCopiedFiles', 'true') 
 920          if removeCopiedData and removeCopiedData.lower() == 'true': 
 921              for remoteFile in self.copiedFiles: 
 922                  self.deleteFile(remoteFile) 
  923   
 925          '''Indicates whether client can copy files to the remote system 
 926          @types: -> bool''' 
 927          return self.__client.canCopyFile() 
  928   
 930          ''' Normalize path to one used in OS client connected to 
 931          @types: str -> str 
 932          @deprecated: Use methods from file system module instead 
 933          ''' 
 934          raise NotImplemented 
  935   
 937          ''' Create output handler depending OS type 
 938          @types: str -> OutputHandler 
 939          @deprecated: Will be moved to the private scope 
 940          @raise ValueError: If decoding is not supported for used protocol type 
 941          ''' 
 942          if self.getClientType() == 'ntadmin': 
 943              trimWSString = self.__client.getProperty(AgentConstants.PROP_NTCMD_AGENT_TRIM_WHITESPACE) 
 944              trimWS = 1 
 945   
 946              if trimWSString: 
 947                  trimWS = Boolean.parseBoolean(trimWSString) 
 948   
 949              return NTCMDOutputHandler(cmd, trimWS) 
 950          elif self.getClientType() == 'ssh': 
 951              return SSHOutputHandler() 
 952          elif self.getClientType() == 'telnet': 
 953              return TelnetOutputHandler() 
 954          elif self.getClientType() == PowerShell.PROTOCOL_TYPE: 
 955              return PowerShellOutputHandler(cmd, 1) 
 956          else: 
 957              raise ValueError("Decoding is not supported for protocol type %s" % self.getClientType()) 
  958   
 960          ''' Execute command and try to decode output using predefined charsets. 
 961          Decoded output considered as valid if it is matched by provided matcher. 
 962          @types: str, OutputMatcher, Framework, int, int, bool, Language -> str 
 963          @param matcher: defines matching case for valid character set 
 964          ''' 
 965          language = language or self.osLanguage 
 966   
 967          commandBytes = self.execCmdAsBytes(cmd, timeout, waitForTimeout, useSudo) 
 968          encodingContext = EncodingContext(commandBytes, language, framework) 
 969   
 970          encodingContext.addOutputHandler(self.createOutputHandler(cmd)) 
 971   
 972          (result, charsetName) = encodingContext.getDecodedString(matcher) 
 973          self.charsetName = charsetName 
 974          return result 
  975   
 976 -    def executeCommandAndDecode(self, cmd, keyword, framework, timeout=0, waitForTimeout=0, useSudo=1, language=None): 
  977          ''' Execute command and try to decode output using predefined charsets. 
 978          Decoded output considered as valid if it is matched by KEYWORD matcher. 
 979          @types: str, str, Framework, int, int, bool, Language -> str''' 
 980          return self.executeCommandAndDecodeByMatcher(cmd, KeywordOutputMatcher(keyword), framework, timeout, waitForTimeout, useSudo, language) 
  981   
 983          ''' Get name of the character set for the latest command execution 
 984          @types: -> str or None 
 985          ''' 
 986          return self.charsetName 
   987   
 988   
 990      'Basic class for Windows shell' 
 991       
 992      DEFAULT_ENGLISH_CODEPAGE = 437 
 993      DEFAULT_WIN_SHARE = 'admin$\\system32\\drivers\etc' 
 994      __DEFAULT_COMMAND_SEPARATOR = '&' 
 995   
 996 -    def __init__(self, client, protocolName): 
  997          ''' @types: Client, str''' 
 998          self.__shellStatusVar = '%ERRORLEVEL%' 
 999          self.__protocolName = protocolName 
1000          self.__osLanguageDiscoverer = WindowsLanguageDiscoverer(self) 
1001          self.__client = client 
1002          self.__pathAppended = 0 
1003          self.__is64Bit = None 
1004   
1005           
1006           
1007          self.__ddm_link_system32 = None 
1008          self.__system32 = None 
1009   
1010          Shell.__init__(self, client) 
 1011   
1013          '@types: -> bool' 
1014          return 1 
 1015   
1017          '@types: -> OsLanguageDiscoverer' 
1018          return self.__osLanguageDiscoverer 
 1019   
1021          """ Get the shell command separator character. 
1022          This is the character used between commands when more than one command is passed on the same command line. 
1023          @types: -> str 
1024          @deprecated: Use getCommandSeparator instead 
1025          """ 
1026          return WinShell.__DEFAULT_COMMAND_SEPARATOR 
 1027   
1028 -    def getCodePage(self): 
 1029          """Get current codepage of remote Windows machine to which the shell client is connected or 437 if codepage was not resolved 
1030          @types: -> Integer 
1031          @command: chcp 
1032          """ 
1033          codePage = WinShell.DEFAULT_ENGLISH_CODEPAGE 
1034          try: 
1035              chcpBuffer = self.execCmd('chcp') 
1036              if chcpBuffer and self.getLastCmdReturnCode() == 0: 
1037                  cpMatch = re.search('(\d{3})',chcpBuffer) 
1038                  if cpMatch: 
1039                      codePage = int(cpMatch.group(1)) 
1040          except: 
1041              logger.warn("Failed to detect codepage, assuming default: 437") 
1042          return codePage 
 1043   
1045          """Set new codepage on remote Windows machine to which the shell client is connected 
1046          @Types: Integer -> Integer 
1047          @command: chcp <codepage> 
1048          """ 
1049          try: 
1050              self.execCmd('chcp %s' % str(newCodePage)) 
1051          except: 
1052              return 0 
1053          else: 
1054              return 1 
 1055   
1057          '@types: -> str' 
1058          return self.__shellStatusVar 
 1059   
1061          """ Get the type of the OS running on the target host to which the shell client is connected. 
1062          types: -> str 
1063          @command: ver 
1064          @raise Exception: Failed getting machine OS type. 
1065          """ 
1066          osBuff = self.execCmd('ver', useCache=1) 
1067          if (self.getLastCmdReturnCode() == self.NO_CMD_RETURN_CODE_ERR_NUMBER and self.__protocolName == 'sshprotocol'): 
1068              self.__shellStatusVar = '$?' 
1069              osBuff = self.execCmd('ver') 
1070          if (self.getLastCmdReturnCode() != 0): 
1071              logger.debug('failed getting os type. command=ver failed with rc=%d' % (self.getLastCmdReturnCode()) + ". Output buffer :" + osBuff) 
1072              raise Exception('Failed getting machine OS type.') 
1073          else: 
1074              match = re.search('(.*)\s*\[', osBuff) 
1075              if (match is None): 
1076                  logger.debug('failed getting os type. unrecognized ver command output') 
1077                  raise Exception('Failed getting machine OS type.') 
1078              else: 
1079                  self.osType = match.group(1).strip() 
1080          return self.osType 
 1081   
1083          ''' Get OS Version 
1084          @types: -> str 
1085          @command: ver 
1086          @raise Exception: Failed getting os type 
1087          ''' 
1088          buffer = self.execCmd('ver') 
1089          if (self.getLastCmdReturnCode() != 0): 
1090              raise Exception('Failed getting os version. command=ver failed with rc=%d' % (self.getLastCmdReturnCode())) 
1091          else: 
1092              match = re.search('\[.*\s(.*)\]', buffer) 
1093              if match: 
1094                  return match.group(1) 
1095              else: 
1096                  raise Exception('Failed getting os type. unrecognized ver command output') 
 1097   
1099          ''' Get the return code for the latest command execution 
1100          @types: -> str 
1101          @command: echo %ERRORLEVEL% 
1102          @deprecated: Will be removed from the public access''' 
1103          return self.__client.executeCmd('echo %ERRORLEVEL%') 
 1104   
1106          '''@types: Command -> Command 
1107          @raise Exception: Command execution does not produced output nor return code 
1108          ''' 
1109          output = self.__client.executeCmd(cmd.line, cmd.executionTimeout, cmd.waitForTimeout) 
1110          cmd.outputInBytes = self.__client.getLastCommandOutputBytes() 
1111          try: 
1112              cmd.returnCode = int(self.getWindowsErrorCode()) 
1113          except: 
1114              cmd.returnCode = self.NO_CMD_RETURN_CODE_ERR_NUMBER 
1115              if output is None: 
1116                  raise Exception('Executing command: "%s" failed. Command produced no output and no return status (we might be connected to an unstable agent)' % cmd.cmd) 
1117          cmd.output = output 
1118          return cmd 
 1119   
1121          """ Delete directory 
1122          @types: str 
1123          @comamnd: rmdir "<dirPath>" /s /q 
1124          @raise ValueError: Specified path is empty 
1125          @raise ValueError: Failed deleting directory 
1126          @deprecated: Use methods from file system module instead 
1127          """ 
1128          if not dirPath: 
1129              raise ValueError("dirPath is empty") 
1130          self.execCmd("rmdir \"%s\" /s /q" % dirPath) 
1131          if self.getLastCmdReturnCode() != 0: 
1132              raise ValueError("Failed deleting directory '%s'" % dirPath) 
 1133   
1135          """ Create directory 
1136          @types: str 
1137          @command: mkdir "<dirPath>" 
1138          @raise ValueError: Specified path is empty 
1139          @raise ValueError: Failed creating directory 
1140          @deprecated: Use methods from file system module instead 
1141          """ 
1142          if not dirPath: 
1143              raise ValueError("dirPath is empty") 
1144          self.execCmd("mkdir \"%s\"" % dirPath) 
1145          if self.getLastCmdReturnCode() != 0: 
1146              raise ValueError("Failed creating directory '%s'" % dirPath) 
 1147   
1149          """ Copy file from the remote share resource 
1150          @types: str, str -> None 
1151          @deprecated: Use methods from file system module instead 
1152          """ 
1153          return self.__client.getFile(remoteFileName, remoteShareName) 
 1154   
1156          """ Delete file from the remote share resource 
1157          @types: str, str -> None 
1158          @deprecated: Use methods from file system module instead 
1159          """ 
1160          return self.__client.deleteFile(remoteFile, remoteShare) 
 1161   
1163          """ Copy file to the remote share. If file exists it will be rewritten. 
1164          @types: str, str -> bool 
1165          """ 
1166          if self.__client.putFile(localFilePath, share): 
1167              remoteFile = self.__composeRemotePath(localFilePath, share) 
1168              self.copiedFiles.append(remoteFile) 
1169              logger.debug("Create file on destination: ", remoteFile) 
1170              return 1 
 1171   
1173          """ Delete remote file 
1174          @types: str, str -> bool 
1175          @deprecated: Use methods from file system module instead 
1176          """ 
1177          isDeleted = self.__client.deleteFile(remoteFile, share) 
1178          if not isDeleted: 
1179              self.execCmd('del ' + remoteFile) 
1180              isDeleted = not self.getLastCmdReturnCode() 
1181          return isDeleted 
 1182   
1184          '''@types: str, str -> str 
1185          @return: String of format "\\<ip address>\<share>\<file name> 
1186          ''' 
1187          file_ = File(localFilePath) 
1188           
1189           
1190          ipAddress = self.__client.getIpAddress() or '127.0.0.1' 
1191          remoteFile = '\\\\' + ipAddress + '\\' + share + '\\' + file_.getName() 
1192          return remoteFile 
 1193   
1195          """ Copy file to the share if it does not exist there 
1196          @types: str, str -> str or None 
1197          @command: dir \\ip_address\share\file_name 
1198          @deprecated: Use methods from file system module instead 
1199          @return: return None if file is not copied 
1200          """ 
1201          remoteFile = self.__composeRemotePath(localFile, share) 
1202          self.execCmd('dir ' + remoteFile) 
1203   
1204          if self.getLastCmdReturnCode() != 0: 
1205              if self.__client.putFile(localFile, share): 
1206                  self.copiedFiles.append(remoteFile) 
1207                  logger.debug("Create file on destination: ", remoteFile) 
1208              else: 
1209                  return None 
1210   
1211           
1212          if not self.__pathAppended: 
1213              try: 
1214                  interpreter = shell_interpreter.Factory().create(self) 
1215                  systemRoot = interpreter.getEnvironment().buildVarRepresentation('SystemRoot') 
1216                  interpreter.getEnvironment().appendPath('PATH', '%s\\system32\\drivers\\etc' % systemRoot, 
1217                      '%s\\SysWOW64' % systemRoot, 
1218                      '%s\\system32' % systemRoot) 
1219                  self.__pathAppended = 1 
1220              except: 
1221                  logger.debugException('Failed to append path using shell_interpreter') 
1222   
1223          return remoteFile 
 1224   
1226          """ Get case sensitive name of Windows %SystemRoot% 
1227          @command: dir %SystemRoot% /O:-D | find /I "system32" 
1228          @raise ValueError: Failed to find system32 folder inside the %SystemRoot% 
1229          @deprecated: Use methods from file system module instead 
1230          """ 
1231          system32Line = self.execCmd('dir %SystemRoot% /O:-D | find /I "system32"') 
1232          system32Name = None 
1233          if self.getLastCmdReturnCode() == 0: 
1234              match = re.search(r'.*\s+(system32)$', system32Line, re.IGNORECASE) 
1235              if match: 
1236                  system32Name = match.group(1) 
1237   
1238          if not system32Name: 
1239              raise ValueError('Failed to find system32 folder inside the %SystemRoot%') 
1240   
1241          return system32Name 
 1242   
1244          """ Creates, locks and returns NTFS junction point to %SystemRoot%\\System32 
1245          using (in fallback order) linkd, mklink and junction commands. 
1246          @types: str, bool, bool -> str or None 
1247          @param lock: variable to control whether to lock or not the created junction point once it is created, default is 1 (meaning lock it) 
1248          @param force: variable to control whether Universal Discovery should decide upon creation of junction point (WinOS + 64bit) or forcibly create it 
1249          @raise ValueError: if creation or locking failed 
1250          @command: linkd <src> <dest> 
1251          @command: mklink /d <src> <dest> 
1252          @command: junction <src> <dest> /accepteula 
1253          @deprecated: Use methods from file system module instead 
1254          """ 
1255          actualLinkFolder = None 
1256          if (0 == force): 
1257              if not (self.isWinOs() and self.is64BitMachine()): 
1258                  return 
1259          if not self.__system32: 
1260              self.__system32 = '%SystemRoot%' + '\\' + self.getSystem32DirectoryName() 
1261              self.__ddm_link_system32 = "%s\\%s" % (DDM_LINK_SYSTEM32_LOCATION, DDM_LINK_SYSTEM32_NAME) 
1262          if location: 
1263              actualLinkFolder = location 
1264          else: 
1265              actualLinkFolder = self.__ddm_link_system32 
1266          if not self.fsObjectExists(actualLinkFolder): 
1267              self.execAlternateCmdsList(['linkd %s %s' % (actualLinkFolder, self.__system32), \ 
1268                                  'mklink /d %s %s' % (actualLinkFolder, self.__system32)]) 
1269              if self.getLastCmdReturnCode() != 0: 
1270                  localFile = CollectorsParameters.BASE_PROBE_MGR_DIR + CollectorsParameters.getDiscoveryResourceFolder() + \ 
1271                      CollectorsParameters.FILE_SEPARATOR + 'junction.exe' 
1272                  self.copyFileIfNeeded(localFile) 
1273                  self.execCmd('junction %s %s /accepteula' % (actualLinkFolder, self.__system32)) 
1274   
1275              if self.getLastCmdReturnCode() != 0: 
1276                  raise ValueError("Failed to create System32 junction point") 
1277          if (lock != 0): 
1278              self.execCmd('cd %s\\' % (actualLinkFolder)) 
1279              if self.getLastCmdReturnCode() == 0: 
1280                  return actualLinkFolder + '\\' 
1281              else: 
1282                  raise ValueError('Unable to lock junction point') 
1283          else: 
1284              return actualLinkFolder + '\\' 
 1285   
1287          """ 
1288          Unlocks and removes NTFS junction point previously created by @createSystem32Link(). 
1289          @types: str 
1290          @command: cd %SystemDrive%\\ 
1291          @command: rd <location> 
1292          @raise ValueError: Unable to delete or unlock junction point 
1293          @deprecated: Use methods from file system module instead 
1294          """ 
1295          location = location or self.__ddm_link_system32 
1296          if not (self.isWinOs() and self.is64BitMachine() and location): 
1297              return 
1298          self.execCmd('cd %SystemDrive%\\') 
1299          if self.getLastCmdReturnCode() == 0: 
1300              self.execCmd('rd %s' % (location)) 
1301              if self.getLastCmdReturnCode() != 0: 
1302                  raise ValueError('Unable to delete junction point') 
1303          else: 
1304              raise ValueError('Unable to unlock junction point') 
 1305   
1307          """ Checks is the discovered machine OS 64 bit. 
1308          32 or 64 bit family detected by checking existence of %SystemRoot%\SysWOW64 folder 
1309          @types: -> bool 
1310          @command: (@if exist %SystemRoot%\SysWOW64 (echo SysWOW64) ELSE (echo FALSE)) 
1311          @deprecated: Will be removed from the public access 
1312          """ 
1313          if self.__is64Bit is None: 
1314              output = self.execCmd('(@if exist %SystemRoot%\SysWOW64 (echo SysWOW64) ELSE (echo FALSE))') 
1315              self.__is64Bit = (output.find('SysWOW64') > -1) 
1316          return self.__is64Bit 
 1317   
1319          """ Indicates whether object by specified path exists on remote file system 
1320          @types: str -> bool 
1321          @command: (@if exist %s (echo TRUE) ELSE (echo FALSE)) 
1322          @deprecated: Use methods from file system module instead 
1323          """ 
1324          if path: 
1325              output = self.execCmd('(@if exist %s (echo TRUE) ELSE (echo FALSE))' % path) 
1326              return output.find('TRUE') > -1 
 1327   
1328 -    def safecat(self, path, forceSudo=0): 
 1329          ''' Get file content by specified path 
1330          @types: str, bool -> str 
1331          @param forceSudo:if true, always uses sudo, if false first tries to run command without sudo 
1332          @command: type 
1333          @deprecated: Use file system module for such purposes 
1334          @raise ValueError: Illegal type command, contains redirect 
1335          @raise Exception: Failed getting contents of file 
1336          ''' 
1337           
1338          m = re.search('>', path) 
1339          if m is not None: 
1340               
1341               
1342              logger.warn('Illegal type command, contains redirect: [%s]' % path) 
1343              raise ValueError('Illegal type command, contains redirect') 
1344   
1345          path = self.rebuildPath(path) 
1346          if (path[0] != '"'): 
1347              path = '"' + path + '"' 
1348          cmd = 'type %s' % path 
1349          self.lastExecutedCommand = cmd 
1350          fileContents = self.execCmd(cmd) 
1351          if not self.getLastCmdReturnCode(): 
1352              return fileContents 
1353          logger.warn('Failed getting contents of %s file' % path) 
1354          raise Exception('Failed getting contents of file') 
 1355   
1357          ''' Normalize path to one used in OS client connected to 
1358          @types: str -> str 
1359          @deprecated: Use file system module for such purposes 
1360          ''' 
1361          return re.sub('/', '\\\\', folder) 
 1362   
1364          '''Perform cleaning of temporary data on destination system and close the client''' 
1365          try: 
1366              self.removeSystem32Link() 
1367          finally: 
1368              Shell.closeClient(self) 
  1369   
1370   
1372      'Cygwin Shell base class' 
1373   
1375          '@types: -> bool' 
1376          return 1 
  1377   
1378   
1380      PROTOCOL_TYPE = PowerShellClient.POWERSHELL_PROTOCOL_NAME 
1381      __DEFAULT_COMMAND_SEPARATOR = ';' 
1382      __INVOKE_COMMAND_SCRIPT_BLOCK = ( 
1383                  'Invoke-Command -ScriptBlock {%s ;$?} -Session $' 
1384                   + PowerShellAgent.REMOTE_SESSION_IDENTIFIER) 
1385      __INVOKE_COMMAND_LOCAL_SCRIPT = ( 
1386                  'Invoke-Command -FilePath %s -Session $' 
1387                   + PowerShellAgent.REMOTE_SESSION_IDENTIFIER 
1388                   + '; $?') 
1389   
1390 -    def __init__(self, client, protocolName): 
 1391          '@types: PowerShellClient, str -> None' 
1392          self.__client = client 
1393          self.__is64Bit = None 
1394          self.__outputHandler = PowerShellOutputHandler() 
1395          self.__consoleCharsetName = self.__getRemoteConsoleEncoding() 
1396          self.__powershellConsoleCharsetName = self.__getPowerShellEncoding() 
1397           
1398           
1399          self.__consoleCommands = ['ver', 'type', 'wmic', 'chcp'] 
1400          consoleCommands = (GeneralSettingsConfigFile.getInstance(). 
1401                              getPropertyTextValue('consoleCommands') 
1402                              or "") 
1403          _isEmptyString = lambda s: s and s.strip() 
1404          _normalize = lambda s: s.strip().lower() 
1405          consoleCommands = filter(_isEmptyString, consoleCommands.split(',')) 
1406          consoleCommands = map(_normalize, consoleCommands) 
1407          self.__consoleCommands.extend(consoleCommands) 
1408          WinShell.__init__(self, client, protocolName) 
1409          self.execCmd('$global:FormatEnumerationLimit = -1', pipeToOutString=0) 
1410          self.useCharset('utf8') 
 1411   
1422   
1424          '''@types: ->str or None 
1425          @command: [System.Console]::OutputEncoding.WebName 
1426          ''' 
1427          cmd = '[System.Console]::OutputEncoding.WebName' 
1428          cmd = PowerShell.__INVOKE_COMMAND_SCRIPT_BLOCK % cmd 
1429          encodingName = self.__client.executeCmd(cmd) 
1430          if self.__outputHandler.isCommandSucceeded(encodingName) == 0: 
1431              return self.__outputHandler.cleanOutput(encodingName, 0).strip() 
 1432   
1434          '''@types: str -> str or None 
1435          @command: [System.Text.Encoding]::GetEncoding(<codePage>).WebName 
1436          ''' 
1437          cmd = '[System.Text.Encoding]::GetEncoding(%s).WebName' % codePage 
1438          cmd = PowerShell.__INVOKE_COMMAND_SCRIPT_BLOCK % cmd 
1439          encodingName = self.__client.executeCmd(cmd) 
1440          if self.__outputHandler.isCommandSucceeded(encodingName) == 0: 
1441              return self.__outputHandler.cleanOutput(encodingName, 0).strip() 
 1442   
1444          """ Checks is the discovered machine OS 64 bit. 32 or 64 bit family 
1445          detected by checking existence of %SystemRoot%\SysWOW64 folder 
1446          @types: -> bool 
1447          @command: Test-Path $env:SystemRoot/SysWOW64 
1448          """ 
1449          if self.__is64Bit is None: 
1450              output = self.execCmd('Test-Path $env:SystemRoot/SysWOW64') 
1451              self.__is64Bit = output.lower().count('true') 
1452          return self.__is64Bit 
 1453   
1455          raise NotImplemented 
 1456   
1458          raise NotImplemented 
 1459   
1465   
1467          ''' If passed command is a windows batch command it should be called in 
1468          batch command interpreter 
1469          @types: str -> str''' 
1470          return "cmd.exe /c '%s'" % cmdline.replace("'", "\\'") 
 1471   
1473          '''Strip WMIC redirection part 
1474          @types: str -> str 
1475          ''' 
1476          if re.search('wmic\s', cmdline): 
1477              cmdline = re.sub('\<\s* [\w\-\.\,\%\\\/\$]+\s*', '', cmdline) 
1478          return cmdline 
 1479   
1481          '''Indicates whether passed command line contains command of batch 
1482          command interpreter 
1483          @types: str -> bool''' 
1484          cmd = cmdline.split()[0].lower() 
1485          for consoleCmd in self.__consoleCommands: 
1486              if re.match('(?<![\w\-])%s$' % consoleCmd, cmd): 
1487                  logger.debug('A console command') 
1488                  return 1 
 1489   
1491          '@types: str, [int] -> str' 
1492          return '%s | Out-String -width %d' % (cmd, lineWidth) 
 1493   
1494 -    def execCmd(self, cmdLine, timeout=0, waitForTimeout=0, useSudo=1, 
1495                  checkErrCode=1, useCache=0, lineWidth=80, pipeToOutString=1): 
 1496          ''' Execute command in powershell 
1497          * If current command is cmdlet: 
1498              1. Method passes output object to 'Out-String' cmdlet to get its 
1499              string representation. 
1500          * If current command is non-cmdlet command(console) 
1501              1. Method prefixes current command with 'cmd.exe /c %cmd%' and 
1502              no passing to 'Out-String' cmdlet performed. 
1503              List of console commands is defined at globalSettings.xml file and 
1504              defaults to ('ver', 'type', 'wmic', 'chcp') if 'consoleCommands' 
1505              attribute is note set. 
1506   
1507          @types: str, int, bool, bool, bool, bool, int, bool -> str 
1508          @param lineWidth: Attribute of the 'Out-String' cmdlet. 
1509                  From the msdn: Specifies the number of characters in each line 
1510                  of output. Any additional characters are truncated, not wrapped 
1511          @see: Shell.execCmd for the param meaning and usage 
1512          ''' 
1513   
1514           
1515          isConsoleCommand = self.__isConsoleCommand(cmdLine) 
1516          if isConsoleCommand: 
1517              cmdLine = self.__makePowerShellCompatible(cmdLine) 
1518          elif pipeToOutString: 
1519              cmdLine = self.__pipeToOutString(cmdLine, lineWidth) 
1520          cmdLine = self.__makePowerShellCompatibleWmicQuery(cmdLine) 
1521          cmdLine = PowerShell.__INVOKE_COMMAND_SCRIPT_BLOCK % cmdLine 
1522          output = Shell.execCmd(self, cmdLine, timeout, waitForTimeout, useSudo, 
1523                                 checkErrCode, useCache) 
1524          if isConsoleCommand: 
1525              output = self.__fixEncoding(self.__powershellConsoleCharsetName, 
1526                                          self.__consoleCharsetName, output) 
1527          return output 
 1528   
1529 -    def execLocalScript(self, path, timeout=0, waitForTimeout=0, useSudo=1, 
1530                          checkErrCode=1, useCache=0): 
 1531          ''' Execute script on the probe 
1532          @types: str, int, bool, bool, bool, bool -> str 
1533          ''' 
1534          cmd = PowerShell.__INVOKE_COMMAND_LOCAL_SCRIPT % path 
1535          return Shell.execCmd(self, cmd, timeout, waitForTimeout, useSudo, 
1536                               checkErrCode, useCache) 
 1537   
1538 -    def execMultilinedCmd(self, cmdLine, timeout=0, waitForTimeout=0, 
1539                            useSudo=1, checkErrCode=1, useCache=0): 
 1540          '''Method intended to execute multiline scripts. It's output is not 
1541          passed to 'Out-String' cmdlet, so all toString conversion should be 
1542          done manually. Powershell remote console encoding used to decode output 
1543          Use ';' to separate different commands. 
1544          @types: str, int, bool, bool, bool, bool -> str 
1545          @see: Shell.execCmd for the param meaning 
1546          ''' 
1547          cmdLine = "".join(cmdLine.split('\n')) 
1548          cmdLine = PowerShell.__INVOKE_COMMAND_SCRIPT_BLOCK % cmdLine 
1549          return Shell.execCmd(self, cmdLine, timeout, waitForTimeout, useSudo, 
1550                               checkErrCode, useCache) 
 1551   
1553          '''@types: Command -> Command 
1554          @raise Exception: Command produced nor output nor return status 
1555          ''' 
1556          output = self.__client.executeCmd(cmd.line, cmd.executionTimeout, 
1557                                            cmd.waitForTimeout) 
1558          cmd.outputInBytes = self.__client.getLastCommandOutputBytes() 
1559          if output is None: 
1560              raise Exception('Executing command: "%s" failed. ' 
1561                              'Command produced nor output nor return status ' 
1562                              '(we might be connected to an unstable agent)' 
1563                              % cmd.cmd) 
1564          output = output.strip() 
1565   
1566          try: 
1567              cmd.returnCode = self.__outputHandler.isCommandSucceeded(output) 
1568          except: 
1569              cmd.returnCode = self.NO_CMD_RETURN_CODE_ERR_NUMBER 
1570          cmd.output = self.__outputHandler.cleanOutput(output, cmd.returnCode) 
1571          return cmd 
 1572   
1574          '''Method is intended to fix string encoding. The root problem comes 
1575          from execution of console commands through the powershell. 
1576          There are two variables defining encodings: $OutputEncoding 
1577          and [Console]::OutputEncoding. The problem is that Exception is raised 
1578          when one tries to set remote [Console]::OutputEncoding, so when chcp 
1579          output differes from [Console]::OutputEncoding.CodePage value, we need 
1580          to fix corrupted string. Fixing is done if passed encodings are 
1581          different only 
1582          @types: str, str -> str 
1583          ''' 
1584          if (fromEncoding != toEncoding): 
1585              logger.debug('Fixing encoding.. from :%s, to: %s' % (fromEncoding, 
1586                                                                   toEncoding)) 
1587              bytes = String(targetStr).getBytes(fromEncoding) 
1588              targetStr = String(bytes, toEncoding) 
1589              logger.debug('Fixed string: %s' % targetStr) 
1590          return str(targetStr) 
  1591   
1592   
1594      'Unix Shell base class' 
1595      ONLY_SUDO_POLICY = 'sudo' 
1596      ONLY_SU_POLICY = 'su' 
1597      SUDO_SU_POLICY = 'sudo or su' 
1598      ERROR_CODE_PREFIX = 'ERROR_CODE:' 
1599   
1601          self.__shellStatusVar = None 
1602          self.__shell = None 
1603          self.__client = client 
1604          self.__sudoPath = None 
1605          self.__sudoPathsArray = None 
1606          self.__sudoCommandsArray = None 
1607          self.__osLanguageDiscoverer = UnixLanguageDiscoverer(self) 
1608          self.__sudoConfiguredCommands = None 
1609          self.__sudoSuPolicy = None 
1610          self.__sudoSplitPattern = "(%s|\s*nice(?:\s*-i\s*\d+)|\s*nice(?:\s*)|\|(?:\s*))" 
1611   
1612          sudoExcludeCommandsPattern = "\s*export\s+|\s*set\s+|\s*LC_ALL\s*=|\s*LANG\s*=|\s*ORACLE_HOME\s*=|\s*PATH\s*=|\s*DB2NODE\s*=" 
1613          self.__sudoExcludeCommandMatcher = re.compile(sudoExcludeCommandsPattern) 
1614   
1615          Shell.__init__(self, client) 
1616   
1617           
1618          if self.__client.supportsSudo(): 
1619              self.__retrieveSudoDetails() 
1620          self.setSessionLocale() 
1621           
1622           
1623           
1624          if self.__isLimitedCommandLength(): 
1625              client.setMaxCommandLength(256) 
1626   
1627          try: 
1628              interpreter = shell_interpreter.Factory().create(self) 
1629              interpreter.getEnvironment().appendPath('PATH', '/bin', '/usr/bin') 
1630          except: 
1631              logger.debugException('Failed to append path using shell_interpreter') 
 1632   
1634          '@types: -> bool' 
1635          return 0 
 1636   
1642   
1644          '@types: -> OsLanguageDiscoverer' 
1645          return self.__osLanguageDiscoverer 
 1646   
1648          ''' Get OS version 
1649          @types: -> str 
1650          @command: uname -r 
1651          @raise Exception: Failed getting OS version 
1652          ''' 
1653          buffer = self.execCmd('uname -r') 
1654          if (self.getLastCmdReturnCode() == 0): 
1655              return buffer 
1656          raise Exception('Failed getting OS version. command="uname -r" failed with rc=%d' % (self.getLastCmdReturnCode())) 
 1657   
1659          """ Get OS type 
1660          @types: -> str 
1661          @command: uname 
1662          @raise Exception: Failed getting machine OS type. 
1663          """ 
1664          osBuff = self.execCmd('uname') 
1665          if (self.getLastCmdReturnCode() == 0): 
1666              return osBuff.strip() 
1667          raise Exception('Failed getting machine OS type.') 
 1668   
1670          '@deprecated: will be removed from the public access' 
1671          locale = self.getAvailableEngLocale() 
1672          if locale: 
1673              environment = shell_interpreter.Factory().create(self).getEnvironment() 
1674              try: 
1675                  environment.setVariable('LANG', locale) 
1676                  environment.setVariable('LC_ALL', locale) 
1677              except: 
1678                  logger.debugException('Failed to set new locale') 
1679              else: 
1680                  logger.debug('Locale set to: %s' % locale) 
 1681   
1683          '''Try to retrieve a shell path from Unix machines (like /bin/sh or /sbin/sh) 
1684          @types: -> str 
1685          @command: echo $SHELL 
1686          ''' 
1687          if not self.__shell: 
1688              logger.debug('determining shell:') 
1689              cmd = 'echo $SHELL' 
1690              logger.debug("trying: '%s'" % cmd) 
1691              resLines = self.__client.executeCmd(cmd) 
1692              logger.debug("res: '%s'" % resLines) 
1693              if resLines: 
1694                  resLines = resLines.strip() 
1695                  logger.debug("response: '%s'" % resLines) 
1696                  if len(resLines) > 0: 
1697                      self.__shell = resLines 
1698          return self.__shell 
 1699   
1701          '@types: -> str' 
1702          if not self.__shellStatusVar: 
1703              logger.debug('Determining shell environment status variable...') 
1704               
1705               
1706              shellName = str(self.getShell()) 
1707              if (shellName and shellName.endswith('csh')): 
1708                  self.__shellStatusVar = self.__getCommandExitStatus('$status') 
1709              else: 
1710                  for statusVar in ["$?", "$status", "$STATUS"]: 
1711                      if (self.__getCommandExitStatus(statusVar) is not None): 
1712                          self.__shellStatusVar = statusVar 
1713                          break 
1714          return self.__shellStatusVar 
 1715   
1717          '''@types: -> str or None 
1718          @command: locale -a | grep -E "en_US.*|^C|POSIX" 
1719          @command: locale -a | /usr/xpg4/bin/grep -E "en_US.*|^C|POSIX" 
1720          ''' 
1721          buff = self.execAlternateCmds('locale -a | grep -E "en_US.*|^C|POSIX"', 'locale -a | /usr/xpg4/bin/grep -E "en_US.*|^C|POSIX"') 
1722          if buff: 
1723              match = re.search(r'en_US\S+', buff) 
1724              if match: 
1725                  return match.group(0).strip() 
1726              match = re.search(r'(?<![\w])C\s+', buff) 
1727              if match: 
1728                  return match.group(0).strip() 
1729              match = re.search(r'POSIX\S+', buff) 
1730              if match: 
1731                  return match.group(0).strip() 
1732          return None 
 1733   
1735          '''@types: str -> str or None 
1736          @command: echo <env variable> 
1737          ''' 
1738          cmd = 'echo %s' % statusVar 
1739          logger.debug('trying: \'%s\'...' % cmd) 
1740          resLines = self.__client.executeCmd(cmd) 
1741          logger.debug('res: \'%s\'...' % resLines) 
1742          if (resLines is not None): 
1743              resLines = resLines.strip() 
1744              logger.debug('response: \'%s\'' % resLines) 
1745              resLinesCount = len(resLines) 
1746              if ((resLinesCount > 0) and (resLines[resLinesCount - 1].isdigit())): 
1747                  logger.debug('found shell environment status variable=\'%s\'' % statusVar) 
1748                  return statusVar 
1749          return None 
 1750   
1752          ''' Specific for Sun OS where shell 'sh' has command length limitation 
1753          @types: -> bool 
1754          ''' 
1755           
1756          return self.getOsType() == 'SunOS' and self.getShell() == '/sbin/sh' 
 1757   
1759          '@types: Command -> Command' 
1760          cmd = command.line 
1761          separator = self.getShellCmdSeperator() 
1762   
1763          cmdWithRc = '%s %s echo %s%s' % (cmd, separator, self.ERROR_CODE_PREFIX, self.getShellStatusVar()) 
1764          buff = self.__client.executeCmd(cmdWithRc, command.executionTimeout, command.waitForTimeout) 
1765          command.outputInBytes = self.__client.getLastCommandOutputBytes() 
1766          if buff is not None: 
1767              try: 
1768                  output, returnCode = _extractCommandOutputAndReturnCode(buff) 
1769              except ValueError: 
1770                  command.returnCode = Shell.NO_CMD_RETURN_CODE_ERR_NUMBER 
1771                  logger.warn("Execution command: \'%s\' failed (we might be connected to an unstable agent)" % cmd) 
1772                  raise Exception("Command produced no return status") 
1773              else: 
1774                  command.returnCode = returnCode 
1775                  command.output = output 
1776          else: 
1777              command.returnCode = self.NO_CMD_RETURN_CODE_ERR_NUMBER 
1778              logger.warn("Executing command: \'%s\' failed (we might be connected to an unstable agent)" % cmd) 
1779              raise Exception("Command produced no output and no return status") 
1780          return command 
 1781   
1783          self.__client.executeSuCommand() 
1784          if not self.__client.isInSuMode(): 
1785              raise Exception('Failed to run command in su mode.') 
1786          command = self.__executeCommand(command) 
1787          self.__client.exitFromSu() 
1788          return command 
 1789   
1791          '@types: str, str -> bool' 
1792          return (self.__sudoCommandsArray 
1793                  and self.__shouldRunAsSuperUser(originalCommand, 1)) 
 1794   
1796          separator = self.getShellCmdSeperator() 
1797          splitPattern = self.__sudoSplitPattern % re.escape(separator) 
1798          commandElements = re.split(splitPattern, originalCommand) 
1799          for i in range(0, len(commandElements)): 
1800              command = commandElements[i] 
1801              if not command or re.match(splitPattern, command): 
1802                   
1803                  continue 
1804              isDestinationConfigured = 1 
1805              if checkDestinationConfiguration: 
1806                  isDestinationConfigured = self.__isCommandConfiguredOnDestination(command) 
1807   
1808              if isDestinationConfigured and self.__shouldCommandElemRunAsSuperUser(command): 
1809                  return 1 
1810   
1811          return None 
 1812   
1820   
1822          if self.__sudoCommandsArray: 
1823              isConfiguredInCreds = 0 
1824              for sudoCommandPattern in self.__sudoCommandsArray: 
1825                  if sudoCommandPattern and sudoCommandPattern.strip() == '.*': 
1826                      isConfiguredInCreds = 1 
1827   
1828              if isConfiguredInCreds: 
1829                  sudoConfiguredCommands = self.__getSudoConfiguredCommands() 
1830                  for sudoCommandPattern in sudoConfiguredCommands: 
1831                      if sudoCommandPattern and sudoCommandPattern.strip() == '.*': 
1832                          return 1 
 1833   
1835          if self.__sudoCommandsArray: 
1836              for sudoCommandPattern in self.__sudoCommandsArray: 
1837                  if re.match(sudoCommandPattern.lstrip(), command.strip()): 
1838                      logger.debug("Command %s is matched by privileged command pattern %s" % (command, sudoCommandPattern)) 
1839                      return 1 
 1840   
1842          try: 
1843              return self.__client.isSuConfigured() and self.__shouldRunAsSuperUser(originalCommand) 
1844          except: 
1845              logger.error('Method isSuConfigured() is missing in client. Wrong content.jar used. Please update.') 
 1846   
1848          from com.hp.ucmdb.discovery.library.credentials.dictionary import ProtocolManager 
1849          return ProtocolManager 
 1850   
1852          if self.__sudoSuPolicy is None: 
1853              try: 
1854                  protocol = self.__getProtocolManager().getProtocolById(self.getCredentialId()) 
1855                  protocolName = self.getClientType() 
1856                  sudoPolicy = None 
1857                  if protocolName in ['ssh', 'telnet']: 
1858                      sudoPolicy = protocol.getProtocolAttribute('%sprotocol_sudo_su_policy' % protocolName) 
1859                  self.__sudoSuPolicy = sudoPolicy or UnixShell.ONLY_SUDO_POLICY 
1860              except: 
1861                  self.__sudoSuPolicy = UnixShell.ONLY_SUDO_POLICY 
1862          return self.__sudoSuPolicy 
 1863   
1879   
1881          '''Get information about sudo paths and sudo enabled commands''' 
1882          sudoPaths = self.__client.getSudoPaths() 
1883          if sudoPaths: 
1884              self.__sudoPathsArray = string.split(sudoPaths, ',') 
1885          sudoCommands = self.__client.getSudoCommands() 
1886          if sudoCommands: 
1887              splitCommands = string.split(sudoCommands, ',') 
1888              if '*' in splitCommands: 
1889                  self.__sudoCommandsArray = ['.*'] 
1890              else: 
1891                  self.__sudoCommandsArray = splitCommands 
 1892   
1894          '@types: str -> str' 
1895           
1896          if not self.__sudoPathsArray: 
1897              return cmd 
1898           
1899          if re.match('\S*sudo\s', cmd): 
1900              return cmd 
1901   
1902          sudoPath = self.__getSudoPath() 
1903   
1904          if sudoPath and len(sudoPath) > 0: 
1905              return self.__getSudoWithCmd(sudoPath, cmd, preserveSudoContext) 
1906          else: 
1907              return cmd 
 1908   
1928   
1945   
1946 -    def __getSudoWithCmd(self, sudoPath, originalCommand, preserveSudoContext = 0): 
 1947          '@types: str, str -> str' 
1948          if not self.__sudoCommandsArray: 
1949              logger.debug('No sudo commands specified.') 
1950              return originalCommand 
1951          else: 
1952              sudoPathWithParams = sudoPath 
1953              if preserveSudoContext: 
1954                  sudoPathWithParams = '%s %s' % (sudoPath, '-E') 
1955              separator = self.getShellCmdSeperator() 
1956   
1957              if self.__shouldAllCommandsRunAsSuperUser(): 
1958                  if self.__sudoExcludeCommandMatcher.match(originalCommand): 
1959                      logger.debug('Command is in excluded for sudo commands list. Sudo will not be added.') 
1960                      return originalCommand 
1961                  logger.debug('Both credentials and destination are configured to run all commands as Super User.') 
1962                  return '%s %s -c "%s"' % (sudoPathWithParams, self.getShell(), re.sub(r'(?<!\\)"', r'\\"', originalCommand)) 
1963   
1964              splitPattern = self.__sudoSplitPattern % re.escape(separator) 
1965              commandElements = re.split(splitPattern, originalCommand) 
1966              for i in range(0, len(commandElements)): 
1967                  command = commandElements[i] 
1968                  if not command or re.match(splitPattern, command): 
1969                       
1970                      continue 
1971                  if self.__shouldCommandElemRunAsSuperUser(command): 
1972                      if self.__isCommandConfiguredOnDestination(command): 
1973                          logger.debug("Command %s will be prefixed with %s" % (command, sudoPathWithParams)) 
1974                          command = "%s %s" % (sudoPathWithParams, command) 
1975                      else: 
1976                          logger.warn('Command %s matches the UCMDB privileged command patterns but is not in the sudo list on the destination.' % command) 
1977                  commandElements[i] = command 
1978   
1979              return ''.join(commandElements) 
 1980   
1982          '@types: -> str' 
1983          if self.__sudoPath is not None: 
1984              return self.__sudoPath 
1985          else: 
1986              if (not self.__sudoPathsArray or not(len(self.__sudoPathsArray) > 0)): 
1987                  self.__sudoPath = '' 
1988              else: 
1989                  for path in self.__sudoPathsArray: 
1990                      cmdWithRc = '%s%secho %s' % (path + ' -V', self.getShellCmdSeperator(), self.getShellStatusVar()) 
1991                      logger.debug('__getSudoPath: checking "%s" command' % cmdWithRc) 
1992                      buff = self.__client.executeCmd(cmdWithRc, 0, 0) 
1993                      if (buff is None): 
1994                          logger.debug('__getSudoPath: execution of %s failed - command produced no output and no return status' % cmdWithRc) 
1995                      else: 
1996                          keepends = 1 
1997                          resLines = buff.strip().splitlines(keepends) 
1998                          lastLineNum = len(resLines) - 1 
1999                           
2000                          if (lastLineNum < 0): 
2001                              logger.debug('__getSudoPath: no output was received for %s - proceeding to check next path' % cmdWithRc) 
2002                              continue 
2003                          lastLine = resLines[lastLineNum].strip() 
2004                          try: 
2005                              lastCmdReturnCode = int(lastLine.strip()) 
2006                               
2007                              if lastCmdReturnCode == 0: 
2008                                  logger.debug("__getSudoPath: execution of '%s' succeeded - setting it as sudo path" % cmdWithRc) 
2009                                  self.__sudoPath = path 
2010                                  return self.__sudoPath 
2011                          except: 
2012                              logger.debug('__getSudoPath: error parsing return code for command: %s=> returned output: %s' % (cmdWithRc, lastLine)) 
2013                              continue 
2014                  logger.debug('__getSudoPath: none of the supplied sudo paths is valid  - proceeding without sudo support') 
2015                  self.__sudoPath = '' 
2016          return self.__sudoPath 
 2017   
2019          '''Indicates whether object by specified path exists on remote file system 
2020          @types: str -> bool 
2021          @command: if [ -d \"%s\" ]; then echo true ; else echo false; fi 
2022          @command: if [ -f \"%s\" ]; then echo true ; else echo false; fi 
2023          @deprecated: Use methods from file system module instead''' 
2024          if path: 
2025              output = self.execCmd("if [ -d \"%s\" ]; then echo true ; else echo false; fi" % path) 
2026              if output.find('true') > -1: 
2027                  return 1 
2028              output = self.execCmd("if [ -f \"%s\" ]; then echo true ; else echo false; fi" % path) 
2029              if output.find('true') > -1: 
2030                  return 1 
 2031   
2032 -    def safecat(self, path, forceSudo=0): 
 2033          ''' Get content of file by specified path 
2034          @types: str, bool -> str 
2035          @param forceSudo:if true, always uses sudo, if false first tries to run command without sudo 
2036          @command: cat <path> 
2037          @raise ValueError: Illegal cat command, contains redirect 
2038          @raise EnvironmentError: sudo for cat is not available on server 
2039          @raise Exception: Failed getting contents of file 
2040          ''' 
2041           
2042          if re.search('>', path): 
2043               
2044              logger.error('Illegal cat command, contains redirect: [%s]' % path) 
2045              raise ValueError('Illegal cat command, contains redirect') 
2046   
2047          path = self.rebuildPath(path) 
2048           
2049           
2050          cmd = 'cat %s' % path 
2051          self.lastExecutedCommand = cmd 
2052          if not forceSudo: 
2053              fileContents = self.execCmd(cmd, useSudo=0) 
2054              if not self.getLastCmdReturnCode(): 
2055                  return fileContents 
2056          fileContents = self.execCmd(cmd) 
2057          if not self.getLastCmdReturnCode(): 
2058              return fileContents 
2059          else: 
2060              m = re.search('you do not have access', fileContents.lower()) 
2061              if m is not None: 
2062                  raise EnvironmentError('sudo for cat is not implemented on server') 
2063              elif re.search('not found', fileContents.lower()): 
2064                  raise EnvironmentError('sudo is not available on server') 
2065              else: 
2066                  logger.warn('Failed getting contents of %s file' % path) 
2067                  raise Exception('Failed getting contents of file') 
 2068   
2070          ''' Normalize path to one used in OS client connected to 
2071          @types: str -> str 
2072          @deprecated: Use file system module for such purposes 
2073          ''' 
2074          return re.sub('\\\\', '/', folder) 
  2075   
2076   
2078      r''' Extract output and return code information by splitting output into 
2079      two parts by ERROR_CODE_PREFIX substring, used in unix shell 
2080      @types: str -> (str, int) 
2081      @raise ValueError: No return code information found 
2082      ''' 
2083      errCodeIndex = buffer.rfind(UnixShell.ERROR_CODE_PREFIX) 
2084      if errCodeIndex != -1: 
2085          output, errorCode = buffer, Shell.NO_CMD_RETURN_CODE_ERR_NUMBER 
2086          output = buffer[:errCodeIndex] 
2087          lastLine = buffer[errCodeIndex:].strip() 
2088          returnCodeStr = lastLine[len(UnixShell.ERROR_CODE_PREFIX):] 
2089          try: 
2090              errorCode = int(returnCodeStr) 
2091          except: 
2092              logger.debug("Failed to process errorcode value: %s" % returnCodeStr) 
2093          return (output, errorCode) 
2094      raise ValueError("No return code information found") 
 2095   
2096   
2103   
2104   
2106      '''Shell for Virtual I/O Server 
2107      ( part of the IBM eServer p5 Advanced Power Virtualization hardware feature)''' 
2108   
2110          ''' Prepare passed command line to run as padmin user 
2111          @types: str -> str''' 
2112          return 'ioscli %s' % cmdLine 
 2113   
2115          ''' Run command as padmin user, using command ioscli 
2116          @types: str -> str''' 
2117          return self.execCmd(self.__prepareCmd(cmdLine), *args, **kwargs) 
 2118   
2120          """ Get OS type 
2121          @types: -> str 
2122          @command: uname 
2123          @raise Exception: Failed getting machine OS type. 
2124          """ 
2125   
2126          osBuff = self.execIoscliCmd('uname') 
2127          if (self.getLastCmdReturnCode() == 0): 
2128              return osBuff.strip() 
2129          raise Exception('Failed getting machine OS type.') 
 2130   
2132          ''' Get OS version 
2133          @types: -> str 
2134          @command: uname -r 
2135          @raise Exception: Failed getting OS version. 
2136          ''' 
2137          buffer = self.execIoscliCmd('uname -r') 
2138          if (self.getLastCmdReturnCode() == 0): 
2139              return buffer 
2140          raise Exception('Failed getting os version. command="ioscli uname -r" failed with rc=%d' % (self.getLastCmdReturnCode())) 
  2141   
2142   
2144      '@types: str, str, Framework -> bundle' 
2145      languageName = language.bundlePostfix  
2146      return framework.getEnvironmentInformation().getBundle(baseName, languageName) 
 2147   
2148   
2150      ''' Read file on the probe machine by the specified path 
2151      @types: str, str -> str or None 
2152      @deprecated: Use methods from file system module instead 
2153      @raise ValueError: specified localFilePath is empty 
2154      ''' 
2155      if not localFilePath: 
2156          raise ValueError("localFilePath is empty") 
2157      fileObject = None 
2158      try: 
2159          fileObject = codecs.open(localFilePath, "r", encoding) 
2160          return fileObject.read() 
2161      finally: 
2162          if fileObject is not None: 
2163              try: 
2164                  fileObject.close() 
2165              except: 
2166                  pass 
 2167   
2168   
2170      ''' Delete file on the probe machine by the specified path 
2171      @types: str -> bool 
2172      @deprecated: Use methods from file system module instead 
2173      @raise ValueError: specified localFilePath is empty 
2174      ''' 
2175      if not localFilePath: 
2176          raise ValueError("localFilePath is empty") 
2177      try: 
2178          file_ = File(localFilePath) 
2179          return file_.delete() 
2180      except: 
2181          logger.debugException("Failed deleting file '%s'\n" % localFilePath) 
 2182