mirror of
https://github.com/SAP/jenkins-library.git
synced 2026-06-19 22:58:55 +02:00
add step healthExecuteCheck (#339)
This step allows to perform a basic health check on an installed application. It verifies that your app has a simple health endpoint available and that there is no error when calling it.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# healthExecuteCheck
|
||||
|
||||
## Description
|
||||
Calls the health endpoint url of the application.
|
||||
|
||||
The intention of the check is to verify that a suitable health endpoint is available. Such a health endpoint is required for operation purposes.
|
||||
|
||||
This check is used as a real-life test for your productive health endpoints.
|
||||
|
||||
!!! note "Check Depth"
|
||||
Typically, tools performing simple health checks are not too smart. Therefore it is important to choose an endpoint for checking wisely.
|
||||
|
||||
This check therefore only checks if the application/service url returns `HTTP 200`.
|
||||
|
||||
This is in line with health check capabilities of platforms which are used for example in load balancing scenarios. Here you can find an [example for Amazon AWS](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-healthchecks.html).
|
||||
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Endpoint for health check is configured.
|
||||
|
||||
!!! warning
|
||||
The health endpoint needs to be available without authentication!
|
||||
|
||||
!!! tip
|
||||
If using Spring Boot framework, ideally the provided `/health` endpoint is used and extended by development. Further information can be found in the [Spring Boot documenation for Endpoints](http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html)
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
Pipeline step:
|
||||
|
||||
```groovy
|
||||
healthExecuteCheck testServerUrl: 'https://testserver.com'
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| parameter | mandatory | default | possible values |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script|yes|||
|
||||
|healthEndpoint|no|``||
|
||||
|testServerUrl|no|||
|
||||
|
||||
|
||||
Details:
|
||||
* `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 storing the measured duration.
|
||||
* Health check function is called providing full qualified `testServerUrl` (and optionally with `healthEndpoint` if endpoint is not the standard url) to the health check.
|
||||
* In case response of the call is different than `HTTP 200 OK` the **health check fails and the pipeline stops**.
|
||||
|
||||
## Step configuration
|
||||
|
||||
We recommend to define values of step parameters via [config.yml file](../configuration.md).
|
||||
|
||||
In following sections the configuration is possible:
|
||||
|
||||
| parameter | general | step | stage |
|
||||
| ----------|-----------|---------|-----------------|
|
||||
|script||||
|
||||
|healthEndpoint|X|X|X|
|
||||
|testServerUrl|X|X|X|
|
||||
@@ -12,6 +12,7 @@ nav:
|
||||
- dockerExecuteOnKubernetes: steps/dockerExecuteOnKubernetes.md
|
||||
- durationMeasure: steps/durationMeasure.md
|
||||
- handlePipelineStepErrors: steps/handlePipelineStepErrors.md
|
||||
- healthExecuteCheck: steps/healthExecuteCheck.md
|
||||
- influxWriteData: steps/influxWriteData.md
|
||||
- mavenExecute: steps/mavenExecute.md
|
||||
- mtaBuild: steps/mtaBuild.md
|
||||
|
||||
@@ -139,6 +139,8 @@ steps:
|
||||
workspace: '**/*.*'
|
||||
stashExcludes:
|
||||
workspace: 'nohup.out'
|
||||
healthExecuteCheck:
|
||||
healthEndpoint: ''
|
||||
influxWriteData:
|
||||
influxServer: 'jenkins'
|
||||
mavenExecute:
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#!groovy
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.BasePiperTest
|
||||
import util.JenkinsLoggingRule
|
||||
import util.JenkinsReadYamlRule
|
||||
import util.JenkinsStepRule
|
||||
import util.Rules
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class HealthExecuteCheckTest extends BasePiperTest {
|
||||
private JenkinsStepRule jsr = new JenkinsStepRule(this)
|
||||
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
|
||||
private ExpectedException thrown = ExpectedException.none()
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(jlr)
|
||||
.around(jsr)
|
||||
.around(thrown)
|
||||
|
||||
|
||||
@Before
|
||||
void init() throws Exception {
|
||||
// register Jenkins commands with mock values
|
||||
def command1 = "curl -so /dev/null -w '%{response_code}' http://testserver"
|
||||
def command2 = "curl -so /dev/null -w '%{response_code}' http://testserver/endpoint"
|
||||
helper.registerAllowedMethod('sh', [Map.class], {map ->
|
||||
return map.script == command1 || map.script == command2 ? "200" : "404"
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHealthCheckOk() throws Exception {
|
||||
def testUrl = 'http://testserver/endpoint'
|
||||
|
||||
jsr.step.healthExecuteCheck(
|
||||
script: nullScript,
|
||||
testServerUrl: testUrl
|
||||
)
|
||||
|
||||
assertThat(jlr.log, containsString("Health check for ${testUrl} successful"))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHealthCheck404() throws Exception {
|
||||
def testUrl = 'http://testserver/404'
|
||||
|
||||
thrown.expect(Exception)
|
||||
thrown.expectMessage('Health check failed: 404')
|
||||
|
||||
jsr.step.healthExecuteCheck(
|
||||
script: nullScript,
|
||||
testServerUrl: testUrl
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testHealthCheckWithEndPoint() throws Exception {
|
||||
jsr.step.healthExecuteCheck(
|
||||
script: nullScript,
|
||||
testServerUrl: 'http://testserver',
|
||||
healthEndpoint: 'endpoint'
|
||||
)
|
||||
|
||||
assertThat(jlr.log, containsString("Health check for http://testserver/endpoint successful"))
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHealthCheckWithEndPointTrailingSlash() throws Exception {
|
||||
jsr.step.healthExecuteCheck(
|
||||
script: nullScript,
|
||||
testServerUrl: 'http://testserver/',
|
||||
healthEndpoint: 'endpoint'
|
||||
)
|
||||
|
||||
assertThat(jlr.log, containsString("Health check for http://testserver/endpoint successful"))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import com.sap.piper.ConfigurationHelper
|
||||
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = 'healthExecuteCheck'
|
||||
@Field Set STEP_CONFIG_KEYS = [
|
||||
'healthEndpoint',
|
||||
'testServerUrl'
|
||||
]
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
|
||||
def script = parameters?.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
|
||||
// load default & individual configuration
|
||||
Map config = ConfigurationHelper
|
||||
.loadStepDefaults(this)
|
||||
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
|
||||
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
|
||||
.mixin(parameters, PARAMETER_KEYS)
|
||||
.withMandatoryProperty('testServerUrl')
|
||||
.use()
|
||||
|
||||
def checkUrl = config.testServerUrl
|
||||
if(config.healthEndpoint){
|
||||
if(!checkUrl.endsWith('/'))
|
||||
checkUrl += '/'
|
||||
checkUrl += config.healthEndpoint
|
||||
}
|
||||
|
||||
def statusCode = curl(checkUrl)
|
||||
if (statusCode != '200') {
|
||||
error "Health check failed: ${statusCode}"
|
||||
} else {
|
||||
echo "Health check for ${checkUrl} successful"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def curl(url){
|
||||
return sh(
|
||||
returnStdout: true,
|
||||
script: "curl -so /dev/null -w '%{response_code}' ${url}"
|
||||
).trim()
|
||||
}
|
||||
Reference in New Issue
Block a user