1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-03-05 15:15:44 +02:00

Add mta extension credentials handling to cloudFoundryDeploy step and infer deployTool default from buildTool (#1761)

This commit is contained in:
Kevin Hudemann 2020-07-06 16:16:48 +02:00 committed by GitHub
parent 520f2cc975
commit c8ca3ea522
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 171 additions and 35 deletions

View File

@ -164,7 +164,6 @@ steps:
apiEndpoint: 'https://api.cf.eu10.hana.ondemand.com'
apiParameters: ''
loginParameters: ''
deployTool: 'cf_native'
deployType: 'standard'
keepOldInstance: false
cfNativeDeployParameters: ''
@ -182,6 +181,16 @@ steps:
mtaDeployPlugin:
dockerImage: 'ppiper/cf-cli'
dockerWorkspace: '/home/piper'
mta:
deployTool: 'mtaDeployPlugin'
maven:
deployTool: 'cf_native'
npm:
deployTool: 'cf_native'
docker:
deployTool: 'cf_native'
kaniko:
deployTool: 'cf_native'
containerExecuteStructureTests:
containerCommand: '/busybox/tail -f /dev/null'
containerShell: '/busybox/sh'

View File

@ -93,7 +93,7 @@ class CloudFoundryDeployTest extends BasePiperTest {
nullScript.commonPipelineEnvironment.configuration = [
general: [
camSystemRole: 'testRole',
cfCredentialsId: 'myCreds'
cfCredentialsId: 'test_cfCredentialsId'
],
stages: [
acceptance: [
@ -106,17 +106,16 @@ class CloudFoundryDeployTest extends BasePiperTest {
cloudFoundryDeploy: []
]
]
nullScript.commonPipelineEnvironment.setBuildTool('mta')
stepRule.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
jenkinsUtilsStub: new JenkinsUtilsMock(),
deployTool: '',
mtaPath: 'target/test.mtar',
stageName: 'acceptance',
])
// asserts
assertThat(loggingRule.log, containsString('[cloudFoundryDeploy] General parameters: deployTool=, deployType=standard, cfApiEndpoint=https://api.cf.eu10.hana.ondemand.com, cfOrg=testOrg, cfSpace=testSpace, cfCredentialsId=myCreds'))
assertThat(loggingRule.log, containsString('[cloudFoundryDeploy] WARNING! Found unsupported deployTool. Skipping deployment.'))
assertThat(loggingRule.log, containsString('[cloudFoundryDeploy] General parameters: deployTool=mtaDeployPlugin, deployType=standard, cfApiEndpoint=https://api.cf.eu10.hana.ondemand.com, cfOrg=testOrg, cfSpace=testSpace, cfCredentialsId=test_cfCredentialsId'))
}
@Test
@ -979,6 +978,7 @@ class CloudFoundryDeployTest extends BasePiperTest {
space: 'testSpace',
manifest: 'test.yml',
],
deployTool: 'cf_native',
cfCredentialsId: 'test_cfCredentialsId',
verbose: true
])
@ -1006,6 +1006,7 @@ class CloudFoundryDeployTest extends BasePiperTest {
space: 'testSpace',
manifest: 'test.yml',
],
deployTool: 'cf_native',
cfCredentialsId: 'test_cfCredentialsId',
verbose: true
])
@ -1149,6 +1150,7 @@ class CloudFoundryDeployTest extends BasePiperTest {
space: 'irrelevant',
appName: 'myValidAppName123'
],
deployTool: 'cf_native',
cfCredentialsId: 'test_cfCredentialsId',
mtaPath: 'irrelevant'
])
@ -1167,6 +1169,7 @@ class CloudFoundryDeployTest extends BasePiperTest {
space: 'irrelevant',
appName: 'my-Valid-AppName123'
],
deployTool: 'cf_native',
cfCredentialsId: 'test_cfCredentialsId',
mtaPath: 'irrelevant'
])
@ -1176,7 +1179,9 @@ class CloudFoundryDeployTest extends BasePiperTest {
@Test
void testMtaExtensionDescriptor() {
fileExistsRule.existingFiles.addAll(
'globalMtaDescriptor.mtaext',
)
stepRule.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
@ -1198,6 +1203,9 @@ class CloudFoundryDeployTest extends BasePiperTest {
@Test
void testTargetMtaExtensionDescriptor() {
fileExistsRule.existingFiles.addAll(
'targetMtaDescriptor.mtaext',
)
stepRule.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
@ -1215,4 +1223,91 @@ class CloudFoundryDeployTest extends BasePiperTest {
])
assertThat(shellRule.shell, hasItem(containsString("-e targetMtaDescriptor.mtaext")))
}
@Test
void testMtaExtensionCredentials() {
fileExistsRule.existingFiles.addAll(
'mtaext.mtaext',
)
credentialsRule.withCredentials("mtaExtCredTest","token")
helper.registerAllowedMethod('readFile', [String], {file ->
if (file == 'mtaext.mtaext') {
return '_schema-version: \'3.1\'\n' +
'ID: test.ext\n' +
'extends: test\n' +
'\n' +
'parameters:\n' +
' test-credentials: "<%= testCred %>"'
}
return ''
})
stepRule.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
jenkinsUtilsStub: new JenkinsUtilsMock(),
cfOrg: 'testOrg',
cfSpace: 'testSpace',
cfCredentialsId: 'test_cfCredentialsId',
deployTool: 'mtaDeployPlugin',
mtaPath: 'target/test.mtar',
mtaExtensionDescriptor: "mtaext.mtaext",
mtaExtensionCredentials: [
testCred: 'mtaExtCredTest'
]
])
assertThat(shellRule.shell, hasItem(containsString('cp mtaext.mtaext mtaext.mtaext.original')))
assertThat(shellRule.shell, hasItem(containsString('mv --force mtaext.mtaext.original mtaext.mtaext')))
assertThat(writeFileRule.files['mtaext.mtaext'], is('_schema-version: \'3.1\'\n' +
'ID: test.ext\n' +
'extends: test\n' +
'\n' +
'parameters:\n' +
' test-credentials: "token"'))
}
@Test
void testMtaExtensionDescriptorNotFound() {
thrown.expect(hudson.AbortException)
thrown.expectMessage('[cloudFoundryDeploy] The mta extension descriptor file mtaext.mtaext does not exist at the configured location.')
stepRule.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
jenkinsUtilsStub: new JenkinsUtilsMock(),
cfOrg: 'testOrg',
cfSpace: 'testSpace',
cfCredentialsId: 'test_cfCredentialsId',
deployTool: 'mtaDeployPlugin',
mtaPath: 'target/test.mtar',
mtaExtensionDescriptor: "mtaext.mtaext"
])
}
@Test
void testMtaExtensionDescriptorReadFails() {
fileExistsRule.existingFiles.addAll(
'mtaext.mtaext',
)
thrown.expect(Exception)
thrown.expectMessage('[cloudFoundryDeploy] Unable to read mta extension file mtaext.mtaext.')
stepRule.step.cloudFoundryDeploy([
script: nullScript,
juStabUtils: utils,
jenkinsUtilsStub: new JenkinsUtilsMock(),
cfOrg: 'testOrg',
cfSpace: 'testSpace',
cfCredentialsId: 'test_cfCredentialsId',
deployTool: 'mtaDeployPlugin',
mtaPath: 'target/test.mtar',
mtaExtensionDescriptor: "mtaext.mtaext",
mtaExtensionCredentials: [
testCred: 'mtaExtCredTest'
],
])
}
}

View File

@ -207,7 +207,6 @@ class MulticloudDeployTest extends BasePiperTest {
assert cloudFoundryDeployRule.hasParameter('deployType', 'standard')
assert cloudFoundryDeployRule.hasParameter('cloudFoundry', cloudFoundry)
assert cloudFoundryDeployRule.hasParameter('mtaPath', nullScript.commonPipelineEnvironment.mtarFilePath)
assert cloudFoundryDeployRule.hasParameter('deployTool', 'cf_native')
}
@Test
@ -225,7 +224,6 @@ class MulticloudDeployTest extends BasePiperTest {
assert cloudFoundryDeployRule.hasParameter('deployType', 'blue-green')
assert cloudFoundryDeployRule.hasParameter('cloudFoundry', cloudFoundry1)
assert cloudFoundryDeployRule.hasParameter('mtaPath', nullScript.commonPipelineEnvironment.mtarFilePath)
assert cloudFoundryDeployRule.hasParameter('deployTool', 'cf_native')
}
@Test
@ -247,7 +245,6 @@ class MulticloudDeployTest extends BasePiperTest {
assert cloudFoundryDeployRule.hasParameter('deployType', 'blue-green')
assert cloudFoundryDeployRule.hasParameter('cloudFoundry', cloudFoundry1)
assert cloudFoundryDeployRule.hasParameter('mtaPath', nullScript.commonPipelineEnvironment.mtarFilePath)
assert cloudFoundryDeployRule.hasParameter('deployTool', 'cf_native')
assert cloudFoundryDeployRule.hasParameter('cloudFoundry', cloudFoundry2)
}
@ -271,7 +268,6 @@ class MulticloudDeployTest extends BasePiperTest {
assert cloudFoundryDeployRule.hasParameter('deployType', 'blue-green')
assert cloudFoundryDeployRule.hasParameter('cloudFoundry', cloudFoundry1)
assert cloudFoundryDeployRule.hasParameter('mtaPath', nullScript.commonPipelineEnvironment.mtarFilePath)
assert cloudFoundryDeployRule.hasParameter('deployTool', 'cf_native')
assert cloudFoundryDeployRule.hasParameter('cloudFoundry', cloudFoundry2)
}
@ -372,19 +368,4 @@ class MulticloudDeployTest extends BasePiperTest {
assertFalse(executedOnKubernetes)
}
@Test
void multicloudParallelCfStandardDeployTest() {
stepRule.step.multicloudDeploy([
script : nullScript,
enableZeroDowntimeDeployment: false,
parallelExecution : true,
source : 'file.mtar'
])
assertTrue(executedInParallel)
assertFalse(executedOnNode)
assertFalse(executedOnKubernetes)
}
}

View File

@ -11,6 +11,7 @@ import static com.sap.piper.Prerequisites.checkScript
@Field String STEP_NAME = getClass().getName()
@Field Set GENERAL_CONFIG_KEYS = [
'buildTool',
'cloudFoundry',
/**
* Cloud Foundry API endpoint.
@ -73,6 +74,7 @@ import static com.sap.piper.Prerequisites.checkScript
'space',
/**
* Defines the tool which should be used for deployment.
* If it is not set it will be inferred automatically based on the buildTool, i.e., for MTA projects `mtaDeployPlugin` will be used and `cf_native` for other types of projects.
* @possibleValues 'cf_native', 'mtaDeployPlugin'
*/
'deployTool',
@ -112,6 +114,11 @@ import static com.sap.piper.Prerequisites.checkScript
* Additional parameters passed to mta deployment command.
*/
'mtaDeployParameters',
/**
* Defines a map of credentials that need to be replaced in the `mtaExtensionDescriptor`.
* This map needs to be created as `value-to-be-replaced`:`id-of-a-credential-in-jenkins`
*/
'mtaExtensionCredentials',
/**
* Defines additional extension descriptor file for deployment with the mtaDeployPlugin.
*/
@ -206,6 +213,8 @@ void call(Map parameters = [:]) {
.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)
.addIfEmpty('buildTool', script.commonPipelineEnvironment.getBuildTool())
.dependingOn('buildTool').mixin('deployTool')
.dependingOn('deployTool').mixin('dockerImage')
.dependingOn('deployTool').mixin('dockerWorkspace')
.withMandatoryProperty('cloudFoundry/org')
@ -306,8 +315,19 @@ def findMtar(){
}
def deployMta(config) {
if (config.mtaExtensionDescriptor == null) config.mtaExtensionDescriptor = ''
if (!config.mtaExtensionDescriptor.isEmpty() && !config.mtaExtensionDescriptor.startsWith('-e ')) config.mtaExtensionDescriptor = "-e ${config.mtaExtensionDescriptor}"
String mtaExtensionDescriptorParam = ''
if (config.mtaExtensionDescriptor) {
if (!fileExists(config.mtaExtensionDescriptor)) {
error "[${STEP_NAME}] The mta extension descriptor file ${config.mtaExtensionDescriptor} does not exist at the configured location."
}
mtaExtensionDescriptorParam = "-e ${config.mtaExtensionDescriptor}"
if (config.mtaExtensionCredentials) {
handleMtaExtensionCredentials(config)
}
}
def deployCommand = 'deploy'
if (config.deployType == 'blue-green') {
@ -317,11 +337,40 @@ def deployMta(config) {
}
}
def deployStatement = "cf ${deployCommand} ${config.mtaPath} ${config.mtaDeployParameters} ${config.mtaExtensionDescriptor}"
def deployStatement = "cf ${deployCommand} ${config.mtaPath} ${config.mtaDeployParameters} ${mtaExtensionDescriptorParam}"
def apiStatement = "cf api ${config.cloudFoundry.apiEndpoint} ${config.apiParameters}"
echo "[${STEP_NAME}] Deploying MTA (${config.mtaPath}) with following parameters: ${config.mtaExtensionDescriptor} ${config.mtaDeployParameters}"
deploy(apiStatement, deployStatement, config, null)
echo "[${STEP_NAME}] Deploying MTA (${config.mtaPath}) with following parameters: ${mtaExtensionDescriptorParam} ${config.mtaDeployParameters}"
try {
deploy(apiStatement, deployStatement, config, null)
} finally {
if (config.mtaExtensionCredentials && config.mtaExtensionDescriptor && fileExists(config.mtaExtensionDescriptor)) {
sh "mv --force ${config.mtaExtensionDescriptor}.original ${config.mtaExtensionDescriptor} || echo 'The file ${config.mtaExtensionDescriptor}.original could not be renamed.'"
}
}
}
private void handleMtaExtensionCredentials(Map<?, ?> config) {
echo "[${STEP_NAME}] Modifying ${config.mtaExtensionDescriptor}. Adding credential values from Jenkins."
sh "cp ${config.mtaExtensionDescriptor} ${config.mtaExtensionDescriptor}.original"
Map mtaExtensionCredentials = config.mtaExtensionCredentials
String fileContent = ''
try {
fileContent = readFile config.mtaExtensionDescriptor
} catch (Exception e) {
error("[${STEP_NAME}] Unable to read mta extension file ${config.mtaExtensionDescriptor}. (${e.getMessage()})")
}
mtaExtensionCredentials.each { key, credentialsId ->
withCredentials([string(credentialsId: credentialsId, variable: 'mtaExtensionCredential')]) {
fileContent = fileContent.replace('<%= ' + key.toString() + ' %>', mtaExtensionCredential.toString())
}
}
writeFile file: config.mtaExtensionDescriptor, text: fileContent
}
private checkAndUpdateDeployTypeForNotSupportedManifest(Map config){

View File

@ -99,11 +99,12 @@ void call(parameters = [:]) {
if (config.cfTargets) {
def deploymentType = DeploymentType.selectFor(CloudPlatform.CLOUD_FOUNDRY, config.enableZeroDowntimeDeployment).toString()
def deployTool = script.commonPipelineEnvironment.configuration.isMta ? 'mtaDeployPlugin' : 'cf_native'
// An isolated workspace is only required when using blue-green deployment with multiple cfTargets,
// An isolated workspace is required when using blue-green deployment with multiple cfTargets,
// since the cloudFoundryDeploy step might edit the manifest.yml file in that case.
Boolean runInIsolatedWorkspace = config.cfTargets.size() > 1 && deploymentType == "blue-green"
// It is also required in case of parallel execution and use of mtaExtensionCredentials, since the
// credentials are inserted in the mtaExtensionDescriptor file.
Boolean runInIsolatedWorkspace = config.cfTargets.size() > 1 && (deploymentType == "blue-green" || config.parallelExecution)
for (int i = 0; i < config.cfTargets.size(); i++) {
@ -121,8 +122,9 @@ void call(parameters = [:]) {
jenkinsUtilsStub: jenkinsUtils,
deployType: deploymentType,
cloudFoundry: target,
mtaExtensionDescriptor: target.mtaExtensionDescriptor,
mtaExtensionCredentials: target.mtaExtensionCredentials,
mtaPath: script.commonPipelineEnvironment.mtarFilePath,
deployTool: deployTool
)
if (runInIsolatedWorkspace) {
deploymentUtils.stashStageFiles(script, stageName)