Groovy 如何获取工件文件';使用Artifactory';s校验和API,其中多个工件具有相同的SHA-1/SHA-256值,即文件';内容

Groovy 如何获取工件文件';使用Artifactory';s校验和API,其中多个工件具有相同的SHA-1/SHA-256值,即文件';内容,groovy,storage,artifactory,checksum,artifactory-query-lang,Groovy,Storage,Artifactory,Checksum,Artifactory Query Lang,人工版本:5.8.4 在Artifactory中,文件通过文件的校验和(SHA1)存储在内部数据库中,出于检索目的,SHA-256非常有用(用于验证文件是否完整) 请先阅读以下内容: 假设有两个Jenkins作业,它们只创建很少的工件/文件(rpm/jar/etc)。在我的例子中,我将使用一个简单的.txt文件,它以MM/DD/YYYY格式存储日期,以及一些其他特定于jobA/B的构建结果文件(jars/rpms等) 如果我们只关注文本文件(如上所述),那么: Jenkins_jobA>生成jo

人工版本:5.8.4

在Artifactory中,文件通过文件的校验和(SHA1)存储在内部数据库中,出于检索目的,SHA-256非常有用(用于验证文件是否完整)

请先阅读以下内容:

假设有两个Jenkins作业,它们只创建很少的工件/文件(rpm/jar/etc)。在我的例子中,我将使用一个简单的.txt文件,它以MM/DD/YYYY格式存储日期,以及一些其他特定于jobA/B的构建结果文件(jars/rpms等)

如果我们只关注文本文件(如上所述),那么: Jenkins_jobA>生成jobA.date_mm_dd_yy.txt

Jenkins\u jobA>生成jobB.date\u mm\u dd\u yy.txt

Jenkins jobA和jobB每天在没有给定运行顺序的情况下运行多次。有时jobA先运行,有时jobB先运行

由于两个作业的文件内容基本相同(每天),jobA.txt文件和jobB.txt文件上的SHA-1值将相同,即在Artifactory中,两个文件将存储在前两个基于字符的directry文件夹结构中(根据基于校验和的存储机制)

在Linux中,基本上在这两个文件上运行sha1sum和sha256sum将返回完全相同的输出

随着时间的推移,这些工件(.txt等)会从一个存储库升级到另一个存储库(升级过程,即从快照->阶段->发布repo),因此我目前用Groovy编写的逻辑是查找位于“虚拟”存储库(以某种顺序包含一组物理本地存储库)后面的工件的URI下列为:

// Groovy code
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
jsonSlurper = new JsonSlurper()

// The following function will take artifact.SHA_256 as it's parameter to find URI of the artifact

def checkSumBasedSearch(artifactSha) {
virt_repo = "jar-repo"    // this virtual may have many physical repos release/stage/snapshot for jar(maven) or it can be a YUM repo for (rpm) or generic repo for (.txt file)
// Note: Virtual repos don't span different repo types (i.e. a virtual repository in Artifactory for "Maven" artifacts (jar/war/etc) can NOT see YUM/PyPi/Generic physical Repos).

// Run aqlCmd on Linux, requires "...", "..", "..." for every distinctive words / characters in the cmd line.
checkSum_URL = artifactoryURL + "/api/search/checksum?sha256="
aqlCmd = ["curl", "-u", username + ":" + password, "${checkSum_URL}" + artifactSha + "&repos=" + virt_repo]
  }

  def procedure = aqlCmd.execute()
  def standardOut = new StringBuilder(), standardErr = new StringBuilder()
  procedure.waitForProcessOutput(standardOut, standardErr) 
  // Fail early

  if (! standardErr ) {
    println "\n\n-- checkSumBasedSearch() - standardErr exists ---\n" + standardErr +"\n\n-- Exiting with error 12!!!\n\n"
    System.exit(12)
  }

  def obj = jsonSlurper.parseText(standardOut.toString())
  def results = obj.results
  def uri = results[0].uri       // This would work, if a file's sha-1 /256 is always different or sits in different repo at least. 
  return uri

  // to get the URL, I can use:
  //aqlCmd = ["curl", "-u", username + ":" + password, "${uri}"]
  //def procedure = aqlCmd.execute()
  //def obj = jsonSlurper.parseText(standardOut.toString())
  //def url = obj.downloadUri 
  //return url
  //aqlCmd = [ "curl", "-u", username + ":" + password, "${url}", "-o", somedirectory + "/" + variableContainingSomeArtifactFilenameThatIWant ]
  //
  // def procedure = aqlCmd.execute()
  //def standardOut = new StringBuilder(), standardErr = new StringBuilder()
  //procedure.waitForProcessOutput(standardOut, standardErr)
  // Now, I'll get the artifact downloaded in some Directory as some Filename.

}
我关心的是,由于这两个文件(即使不同的名称-或
文件-.txt
)中的内容相同,并且每天生成多次,我如何获得为jobA或jobB下载的特定版本文件

在Artifactory中,包含相同内容的所有文件的SHA_256属性将是相同的!!(Artifactory将使用SHA-1高效地存储这些文件以节省空间,新的上传将只是对用户透明的最小数据库级事务)

问题:

  • 上述逻辑是否会将jobA的文件或jobB的.txt文件或任何先上传其文件或最新上传的Job的.txt文件/acc.返回至LastModified-aka-last upload time

  • 如何在给定的时间戳下下载jobA的.txt文件和jobB的.txt文件

  • 我需要在RESTAPI调用期间添加更多属性吗

  • 如果我只是关心文件内容,那么它是否来自JobA.txt或job的.txt文件并不重要(取决于sha-1/256),但在复杂的情况下,可能有一个文件名包含有意义的信息,他们希望知道下载的文件(a/B)

    您可以使用AQL(人工查询语言)

    curl-u:-XPOSThttps://repo.jfrog.io/artifactory/api/search/aql -H“内容类型:文本/普通”-T./search
    
    名为search的文件的内容为:

    items.find(
      {
        "artifact.module.build.name":{"$eq":"<build name>"},
        "artifact.sha1":"<sha1>"
      }
    )
    
    items.find(
    {
    “artifact.module.build.name”:{“$eq”:”},
    “artifact.sha1”:”
    }
    )
    
  • 上面的逻辑(在原始问题中)将返回其中一个任意值,因为您使用的是返回的第一个结果,并且对订单没有任何保证

  • 由于您的文本文件在名称中包含时间戳,因此您可以将该名称添加到上面给出的aql中,它还将根据名称进行过滤

  • AQL搜索API比校验和搜索更灵活,使用它并根据需要的参数自定义查询


  • 因此,我最终这样做,而不是在任何情况下都从数组返回第[0]个元素

      // Do NOT return [0] first element as yet as Artifactory uses SHA-1/256 so return [Nth].uri where artifact's full name matches with the sha256
      // def uri = results[0].uri
    
      def nThIndex=0
      def foundFlag = 'false'
      for (r in results) {
        println "> " + r.uri + " < " + r.uri.toString() + " artifact: " + artFullName
        if ( r.uri.toString().contains(artFullName) ) {
           foundFlag = 'true'
           println "- OK - Found artifact: " + artFullName + " at results[" + nThIndex + "] index."
           break; // i.e. a match for the artifact name with SHA-256 we want - has been found.
        } else {
           nThIndex++;
        }
      }
    
      if ( foundFlag == 'true' ) {
          def uri = results[nThIndex].uri
          return uri
      } else {
        // Fail early if results were found based on SHA256 but not for the artifact but for some other filename with same SHA256
        if (! standardErr ) {
          println "\n\n\n\n-- [Cool] -- checkSum_Search() - SHA-256 unwanted situation occurred !!! -- results Array was set with some values BUT it didn't contain the artifact (" + artFullName + ") that we were looking for \n\n\n-- !!! Artifact NOT FOUND in the results array during checkSum_Search()---\n\n\n-- Exiting with error 17!!!\n\n\n\n"
          System.exit(17)   // Nooka
        }
      }
    
    //暂时不要返回[0]第一个元素,因为Artifactory使用SHA-1/256,所以返回[n].uri,其中工件的全名和sha256匹配
    //def uri=结果[0]。uri
    def nThIndex=0
    def foundFlag='false'
    对于(结果中的r){
    println“>”+r.uri+“<”+r.uri.toString()+“工件:“+artFullName”
    if(r.uri.toString().contains(artFullName)){
    foundFlag='true'
    println“-OK-在结果[“+nThIndex+”]index处找到工件:“+artFullName+”
    break;//即找到了与我们想要的SHA-256匹配的工件名称。
    }否则{
    nThIndex++;
    }
    }
    如果(foundFlag==“true”){
    def uri=results[nThIndex].uri
    返回uri
    }否则{
    //如果根据SHA256找到结果,但不是针对工件,而是针对具有相同SHA256的其他文件名,则提前失败
    如果(!standardErr){
    println“\n\n\n--[Cool]--checkSum_Search()-SHA-256出现了不必要的情况!!!--results数组设置了一些值,但它不包含我们正在查找的工件(“+artFullName+”)。\n\n\n--!!!在checkSum_Search()期间在结果数组中找不到工件--\n\n\n--退出,出现错误17!!\n\n\n\n\n”
    系统出口(17)//Nooka
    }
    }
    
    是的,这很有意义。我目前正在使用校验和(geturi),然后使用checksumURL(passuri,togeturl),然后使用AQL,下载工件。似乎,要将文件缩小到一个文件,还需要有另一个字段,如artifact name,所以我过去使用过AQL,但我们没有使用AQL的原因是:一个artifact可以在同一个实例中更改repo(AQL仍然可以找到它,但是您需要指定哪个repo?),但我可以再次指定“虚拟repo”为了解决这个问题,但在我们的例子中,我们将工件从一个工件实例以不同的repo名称移动到另一个实例(考虑非安全/安全方面)。所以,校验和方法更好,因为校验和可以告诉SHA256文件的确切位置,而不依赖于将来处理的任何回购协议或实例。但是,返回[0]。uri(获取第一个索引)不正确,无法修复
      // Do NOT return [0] first element as yet as Artifactory uses SHA-1/256 so return [Nth].uri where artifact's full name matches with the sha256
      // def uri = results[0].uri
    
      def nThIndex=0
      def foundFlag = 'false'
      for (r in results) {
        println "> " + r.uri + " < " + r.uri.toString() + " artifact: " + artFullName
        if ( r.uri.toString().contains(artFullName) ) {
           foundFlag = 'true'
           println "- OK - Found artifact: " + artFullName + " at results[" + nThIndex + "] index."
           break; // i.e. a match for the artifact name with SHA-256 we want - has been found.
        } else {
           nThIndex++;
        }
      }
    
      if ( foundFlag == 'true' ) {
          def uri = results[nThIndex].uri
          return uri
      } else {
        // Fail early if results were found based on SHA256 but not for the artifact but for some other filename with same SHA256
        if (! standardErr ) {
          println "\n\n\n\n-- [Cool] -- checkSum_Search() - SHA-256 unwanted situation occurred !!! -- results Array was set with some values BUT it didn't contain the artifact (" + artFullName + ") that we were looking for \n\n\n-- !!! Artifact NOT FOUND in the results array during checkSum_Search()---\n\n\n-- Exiting with error 17!!!\n\n\n\n"
          System.exit(17)   // Nooka
        }
      }