You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-07-17 01:42:43 +02:00
Invalidate cache for neo deployments (#2209)
* Add additional parameters for invalidating cache * Fetch bearer token * Fetch x-csrf token * Add echo for testing * Add echo * Add another echo * Check status * Debug * Clean up * Throw exception * Code review changes * Review changes * Add test * Fix tests * Fetch bearer token * Fetch x-csrf token * Add echo for testing * Add echo * Add another echo * Check status * Debug * Resolve conflicts * Resolve conflicts * Code review changes * Review changes * fix conflicts * Fix indent * Add new parameter to define portal landscape region * Add default value for new param * Fix test * Remove example Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com> * Check cache invalidation for html5 apps * Add nesting Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com> * Add docu for invalidating cache for html5 apps (#2306) * Add docu for invalidating cache for html5 apps * Improve content * Docu review changes * Remove heading Co-authored-by: Sarah Lendle <44202907+SarahLendle@users.noreply.github.com> * Update documentation/docs/steps/neoDeploy.md Co-authored-by: Sarah Lendle <44202907+SarahLendle@users.noreply.github.com> Co-authored-by: Sarah Lendle <44202907+SarahLendle@users.noreply.github.com> Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com> Co-authored-by: Sarah Lendle <44202907+SarahLendle@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
e859ed3375
commit
0234e4908c
BIN
documentation/docs/images/oauthClientCreation.png
Normal file
BIN
documentation/docs/images/oauthClientCreation.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
documentation/docs/images/portalSiteSetToDefault.png
Normal file
BIN
documentation/docs/images/portalSiteSetToDefault.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
documentation/docs/images/portalSubscription.png
Normal file
BIN
documentation/docs/images/portalSubscription.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@ -54,3 +54,46 @@ steps:
|
|||||||
account: <myDeployAccount>
|
account: <myDeployAccount>
|
||||||
host: hana.example.org
|
host: hana.example.org
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Example for invalidating the cache
|
||||||
|
|
||||||
|
Set the parameter `invalidateCache` to `true` to clean up the cache of an SAP Fiori launchpad site by refreshing the content of HTML5 applications deployed in it.
|
||||||
|
|
||||||
|
**Note:** This section is only applicable for HTML5 applications accessed through an SAP Fiori launchpad site.
|
||||||
|
|
||||||
|
Setting this parameter to `true` requires additional configuration:
|
||||||
|
|
||||||
|
### Create an OAuth credential
|
||||||
|
|
||||||
|
1. In your subaccount, choose **OAuth**.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
2. In the **Subscription** field, select the portal landscape to which you would like to subscribe, for example, `portal/nwc` or `portal/sandbox`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
3. From the drop-down menu in the **Authorization Grant** field, choose **Client Credentials**.
|
||||||
|
|
||||||
|
4. In the **Secret** field, enter a user-defined password and save your changes.
|
||||||
|
|
||||||
|
5. In Jenkins, create new username/password credentials. As username, use the client ID and as password, use the client secret.
|
||||||
|
|
||||||
|
### Configure the site ID
|
||||||
|
|
||||||
|
When you're logged in to the portal service, you can retrieve the site ID. Either configure it in your configuration file or set the site as default through the **Site Directory** tile.
|
||||||
|
If you don't set it as default, configure the parameter `siteId` as follows in your configuration file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
<...>
|
||||||
|
neoDeploy:
|
||||||
|
neo:
|
||||||
|
account: <myDeployAccount>
|
||||||
|
host: hana.example.org
|
||||||
|
credentialsId: 'my-credentials-id'
|
||||||
|
invalidateCache: true
|
||||||
|
portalLandscape: "cloudnwcportal"
|
||||||
|
oauthCredentialId: <OAUTH_CREDENTIAL_ID>
|
||||||
|
siteId: <PORTAL_SITE_ID> # not required, if the default site is already set in the portal service (SAP Cloud Platform)
|
||||||
|
```
|
||||||
|
@ -333,6 +333,7 @@ steps:
|
|||||||
neo:
|
neo:
|
||||||
size: 'lite'
|
size: 'lite'
|
||||||
credentialsId: 'CI_CREDENTIALS_ID'
|
credentialsId: 'CI_CREDENTIALS_ID'
|
||||||
|
portalLandscape: "cloudnwcportal"
|
||||||
multicloudDeploy:
|
multicloudDeploy:
|
||||||
cfTargets: []
|
cfTargets: []
|
||||||
neoTargets: []
|
neoTargets: []
|
||||||
|
@ -3,9 +3,12 @@ import com.sap.piper.Utils
|
|||||||
|
|
||||||
import groovy.lang.Script
|
import groovy.lang.Script
|
||||||
import hudson.AbortException
|
import hudson.AbortException
|
||||||
|
import util.JenkinsReadJsonRule
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.allOf
|
import static org.hamcrest.Matchers.allOf
|
||||||
|
import static org.hamcrest.Matchers.contains
|
||||||
import static org.hamcrest.Matchers.containsString
|
import static org.hamcrest.Matchers.containsString
|
||||||
|
import static org.hamcrest.Matchers.hasItem
|
||||||
import static org.hamcrest.Matchers.not
|
import static org.hamcrest.Matchers.not
|
||||||
import static org.junit.Assert.assertThat
|
import static org.junit.Assert.assertThat
|
||||||
|
|
||||||
@ -52,7 +55,9 @@ class NeoDeployTest extends BasePiperTest {
|
|||||||
.around(shellRule)
|
.around(shellRule)
|
||||||
.around(new JenkinsCredentialsRule(this)
|
.around(new JenkinsCredentialsRule(this)
|
||||||
.withCredentials('myCredentialsId', 'anonymous', '********')
|
.withCredentials('myCredentialsId', 'anonymous', '********')
|
||||||
.withCredentials('CI_CREDENTIALS_ID', 'defaultUser', '********'))
|
.withCredentials('CI_CREDENTIALS_ID', 'defaultUser', '********')
|
||||||
|
.withCredentials('testOauthId', 'clientId', '********'))
|
||||||
|
.around(new JenkinsReadJsonRule(this))
|
||||||
.around(stepRule)
|
.around(stepRule)
|
||||||
.around(new JenkinsLockRule(this))
|
.around(new JenkinsLockRule(this))
|
||||||
.around(new JenkinsWithEnvRule(this))
|
.around(new JenkinsWithEnvRule(this))
|
||||||
@ -417,6 +422,43 @@ class NeoDeployTest extends BasePiperTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void invalidateCache_Success_Test() {
|
||||||
|
|
||||||
|
nullScript.commonPipelineEnvironment.configuration = [steps: [neoDeploy: [neo: [host: 'test.deploy.host.com', account: 'trialuser123', invalidateCache: true, oauthCredentialId: 'testOauthId', siteId: "12346"]]]]
|
||||||
|
fileExistsRule.registerExistingFile('./target/artifact.war')
|
||||||
|
|
||||||
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, "https:\\/\\/oauthasservices-trialuser123\\.test\\.deploy\\.host\\.com\\/oauth2\\/api\\/v1\\/token", "{\"access_token\":\"xxx\"}")
|
||||||
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, "fiori\\/api\\/v1\\/csrf", "X-CSRF-Token=xxx")
|
||||||
|
shellRule.setReturnValue(JenkinsShellCallRule.Type.REGEX, "fiori\\/v1\\/operations\\/invalidateCache", "{\"statusCode\":\"200\"}")
|
||||||
|
|
||||||
|
stepRule.step.neoDeploy(script: nullScript,
|
||||||
|
source: archiveName,
|
||||||
|
deployMode: 'mta')
|
||||||
|
|
||||||
|
Assert.assertThat(shellRule.shell, hasItem(containsString("curl -X POST -u \"clientId:********\" --fail \"https://oauthasservices-trialuser123.test.deploy.host.com/oauth2/api/v1/token?grant_type=client_credentials&scope=write,read")))
|
||||||
|
Assert.assertThat(shellRule.shell[3], containsString("#!/bin/bash curl -i -L -c 'cookies.jar' -H 'X-CSRF-Token: Fetch' -H \"Authorization: Bearer xxx\" --fail \"https://cloudnwcportal-trialuser123.test.deploy.host.com/fiori/api/v1/csrf\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void invalidateCache_notPerformed_warFiles() {
|
||||||
|
|
||||||
|
nullScript.commonPipelineEnvironment.configuration = [steps: [neoDeploy: [neo: [host: 'test.deploy.host.com', account: 'trialuser123', invalidateCache: true]]]]
|
||||||
|
|
||||||
|
stepRule.step.neoDeploy(script: nullScript,
|
||||||
|
neo: [
|
||||||
|
application: 'testApp',
|
||||||
|
runtime: 'neo-javaee6-wp',
|
||||||
|
runtimeVersion: '2.125',
|
||||||
|
size: 'lite',
|
||||||
|
],
|
||||||
|
deployMode: 'warParams',
|
||||||
|
warAction: 'deploy',
|
||||||
|
source: warArchiveName)
|
||||||
|
|
||||||
|
assertThat(loggingRule.log, containsString("Invalidation of cache is ignored. It is performed only for html5 applications."))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void warFileParamsDeployModeTest() {
|
void warFileParamsDeployModeTest() {
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ import static com.sap.piper.Prerequisites.checkScript
|
|||||||
* @mandatory for deployMode=warParams
|
* @mandatory for deployMode=warParams
|
||||||
*/
|
*/
|
||||||
'host',
|
'host',
|
||||||
/**
|
/**
|
||||||
* The path to the .properties file in which all necessary deployment properties for the application are defined.
|
* The path to the .properties file in which all necessary deployment properties for the application are defined.
|
||||||
* @parentConfigKey neo
|
* @parentConfigKey neo
|
||||||
* @mandatory for deployMode=warPropertiesFile
|
* @mandatory for deployMode=warPropertiesFile
|
||||||
@ -59,16 +59,37 @@ import static com.sap.piper.Prerequisites.checkScript
|
|||||||
* @mandatory for deployMode=warParams
|
* @mandatory for deployMode=warParams
|
||||||
*/
|
*/
|
||||||
'runtimeVersion',
|
'runtimeVersion',
|
||||||
/**
|
/**
|
||||||
* Compute unit (VM) size. Acceptable values: lite, pro, prem, prem-plus.
|
* Compute unit (VM) size. Acceptable values: lite, pro, prem, prem-plus.
|
||||||
* @parentConfigKey neo
|
* @parentConfigKey neo
|
||||||
*/
|
*/
|
||||||
'size',
|
'size',
|
||||||
/**
|
/**
|
||||||
* String of VM arguments passed to the JVM.
|
* String of VM arguments passed to the JVM.
|
||||||
* @parentConfigKey neo
|
* @parentConfigKey neo
|
||||||
*/
|
*/
|
||||||
'vmArguments'
|
'vmArguments',
|
||||||
|
/**
|
||||||
|
* Boolean to enable/disable invalidating the cache after deployment.
|
||||||
|
* @possibleValues `true`, `false`
|
||||||
|
* @parentConfigKey neo
|
||||||
|
*/
|
||||||
|
'invalidateCache',
|
||||||
|
/**
|
||||||
|
* Portal landscape region subscribed to in SAP Cloud Platform.
|
||||||
|
* @parentConfigKey neo
|
||||||
|
*/
|
||||||
|
'portalLandscape',
|
||||||
|
/**
|
||||||
|
* UsernamePassword type credential containing SAP Cloud Platform OAuth client ID and client secret.
|
||||||
|
* @parentConfigKey neo
|
||||||
|
*/
|
||||||
|
'oauthCredentialId',
|
||||||
|
/**
|
||||||
|
* Site ID of the SAP Fiori Launchpad containing the SAP Fiori app. If not set, the cache of the default site, as defined in the Portal service, is invalidated.
|
||||||
|
* @parentConfigKey neo
|
||||||
|
*/
|
||||||
|
'siteId'
|
||||||
]
|
]
|
||||||
|
|
||||||
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
|
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS.plus([
|
||||||
@ -216,11 +237,84 @@ void call(parameters = [:]) {
|
|||||||
lock("$STEP_NAME:${neoCommandHelper.resourceLock()}") {
|
lock("$STEP_NAME:${neoCommandHelper.resourceLock()}") {
|
||||||
deploy(script, configuration, neoCommandHelper, configuration.dockerImage, deployMode)
|
deploy(script, configuration, neoCommandHelper, configuration.dockerImage, deployMode)
|
||||||
}
|
}
|
||||||
|
if(configuration.neo.invalidateCache == true) {
|
||||||
|
if (configuration.deployMode == 'mta') {
|
||||||
|
echo "Triggering invalidation of cache for html5 applications"
|
||||||
|
invalidateCache(configuration)
|
||||||
|
} else {
|
||||||
|
echo "Invalidation of cache is ignored. It is performed only for html5 applications."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private invalidateCache(configuration){
|
||||||
|
def account = configuration.neo.account
|
||||||
|
def host = configuration.neo.host
|
||||||
|
def portalLandscape = configuration.neo.portalLandscape
|
||||||
|
|
||||||
|
withCredentials([usernamePassword(
|
||||||
|
credentialsId: configuration.neo.oauthCredentialId,
|
||||||
|
passwordVariable: 'OAUTH_NEO_CLIENT_SECRET',
|
||||||
|
usernameVariable: 'OAUTH_NEO_CLIENT_ID')]) {
|
||||||
|
def bearerTokenResponse = sh(
|
||||||
|
script: """#!/bin/bash
|
||||||
|
curl -X POST -u "${OAUTH_NEO_CLIENT_ID}:${OAUTH_NEO_CLIENT_SECRET}" \
|
||||||
|
--fail \
|
||||||
|
"https://oauthasservices-${account}.${host}/oauth2/api/v1/token?grant_type=client_credentials&scope=write,read"
|
||||||
|
""",
|
||||||
|
returnStdout: true)
|
||||||
|
def bearerToken = readJSON(text: bearerTokenResponse).access_token
|
||||||
|
|
||||||
|
echo "Retrieved bearer token."
|
||||||
|
|
||||||
|
def fetchXcsrfTokenResponse = sh(
|
||||||
|
script: """#!/bin/bash
|
||||||
|
curl -i -L \
|
||||||
|
-c 'cookies.jar' \
|
||||||
|
-H 'X-CSRF-Token: Fetch' \
|
||||||
|
-H "Authorization: Bearer ${bearerToken}" \
|
||||||
|
--fail \
|
||||||
|
"https://${portalLandscape}-${account}.${host}/fiori/api/v1/csrf"
|
||||||
|
""",
|
||||||
|
returnStdout: true)
|
||||||
|
|
||||||
|
def xcsrfToken = readProperties(text: fetchXcsrfTokenResponse)["X-CSRF-Token"]
|
||||||
|
def siteId = configuration.neo.siteId ?: ""
|
||||||
|
|
||||||
|
if(! siteId){
|
||||||
|
echo "Using the default site defined in Portal service and invalidating the cache."
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
echo "Invalidating the cache for site with Id: ${siteId}."
|
||||||
|
}
|
||||||
|
def statusCode = sh(
|
||||||
|
script: """#!/bin/bash
|
||||||
|
curl -X POST -L \
|
||||||
|
-b 'cookies.jar' \
|
||||||
|
-H "X-CSRF-Token: ${xcsrfToken}" \
|
||||||
|
-H "Authorization: Bearer ${bearerToken}" \
|
||||||
|
-d "{\"siteId\":${siteId}}" \
|
||||||
|
-so /dev/null \
|
||||||
|
-w '%{response_code}' \
|
||||||
|
"https://${portalLandscape}-${account}.${host}/fiori/v1/operations/invalidateCache"
|
||||||
|
""",
|
||||||
|
returnStdout: true).trim()
|
||||||
|
|
||||||
|
if(! siteId && statusCode == "500") {
|
||||||
|
error "Invalidating the cache failed. " +
|
||||||
|
"As no siteId is set, the default site defined in the portal UI is used. " +
|
||||||
|
"Please verify a default site is defined in Portal service. " +
|
||||||
|
"Alternatively, configure the siteId parameter for this step to invalidate the cache of that specific site."
|
||||||
|
} else if(! statusCode == "200" || ! statusCode == "201" ){
|
||||||
|
error "Invalidating the cache failed with response code: ${statusCode}."
|
||||||
|
}
|
||||||
|
echo "Successfully invalidated the cache."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private deploy(script, Map configuration, NeoCommandHelper neoCommandHelper, dockerImage, DeployMode deployMode) {
|
private deploy(script, Map configuration, NeoCommandHelper neoCommandHelper, dockerImage, DeployMode deployMode) {
|
||||||
|
|
||||||
String logFolder = "logs/neo/${UUID.randomUUID()}"
|
String logFolder = "logs/neo/${UUID.randomUUID()}"
|
||||||
|
Reference in New Issue
Block a user