diff --git a/documentation/docs/steps/cloudFoundryDeploy.md b/documentation/docs/steps/cloudFoundryDeploy.md index 1a80cd61e..aea6e46a8 100644 --- a/documentation/docs/steps/cloudFoundryDeploy.md +++ b/documentation/docs/steps/cloudFoundryDeploy.md @@ -1,18 +1,6 @@ -# cloudFoundryDeploy +# ${docGenStepName} -## Description - -The application will be deployed to a test or production space within Cloud Foundry. -Deployment can be done - -* in a standard way -* in a zero downtime manner (using a [blue-green deployment approach](https://martinfowler.com/bliki/BlueGreenDeployment.html)) - -!!! note "Deployment supports multiple deployment tools" - Currently the following are supported: - - * Standard `cf push` and [Bluemix blue-green plugin](https://github.com/bluemixgaragelondon/cf-blue-green-deploy#how-to-use) - * [MTA CF CLI Plugin](https://github.com/cloudfoundry-incubator/multiapps-cli-plugin) +## ${docGenDescription} ## Prerequisites @@ -21,90 +9,9 @@ Deployment can be done ![Jenkins credentials configuration](../images/cf_credentials.png) -## Parameters +## ${docGenParameters} -| parameter | mandatory | default | possible values | -| ----------|-----------|---------|-----------------| -| script | yes | | | -| cloudFoundry | yes | | | -| deployTool | no | cf_native | cf_native, mtaDeployPlugin | -| deployType | no | standard | standard, blue-green | -| keepOldInstance | no | false | true, false | -| dockerImage | no | s4sdk/docker-cf-cli | | -| dockerWorkspace | no | /home/piper | | -| mtaDeployParameters | | for _deployType:standard_ `-f`
for _deployType:blue-green_ `-f --no-confirm` | | -| mtaExtensionDescriptor | no | '' | | -| mtaPath | no | '' | | -| smokeTestScript | no | blueGreenCheckScript.sh (provided by library).
Can be overwritten using config property 'smokeTestScript' | | -| smokeTestStatusCode | no | 200 | | -| stashContent | no | [] | | - -* `script` defines the global script environment of the Jenkinsfile run. Typically `this` is passed to this parameter. This allows the function to access the [`commonPipelineEnvironment`](commonPipelineEnvironment.md) for retrieving e.g. configuration parameters. -* `cloudFoundry` defines a map containing following properties: - * `apiEndpoint`: Cloud Foundry API endpoint (default: `https://api.cf.eu10.hana.ondemand.com`) - * `appName`: App name of application to be deployed (optional) - * `credentialsId`: Credentials to be used for deployment (mandatory) - * `manifest`: Manifest to be used for deployment - * `org`: Cloud Foundry target organization (mandatory) - * `space`: Cloud Foundry target space (mandatory) - - Example: `cloudFoundry: [apiEndpoint: 'https://test.server.com', appName:'cfAppName', credentialsId: 'cfCredentialsId', manifest: 'cfManifest', org: 'cfOrg', space: 'cfSpace']` - -!!! note - It is also possible to use following configuration parameters instead of `cloudFoundry` map: - - - cfApiEndpoint - - cfAppName - - cfCredentialsId - - cfManifest - - cfOrg - - cfSpace - -!!! note - Due to [an incompatible change](https://github.com/cloudfoundry/cli/issues/1445) in the Cloud Foundry CLI, multiple buildpacks are not supported by this step. - If your `application` contains a list of `buildpacks` instead a single `buildpack`, this will be automatically re-written by the step when blue-green deployment is used. - -* `deployTool` defines the tool which should be used for deployment. -* `deployType` defines the type of deployment, either `standard` deployment which results in a system downtime or a zero-downtime `blue-green` deployment. -* `keepOldInstance` in case of a `blue-green` deployment the old instance will be deleted by default. If this option is set to true the old instance will remain stopped in the Cloud Foundry space. -* `dockerImage` defines the Docker image containing the deployment tools (like cf cli, ...) and `dockerWorkspace` defines the home directory of the default user of the `dockerImage` -* `smokeTestScript` allows to specify a script which performs a check during blue-green deployment. The script gets the FQDN as parameter and returns `exit code 0` in case check returned `smokeTestStatusCode`. More details can be found [here](https://github.com/bluemixgaragelondon/cf-blue-green-deploy#how-to-use)
Currently this option is only considered for deployTool `cf_native`. -* `stashContent` defines the stash names which should be unstashed at the beginning of the step. This makes the files available in case the step is started on an empty node. - -### Deployment with cf_native - -* `appName` in `cloudFoundry` map (or `cfAppName`) defines the name of the application which will be deployed to the Cloud Foundry space. -* `manifest` in `cloudFoundry` maps (or `cfManifest`) defines the manifest to be used for Cloud Foundry deployment. - -!!! note - Cloud Foundry supports the deployment of multiple applications using a single manifest file. - This option is supported with Piper. - - In this case define `appName: ''` since the app name for the individual applications have to be defined via the manifest. - You can find details in the [Cloud Foundry Documentation](https://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html#multi-apps) - -### Deployment with mtaDeployPlugin - -* `mtaPath` define path to *.mtar for deployment. -* `mtaExtensionDescriptor` defines additional extension descriptor file for deployment. -* `mtaDeployParameters` defines additional parameters passed to mta deployment. - -## Step configuration - -The following parameters can also be specified as step/stage/general parameters using the [global configuration](../configuration.md): - -* cloudFoundry -* deployUser -* deployTool -* deployType -* dockerImage -* dockerWorkspace -* mtaDeployParameters -* mtaExtensionDescriptor -* mtaPath -* smokeTestScript -* smokeTestStatusCode -* stashContent +## ${docGenConfiguration} ## Example diff --git a/test/groovy/CloudFoundryDeployTest.groovy b/test/groovy/CloudFoundryDeployTest.groovy index beadba16b..deb56fcce 100644 --- a/test/groovy/CloudFoundryDeployTest.groovy +++ b/test/groovy/CloudFoundryDeployTest.groovy @@ -96,7 +96,7 @@ class CloudFoundryDeployTest extends BasePiperTest { 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, deployUser=testUser')) + assertThat(loggingRule.log, containsString('[cloudFoundryDeploy] General parameters: deployTool=, deployType=standard, cfApiEndpoint=https://api.cf.eu10.hana.ondemand.com, cfOrg=testOrg, cfSpace=testSpace, cfCredentialsId=myCreds')) } @Test @@ -125,7 +125,7 @@ class CloudFoundryDeployTest extends BasePiperTest { stageName: 'acceptance' ]) // asserts - assertThat(loggingRule.log, containsString('[cloudFoundryDeploy] General parameters: deployTool=notAvailable, deployType=standard, cfApiEndpoint=https://api.cf.eu10.hana.ondemand.com, cfOrg=testOrg, cfSpace=testSpace, cfCredentialsId=myCreds, deployUser=testUser')) + assertThat(loggingRule.log, containsString('[cloudFoundryDeploy] General parameters: deployTool=notAvailable, deployType=standard, cfApiEndpoint=https://api.cf.eu10.hana.ondemand.com, cfOrg=testOrg, cfSpace=testSpace, cfCredentialsId=myCreds')) } @Test diff --git a/test/groovy/NeoDeployTest.groovy b/test/groovy/NeoDeployTest.groovy index e25279735..6a0377bf6 100644 --- a/test/groovy/NeoDeployTest.groovy +++ b/test/groovy/NeoDeployTest.groovy @@ -6,6 +6,8 @@ import static org.hamcrest.Matchers.containsString import static org.hamcrest.Matchers.not import org.hamcrest.Matchers +import org.hamcrest.BaseMatcher +import org.hamcrest.Description import org.jenkinsci.plugins.credentialsbinding.impl.CredentialNotFoundException import org.junit.Assert import org.junit.Before @@ -460,4 +462,57 @@ class NeoDeployTest extends BasePiperTest { size: 'lite' ]) } + + @Test + void dontSwallowExceptionWhenUnableToProvideLogsTest() { + + thrown.expect(AbortException) + thrown.expectMessage('Something went wrong during neo deployment') + thrown.expect(new BaseMatcher() { + + def expectedException = AbortException + def expectedText = 'Cannot provide logs.' + + boolean matches(def ex) { + def suppressed = ex.getSuppressed() + return (suppressed.size() == 1 && + suppressed[0] in expectedException && + suppressed[0].message == expectedText) + + } + + void describeTo(Description d) { + d.appendText(" a suppressed ${expectedException} with message ${expectedText}.") + } + }) + + loggingRule.expect('Unable to provide the logs.') + + helper.registerAllowedMethod('fileExists', [String], + { f -> + f == 'archive.mtar' + } + ) + helper.registerAllowedMethod('sh', [Map], + { m -> + if(m.script.toString().contains('neo.sh deploy-mta')) + throw new AbortException('Something went wrong during neo deployment.') + } + ) + + helper.registerAllowedMethod("sh", [String], + { cmd -> + if (cmd == 'cat logs/neo/*') + throw new AbortException('Cannot provide logs.') + } + ) + + stepRule.step.neoDeploy(script: nullScript, + + source: archiveName, + neo:[credentialsId: 'myCredentialsId'], + deployMode: 'mta', + utils: utils, + ) + } } diff --git a/vars/cloudFoundryDeploy.groovy b/vars/cloudFoundryDeploy.groovy index 5128f6002..af5232fb5 100644 --- a/vars/cloudFoundryDeploy.groovy +++ b/vars/cloudFoundryDeploy.groovy @@ -2,6 +2,7 @@ import com.sap.piper.JenkinsUtils import static com.sap.piper.Prerequisites.checkScript +import com.sap.piper.GenerateDocumentation import com.sap.piper.Utils import com.sap.piper.ConfigurationHelper import com.sap.piper.CfManifestUtils @@ -14,22 +15,109 @@ import groovy.transform.Field @Field Set STEP_CONFIG_KEYS = [ 'cloudFoundry', - 'deployUser', + /** + * Cloud Foundry API endpoint. + * @parentConfigKey cloudFoundry + */ + 'apiEndpoint', + /** + * Defines the name of the application to be deployed to the Cloud Foundry space. + * @parentConfigKey cloudFoundry + */ + 'appName', + /** + * Credentials to be used for deployment. + * @parentConfigKey cloudFoundry + */ + 'credentialsId', + /** + * Defines the manifest to be used for deployment to Cloud Foundry. + * @parentConfigKey cloudFoundry + */ + 'manifest', + /** + * Cloud Foundry target organization. + * @parentConfigKey cloudFoundry + */ + 'org', + /** + * Cloud Foundry target space. + * @parentConfigKey cloudFoundry + */ + 'space', + /** + * Defines the tool which should be used for deployment. + * @possibleValues 'cf_native', 'mtaDeployPlugin' + */ 'deployTool', + /** + * Defines the type of deployment, either `standard` deployment which results in a system downtime or a zero-downtime `blue-green` deployment. + * @possibleValues 'standard', 'blue-green' + */ 'deployType', + /** + * In case of a `blue-green` deployment the old instance will be deleted by default. If this option is set to true the old instance will remain stopped in the Cloud Foundry space. + * @possibleValues true, false + */ 'keepOldInstance', + /** @see dockerExecute */ 'dockerImage', + /** @see dockerExecute */ 'dockerWorkspace', + /** @see dockerExecute */ + 'stashContent', + /** + * Defines additional parameters passed to mta for deployment with the mtaDeployPlugin. + */ 'mtaDeployParameters', + /** + * Defines additional extension descriptor file for deployment with the mtaDeployPlugin. + */ 'mtaExtensionDescriptor', + /** + * Defines the path to *.mtar for deployment with the mtaDeployPlugin. + */ 'mtaPath', + /** + * Allows to specify a script which performs a check during blue-green deployment. The script gets the FQDN as parameter and returns `exit code 0` in case check returned `smokeTestStatusCode`. + * More details can be found [here](https://github.com/bluemixgaragelondon/cf-blue-green-deploy#how-to-use)
Currently this option is only considered for deployTool `cf_native`. + */ 'smokeTestScript', - 'smokeTestStatusCode', - 'stashContent'] + /** + * Expected status code returned by the check. + */ + 'smokeTestStatusCode' +] + @Field Map CONFIG_KEY_COMPATIBILITY = [cloudFoundry: [apiEndpoint: 'cfApiEndpoint', appName:'cfAppName', credentialsId: 'cfCredentialsId', manifest: 'cfManifest', org: 'cfOrg', space: 'cfSpace']] @Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS +/** + * Deploys an application to a test or production space within Cloud Foundry. + * Deployment can be done + * + * * in a standard way + * * in a zero downtime manner (using a [blue-green deployment approach](https://martinfowler.com/bliki/BlueGreenDeployment.html)) + * + * !!! note "Deployment supports multiple deployment tools" + * Currently the following are supported: + * + * * Standard `cf push` and [Bluemix blue-green plugin](https://github.com/bluemixgaragelondon/cf-blue-green-deploy#how-to-use) + * * [MTA CF CLI Plugin](https://github.com/cloudfoundry-incubator/multiapps-cli-plugin) + * + * !!! note + * Due to [an incompatible change](https://github.com/cloudfoundry/cli/issues/1445) in the Cloud Foundry CLI, multiple buildpacks are not supported by this step. + * If your `application` contains a list of `buildpacks` instead a single `buildpack`, this will be automatically re-written by the step when blue-green deployment is used. + * + * !!! note + * Cloud Foundry supports the deployment of multiple applications using a single manifest file. + * This option is supported with Piper. + * + * In this case define `appName: ''` since the app name for the individual applications have to be defined via the manifest. + * You can find details in the [Cloud Foundry Documentation](https://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html#multi-apps) + */ +@GenerateDocumentation void call(Map parameters = [:]) { handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) { @@ -62,7 +150,7 @@ void call(Map parameters = [:]) { stepParam3: parameters?.script == null ], config) - echo "[${STEP_NAME}] General parameters: deployTool=${config.deployTool}, deployType=${config.deployType}, cfApiEndpoint=${config.cloudFoundry.apiEndpoint}, cfOrg=${config.cloudFoundry.org}, cfSpace=${config.cloudFoundry.space}, cfCredentialsId=${config.cloudFoundry.credentialsId}, deployUser=${config.deployUser}" + echo "[${STEP_NAME}] General parameters: deployTool=${config.deployTool}, deployType=${config.deployType}, cfApiEndpoint=${config.cloudFoundry.apiEndpoint}, cfOrg=${config.cloudFoundry.org}, cfSpace=${config.cloudFoundry.space}, cfCredentialsId=${config.cloudFoundry.credentialsId}" //make sure that all relevant descriptors, are available in workspace utils.unstashAll(config.stashContent) diff --git a/vars/neoDeploy.groovy b/vars/neoDeploy.groovy index c136fb6ab..a55ff837d 100644 --- a/vars/neoDeploy.groovy +++ b/vars/neoDeploy.groovy @@ -150,9 +150,15 @@ private deploy(script, utils, Map configuration, NeoCommandHelper neoCommandHelp } } catch (Exception ex) { + if (dockerImage) { echo "Error while deploying to SAP Cloud Platform. Here are the neo.sh logs:" - sh "cat logs/neo/*" + try { + sh "cat logs/neo/*" + } catch(Exception e) { + echo "Unable to provide the logs." + ex.addSuppressed(e) + } } throw ex }