Skip to content

Commit

Permalink
feat(webhooks): allow custom headers on monitor task of webhook stage (
Browse files Browse the repository at this point in the history
…#1313)

Add custom header support to monitor (getStatus) task  of webhook stage.
  • Loading branch information
Nagarajj authored and anotherchrisberry committed May 2, 2017
1 parent 2b1aaaa commit 12a1517
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,21 @@ class WebhookService {

ResponseEntity<Object> exchange(HttpMethod httpMethod, String url, Object payload, Object customHeaders) {
URI validatedUri = userConfiguredUrlRestrictions.validateURI(url)
HttpHeaders headers = new HttpHeaders()
customHeaders?.each{ key, value -> headers.add(key as String, value as String) }
HttpHeaders headers = buildHttpHeaders(customHeaders)
HttpEntity<Object> payloadEntity = new HttpEntity<>(payload, headers)
return restTemplate.exchange(validatedUri, httpMethod, payloadEntity, Object)
}

ResponseEntity<Object> getStatus(String url) {
ResponseEntity<Object> getStatus(String url, Object customHeaders) {
URI validatedUri = userConfiguredUrlRestrictions.validateURI(url)
return restTemplate.getForEntity(validatedUri, Object)
HttpHeaders headers = buildHttpHeaders(customHeaders)
HttpEntity<Object> httpEntity = new HttpEntity<>(headers)
return restTemplate.exchange(validatedUri, HttpMethod.GET, httpEntity, Object)
}

private static HttpHeaders buildHttpHeaders(Object customHeaders) {
HttpHeaders headers = new HttpHeaders()
customHeaders?.each { key, value -> headers.add(key as String, value as String) }
return headers
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import com.netflix.spinnaker.orca.Task
import com.netflix.spinnaker.orca.TaskResult
import com.netflix.spinnaker.orca.pipeline.model.Stage
import com.netflix.spinnaker.orca.webhook.WebhookService
import groovy.transform.CompileStatic
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

Expand All @@ -49,8 +48,9 @@ class MonitorWebhookTask implements Task {
String successStatuses = stage.context.successStatuses
String canceledStatuses = stage.context.canceledStatuses
String terminalStatuses = stage.context.terminalStatuses
def customHeaders = stage.context.customHeaders

def response = webhookService.getStatus(statusEndpoint)
def response = webhookService.getStatus(statusEndpoint, customHeaders)
def result
try {
result = JsonPath.read(response.body, statusJsonPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,28 @@ class WebhookServiceSpec extends Specification {

}

def "Status endpoint is being called"() {
@Unroll
def "Status endpoint is being called with headers #customHeaders"() {

expect:
server.expect(requestTo("https://localhost/v1/status/123"))
def responseActions = server.expect(requestTo("https://localhost/v1/status/123"))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess('["element1", 123, false]', MediaType.APPLICATION_JSON))

if(customHeaders){
customHeaders.each {k, v -> responseActions.andExpect(header(k, v))}
}

responseActions.andRespond(withSuccess('["element1", 123, false]', MediaType.APPLICATION_JSON))

when:
def responseEntity = webhookService.getStatus("https://localhost/v1/status/123")
def responseEntity = webhookService.getStatus("https://localhost/v1/status/123", [Authorization: "Basic password"])

then:
server.verify()
responseEntity.statusCode == HttpStatus.OK
responseEntity.body == ["element1", 123, false]

where:
customHeaders << [[Authorization: "Basic password"], [:], null]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,15 @@ class MonitorWebhookTaskSpec extends Specification {
def "should do a get request to the defined statusEndpoint"() {
setup:
monitorWebhookTask.webhookService = Mock(WebhookService) {
1 * getStatus("https://my-service.io/api/status/123") >> new ResponseEntity<Map>([status:"RUNNING"], HttpStatus.OK)
1 * getStatus("https://my-service.io/api/status/123", [Authorization: "Basic password"]) >> new ResponseEntity<Map>([status:"RUNNING"], HttpStatus.OK)
}
def stage = new Stage(pipeline, "webhook", [
statusEndpoint: 'https://my-service.io/api/status/123',
statusJsonPath: '$.status',
successStatuses: 'SUCCESS',
canceledStatuses: 'CANCELED',
terminalStatuses: 'TERMINAL',
customHeaders: [Authorization: "Basic password"],
someVariableWeDontCareAbout: 'Hello!'
])

Expand All @@ -95,7 +96,7 @@ class MonitorWebhookTaskSpec extends Specification {
def "should find correct element using statusJsonPath parameter"() {
setup:
monitorWebhookTask.webhookService = Mock(WebhookService) {
1 * getStatus("https://my-service.io/api/status/123") >> new ResponseEntity<Map>([status:"TERMINAL"], HttpStatus.OK)
1 * getStatus("https://my-service.io/api/status/123", null) >> new ResponseEntity<Map>([status:"TERMINAL"], HttpStatus.OK)
}
def stage = new Stage(pipeline, "webhook", [
statusEndpoint: 'https://my-service.io/api/status/123',
Expand All @@ -117,15 +118,16 @@ class MonitorWebhookTaskSpec extends Specification {
def "should return percentComplete if supported by endpoint"() {
setup:
monitorWebhookTask.webhookService = Mock(WebhookService) {
1 * getStatus("https://my-service.io/api/status/123") >> new ResponseEntity<Map>([status:42], HttpStatus.OK)
1 * getStatus("https://my-service.io/api/status/123", [:]) >> new ResponseEntity<Map>([status:42], HttpStatus.OK)
}
def stage = new Stage(pipeline, "webhook", [
statusEndpoint: 'https://my-service.io/api/status/123',
statusJsonPath: '$.status',
successStatuses: 'SUCCESS',
canceledStatuses: 'CANCELED',
terminalStatuses: 'TERMINAL',
someVariableWeDontCareAbout: 'Hello!'
someVariableWeDontCareAbout: 'Hello!',
customHeaders: [:]
])

when:
Expand All @@ -139,7 +141,7 @@ class MonitorWebhookTaskSpec extends Specification {
def "100 percent complete should result in SUCCEEDED status"() {
setup:
monitorWebhookTask.webhookService = Mock(WebhookService) {
1 * getStatus("https://my-service.io/api/status/123") >> new ResponseEntity<Map>([status:100], HttpStatus.OK)
1 * getStatus("https://my-service.io/api/status/123", null) >> new ResponseEntity<Map>([status:100], HttpStatus.OK)
}
def stage = new Stage(pipeline, "webhook", [
statusEndpoint: 'https://my-service.io/api/status/123',
Expand All @@ -161,7 +163,7 @@ class MonitorWebhookTaskSpec extends Specification {
def "should return TERMINAL status if jsonPath can not be found"() {
setup:
monitorWebhookTask.webhookService = Mock(WebhookService) {
1 * getStatus("https://my-service.io/api/status/123") >> new ResponseEntity<Map>([status:"SUCCESS"], HttpStatus.OK)
1 * getStatus("https://my-service.io/api/status/123", null) >> new ResponseEntity<Map>([status:"SUCCESS"], HttpStatus.OK)
}
def stage = new Stage(pipeline, "webhook", [
statusEndpoint: 'https://my-service.io/api/status/123',
Expand All @@ -180,7 +182,7 @@ class MonitorWebhookTaskSpec extends Specification {
def "should return TERMINAL status if jsonPath isn't evaluated to single value"() {
setup:
monitorWebhookTask.webhookService = Mock(WebhookService) {
1 * getStatus("https://my-service.io/api/status/123") >> new ResponseEntity<Map>([status:["some", "complex", "list"]], HttpStatus.OK)
1 * getStatus("https://my-service.io/api/status/123", null) >> new ResponseEntity<Map>([status:["some", "complex", "list"]], HttpStatus.OK)
}
def stage = new Stage(pipeline, "webhook", [
statusEndpoint: 'https://my-service.io/api/status/123',
Expand Down

0 comments on commit 12a1517

Please sign in to comment.