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

alerts.package.scala Maven / Gradle / Ivy

The newest version!
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//:
//:   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 nelson

/**
 * Contains code related to validating alerts and storing their configuration in
 * Consul.
 *
 * In theory, we can support multiple alerting systems.  In current practice, we
 * only support Prometheus.
 */
package object alerts {
  import helm.ConsulOp
  import nelson.Datacenter.StackName
  import nelson.Manifest._
  import Manifest.AlertOptOut
  import scalaz.{\/, Free}
  import scalaz.concurrent.Task
  import scalaz.syntax.either._
  import scalaz.syntax.functor._
  import journal.Logger

  private[this] val logger = Logger("nelson.alerts")

  def alertingKey(stackName: StackName): String =
    s"nelson/alerting/v2/${stackName}"

  /**
   * Writes alert configuration to consul, if not opted out.
   */
  def writeToConsul(sn: StackName, ns: NamespaceName, plan: PlanRef, u: UnitDef, outs: List[AlertOptOut]): ConsulOp.ConsulOpF[Option[String]] = {
    import ConsulOp.ConsulOpFMonad

    if (outs.contains(ns.asString))
      Free.pure(None)
    else {
      val key = alertingKey(sn)
      // TODO a run not at the end of the world and a throw.  The horror.
      // ConsulOp doesn't represent other tasks well, nor does it represent failure
      val rules = rewriteRules(u, sn, plan, ns, outs).run.valueOr(throw _)
      ConsulOp.set(key, rules) as Some(rules)
    }
  }

  def optedOutPrometheusConfig(unit: UnitDef, outs: List[AlertOptOut]): PrometheusConfig = {
    val optedOut = outs.map(_.ref).toSet
    val pc = unit.alerting.prometheus
    pc.copy(alerts = pc.alerts.filterNot(a => optedOut(a.alert)))
  }

  def rewriteRules(unit: UnitDef, stackName: StackName, plan: PlanRef, ns: NamespaceName, outs: List[AlertOptOut]): Task[NelsonError \/ String] = {
    val pc = optedOutPrometheusConfig(unit, outs)
    for {
      rewriter <- RuleRewriter.autoDetect
      result <- rewriter.rewriteRules(stackName, ns, plan, pc)
    } yield result match {
      case RuleRewriter.Rewritten(s) =>
        s.right
      case RuleRewriter.Invalid(s) =>
        InvalidPrometheusRules(s).left
    }
  }

  /**
   * Deletes an alert configuration from consul.  This includes alert
   * definitions, recording rules, and per-namespace opt-outs.
   */
  def deleteFromConsul(stackName: StackName): ConsulOp.ConsulOpF[Unit] =
    ConsulOp.delete(alertingKey(stackName))
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy