All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.spinnaker.gate.services.NotificationService.groovy Maven / Gradle / Ivy

/*
 * Copyright 2014 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.netflix.spinnaker.gate.services

import com.netflix.spinnaker.config.DefaultServiceEndpoint
import com.netflix.spinnaker.config.okhttp3.OkHttpClientProvider
import com.netflix.spinnaker.gate.config.ServiceConfiguration
import com.netflix.spinnaker.gate.services.internal.EchoService
import com.netflix.spinnaker.gate.services.internal.Front50Service
import com.netflix.spinnaker.kork.web.exceptions.InvalidRequestException
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.RequestEntity
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Component
import retrofit.Endpoint
import retrofit.RetrofitError

import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR
import static retrofit.RetrofitError.Kind.HTTP

@CompileStatic
@Component
@Slf4j
class NotificationService {

  private Front50Service front50Service
  private EchoService echoService

  private OkHttpClient echoOkHttpClient
  private OkHttpClient keelOkHttpClient
  private Endpoint echoEndpoint
  private Endpoint keelEndpoint

  NotificationService(@Autowired(required = false) Front50Service front50Service,
                      @Autowired OkHttpClientProvider okHttpClientProvider,
                      @Autowired ServiceConfiguration serviceConfiguration,
                      @Autowired(required = false) EchoService echoService) {
    this.front50Service = front50Service
    this.echoService = echoService
    // We use the "raw" OkHttpClient here instead of EchoService because retrofit messes up with the encoding
    // of the body for the x-www-form-urlencoded content type, which is what Slack uses. This allows us to pass
    // the original body unmodified along to echo.
    this.echoEndpoint = serviceConfiguration.getServiceEndpoint("echo")
    this.keelEndpoint = serviceConfiguration.getServiceEndpoint("keel")
    this.echoOkHttpClient =  okHttpClientProvider.getClient(new DefaultServiceEndpoint("echo", echoEndpoint.url))
    this.keelOkHttpClient =  okHttpClientProvider.getClient(new DefaultServiceEndpoint("keel", keelEndpoint.url))
  }

  Map getNotificationConfigs(String type, String app) {
    front50Service.getNotificationConfigs(type, app)
  }

  void saveNotificationConfig(String type, String app, Map notification) {
    front50Service.saveNotificationConfig(type, app, notification)
  }

  void deleteNotificationConfig(String type, String app) {
    front50Service.deleteNotificationConfig(type, app)
  }

  List getNotificationTypeMetadata() {
    echoService.getNotificationTypeMetadata()
  }

  /**
   * processNotificationCallback can be called from 2 places:
   * 1. from NotificationController, which is the generic implementation and will use echo for further processing
   * 2. from ManagedController, which is keel's (MD) specific implementation and will use keel for further processing
   * @param source
   * @param request
   * @param service
   * @return
   */
  ResponseEntity processNotificationCallback(String source, RequestEntity request, String service = "echo") {
    Endpoint endpointToUse = echoEndpoint
    OkHttpClient clientToUse = echoOkHttpClient
    String path = request.url.path

    log.debug("Processing notification callback: ${request.getMethod()} ${request.getUrl()}, ${request.getHeaders()}")
    String contentType = request.getHeaders().getFirst("Content-Type")?.toLowerCase()

    if (!contentType) {
      throw new InvalidRequestException("No Content-Type header present in request. Unable to process notification callback.")
    }

    final MediaType mediaType = MediaType.parse(contentType)

    // If the call is coming from ManagedController, use keel client and keel endpoint instead of echo
    if (service == "keel") {
      endpointToUse = keelEndpoint
      clientToUse = keelOkHttpClient
      path = "/slack/notifications/callbacks"
    }

    log.debug("Building request with URL ${endpointToUse.url + path}, Content-Type: $contentType")
    Request.Builder builder = new Request.Builder()
      .url(endpointToUse.url + path)
      .post(RequestBody.create(mediaType, request.body))

    request.getHeaders().each { String name, List values ->
      values.each { value ->
        log.debug("Relaying request header $name: $value")
        builder.addHeader(name, value.toString())
      }
    }

    Request callbackRequest = builder.build();
    try {
      Response response = clientToUse.newCall(callbackRequest).execute()
      // convert retrofit response to Spring format
      String body = response.body().contentLength() > 0 ? response.body().string() : null
      HttpHeaders headers = new HttpHeaders()
      headers.putAll(response.headers().toMultimap())
      return new ResponseEntity(body, headers, HttpStatus.valueOf(response.code()))
    } catch (RetrofitError error) {
      log.error("Error proxying notification callback to {}: $error", service)
      if (error.getKind() == HTTP) {
        throw error
      } else {
        return new ResponseEntity(INTERNAL_SERVER_ERROR)
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy