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

     1  import com.sap.piper.ConfigurationHelper
     2  import com.sap.piper.GenerateDocumentation
     3  import com.sap.piper.JenkinsUtils
     4  import com.sap.piper.JsonUtils
     5  import com.sap.piper.Utils
     6  import com.sap.piper.integration.TransportManagementService
     7  import groovy.transform.Field
     8  
     9  import static com.sap.piper.Prerequisites.checkScript
    10  
    11  @Field String STEP_NAME = getClass().getName()
    12  
    13  @Field Set GENERAL_CONFIG_KEYS = [
    14      /**
    15       * Print more detailed information into the log.
    16       * @possibleValues `true`, `false`
    17       */
    18      'verbose'
    19  ]
    20  @Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
    21      /**
    22       * If specific stashes should be considered, their names need to be passed via the parameter `stashContent`.
    23       */
    24      'stashContent',
    25      /**
    26       * Defines the relative path to *.mtar for the upload to the Transport Management Service. If not specified, it will use the mtar file created in mtaBuild.
    27       */
    28      'mtaPath',
    29      /**
    30       * Defines the name of the node to which the *.mtar file should be uploaded.
    31       */
    32      'nodeName',
    33      /**
    34       * Defines the version of the MTA for which the MTA extension descriptor will be used. You can use an asterisk (*) to accept any MTA version, or use a specific version compliant with SemVer 2.0, e.g. 1.0.0 (see semver.org). If the parameter is not configured, an asterisk is used.
    35       */
    36      'mtaVersion',
    37      /**
    38       * Available only for transports in Cloud Foundry environment. Defines a mapping between a transport node name and an MTA extension descriptor file path that you want to use for the transport node, e.g. nodeExtDescriptorMapping: [nodeName: 'example.mtaext', nodeName2: 'example2.mtaext', …]`.
    39       */
    40      'nodeExtDescriptorMapping',
    41      /**
    42       * Credentials to be used for the file and node uploads to the Transport Management Service.
    43       */
    44      'credentialsId',
    45      /**
    46       * Can be used as the description of a transport request. Will overwrite the default. (Default: Corresponding Git Commit-ID)
    47       */
    48      'customDescription',
    49      /**
    50       * Proxy which should be used for the communication with the Transport Management Service Backend.
    51       */
    52      'proxy'
    53  ])
    54  @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS + GENERAL_CONFIG_KEYS
    55  
    56  /**
    57   * This step allows you to upload an MTA file (multi-target application archive) and multiple MTA extension descriptors into a TMS (SAP Cloud Platform Transport Management Service) landscape for further TMS-controlled distribution through a TMS-configured landscape.
    58   * TMS lets you manage transports between SAP Cloud Platform accounts in Neo and Cloud Foundry, such as from DEV to TEST and PROD accounts.
    59   * For more information, see [official documentation of Transport Management Service](https://help.sap.com/viewer/p/TRANSPORT_MANAGEMENT_SERVICE)
    60   *
    61   * !!! note "Prerequisites"
    62   *     * You have subscribed to and set up TMS, as described in [Setup and Configuration of SAP Cloud Platform Transport Management](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/66fd7283c62f48adb23c56fb48c84a60.html), which includes the configuration of a node to be used for uploading an MTA file.
    63   *     * A corresponding service key has been created, as described in [Set Up the Environment to Transport Content Archives directly in an Application](https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/8d9490792ed14f1bbf8a6ac08a6bca64.html). This service key (JSON) must be stored as a secret text within the Jenkins secure store.
    64   *
    65   */
    66  @GenerateDocumentation
    67  void call(Map parameters = [:]) {
    68      handlePipelineStepErrors(stepName: STEP_NAME, stepParameters: parameters) {
    69  
    70          def script = checkScript(this, parameters) ?: this
    71          def utils = parameters.juStabUtils ?: new Utils()
    72          def jenkinsUtils = parameters.jenkinsUtilsStub ?: new JenkinsUtils()
    73          String stageName = parameters.stageName ?: env.STAGE_NAME
    74  
    75          // load default & individual configuration
    76          Map config = ConfigurationHelper.newInstance(this)
    77              .loadStepDefaults([:], stageName)
    78              .mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS)
    79              .mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
    80              .mixinStageConfig(script.commonPipelineEnvironment, stageName, STEP_CONFIG_KEYS)
    81              .mixin(parameters, PARAMETER_KEYS)
    82              .addIfEmpty('mtaPath', script.commonPipelineEnvironment.mtarFilePath)
    83              //mandatory parameters
    84              .withMandatoryProperty('mtaPath')
    85              .withMandatoryProperty('nodeName')
    86              .withMandatoryProperty('credentialsId')
    87              .use()
    88  
    89          // telemetry reporting
    90          new Utils().pushToSWA([
    91              step         : STEP_NAME,
    92              stepParamKey1: 'scriptMissing',
    93              stepParam1   : parameters?.script == null
    94          ], config)
    95  
    96          def jsonUtilsObject = new JsonUtils()
    97  
    98          // make sure that all relevant descriptors, are available in workspace
    99          utils.unstashAll(config.stashContent)
   100          // make sure that for further execution whole workspace, e.g. also downloaded artifacts are considered
   101          config.stashContent = []
   102  
   103          def customDescription = config.customDescription ? "${config.customDescription}" : "Git CommitId: ${script.commonPipelineEnvironment.getGitCommitId()}"
   104          def description = customDescription
   105  
   106          def namedUser = jenkinsUtils.getJobStartedByUserId() ?: config.namedUser
   107  
   108          def nodeName = config.nodeName
   109          def mtaPath = config.mtaPath
   110  
   111          def mtaVersion = config.mtaVersion ? "${config.mtaVersion}" : "*"
   112          Map nodeExtDescriptorMapping = (config.nodeExtDescriptorMapping && config.nodeExtDescriptorMapping.size()>0) ? config.nodeExtDescriptorMapping : null
   113  
   114          if(!fileExists(mtaPath)) {
   115              error("Mta file '${mtaPath}' does not exist.")
   116          }
   117  
   118          if (config.verbose) {
   119              echo "[TransportManagementService] CredentialsId: '${config.credentialsId}'"
   120              echo "[TransportManagementService] Node name: '${nodeName}'"
   121              echo "[TransportManagementService] MTA path: '${mtaPath}'"
   122              echo "[TransportManagementService] Named user: '${namedUser}'"
   123          }
   124  
   125          def tms = parameters.transportManagementService ?: new TransportManagementService(script, config)
   126  
   127          withCredentials([string(credentialsId: config.credentialsId, variable: 'tmsServiceKeyJSON')]) {
   128  
   129              def tmsServiceKey = jsonUtilsObject.jsonStringToGroovyObject(tmsServiceKeyJSON)
   130  
   131              def clientId = tmsServiceKey.uaa.clientid
   132              def clientSecret = tmsServiceKey.uaa.clientsecret
   133              def uaaUrl = tmsServiceKey.uaa.url
   134              def uri = tmsServiceKey.uri
   135  
   136              if (config.verbose) {
   137                  echo "[TransportManagementService] UAA URL: '${uaaUrl}'"
   138                  echo "[TransportManagementService] TMS URL: '${uri}'"
   139                  echo "[TransportManagementService] ClientId: '${clientId}'"
   140              }
   141  
   142              def token = tms.authentication(uaaUrl, clientId, clientSecret)
   143  
   144              if(nodeExtDescriptorMapping) {
   145                  // validate the whole mapping and then throw errors together,
   146                  // so that user can get them in one pipeline run
   147                  // put the validation here, because we need uri and token to call tms get nodes api
   148                  List nodes = tms.getNodes(uri, token).getAt("nodes");
   149                  Map mtaYaml = getMtaYaml(script.commonPipelineEnvironment.getValue('mtaBuildToolDesc'));
   150                  Map nodeIdExtDesMap = validateNodeExtDescriptorMapping(nodeExtDescriptorMapping, nodes, mtaYaml, mtaVersion)
   151  
   152                  if(nodeIdExtDesMap) {
   153                      nodeIdExtDesMap.each{ key, value ->
   154                          Map mtaExtDescriptor = tms.getMtaExtDescriptor(uri, token, key, mtaYaml.ID, mtaVersion)
   155                          if(mtaExtDescriptor) {
   156                              def updateMtaExtDescriptorResponse = tms.updateMtaExtDescriptor(uri, token, key, mtaExtDescriptor.getAt("id"), "${workspace}/${value.get(1)}", mtaVersion, description, namedUser)
   157                              echo "[TransportManagementService] MTA Extension Descriptor with ID '${updateMtaExtDescriptorResponse.mtaExtId}' successfully updated for Node '${value.get(0)}'."
   158                          } else {
   159                              def uploadMtaExtDescriptorToNodeResponse = tms.uploadMtaExtDescriptorToNode(uri, token, key, "${workspace}/${value.get(1)}", mtaVersion, description, namedUser)
   160                              echo "[TransportManagementService] MTA Extension Descriptor with ID '${uploadMtaExtDescriptorToNodeResponse.mtaExtId}' successfully uploaded to Node '${value.get(0)}'."
   161                          }
   162                      }
   163                  }
   164              }
   165  
   166              def fileUploadResponse = tms.uploadFile(uri, token, "${workspace}/${mtaPath}", namedUser)
   167              def uploadFileToNodeResponse = tms.uploadFileToNode(uri, token, nodeName, fileUploadResponse.fileId, description, namedUser)
   168              echo "[TransportManagementService] File '${fileUploadResponse.fileName}' successfully uploaded to Node '${uploadFileToNodeResponse.queueEntries.nodeName}' (Id: '${uploadFileToNodeResponse.queueEntries.nodeId}')."
   169              echo "[TransportManagementService] Corresponding Transport Request: '${uploadFileToNodeResponse.transportRequestDescription}' (Id: '${uploadFileToNodeResponse.transportRequestId}')"
   170          }
   171  
   172      }
   173  }
   174  
   175  def String getMtaId(String extDescriptorFilePath){
   176      def extDescriptor = readYaml file: extDescriptorFilePath
   177      def mtaId = ""
   178      if (extDescriptor.extends) {
   179          mtaId = extDescriptor.extends
   180      }
   181      return mtaId
   182  }
   183  
   184  def Map getMtaYaml(String mtaBuildToolDesc) {
   185      mtaBuildToolDesc = mtaBuildToolDesc?:"mta.yaml"
   186      if(fileExists(mtaBuildToolDesc)) {
   187          def mtaYaml = readYaml file: mtaBuildToolDesc
   188          if (!mtaYaml.ID || !mtaYaml.version) {
   189              def errorMsg
   190              if (!mtaYaml.ID) {
   191                  errorMsg = "Property 'ID' is not found in ${mtaBuildToolDesc}."
   192              }
   193              if (!mtaYaml.version) {
   194                  errorMsg += "Property 'version' is not found in ${mtaBuildToolDesc}."
   195              }
   196              error errorMsg
   197          }
   198          return mtaYaml
   199      } else {
   200          error "${mtaBuildToolDesc} is not found in the root folder of the project."
   201      }
   202  }
   203  
   204  def Map validateNodeExtDescriptorMapping(Map nodeExtDescriptorMapping, List nodes, Map mtaYaml, String mtaVersion) {
   205      def errorPathList = []
   206      def errorMtaId = []
   207      def errorNodeNameList = []
   208      def errorMsg = ""
   209      Map nodeIdExtDesMap = [:]
   210  
   211      if(mtaVersion != "*" && mtaVersion != mtaYaml.version) {
   212          errorMsg = "Parameter 'mtaVersion' does not match the MTA version in mta.yaml. "
   213      }
   214  
   215      nodeExtDescriptorMapping.each{ key, value ->
   216          if(nodes.any {it.name == key}) {
   217              nodeIdExtDesMap.put(nodes.find {it.name == key}.getAt("id"), [key, value])
   218          } else {
   219              errorNodeNameList.add(key)
   220          }
   221  
   222          if(!fileExists(value)) {
   223              errorPathList.add(value)
   224          } else {
   225              if(mtaYaml.ID != getMtaId("${value}")) {
   226                  errorMtaId.add(value)
   227              }
   228          }
   229      }
   230  
   231      if(!errorPathList.isEmpty() || !errorMtaId.isEmpty() || !errorNodeNameList.isEmpty() ) {
   232          if(!errorPathList.isEmpty()) {
   233              errorMsg += "MTA extension descriptor files ${errorPathList} don't exist. "
   234          }
   235          if(!errorMtaId.isEmpty()) {
   236              errorMsg += "Parameter [extends] in MTA extension descriptor files ${errorMtaId} is not the same as MTA ID."
   237          }
   238          if(!errorNodeNameList.isEmpty()) {
   239              errorMsg += "Nodes ${errorNodeNameList} don't exist. Please check the node name or create these nodes."
   240          }
   241          error(errorMsg)
   242      }
   243  
   244      return nodeIdExtDesMap
   245  }