Skip to main content
O sistema de notificações da plataforma AIOps envia as mudanças de estado das Issues para as equipes certas, nos canais certos (Slack, PagerDuty, OpsGenie, email, webhooks genéricos e Microsoft Teams). As políticas de escalação acrescentam uma cadeia de níveis temporizada para as Issues que a remediação automática não conseguiu resolver. Tudo o que esta página descreve é feito por um único controller do operator, o controller de notificação (NotificationReconciler), que observa os recursos Issue. NotificationPolicy e EscalationPolicy não têm controller próprio: o controller de notificação as lê sempre que uma Issue muda.

Visão Geral

O que dispara uma notificação

O único gatilho é uma mudança de status.state em uma Issue. O controller guarda o último estado tratado na annotation platform.chatcli.io/last-notified-state da Issue e avalia as policies uma vez para cada estado novo: Detected, Analyzing, Remediating, Contained, Resolved, Escalated, Failed. Outros eventos só chegam a um canal se virarem uma mudança de estado de Issue:
IncidentSLA.spec.notificationPolicyRef, IncidentSLA.spec.escalationPolicyRef e ServiceLevelObjective.spec.alertPolicy.notificationPolicyRef são reservados: os CRDs os aceitam, mas nenhum controller os lê ainda. O roteamento é decidido apenas pelas rules das suas NotificationPolicies. Para rotear alertas de SLO, filtre por signalTypes: [slo_violation].
Issues criadas por um ChaosExperiment (label platform.chatcli.io/source: chaos-experiment) continuam gerando as notificações normais de mudança de estado. Elas nunca iniciam uma escalação, então um exercício de chaos nunca aciona ninguém por meio de uma EscalationPolicy.

CRD NotificationPolicy

Uma NotificationPolicy (short name np) declara um conjunto de canais nomeados, uma lista de regras que escolhem canais pelo nome, throttling e templates opcionais de mensagem.
Os Secrets referenciados acima ficam no mesmo namespace da policy:

Como as policies são aplicadas

  • Toda policy habilitada, de qualquer namespace, é avaliada para toda Issue do cluster. O namespace da policy não limita o seu alcance. Para isso, use o filtro namespaces da regra.
  • Dentro de uma policy, toda regra que casar envia para os seus canais. O mesmo canal pode receber a mesma Issue duas vezes se duas regras casarem, mas a janela de dedup (abaixo) normalmente suprime o segundo envio.
  • Uma regra que cita um canal ausente em spec.channels é ignorada com a linha de log channel not found in policy.

Campos do Spec

NotificationPolicySpec

NotificationChannel

config é um mapa de strings. Números, booleanos, listas e mapas precisam ser escritos como strings: smtp_port: "587", tls_skip_verify: "true", to: "a@example.com,b@example.com", headers: '{"X-Env":"prod"}'. Um 587 sem aspas ou uma lista YAML é rejeitado pelo API server.
GET /api/v1/policies/notification na API REST do operator devolve o spec completo, incluindo config, para qualquer chave com a role viewer. Mantenha URLs de webhook, routing keys, API keys e senhas no Secret do secretRef, e não em config.

NotificationRule

Os filtros ficam direto na regra (não existe bloco match). Um filtro omitido ou vazio casa com tudo. A lógica é AND entre filtros e OR dentro de cada filtro.
Sempre defina states. Sem ele, toda transição da Issue (Detected → Analyzing → Remediating → …) é candidata. Inclua também Resolved nos canais de PagerDuty e OpsGenie: é isso que resolve ou fecha o alerta do lado deles.

ThrottleConfig

Notificações barradas pelo throttle são descartadas, não enfileiradas, e o estado mesmo assim é marcado como tratado, então ele nunca é enviado depois. Com a janela padrão de 5m, uma Issue que passa por Detected → Analyzing → Remediating → Resolved em menos de cinco minutos envia apenas o primeiro estado que casar para canais de Slack, email, webhook e Teams. Para canais que precisam ver toda transição, use uma janela curta, como 30s.Uma exceção: uma notificação de Resolved para um canal de PagerDuty ou OpsGenie nunca é barrada, nem por deduplicationWindow nem por maxPerHour, porque é ela que resolve o evento ou fecha o alerta do lado deles.O estado do throttle fica na memória do operator: ele é zerado quando o operator reinicia. A janela é contada por nome de canal, então duas policies que usam o mesmo nome de canal a compartilham.

Templates

templates substitui o corpo da mensagem (o título e o assunto do email não mudam). A chave é escolhida pelo novo estado: A chave remediation_completed é aceita, mas nunca usada. Os templates não são text/template do Go: é uma simples substituição de placeholders, e só estes tokens exatos são trocados: {{.Name}} (nome da Issue), {{.Namespace}}, {{.Severity}}, {{.State}}, {{.Resource}} (Kind/nome), {{.Description}}, {{.Source}}, {{.SignalType}}, {{.RiskScore}}. Qualquer outra coisa (condicionais, funções, outros campos) é enviada literalmente. Sem template, o corpo é o spec.description da Issue, ou Issue <name> on <Kind>/<name> transitioned to <State>. quando a descrição está vazia.

Conteúdo da mensagem

Todos os canais recebem a mesma mensagem:
  • Título: <emoji da severidade> [<SEVERIDADE>] <namespace>/<nome do recurso> — <Estado>, por exemplo 🔴 [CRITICAL] production/api-gateway — Detected.
  • Corpo: o template ou a descrição (veja acima).
  • Campos: Source, SignalType, RiskScore, mais CorrelationID, RemediationAttempts (n/max) e Resolution quando estão preenchidos.
  • Cor por severidade: critical #FF0000, high #FF8C00, medium #FFD700, low #00CC00.
A mensagem não inclui a análise da IA, o plano de remediação nem link para dashboard. Todo canal HTTP usa timeout de 30 segundos e faz uma única tentativa, sem retries.

Status

Notificações de escalação não entram nesse status. Toda tentativa de entrega, inclusive as de escalação, também é registrada como um AuditEvent com eventType: notification_sent (veja Auditoria e Compliance).

Canais de Notificação

1. Slack

Publica em um Incoming Webhook do Slack usando Block Kit.
Nenhuma outra chave é lida (não existe opção de menção nem de ícone). Para mencionar um grupo, coloque a menção em um template, por exemplo issue_created: "<!subteam^S0123ABC> {{.Description}}".Payload enviado:
Os campos extras (SignalType, RiskScore, …) vêm de um mapa, então a ordem pode mudar entre mensagens.
Exemplo mínimo:

2. PagerDuty

Envia eventos para a Events API v2 do PagerDuty (https://events.pagerduty.com/v2/enqueue; o endpoint é fixo).
Nenhuma outra chave é lida. O mapeamento de severidade e a dedup key são fixos (a chave severity_map citada na descrição do campo no CRD não está implementada):Deduplicação: o dedup_key é sempre chatcli-<namespace do recurso>-<nome da issue>, então todo estado notificado de uma Issue atualiza o mesmo alerta no PagerDuty.Payload enviado:
Resolução automática: quando uma notificação é enviada para o estado Resolved, o evento usa event_action: resolve com o mesmo dedup_key. Isso acontece sempre que alguma regra envia Resolved para este canal: resolves para o PagerDuty nunca são barrados pelo throttle.

3. OpsGenie

Cria alertas pela Alert API do OpsGenie (https://api.opsgenie.com/v2/alerts; o endpoint é fixo, então contas na instância EU não são suportadas).
Mapeamento de prioridade (fixo): critical → P1, high → P2, medium → P3, low → P4.Responders:
O alias do alerta é chatcli-<namespace do recurso>-<nome da issue>, o source é ChatCLI AIOps, o entity é o recurso, e details traz resource, namespace, severity, state e issue.Fechamento automático: para o estado Resolved, o canal fecha o alerta pelo alias em vez de criar um novo (mesmas condições do PagerDuty).

4. Email

Envia um email HTML via SMTP.
Não existem opções de cc, bcc, assunto ou template HTML. O assunto é sempre [<SEVERIDADE>] <título> e o corpo é um layout HTML fixo com a tabela de campos.Comportamento de TLS:
  • TLS implícito (SMTPS) é usado na porta 465, ou em qualquer porta com smtp_tls: implicit: a conexão é criptografada desde o primeiro byte.
  • Nos demais casos, a conexão começa em texto puro e é elevada com STARTTLS quando o servidor o anuncia. smtp_tls: starttls força esse modo mesmo na porta 465.
  • Se a conexão não estiver criptografada e smtp_user estiver definido, a autenticação falha (o Go se recusa a enviar credenciais PLAIN por conexão sem criptografia, exceto para localhost).
  • Toda a conversa, conexão inclusa, é limitada por smtp_timeout (padrão 30s), então um servidor inacessível ou mudo faz o envio falhar em vez de segurar o reconcile.
Exemplo:
Nunca coloque credenciais SMTP diretamente no YAML da NotificationPolicy. Coloque smtp_user e smtp_password em um Secret e referencie-o com secretRef.

5. Webhook

Envia a mensagem como JSON para qualquer endpoint HTTP, com assinatura HMAC-SHA256 opcional.
Toda requisição leva Content-Type: application/json e User-Agent: ChatCLI-AIOps/1.0. O timeout é de 30 segundos e não há retries.Assinatura HMAC-SHA256:Quando secret está definido, a requisição leva o header X-Signature-256 com o HMAC-SHA256 do body bruto:
Validação no receptor:
Payload JSON enviado:

6. Microsoft Teams

Publica um Adaptive Card (versão 1.4) em uma URL de webhook do Teams.
Nenhuma outra chave é lida.Card gerado:
  • Um título grande em negrito (o título da mensagem)
  • O texto do corpo
  • Um FactSet com Severity, Resource, Namespace, State, Issue e os campos extras
  • Um rodapé com o horário de geração
A mensagem também leva themeColor com a cor da severidade sem # (FF0000, FF8C00, FFD700, 00CC00).

CRD EscalationPolicy

Uma EscalationPolicy (short name ep) é uma cadeia ordenada de níveis. Ela é usada quando uma Issue entra no estado Escalated, que o controller de Issue define quando a remediação automática desiste (por exemplo, quando todas as tentativas de remediação falharam).

Campos do Spec

EscalationLevel

EscalationTarget

Os targets são apenas informativos. O operator não contata usuários, times nem escalas de plantão. Ele escreve a lista (por exemplo oncall:sre-primary, user:sre-lead@example.com) na mensagem de escalação e envia essa mensagem para os notifyChannels do nível. Um nível sem notifyChannels não notifica ninguém.

Como a Escalação Funciona

  1. Início. Quando uma Issue muda para Escalated (e não foi induzida por chaos), o controller escolhe uma policy: a primeira policy habilitada, de qualquer namespace, cujo severities contém a severidade da Issue, ou que não tem severities. Uma policy com defaultPolicy: true só é usada quando nenhuma casou. Se nada for encontrado, não há escalação (linha de log no escalation policy found for issue).
  2. Nível 1 é notificado na hora. A Issue recebe as annotations abaixo e o status da policy ganha uma entrada em activeEscalations.
  3. Avanço. Quando o timeoutMinutes do nível atual passa, o próximo nível é notificado com o título <emoji> ESCALATION [<SEVERIDADE>] <issue> — Level <n>: <nome do nível>. O novo nível e o horário em que começou ficam salvos na Issue, então a cadeia avança nível a nível (L1 → L2 → L3) e cada nível é notificado uma vez, mais as repetições (repeatIntervalMinutes).
  4. Último nível. A cadeia para ali. O último nível só é reenviado se tiver repeatIntervalMinutes.
  5. Fim. Um reconhecimento (acknowledge) congela a cadeia no nível atual: nenhum nível a mais e nenhuma repetição (veja abaixo). A escalação termina quando a Issue chega a Resolved: as annotations de escalação são removidas e a entrada da Issue sai de status.activeEscalations.
As mensagens de escalação são enviadas para todo canal, em qualquer NotificationPolicy habilitada, cujo nome esteja em notifyChannels (os Secrets são lidos do namespace dessa policy). Elas não passam pelas regras, pelo throttle nem pelos templates. Annotations da Issue usadas no acompanhamento:
Cada entrada de status.activeEscalations traz issueName, currentLevel (a partir de 0), escalatedAt e, depois que a Issue é reconhecida, acknowledgedAt e acknowledgedBy. A entrada é removida quando a Issue é resolvida; status.totalEscalations conta toda escalação iniciada.

Reconhecimento e como encerrar uma escalação

As duas ações passam pela API REST (role operator, header X-API-Key) ou pelo dashboard:
  • Acknowledge. POST /api/v1/incidents/{name}/acknowledge adiciona as annotations aiops.chatcli.io/acknowledged, aiops.chatcli.io/acknowledged-at e aiops.chatcli.io/acknowledged-by (a role de quem chamou). A escalação para no nível atual: nenhum nível a mais é alcançado e nenhuma repetição é enviada. O reconhecimento é registrado na entrada de status.activeEscalations da policy (acknowledgedAt, acknowledgedBy). Uma Issue reconhecida antes de chegar a Escalated nunca inicia uma escalação. As notificações de mudança de estado continuam saindo.
  • Snooze. POST /api/v1/incidents/{name}/snooze com um corpo como {"duration": "30m"} registra aiops.chatcli.io/snoozed-until e aiops.chatcli.io/snoozed-by. Uma duração zero ou negativa é recusada com 400. Até o snooze terminar, a Issue não envia nenhuma notificação exceto Resolved (uma mudança de estado que acontece durante o snooze não é enviada depois), e a escalação segura o nível: sem avanço e sem repetição. Uma mensagem de nível que cai dentro do snooze fica retida (escalation-pending-notify) e é enviada quando o snooze termina, e o timer do nível recomeça nesse momento.
  • Reconhecer no PagerDuty ou no OpsGenie não tem efeito no cluster: não existe webhook de retorno.
Para encerrar uma escalação, resolva a Issue, por exemplo com POST /api/v1/incidents/{name}/resolve (role operator) ou pelo dashboard. Isso também envia as notificações de Resolved que resolvem o evento no PagerDuty e fecham o alerta no OpsGenie.

Exemplos Completos

Notification Policy: Slack + PagerDuty

A janela curta de 30s deixa os canais de Slack verem cada transição de uma recuperação rápida. O evento Resolved que resolve o incidente no PagerDuty nunca é barrado pelo throttle, qualquer que seja a janela.

Escalation Policy com dois níveis

email-leadership precisa ser um canal definido em alguma NotificationPolicy. Depois que o segundo nível é alcançado, nada mais é enviado até a Issue ser resolvida; adicione repeatIntervalMinutes ao segundo nível para continuar lembrando até alguém reconhecer.

Alertas de violação de SLO

Os alertas de burn rate e de budget esgotado de SLO chegam como Issues com signalType: slo_violation e source: watcher:

Troubleshooting

Checklist de diagnóstico:
  1. Verifique se a policy existe e está habilitada (policies de qualquer namespace se aplicam):
  1. Veja o status da policy em busca de erros de entrega:
  1. Verifique os logs do operator (rule matched, notification sent, failed to send notification, channel not found in policy, failed to resolve channel config):
  1. Compare a Issue com os filtros da regra. Lembre que namespaces é comparado com spec.resource.namespace:
  1. Verifique se o throttle descartou o envio (linha de log notification throttled). Outro estado da mesma Issue pode ter sido enviado para aquele canal dentro do deduplicationWindow.
  2. Se platform.chatcli.io/last-notified-state já é igual ao estado atual, esse estado já foi tratado e não é avaliado de novo.
  • Todo valor de config precisa ser string: coloque aspas em números (smtp_port: "587") e booleanos (tls_skip_verify: "true"), e escreva listas como strings separadas por vírgula.
  • Todo canal precisa de name, type e config (use config: {} quando os valores vierem do secretRef).
  • Os filtros ficam direto na regra; um bloco match: não faz parte do schema.
  • Confirme que o webhook_url está correto e que o app do Slack continua instalado no workspace
  • Teste o webhook manualmente:
  • Confirme que o routing_key é uma Integration Key da Events API v2 (não uma chave da REST API)
  • Confirme que o serviço no PagerDuty está ativo e confira o payload no PagerDuty Event Debugger
  • Se os incidentes nunca são resolvidos, garanta que alguma regra envia Resolved para o canal (resolves para o PagerDuty nunca são barrados pelo throttle)
  • Teste a conectividade SMTP de dentro do cluster:
  • Na porta 465 o canal usa TLS implícito; na 587 ou na 25 ele eleva com STARTTLS. Defina smtp_tls se o seu servidor usa uma porta fora do padrão.
  • Um envio que falha por timeout atingiu o smtp_timeout (padrão 30s)
  • Confirme que o Secret tem as chaves smtp_user e smtp_password (e não username/password)
  • Cheque a pasta de spam dos destinatários
  • A escalação só começa quando a Issue entra em Escalated. Confira com kubectl get issue <nome> -o jsonpath='{.status.state}'.
  • Issues induzidas por chaos nunca escalam.
  • Verifique as annotations platform.chatcli.io/escalation-level, escalation-time e escalation-policy.
  • Garanta que cada nível tenha notifyChannels com nomes que existem em uma NotificationPolicy habilitada.
  • Procure escalation initiated, escalation advanced e no escalation policy found for issue nos logs do operator.
  • Uma Issue reconhecida não avança, e uma em snooze segura o nível até aiops.chatcli.io/snoozed-until.
  • Leia a assinatura do header X-Signature-256
  • Confirme que o secret no Secret da policy é o mesmo usado pelo receptor
  • Calcule o HMAC sobre o body bruto, antes de fazer o parse do JSON
  • Use hmac.compare_digest (ou equivalente) para evitar timing attacks

Métricas Prometheus

O operator expõe estas métricas no seu endpoint de métricas (porta 8080, caminho /metrics): Não há métrica de notificações barradas pelo throttle. O throttle só aparece nos logs (notification throttled). Alertas Prometheus recomendados:

Próximos Passos

SLOs e SLAs

Gestão de Service Level Objectives com alertas de burn rate

Workflow de Aprovação

Controle de mudanças com approval policies e blast radius

AIOps Platform

Deep-dive na arquitetura AIOps

K8s Operator

Configuração e CRDs do operator