Esempio n. 1
0
class PatchSequenceApply(object):
  DEFAULT_VISTA_LOG_FILENAME = "VistAInteraction.log"
  DEFAULT_OUTPUT_FILE_LOG = "PatchAnalyzer.log"
  def __init__(self, testClient, logFileDir, testClient2=None):
    self._testClient = testClient
    self._testClient2 = testClient2
    curTimestamp = getCurrentTimestamp()
    logFileName = "%s.%s" % (self.DEFAULT_VISTA_LOG_FILENAME, curTimestamp)
    self._logFileName = os.path.join(logFileDir,
                             logFileName)
    self._testClient.setLogFile(self._logFileName)
    self._patchOrderGen = PatchOrderGenerator()
    self._vistaPatchInfo = VistAPackageInfoFetcher(testClient)
    self._outPatchList = []
    self._patchSet = set()
    initFileLogging(os.path.join(logFileDir, self.DEFAULT_OUTPUT_FILE_LOG))

  """ generate the patch order sequence base on input """
  def generatePatchSequence(self, patchDir, installName=None,
                                isUpToPatch=False):
    patchOrderGen = self._patchOrderGen
    patchHistInfo = self._vistaPatchInfo
    patchList = []
    if isUpToPatch:
      patchList = patchOrderGen.generatePatchOrderTopologic(patchDir)
    else:
      patchList = patchOrderGen.generatePatchOrderTopologic(patchDir, installName)
    self._patchSet.update([x.installName for x in patchList])
    if installName and installName not in self._patchSet:
      errMsg = ("Can not find patch for install name %s" % installName)
      raise Exception(errMsg)
    dependencyIssues = {}
    for patchInfo in patchList:
      namespace = patchInfo.namespace
      self.__updatePatchInfoPackageName__(patchInfo)
      logger.info("Checking for patch info %s" % patchInfo.installName)
      logger.debug("Checking for patch info %s" % patchInfo)
      """ check to see if the patch is already installed """
      if not self.__isPatchInstalled__(patchInfo):
        if self.__isPatchReadyToInstall__(patchInfo, patchList):
          self._outPatchList.append(patchInfo)
        else:
          dependencyIssues[patchInfo.installName] = patchInfo.depKIDSBuild
          continue #raise Exception(errorMsg)
      if isUpToPatch and installName and installName == patchInfo.installName:
        break
    if len(dependencyIssues):
        for obj in dependencyIssues:
            logger.error("Problems found with dependencies of %s in: %s" % (obj, dependencyIssues[obj]))
        raise Exception("Dependency Errors Found")
    logger.info("Total patches are %d" % len(self._outPatchList))
    for patchInfo in self._outPatchList:
      logger.info("%s, %s, %s" % (patchInfo.installName,
                                  patchInfo.namespace,
                                  patchInfo.kidsFilePath))
    return self._outPatchList

  """ Apply up to maxPatches Patches ordered by sequence number """
  def applyPatchSequenceByNumber(self, maxPatches=1):
    totalPatch = len(self._outPatchList)
    numOfPatch = 1
    if re.match("All", str(maxPatches), re.IGNORECASE):
      numOfPatch = totalPatch
    else:
      numOfPatch = int(maxPatches)
    endIndex = min(totalPatch, numOfPatch)
    return self.__applyPatchUptoIndex__(endIndex)

  def applyPatchSequenceByInstallName(self, installName, patchOnly=False):
    """ apply the Patch in sequence order up to specified install name
        if patchOnly is set to True, will only apply that patch
    """
    if installName not in self._patchSet:
      raise Exception("Invalid install name: %s" % installName)
    if len(self._outPatchList) == 0:
      logger.info("No Patch to apply")
      return 0
    logger.info("Apply patches up to %s" % installName)
    patchIndex = self.__getPatchIndexByInstallName__(installName)
    endIndex = patchIndex + 1
    startIndex = 0
    if patchOnly:
      startIndex = patchIndex
    return self.__applyPatchUptoIndex__(endIndex, startIndex)

  @staticmethod
  def generateSha1SumForPatchInfo(patchInfo):
    if patchInfo.kidsSha1 is None:
      patchInfo.kidsSha1 = generateSha1Sum(patchInfo.kidsFilePath)
    if patchInfo.kidsInfoPath:
      patchInfo.kidsInfoSha1 = generateSha1Sum(patchInfo.kidsInfoPath)
    if patchInfo.otherKidsInfoList:
      for item in patchInfo.otherKidsInfoList:
        if item[0]:
          item[1] = generateSha1Sum(item[0])

  @staticmethod
  def indexInPatchList(installName, patchList):
    for index in range(0,len(patchList)):
      if patchList[index].installName == installName:
        return index
    return -1

#---------------------------------------------------------------------------
# private implementation
#---------------------------------------------------------------------------
  """
    apply patch incrementally up to the end index in self._outPatchList
  """
  def __applyPatchUptoIndex__(self, endIndex, startIndex=0):
    assert endIndex >= 0 and endIndex <= len(self._outPatchList)
    assert startIndex >=0 and startIndex <= endIndex
    """ make sure taskman is running """
    taskmanUtil = VistATaskmanUtil()
    taskmanUtil.startTaskman(self._testClient)
    result = 0
    for index in range(startIndex, endIndex):
      patchInfo = self._outPatchList[index]
      result = self.__applyIndividualPatch__(patchInfo)
      if result < 0:
        logger.error("Failed to install patch %s: KIDS %s" %
                      (patchInfo.installName, patchInfo.kidsFilePath))
        return result
    """ wait until taskman is current """
    taskmanUtil.waitTaskmanToCurrent(self._testClient)
    return result

#---------------------------------------------------------------------------
# private implementation
#---------------------------------------------------------------------------
  """
    get index of a patch in self._outPatchList by install name
  """
  def __getPatchIndexByInstallName__(self, installName):
    idx = 0
    for patchInfo in self._outPatchList:
      if patchInfo.installName == installName:
        return idx
      idx += 1
    return -1
  """
    apply individual patch
    @return:
      throw exception for installation error.
      0 if patch is already installed.
      -1 if patch is not ready to install
      1 if patch installed sucessfully
  """
  def __applyIndividualPatch__(self, patchInfo):
    """ double check to see if patch is already installed """
    if self.__isPatchInstalled__(patchInfo):
      return 0
    if not self.__isPatchReadyToInstall__(patchInfo):
      return -1
    """ generate Sha1 Sum for patch Info """
    self.generateSha1SumForPatchInfo(patchInfo)
    """ install the Patch """
    result = self.__installPatch__(patchInfo)
    if not result:
      errorMsg = ("Failed to install patch %s: KIDS %s" %
                 (patchInfo.installName, patchInfo.kidsFilePath))
      logger.error(errorMsg)
      raise Exception(errorMsg)
    else:
      # also need to reload the package patch hist
      self.__reloadPackagePatchHistory__(patchInfo)
      """ special logic to handle release code """
      installed = False
      namespace,ver,patch = extractInfoFromInstallName(patchInfo.installName)
      if not patch:
        if namespace and ver:
          updVer = getPackageLatestVersionByNamespace(namespace,
                                                      self._testClient)
          if updVer and updVer == ver:
            installed = True
      if not installed:
        assert self.__isPatchInstalled__(patchInfo)
    return 1
  """ get the package patch history and update package name
      for KIDS only build
  """
  def __updatePatchInfoPackageName__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    packageName = patchInfo.package
    namespace = patchInfo.namespace
    verInfo = patchInfo.version
    if namespace:
      patchHistInfo.getPackagePatchHistByNamespace(namespace, verInfo)
      if packageName:
        vistAPackageName = patchHistInfo.getPackageName(namespace)
        if vistAPackageName != packageName:
          logger.error("Different PackageName for %s, %s:%s" %
                       (patchInfo.installName, vistAPackageName, packageName))
          patchInfo.package = vistAPackageName
      else:
        packageName = patchHistInfo.getPackageName(namespace)
        patchInfo.package = packageName

  """ check to see if the patch is already installed """
  def __isPatchInstalled__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    namespace = patchInfo.namespace
    installName = patchInfo.installName
    if patchHistInfo.hasPatchInstalled(patchInfo.installName,
                                       patchInfo.namespace,
                                       patchInfo.version,
                                       patchInfo.patchNo,
                                       patchInfo.seqNo):
      logger.info("%s is already installed" % installName)
      return True
    installStatus = patchHistInfo.getInstallationStatus(installName)
    logger.debug("%s installation status is %d" %
                 (installName, installStatus))
    if patchHistInfo.isInstallCompleted(installStatus):
      logger.info("%s installed completed" % installName)
      return True
    else:
      return False

  """ update package patch history """
  def __reloadPackagePatchHistory__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    patchHistInfo.createAllPackageMapping()
    installNameList = []
    if patchInfo.isMultiBuilds:
      installNameList = patchInfo.multiBuildsList
    else:
      installNameList.append(patchInfo.installName)
    for installName in installNameList:
      (namespace,ver,patch) = extractInfoFromInstallName(installName)
      if not patchHistInfo.hasNamespace(namespace):
        ns = patchHistInfo.getPackageNamespaceByName(namespace)
        if not ns:
          patchHistInfo.createAllPackageMapping()
        else:
          namespace = ns
      if patchHistInfo.hasNamespace(namespace):
        packageName = patchHistInfo.getPackageName(namespace)
        patchHistInfo.getPackagePatchHistory(packageName, namespace, ver)

  """ create Patch Installer by patch Info and install
      the patch specified in patchInfo, return the result
      @return, True indicates on error, False indicates failure
  """
  def __installPatch__(self, patchInfo):
    installName = patchInfo.installName
    kidsPath = patchInfo.kidsFilePath
    seqNo = patchInfo.seqNo
    logFileName = self._logFileName
    multiBuildsList = patchInfo.multiBuildsList
    kidsInstaller = None
    """ handle patch stored as external link """
    if patchInfo.kidsSha1Path != None:
      kidsSha1 = patchInfo.kidsSha1
      (result, resultPath) = obtainKIDSBuildFileBySha1(kidsPath,
                                                       kidsSha1,
                                                       DEFAULT_CACHE_DIR)
      if not result:
        logger.error("Could not obtain external Patch for %s" % kidsPath)
        return result
      kidsPath = resultPath # set the KIDS Path
    """ get the right KIDS installer """
    associateFiles = patchInfo.associatedInfoFiles
    associatedGlobals = patchInfo.associatedGlobalFiles
    if patchInfo.hasCustomInstaller:
      """ use python imp module to load the source """
      logger.info("using custom installer %s" % patchInfo.customInstallerPath)
      import imp
      installerModule = imp.load_source("KIDS",
                                patchInfo.customInstallerPath)
      from KIDS import CustomInstaller
      kidsInstaller = CustomInstaller(kidsPath, installName,
                                      seqNo, logFileName,
                                      multiBuildsList,
                                      files=associateFiles,
                                      globals=associatedGlobals,
                                      duz = self._duz)

    else:
      kidsInstaller = KIDSInstallerFactory.createKIDSInstaller(
                            kidsPath, installName, seqNo, logFileName,
                            multiBuildsList,
                            files=associateFiles,
                            globals=associatedGlobals,
                            duz = self._duz)
    logger.info("Applying Patch %s" % patchInfo)
    assert kidsInstaller
    return kidsInstaller.runInstallation(self._testClient, self._testClient2)

  """ check to see if patch is ready to be installed """
  def __isPatchReadyToInstall__(self, patchInfo, patchList = None):
    packageName = patchInfo.package
    ver = patchInfo.version
    patchHist = self._vistaPatchInfo.getPackagePatchHistByName(packageName, ver)
    if not patchHist or not patchHist.hasPatchHistory():
      logger.info("no patch hist for %s, ver: %s" % (packageName, ver))
      return True # if no such an package or hist info, just return True
    """ check patch sequence no to see if it is out of order """
    if patchInfo.seqNo:
      seqNo = patchHist.getLatestSeqNo()
      if patchInfo.seqNo < seqNo:
        logger.error("SeqNo out of order, %s less than latest one %s" % (patchInfo.seqNo, seqNo))
        return False
    # check all the dependencies
    for item in patchInfo.depKIDSBuild:
      if patchList and item in self._patchSet: # we are going to install the dep patch
        logger.info("We are going to install the patch %s" % item)
        """ make sure installation is in the right order """
        itemIndex = self.indexInPatchList(item, patchList)
        patchIndex = self.indexInPatchList(patchInfo.installName, patchList)
        if itemIndex >= patchIndex:
          logger.warn("%s is out of order with %s" % (item, patchInfo))
          return False
        else:
          continue
      (namespace,ver,patch) = extractInfoFromInstallName(item)
      if self._vistaPatchInfo.hasPatchInstalled(item, namespace, ver, patch):
        logger.debug("%s is arelady installed" % item)
        continue
      installStatus = self._vistaPatchInfo.getInstallationStatus(item)
      if self._vistaPatchInfo.isInstallCompleted(installStatus):
        continue
      elif item in patchInfo.optionalDepSet:
        logger.warn("Patch specified in KIDS info file %s is not installed for %s" %
                    (item, patchInfo.installName))
        continue
      else:
        logger.error("dep %s is not installed for %s %s" %
                    (item, patchInfo.installName, patchInfo.kidsFilePath))
        patchInfo.depKIDSBuild.remove(item)
        patchInfo.depKIDSBuild.add(item+" <---")
        return False
    return True
Esempio n. 2
0
class KIDSPatchSequenceApply(object):
  DEFAULT_VISTA_LOG_FILENAME = "VistAInteraction.log"
  DEFAULT_OUTPUT_FILE_LOG = "PatchAnalyzer.log"
  def __init__(self, testClient, logFileDir):
    self._testClient = testClient
    curTimestamp = getCurrentTimestamp()
    logFileName = "%s.%s" % (self.DEFAULT_VISTA_LOG_FILENAME, curTimestamp)
    self._logFileName = os.path.join(logFileDir,
                             logFileName)
    self._testClient.setLogFile(self._logFileName)
    self._kidsOrderGen = KIDSPatchOrderGenerator()
    self._vistaPatchInfo = VistAPackageInfoFetcher(testClient)
    self._outPatchList = []
    self._patchSet = set()
    initConsoleLogging()
    initFileLogging(os.path.join(logFileDir, self.DEFAULT_OUTPUT_FILE_LOG))

  """ generate the patch order sequence base on input """
  def generateKIDSPatchSequence(self, patchDir, installName=None,
                                isUpToPatch=False):
    kidsOrderGen = self._kidsOrderGen
    patchHistInfo = self._vistaPatchInfo
    patchList = []
    if isUpToPatch:
      patchList = kidsOrderGen.generatePatchOrderTopologic(patchDir)
    else:
      patchList = kidsOrderGen.generatePatchOrderTopologic(patchDir, installName)
    self._patchSet.update([x.installName for x in patchList])
    if installName and installName not in self._patchSet:
      errMsg = ("Can not find patch for install name %s" % installName)
      raise Exception(errMsg)
    for patchInfo in patchList:
      namespace = patchInfo.namespace
      self.__updatePatchInfoPackageName__(patchInfo)
      logger.info("Checking for patch info %s" % patchInfo.installName)
      logger.debug("Checking for patch info %s" % patchInfo)
      """ check to see if the patch is already installed """
      if not self.__isPatchInstalled__(patchInfo):
        if self.__isPatchReadyToInstall__(patchInfo, patchList):
          self._outPatchList.append(patchInfo)
        else:
          errorMsg = ("Can not install patch %s" % patchInfo.installName)
          logger.error(errorMsg)
          raise Exception(errorMsg)
      if isUpToPatch and installName and installName == patchInfo.installName:
        break

    logger.info("Total patches are %d" % len(self._outPatchList))
    for patchInfo in self._outPatchList:
      logger.info("%s, %s, %s" % (patchInfo.installName,
                                  patchInfo.namespace,
                                  patchInfo.kidsFilePath))

  """ Apply up to maxPatches KIDS Patches ordered by sequence number """
  def applyKIDSPatchSequenceByNumber(self, maxPatches=1):
    totalPatch = len(self._outPatchList)
    numOfPatch = 1
    if re.match("All", str(maxPatches), re.IGNORECASE):
      numOfPatch = totalPatch
    else:
      numOfPatch = int(maxPatches)
    endIndex = min(totalPatch, numOfPatch)
    self.__applyKIDSPatchUptoIndex__(endIndex)

  """ apply the KIDS Patch in sequence order up to specified install name """
  def applyKIDSPatchSequenceByInstallName(self, installName, patchOnly=False):
    if installName not in self._patchSet:
      raise Exception("Invalid install name: %s" % installName)
    if len(self._outPatchList) == 0:
      logger.info("No Patch to apply")
      return
    logger.info("Apply patches up to %s" % installName)
    self.__applyKIDSPatchUptoIndex__(len(self._outPatchList))

  @staticmethod
  def generateSha1SumForPatchInfo(patchInfo):
    if patchInfo.kidsSha1 is None:
      patchInfo.kidsSha1 = generateSha1Sum(patchInfo.kidsFilePath)
    if patchInfo.kidsInfoPath:
      patchInfo.kidsInfoSha1 = generateSha1Sum(patchInfo.kidsInfoPath)
    if patchInfo.otherKidsInfoList:
      for item in patchInfo.otherKidsInfoList:
        if item[0]:
          item[1] = generateSha1Sum(item[0])

  @staticmethod
  def indexInPatchList(installName, patchList):
    for index in range(0,len(patchList)):
      if patchList[index].installName == installName:
        return index
    return -1

#---------------------------------------------------------------------------
# private implementation
#---------------------------------------------------------------------------
  """
    apply patch incrementally up to the end index in self._outPatchList
  """
  def __applyKIDSPatchUptoIndex__(self, endIndex):
    assert endIndex >= 0 and endIndex <= len(self._outPatchList)
    """ make sure taskman is running """
    taskmanUtil = VistATaskmanUtil()
    taskmanUtil.startTaskman(self._testClient)
    for index in range(0, endIndex):
      patchInfo = self._outPatchList[index]
      result = self.__applyIndividualKIDSPatch__(patchInfo)
      if not result:
        logger.error("Failed to install patch %s: KIDS %s" %
                      (patchInfo.installName, patchInfo.kidsFilePath))
        return
    """ wait until taskman is current """
    taskmanUtil.waitTaskmanToCurrent(self._testClient)

#---------------------------------------------------------------------------
# private implementation
#---------------------------------------------------------------------------
  """
    get index of a patch in self._outPatchList by install name
  """
  def __getPatchIndexByInstallName__(self, installName):
    idx = 0
    for patchInfo in self._outPatchList:
      if patchInfo.installName == installName:
        return idx
      idx += 1
    return -1
  """
    apply individual KIDS patch
  """
  def __applyIndividualKIDSPatch__(self, patchInfo):
    """ double check to see if patch is already installed """
    if self.__isPatchInstalled__(patchInfo):
      return True
    if not self.__isPatchReadyToInstall__(patchInfo):
      return False
    """ generate Sha1 Sum for patch Info """
    self.generateSha1SumForPatchInfo(patchInfo)
    """ install the KIDS patch """
    result = self.__installKIDSPatch__(patchInfo)
    if not result:
      errorMsg = ("Failed to install patch %s: KIDS %s" %
                 (patchInfo.installName, patchInfo.kidsFilePath))
      logger.error(errorMsg)
      raise Exception(errorMsg)
    else:
      # also need to reload the package patch hist
      self.__reloadPackagePatchHistory__(patchInfo)
      assert self.__isPatchInstalled__(patchInfo)
    return True
  """ get the package patch history and update package name
      for KIDS only build
  """
  def __updatePatchInfoPackageName__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    packageName = patchInfo.package
    namespace = patchInfo.namespace
    verInfo = patchInfo.version
    if namespace:
      patchHistInfo.getPackagePatchHistByNamespace(namespace, verInfo)
      if packageName:
        vistAPackageName = patchHistInfo.getPackageName(namespace)
        if vistAPackageName != packageName:
          logger.error("Different PackageName for %s, %s:%s" %
                       (patchInfo.installName, vistAPackageName, packageName))
          patchInfo.package = vistAPackageName
      else:
        packageName = patchHistInfo.getPackageName(namespace)
        patchInfo.package = packageName

  """ check to see if the patch is already installed """
  def __isPatchInstalled__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    namespace = patchInfo.namespace
    installName = patchInfo.installName
    if patchHistInfo.hasPatchInstalled(patchInfo.installName,
                                       patchInfo.namespace,
                                       patchInfo.version,
                                       patchInfo.patchNo,
                                       patchInfo.seqNo):
      logger.info("%s is already installed" % installName)
      return True
    installStatus = patchHistInfo.getInstallationStatus(installName)
    logger.debug("%s installation status is %d" %
                 (installName, installStatus))
    if patchHistInfo.isInstallCompleted(installStatus):
      logger.info("%s installed completed" % installName)
      return True
    else:
      return False

  """ update package patch history """
  def __reloadPackagePatchHistory__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    installNameList = []
    if patchInfo.isMultiBuilds:
      installNameList = patchInfo.multiBuildsList
    else:
      installNameList.append(patchInfo.installName)
    for installName in installNameList:
      (namespace,ver,patch) = extractInfoFromInstallName(installName)
      if not patchHistInfo.hasNamespace(namespace):
        patchHistInfo.createAllPackageMapping()
      if patchHistInfo.hasNamespace(namespace):
        packageName = patchHistInfo.getPackageName(namespace)
        patchHistInfo.getPackagePatchHistory(packageName, namespace, ver)

  """ create KIDS Patch Installer by patch Info and install
      the patch specified in patchInfo, return the result
      @return, True indicates on error, False indicates failure
  """
  def __installKIDSPatch__(self, patchInfo):
    installName = patchInfo.installName
    kidsPath = patchInfo.kidsFilePath
    seqNo = patchInfo.seqNo
    logFileName = self._logFileName
    multiBuildsList = patchInfo.multiBuildsList
    kidsInstaller = None
    """ handle patch stored as external link """
    if patchInfo.kidsSha1Path != None:
      kidsSha1 = patchInfo.kidsSha1
      (result, resultPath) = obtainKIDSPatchFileBySha1(kidsPath,
                                                       kidsSha1,
                                                       DEFAULT_CACHE_DIR)
      if not result:
        logger.error("Could not obtain external KIDS patch for %s" % kidsPath)
        return result
      kidsPath = resultPath # set the KIDS Path
    """ get the right KIDS installer """
    associateFiles = patchInfo.associatedInfoFiles
    associatedGlobals = patchInfo.associatedGlobalFiles
    if patchInfo.hasCustomInstaller:
      """ use python imp module to load the source """
      logger.info("using custom installer %s" % patchInfo.customInstallerPath)
      import imp
      installerModule = imp.load_source("KIDS",
                                patchInfo.customInstallerPath)
      from KIDS import CustomInstaller
      kidsInstaller = CustomInstaller(kidsPath, installName,
                                      seqNo, logFileName,
                                      multiBuildsList,
                                      files=associateFiles,
                                      globals=associatedGlobals)

    else:
      kidsInstaller = KIDSInstallerFactory.createKIDSInstaller(
                            kidsPath, installName, seqNo, logFileName,
                            multiBuildsList,
                            files=associateFiles,
                            globals=associatedGlobals)
    logger.info("Applying KIDS Patch %s" % patchInfo)
    assert kidsInstaller
    return kidsInstaller.runInstallation(self._testClient)

  """ check to see if patch is ready to be installed """
  def __isPatchReadyToInstall__(self, patchInfo, patchList = None):
    packageName = patchInfo.package
    ver = patchInfo.version
    patchHist = self._vistaPatchInfo.getPackagePatchHistByName(packageName, ver)
    if not patchHist or not patchHist.hasPatchHistory():
      logger.info("no patch hist for %s, ver: %s" % (packageName, ver))
      return True # if no such an package or hist info, just return True
    """ check patch sequence no to see if it is out of order """
    if patchInfo.seqNo:
      seqNo = patchHist.getLatestSeqNo()
      if patchInfo.seqNo < seqNo:
        logger.error("SeqNo out of order, %s less than latest one %s" %
                      (patchInfo.seqNo), seqNo)
        return False
    # check all the dependencies
    for item in patchInfo.depKIDSPatch:
      if patchList and item in self._patchSet: # we are going to install the dep patch
        logger.info("We are going to install the patch %s" % item)
        """ make sure installation is in the right order """
        itemIndex = self.indexInPatchList(item, patchList)
        patchIndex = self.indexInPatchList(patchInfo.installName, patchList)
        if itemIndex >= patchIndex:
          logger.warn("%s is out of order with %s" % (item, patchInfo))
          return False
        else:
          continue
      (namespace,ver,patch) = extractInfoFromInstallName(item)
      if self._vistaPatchInfo.hasPatchInstalled(item, namespace, ver, patch):
        logger.debug("%s is arelady installed" % item)
        continue
      installStatus = self._vistaPatchInfo.getInstallationStatus(item)
      if self._vistaPatchInfo.isInstallCompleted(installStatus):
        continue
      else:
        logger.error("dep %s is not installed for %s %s" %
                    (item, patchInfo.installName, patchInfo.kidsFilePath))
        return False
    return True
Esempio n. 3
0
class KIDSPatchSequenceApply(object):
  DEFAULT_VISTA_LOG_FILENAME = "VistAInteraction.log"
  DEFAULT_OUTPUT_FILE_LOG = "PatchAnalyzer.log"
  def __init__(self, testClient, logFileDir):
    self._testClient = testClient
    curTimestamp = getCurrentTimestamp()
    logFileName = "%s.%s" % (self.DEFAULT_VISTA_LOG_FILENAME, curTimestamp)
    self._logFileName = os.path.join(logFileDir,
                             logFileName)
    self._testClient.setLogFile(self._logFileName)
    self._kidsOrderGen = KIDSPatchOrderGenerator()
    self._vistaPatchInfo = VistAPackageInfoFetcher(testClient)
    self._outPatchList = []
    self._patchSet = set()
    initConsoleLogging()
    initFileLogging(os.path.join(logFileDir, self.DEFAULT_OUTPUT_FILE_LOG))

  """ generate the patch order sequence base on input """
  def generateKIDSPatchSequence(self, patchDir, patchesCSV=None):
    kidsOrderGen = self._kidsOrderGen
    patchHistInfo = self._vistaPatchInfo
    patchList = []
    if patchesCSV and os.path.exists(patchCSVFile):
      patchList = kidsOrderGen.generatePatchOrderByCSV(patchDir, patchCSVFile)
    else:
      patchList = kidsOrderGen.generatePatchOrderTopologic(patchDir)
    self._patchSet.update([x.installName for x in patchList])
    for patchInfo in patchList:
      namespace = patchInfo.namespace
      self.__updatePatchInfoPackageName__(patchInfo)
      logger.info("Checking for patch info %s" % patchInfo.installName)
      logger.debug("Checking for patch info %s" % patchInfo)
      """ check to see if the patch is already installed """
      if self.__isPatchInstalled__(patchInfo):
        continue
      if self.__isPatchReadyToInstall__(patchInfo, patchList):
        self._outPatchList.append(patchInfo)
      else:
        logger.error("Can not install patch %s" % patchInfo.installName)
        break
    logger.info("Total patches are %d" % len(self._outPatchList))
    for patchInfo in self._outPatchList:
      logger.info("%s, %s, %s" % (patchInfo.installName,
                                  patchInfo.namespace,
                                  patchInfo.kidsFilePath))

  """ apply the KIDS Patch in order """
  def applyKIDSPatchSequence(self, numOfPatches = 1, restart = True):
    totalPatch = len(self._outPatchList)
    numOfPatch = 1
    if re.match("All", str(numOfPatches), re.IGNORECASE):
      numOfPatch = totalPatch
    else:
      numOfPatch = int(numOfPatches)
    restartCache = False
    taskmanUtil = VistATaskmanUtil()
    """ make sure taskman is running """
    taskmanUtil.startTaskman(self._testClient)
    for index in range(0,min(totalPatch, numOfPatch)):
      patchInfo = self._outPatchList[index]
      """ double check to see if patch is already installed """
      if self.__isPatchInstalled__(patchInfo):
        continue
      if not self.__isPatchReadyToInstall__(patchInfo):
        break
      """ generate Sha1 Sum for patch Info """
      self.generateSha1SumForPatchInfo(patchInfo)
      """ install the KIDS patch """
      result = self.__installKIDSPatch__(patchInfo)
      if not result:
        logger.error("Failed to install patch %s: KIDS %s" %
                      (patchInfo.installName, patchInfo.kidsFilePath))
        return
      else:
        # also need to reload the package patch hist
        self.__reloadPackagePatchHistory__(patchInfo)
        assert self.__isPatchInstalled__(patchInfo)
        restartCache = True
    taskmanUtil.waitTaskmanToCurrent(self._testClient)
    """ restart Cache if needed """
    if restart and restartCache and self._testClient.isCache():
      self.__restartCache__()

  @staticmethod
  def generateSha1SumForPatchInfo(patchInfo):
    if patchInfo.kidsSha1 is None:
      patchInfo.kidsSha1 = generateSha1Sum(patchInfo.kidsFilePath)
    if patchInfo.kidsInfoPath:
      patchInfo.kidsInfoSha1 = generateSha1Sum(patchInfo.kidsInfoPath)
    if patchInfo.otherKidsInfoList:
      for item in patchInfo.otherKidsInfoList:
        if item[0]:
          item[1] = generateSha1Sum(item[0])

  @staticmethod
  def indexInPatchList(installName, patchList):
    for index in range(0,len(patchList)):
      if patchList[index].installName == installName:
        return index
    return -1

#---------------------------------------------------------------------------
# private implementation
#---------------------------------------------------------------------------
  """ get the package patch history and update package name
      for KIDS only build
  """
  def __updatePatchInfoPackageName__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    packageName = patchInfo.package
    namespace = patchInfo.namespace
    verInfo = patchInfo.version
    if namespace:
      patchHistInfo.getPackagePatchHistByNamespace(namespace, verInfo)
      if packageName:
        vistAPackageName = patchHistInfo.getPackageName(namespace)
        if vistAPackageName != packageName:
          logger.error("Different PackageName for %s, %s:%s" %
                       (patchInfo.installName, vistAPackageName, packageName))
          patchInfo.package = vistAPackageName
      else:
        packageName = patchHistInfo.getPackageName(namespace)
        patchInfo.package = packageName

  """ check to see if the patch is already installed """
  def __isPatchInstalled__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    namespace = patchInfo.namespace
    installName = patchInfo.installName
    if patchHistInfo.hasPatchInstalled(patchInfo.installName,
                                       patchInfo.namespace,
                                       patchInfo.version,
                                       patchInfo.patchNo,
                                       patchInfo.seqNo):
      logger.info("%s is already installed" % installName)
      return True
    installStatus = patchHistInfo.getInstallationStatus(installName)
    logger.debug("%s installation status is %d" %
                 (installName, installStatus))
    if patchHistInfo.isInstallCompleted(installStatus):
      logger.info("%s installed completed" % installName)
      return True
    else:
      return False

  """ update package patch history """
  def __reloadPackagePatchHistory__(self, patchInfo):
    patchHistInfo = self._vistaPatchInfo
    installNameList = []
    if patchInfo.isMultiBuilds:
      installNameList = patchInfo.multiBuildsList
    else:
      installNameList.append(patchInfo.installName)
    for installName in installNameList:
      (namespace,ver,patch) = extractInfoFromInstallName(installName)
      if not patchHistInfo.hasNamespace(namespace):
        patchHistInfo.createAllPackageMapping()
      assert patchHistInfo.hasNamespace(namespace)
      packageName = patchHistInfo.getPackageName(namespace)
      patchHistInfo.getPackagePatchHistory(packageName, namespace, ver)

  """ create KIDS Patch Installer by patch Info and install
      the patch specified in patchInfo, return the result
      @return, True indicates on error, False indicates failure
  """
  def __installKIDSPatch__(self, patchInfo):
    installName = patchInfo.installName
    kidsPath = patchInfo.kidsFilePath
    seqNo = patchInfo.seqNo
    logFileName = self._logFileName
    multiBuildsList = patchInfo.multiBuildsList
    kidsInstaller = None
    """ handle patch stored as external link """
    if patchInfo.kidsSha1Path != None:
      kidsSha1 = patchInfo.kidsSha1
      (result, resultPath) = obtainKIDSPatchFileBySha1(kidsPath,
                                                       kidsSha1,
                                                       DEFAULT_CACHE_DIR)
      if not result:
        logger.error("Could not obtain external KIDS patch for %s" % kidsPath)
        return result
      kidsPath = resultPath # set the KIDS Path
    """ get the right KIDS installer """
    associateFiles = patchInfo.associatedInfoFiles
    associatedGlobals = patchInfo.associatedGlobalFiles
    if patchInfo.hasCustomInstaller:
      """ use python imp module to load the source """
      logger.info("using custom installer %s" % patchInfo.customInstallerPath)
      import imp
      installerModule = imp.load_source("KIDS",
                                patchInfo.customInstallerPath)
      from KIDS import CustomInstaller
      kidsInstaller = CustomInstaller(kidsPath, installName,
                                      seqNo, logFileName,
                                      multiBuildsList,
                                      files=associateFiles,
                                      globals=associatedGlobals)

    else:
      kidsInstaller = KIDSInstallerFactory.createKIDSInstaller(
                            kidsPath, installName, seqNo, logFileName,
                            multiBuildsList,
                            files=associateFiles,
                            globals=associatedGlobals)
    logger.info("Applying KIDS Patch %s" % patchInfo)
    assert kidsInstaller
    return kidsInstaller.runInstallation(self._testClient)

  """ restart the cache instance """
  def __restartCache__(self):
    self._testClient.getConnection().terminate()
    logger.info("Wait for 5 seconds")
    time.sleep(5)
    logger.info("Restart CACHE instance")
    instanceName = self._testClient.getInstanceName()
    result = stopCache(instanceName, True)
    if not result:
      result = forceDownCache(instanceName)
      if result:
        startCache(instanceName)
      else:
        logger.error("Can not stop cache instance %s" % instanceName)

  """ check to see if patch is ready to be installed """
  def __isPatchReadyToInstall__(self, patchInfo, patchList = None):
    packageName = patchInfo.package
    ver = patchInfo.version
    patchHist = self._vistaPatchInfo.getPackagePatchHistByName(packageName, ver)
    if not patchHist or not patchHist.hasPatchHistory():
      logger.info("no patch hist for %s, ver: %s" % (packageName, ver))
      return True # if no such an package or hist info, just return True
    """ check patch sequence no to see if it is out of order """
    if patchInfo.seqNo:
      seqNo = patchHist.getLatestSeqNo()
      if patchInfo.seqNo < seqNo:
        logger.error("SeqNo out of order, %s less than latest one %s" %
                      (patchInfo.seqNo), seqNo)
        return False
    # check all the dependencies
    for item in patchInfo.depKIDSPatch:
      if patchList and item in self._patchSet: # we are going to install the dep patch
        logger.info("We are going to install the patch %s" % item)
        """ make sure installation is in the right order """
        itemIndex = self.indexInPatchList(item, patchList)
        patchIndex = self.indexInPatchList(patchInfo.installName, patchList)
        if itemIndex >= patchIndex:
          logger.warn("%s is out of order with %s" % (item, patchInfo))
          return False
        else:
          continue
      (namespace,ver,patch) = extractInfoFromInstallName(item)
      if self._vistaPatchInfo.hasPatchInstalled(item, namespace, ver, patch):
        logger.debug("%s is arelady installed" % item)
        continue
      else:
        logger.error("dep %s is not installed for %s %s" %
                    (item, patchInfo.installName, patchInfo.kidsFilePath))
        return False
    return True