1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/vars/cloudFoundryCreateService.groovy
Shanuson 8cfac8d43f new step cloudFoundryServiceCreate (#892)
# Changes
This PR adds a new step: cloudFoundryServiceCreate

There is a cf community plugin [Create-Service-Push](https://github.com/dawu415/CF-CLI-Create-Service-Push-Plugin) available to apply infrastructure as code  to Cloud Foundry. The plugin uses a manifest.yml to create services in a targeted CF space. 

The proposed step provides an interface to this plugin. 

Already done:
- [x] Tests
- [x] Documentation

Further actions:
- a Refactoring: Move varOptions and varsFileOption code into a class and make us of this here and in cloudFoundryDeploy step. -> Is it ok to use the CfManifestUtils, or add it as a new class to variablesubstitiion package? 
- enhance the s4sdk cf cli docker image to include the plugin.
2019-10-22 11:15:03 +02:00

180 lines
8.3 KiB
Groovy

import com.sap.piper.GenerateDocumentation
import com.sap.piper.BashUtils
import com.sap.piper.JenkinsUtils
import com.sap.piper.Utils
import com.sap.piper.ConfigurationHelper
import groovy.transform.Field
import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = 'cloudFoundryCreateService'
@Field Set STEP_CONFIG_KEYS = [
'cloudFoundry',
/**
* Cloud Foundry API endpoint.
* @parentConfigKey cloudFoundry
*/
'apiEndpoint',
/**
* Credentials to be used for deployment.
* @parentConfigKey cloudFoundry
*/
'credentialsId',
/**
* Defines the manifest Yaml file that contains the information about the to be created services that will be passed to a Create-Service-Push cf cli plugin.
* @parentConfigKey cloudFoundry
*/
'serviceManifest',
/**
* Defines the manifest variables Yaml files to be used to replace variable references in manifest. This parameter
* is optional and will default to `["manifest-variables.yml"]`. This can be used to set variable files like it
* is provided by `cf push --vars-file <file>`.
*
* If the manifest is present and so are all variable files, a variable substitution will be triggered that uses
* the `cfManifestSubstituteVariables` step before deployment. The format of variable references follows the
* [Cloud Foundry standard](https://docs.cloudfoundry.org/devguide/deploy-apps/manifest-attributes.html#variable-substitution).
* @parentConfigKey cloudFoundry
*/
'manifestVariablesFiles',
/**
* Defines a `List` of variables as key-value `Map` objects used for variable substitution within the file given by `manifest`.
* Defaults to an empty list, if not specified otherwise. This can be used to set variables like it is provided
* by `cf push --var key=value`.
*
* The order of the maps of variables given in the list is relevant in case there are conflicting variable names and values
* between maps contained within the list. In case of conflicts, the last specified map in the list will win.
*
* Though each map entry in the list can contain more than one key-value pair for variable substitution, it is recommended
* to stick to one entry per map, and rather declare more maps within the list. The reason is that
* if a map in the list contains more than one key-value entry, and the entries are conflicting, the
* conflict resolution behavior is undefined (since map entries have no sequence).
*
* Note: variables defined via `manifestVariables` always win over conflicting variables defined via any file given
* by `manifestVariablesFiles` - no matter what is declared before. This is the same behavior as can be
* observed when using `cf push --var` in combination with `cf push --vars-file`.
*/
'manifestVariables',
/**
* Cloud Foundry target organization.
* @parentConfigKey cloudFoundry
*/
'org',
/**
* Cloud Foundry target space.
* @parentConfigKey cloudFoundry
*/
'space',
/** @see dockerExecute */
'dockerImage',
/** @see dockerExecute */
'dockerWorkspace',
/** @see dockerExecute */
'stashContent'
]
@Field Map CONFIG_KEY_COMPATIBILITY = [cloudFoundry: [apiEndpoint: 'cfApiEndpoint', appName:'cfAppName', credentialsId: 'cfCredentialsId', serviceManifest: 'cfServiceManifest', manifestVariablesFiles: 'cfManifestVariablesFiles', manifestVariables: 'cfManifestVariables', org: 'cfOrg', space: 'cfSpace']]
@Field Set GENERAL_CONFIG_KEYS = STEP_CONFIG_KEYS
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
/**
* Uses the Create-Service-Push plugin to create services in a Cloud Foundry space.
*
* For details how to specify the services see the [github page of the plugin](https://github.com/dawu415/CF-CLI-Create-Service-Push-Plugin).
*
* The `--no-push` options is always used with the plugin. To deploy the application make use of the cloudFoundryDeploy step!
*/
@GenerateDocumentation
void call(Map parameters = [:]) {
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
def script = checkScript(this, parameters) ?: this
def utils = parameters.juStabUtils ?: new Utils()
def jenkinsUtils = parameters.jenkinsUtilsStub ?: new JenkinsUtils()
// load default & individual configuration
Map config = ConfigurationHelper.newInstance(this)
.loadStepDefaults()
.mixinGeneralConfig(script.commonPipelineEnvironment, GENERAL_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS, CONFIG_KEY_COMPATIBILITY)
.mixin(parameters, PARAMETER_KEYS, CONFIG_KEY_COMPATIBILITY)
.withMandatoryProperty('cloudFoundry/org')
.withMandatoryProperty('cloudFoundry/space')
.withMandatoryProperty('cloudFoundry/credentialsId')
.withMandatoryProperty('cloudFoundry/serviceManifest')
.use()
utils.pushToSWA([step: STEP_NAME],config)
utils.unstashAll(config.stashContent)
if (fileExists(config.cloudFoundry.serviceManifest)) {
executeCreateServicePush(script, config)
}
}
}
private def executeCreateServicePush(script, Map config) {
dockerExecute(script:script,dockerImage: config.dockerImage, dockerWorkspace: config.dockerWorkspace) {
String varPart = varOptions(config)
String varFilePart = varFileOptions(config)
withCredentials([
usernamePassword(credentialsId: config.cloudFoundry.credentialsId, passwordVariable: 'CF_PASSWORD', usernameVariable: 'CF_USERNAME')
]) {
def returnCode = sh returnStatus: true, script: """#!/bin/bash
set +x
set -e
export HOME=${config.dockerWorkspace}
cf login -u ${BashUtils.quoteAndEscape(CF_USERNAME)} -p ${BashUtils.quoteAndEscape(CF_PASSWORD)} -a ${config.cloudFoundry.apiEndpoint} -o ${BashUtils.quoteAndEscape(config.cloudFoundry.org)} -s ${BashUtils.quoteAndEscape(config.cloudFoundry.space)};
cf create-service-push --no-push -f ${BashUtils.quoteAndEscape(config.cloudFoundry.serviceManifest)}${varPart}${varFilePart}
"""
sh "cf logout"
if (returnCode!=0) {
error "[${STEP_NAME}] ERROR: The execution of the create-service-push plugin failed, see the logs above for more details."
}
}
}
}
private varOptions(Map config) {
String varPart = ''
if (config.cloudFoundry.manifestVariables) {
if (!(config.cloudFoundry.manifestVariables in List)) {
error "[${STEP_NAME}] ERROR: Parameter config.cloudFoundry.manifestVariables is not a List!"
}
config.cloudFoundry.manifestVariables.each {
if (!(it in Map)) {
error "[${STEP_NAME}] ERROR: Parameter config.cloudFoundry.manifestVariables.$it is not a Map!"
}
it.keySet().each { varKey ->
String varValue=BashUtils.quoteAndEscape(it.get(varKey).toString())
varPart += " --var $varKey=$varValue"
}
}
}
if (varPart) echo "We will add the following string to the cf push call: '$varPart'"
return varPart
}
private String varFileOptions(Map config) {
String varFilePart = ''
if (config.cloudFoundry.manifestVariablesFiles) {
if (!(config.cloudFoundry.manifestVariablesFiles in List)) {
error "[${STEP_NAME}] ERROR: Parameter config.cloudFoundry.manifestVariablesFiles is not a List!"
}
config.cloudFoundry.manifestVariablesFiles.each {
if (fileExists(it)) {
varFilePart += " --vars-file ${BashUtils.quoteAndEscape(it)}"
} else {
echo "[${STEP_NAME}] [WARNING] We skip adding not-existing file '$it' as a vars-file to the cf create-service-push call"
}
}
}
if (varFilePart) echo "We will add the following string to the cf push call: '$varFilePart'"
return varFilePart
}