github.com/jaylevin/jenkins-library@v1.230.4/vars/piperExecuteBin.groovy (about)

     1  import com.sap.piper.BashUtils
     2  import com.sap.piper.DebugReport
     3  import com.sap.piper.DefaultValueCache
     4  import com.sap.piper.JenkinsUtils
     5  import com.sap.piper.MapUtils
     6  import com.sap.piper.PiperGoUtils
     7  import com.sap.piper.Utils
     8  import com.sap.piper.analytics.InfluxData
     9  import groovy.transform.Field
    10  
    11  import static com.sap.piper.Prerequisites.checkScript
    12  
    13  @Field String STEP_NAME = getClass().getName()
    14  
    15  void call(Map parameters = [:], String stepName, String metadataFile, List credentialInfo, boolean failOnMissingReports = false, boolean failOnMissingLinks = false, boolean failOnError = false) {
    16  
    17      Map handlePipelineStepErrorsParameters = [stepName: stepName, stepParameters: parameters]
    18      if (failOnError) {
    19          handlePipelineStepErrorsParameters.failOnError = true
    20      }
    21  
    22      handlePipelineStepErrors(handlePipelineStepErrorsParameters) {
    23          Script script = checkScript(this, parameters) ?: this
    24          def jenkinsUtils = parameters.jenkinsUtilsStub ?: new JenkinsUtils()
    25          def utils = parameters.juStabUtils ?: new Utils()
    26  
    27          String piperGoPath = parameters.piperGoPath ?: './piper'
    28  
    29          prepareExecution(script, utils, parameters)
    30          prepareMetadataResource(script, metadataFile)
    31          Map stepParameters = prepareStepParameters(parameters)
    32          echo "Step params $stepParameters"
    33  
    34          withEnv([
    35              "PIPER_parametersJSON=${groovy.json.JsonOutput.toJson(stepParameters)}",
    36              "PIPER_correlationID=${env.BUILD_URL}",
    37              //ToDo: check if parameters make it into docker image on JaaS
    38          ]) {
    39              String defaultConfigArgs = getCustomDefaultConfigsArg()
    40              String customConfigArg = getCustomConfigArg(script)
    41  
    42              echo "PIPER_parametersJSON: ${groovy.json.JsonOutput.toJson(stepParameters)}"
    43  
    44              // get context configuration
    45              Map config
    46              handleErrorDetails(stepName) {
    47                  config = getStepContextConfig(script, piperGoPath, metadataFile, defaultConfigArgs, customConfigArg)
    48                  echo "Context Config: ${config}"
    49              }
    50  
    51              // prepare stashes
    52              // first eliminate empty stashes
    53              config.stashContent = utils.unstashAll(config.stashContent)
    54              // then make sure that commonPipelineEnvironment, config, ... is also available when step stashing is active
    55              if (config.stashContent?.size() > 0) {
    56                  config.stashContent.add('pipelineConfigAndTests')
    57                  config.stashContent.add('piper-bin')
    58                  config.stashContent.add('pipelineStepReports')
    59              }
    60  
    61              if (parameters.stashNoDefaultExcludes) {
    62                  // Merge this parameter which is only relevant in Jenkins context
    63                  // (for dockerExecuteOnKubernetes step) and go binary doesn't know about
    64                  config.stashNoDefaultExcludes = parameters.stashNoDefaultExcludes
    65              }
    66  
    67              dockerWrapper(script, stepName, config) {
    68                  handleErrorDetails(stepName) {
    69                      writePipelineEnv(script: script, piperGoPath: piperGoPath)
    70                      utils.unstash('pipelineStepReports')
    71                      try {
    72                          try {
    73                              try {
    74                                  credentialWrapper(config, credentialInfo) {
    75                                      sh "${piperGoPath} ${stepName}${defaultConfigArgs}${customConfigArg}"
    76                                  }
    77                              } finally {
    78                                  jenkinsUtils.handleStepResults(stepName, failOnMissingReports, failOnMissingLinks)
    79                              }
    80                          } finally {
    81                             readPipelineEnv(script: script, piperGoPath: piperGoPath)
    82                          }
    83                      } finally {
    84                          InfluxData.readFromDisk(script)
    85                          stash name: 'pipelineStepReports', includes: '.pipeline/stepReports/**', allowEmpty: true
    86                      }
    87                  }
    88              }
    89          }
    90      }
    91  }
    92  
    93  // reused in sonarExecuteScan
    94  static void prepareExecution(Script script, Utils utils, Map parameters = [:]) {
    95      def piperGoUtils = parameters.piperGoUtils ?: new PiperGoUtils(script, utils)
    96      piperGoUtils.unstashPiperBin()
    97      utils.unstash('pipelineConfigAndTests')
    98  }
    99  
   100  // reused in sonarExecuteScan
   101  static Map prepareStepParameters(Map parameters) {
   102      Map stepParameters = [:].plus(parameters)
   103  
   104      stepParameters.remove('script')
   105      stepParameters.remove('jenkinsUtilsStub')
   106      stepParameters.remove('piperGoPath')
   107      stepParameters.remove('juStabUtils')
   108      stepParameters.remove('piperGoUtils')
   109  
   110      // When converting to JSON and back again, entries which had a 'null' value will now have a value
   111      // of type 'net.sf.json.JSONNull', for which the Groovy Truth resolves to 'true' in for example if-conditions
   112      return MapUtils.pruneNulls(stepParameters)
   113  }
   114  
   115  // reused in sonarExecuteScan
   116  static void prepareMetadataResource(Script script, String metadataFile) {
   117      script.writeFile(file: ".pipeline/tmp/${metadataFile}", text: script.libraryResource(metadataFile))
   118  }
   119  
   120  // reused in sonarExecuteScan
   121  static Map getStepContextConfig(Script script, String piperGoPath, String metadataFile, String defaultConfigArgs, String customConfigArg) {
   122      return script.readJSON(text: script.sh(returnStdout: true, script: "${piperGoPath} getConfig --contextConfig --stepMetadata '.pipeline/tmp/${metadataFile}'${defaultConfigArgs}${customConfigArg}"))
   123  }
   124  
   125  static String getCustomDefaultConfigs() {
   126      // The default config files were extracted from merged library
   127      // resources by setupCommonPipelineEnvironment.groovy into .pipeline/.
   128      List customDefaults = DefaultValueCache.getInstance().getCustomDefaults()
   129      for (int i = 0; i < customDefaults.size(); i++) {
   130          customDefaults[i] = BashUtils.quoteAndEscape(".pipeline/${customDefaults[i]}")
   131      }
   132      return customDefaults.join(',')
   133  }
   134  
   135  // reused in sonarExecuteScan
   136  static String getCustomDefaultConfigsArg() {
   137      String customDefaults = getCustomDefaultConfigs()
   138      if (customDefaults) {
   139          return " --defaultConfig ${customDefaults} --ignoreCustomDefaults"
   140      }
   141      return ''
   142  }
   143  
   144  // reused in sonarExecuteScan
   145  static String getCustomConfigArg(def script) {
   146      if (script?.commonPipelineEnvironment?.configurationFile
   147          && script.commonPipelineEnvironment.configurationFile != '.pipeline/config.yml'
   148          && script.commonPipelineEnvironment.configurationFile != '.pipeline/config.yaml') {
   149          return " --customConfig ${BashUtils.quoteAndEscape(script.commonPipelineEnvironment.configurationFile)}"
   150      }
   151      return ''
   152  }
   153  
   154  // reused in sonarExecuteScan
   155  void dockerWrapper(script, stepName, config, body) {
   156      if (config.dockerImage) {
   157          echo "[INFO] executing pipeline step '${stepName}' with docker image '${config.dockerImage}'"
   158          Map dockerExecuteParameters = [:].plus(config)
   159          dockerExecuteParameters.script = script
   160          dockerExecute(dockerExecuteParameters) {
   161              body()
   162          }
   163      } else {
   164          body()
   165      }
   166  }
   167  
   168  // reused in sonarExecuteScan
   169  void credentialWrapper(config, List credentialInfo, body) {
   170      credentialInfo = handleVaultCredentials(config, credentialInfo)
   171  
   172      if (credentialInfo.size() > 0) {
   173          def creds = []
   174          def sshCreds = []
   175          credentialInfo.each { cred ->
   176              def credentialsId
   177              if (cred.resolveCredentialsId == false) {
   178                  credentialsId = cred.id
   179              } else {
   180                  credentialsId = config[cred.id]
   181              }
   182              if (credentialsId) {
   183                  switch (cred.type) {
   184                      case "file":
   185                          creds.add(file(credentialsId: credentialsId, variable: cred.env[0]))
   186                          break
   187                      case "token":
   188                          creds.add(string(credentialsId: credentialsId, variable: cred.env[0]))
   189                          break
   190                      case "usernamePassword":
   191                          creds.add(usernamePassword(credentialsId: credentialsId, usernameVariable: cred.env[0], passwordVariable: cred.env[1]))
   192                          break
   193                      case "ssh":
   194                          sshCreds.add(credentialsId)
   195                          break
   196                      default:
   197                          error("invalid credential type: ${cred.type}")
   198                  }
   199              }
   200          }
   201  
   202          // remove credentialIds that were probably defaulted and which are not present in jenkins
   203          if (containsVaultConfig(config)) {
   204              creds = removeMissingCredentials(creds, config)
   205              sshCreds = removeMissingCredentials(sshCreds, config)
   206          }
   207  
   208          if (sshCreds.size() > 0) {
   209              sshagent (sshCreds) {
   210                  withCredentials(creds) {
   211                      body()
   212                  }
   213              }
   214          } else {
   215              withCredentials(creds) {
   216                  body()
   217              }
   218          }
   219      } else {
   220          body()
   221      }
   222  }
   223  
   224  List removeMissingCredentials(List creds, Map config) {
   225      return creds.findAll { credentialExists(it, config) }
   226  }
   227  
   228  boolean credentialExists(cred, Map config) {
   229      try {
   230          withCredentials([cred]) {
   231              return true
   232          }
   233      } catch (e) {
   234          return false
   235      }
   236  }
   237  
   238  boolean containsVaultConfig(Map config) {
   239      def approleIsUsed = config.containsKey('vaultAppRoleTokenCredentialsId') && config.containsKey('vaultAppRoleSecretTokenCredentialsId')
   240      def tokenIsUsed = config.containsKey('vaultTokenCredentialsId')
   241  
   242      return approleIsUsed || tokenIsUsed
   243  }
   244  
   245  // Injects vaultCredentials if steps supports resolving parameters from vault
   246  List handleVaultCredentials(config, List credentialInfo) {
   247      if (config.containsKey('vaultAppRoleTokenCredentialsId') && config.containsKey('vaultAppRoleSecretTokenCredentialsId')) {
   248          credentialInfo += [[type: 'token', id: 'vaultAppRoleTokenCredentialsId', env: ['PIPER_vaultAppRoleID']],
   249                              [type: 'token', id: 'vaultAppRoleSecretTokenCredentialsId', env: ['PIPER_vaultAppRoleSecretID']]]
   250      }
   251  
   252      if (config.containsKey('vaultTokenCredentialsId')) {
   253          credentialInfo += [[type: 'token', id: 'vaultTokenCredentialsId', env: ['PIPER_vaultToken']]]
   254      }
   255  
   256      return credentialInfo
   257  }
   258  
   259  // reused in sonarExecuteScan
   260  void handleErrorDetails(String stepName, Closure body) {
   261      try {
   262          body()
   263      } catch (ex) {
   264          def errorDetailsFileName = "${stepName}_errorDetails.json"
   265          if (fileExists(file: errorDetailsFileName)) {
   266              def errorDetails = readJSON(file: errorDetailsFileName)
   267              def errorCategory = ""
   268              if (errorDetails.category) {
   269                  errorCategory = " (category: ${errorDetails.category})"
   270                  DebugReport.instance.failedBuild.category = errorDetails.category
   271              }
   272              error "[${stepName}] Step execution failed${errorCategory}. Error: ${errorDetails.error ?: errorDetails.message}"
   273          }
   274          error "[${stepName}] Step execution failed. Error: ${ex}, please see log file for more details."
   275      }
   276  }