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 destatus.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:
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
UmaNotificationPolicy (short name np) declara um conjunto de canais nomeados, uma lista de regras que escolhem canais pelo nome, throttling e templates opcionais de mensagem.
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
namespacesda 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 logchannel not found in policy.
Campos do Spec
NotificationPolicySpec
NotificationChannel
NotificationRule
Os filtros ficam direto na regra (não existe blocomatch). Um filtro omitido ou vazio casa com tudo. A lógica é AND entre filtros e OR dentro de cada filtro.
ThrottleConfig
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, maisCorrelationID,RemediationAttempts(n/max) eResolutionquando estão preenchidos. - Cor por severidade: critical
#FF0000, high#FF8C00, medium#FFD700, low#00CC00.
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.Configuração completa do Slack
Configuração completa do Slack
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:SignalType, RiskScore, …) vêm de um mapa, então a ordem pode mudar entre mensagens.2. PagerDuty
Envia eventos para a Events API v2 do PagerDuty (https://events.pagerduty.com/v2/enqueue; o endpoint é fixo).
Configuração completa do PagerDuty
Configuração completa do PagerDuty
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: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).
Configuração completa do OpsGenie
Configuração completa do OpsGenie
Mapeamento de prioridade (fixo):
critical → P1, high → P2, medium → P3, low → P4.Responders: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.Configuração completa do Email
Configuração completa do Email
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 comsmtp_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: starttlsforça esse modo mesmo na porta465. - Se a conexão não estiver criptografada e
smtp_userestiver definido, a autenticação falha (o Go se recusa a enviar credenciaisPLAINpor conexão sem criptografia, exceto paralocalhost). - Toda a conversa, conexão inclusa, é limitada por
smtp_timeout(padrão30s), então um servidor inacessível ou mudo faz o envio falhar em vez de segurar o reconcile.
5. Webhook
Envia a mensagem como JSON para qualquer endpoint HTTP, com assinatura HMAC-SHA256 opcional.Configuração completa do Webhook
Configuração completa do Webhook
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:6. Microsoft Teams
Publica um Adaptive Card (versão 1.4) em uma URL de webhook do Teams.Configuração completa do Microsoft Teams
Configuração completa do Microsoft 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,Issuee os campos extras - Um rodapé com o horário de geração
themeColor com a cor da severidade sem # (FF0000, FF8C00, FFD700, 00CC00).CRD EscalationPolicy
UmaEscalationPolicy (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
Como a Escalação Funciona
- 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, cujoseveritiescontém a severidade da Issue, ou que não temseverities. Uma policy comdefaultPolicy: truesó é usada quando nenhuma casou. Se nada for encontrado, não há escalação (linha de logno escalation policy found for issue). - Nível 1 é notificado na hora. A Issue recebe as annotations abaixo e o status da policy ganha uma entrada em
activeEscalations. - Avanço. Quando o
timeoutMinutesdo 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). - Último nível. A cadeia para ali. O último nível só é reenviado se tiver
repeatIntervalMinutes. - 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 destatus.activeEscalations.
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:
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, headerX-API-Key) ou pelo dashboard:
- Acknowledge.
POST /api/v1/incidents/{name}/acknowledgeadiciona as annotationsaiops.chatcli.io/acknowledged,aiops.chatcli.io/acknowledged-ateaiops.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 destatus.activeEscalationsda policy (acknowledgedAt,acknowledgedBy). Uma Issue reconhecida antes de chegar aEscalatednunca inicia uma escalação. As notificações de mudança de estado continuam saindo. - Snooze.
POST /api/v1/incidents/{name}/snoozecom um corpo como{"duration": "30m"}registraaiops.chatcli.io/snoozed-untileaiops.chatcli.io/snoozed-by. Uma duração zero ou negativa é recusada com400. Até o snooze terminar, a Issue não envia nenhuma notificação excetoResolved(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.
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
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 comsignalType: slo_violation e source: watcher:
Troubleshooting
Notificações não estão sendo enviadas
Notificações não estão sendo enviadas
Checklist de diagnóstico:
- Verifique se a policy existe e está habilitada (policies de qualquer namespace se aplicam):
- Veja o status da policy em busca de erros de entrega:
- Verifique os logs do operator (
rule matched,notification sent,failed to send notification,channel not found in policy,failed to resolve channel config):
- Compare a Issue com os filtros da regra. Lembre que
namespacesé comparado comspec.resource.namespace:
-
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 dodeduplicationWindow. -
Se
platform.chatcli.io/last-notified-statejá é igual ao estado atual, esse estado já foi tratado e não é avaliado de novo.
A policy é rejeitada pelo kubectl apply
A policy é rejeitada pelo kubectl apply
- Todo valor de
configprecisa 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,typeeconfig(useconfig: {}quando os valores vierem dosecretRef). - Os filtros ficam direto na regra; um bloco
match:não faz parte do schema.
Slack retorna erro 404 ou invalid_payload
Slack retorna erro 404 ou invalid_payload
- Confirme que o
webhook_urlestá correto e que o app do Slack continua instalado no workspace - Teste o webhook manualmente:
PagerDuty não cria ou não resolve incidentes
PagerDuty não cria ou não resolve incidentes
- 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
Resolvedpara o canal (resolves para o PagerDuty nunca são barrados pelo throttle)
Emails não chegam
Emails não chegam
- Teste a conectividade SMTP de dentro do cluster:
- Na porta
465o canal usa TLS implícito; na587ou na25ele eleva com STARTTLS. Definasmtp_tlsse o seu servidor usa uma porta fora do padrão. - Um envio que falha por timeout atingiu o
smtp_timeout(padrão30s) - Confirme que o Secret tem as chaves
smtp_useresmtp_password(e nãousername/password) - Cheque a pasta de spam dos destinatários
A escalação não começa ou não avança
A escalação não começa ou não avança
- A escalação só começa quando a Issue entra em
Escalated. Confira comkubectl get issue <nome> -o jsonpath='{.status.state}'. - Issues induzidas por chaos nunca escalam.
- Verifique as annotations
platform.chatcli.io/escalation-level,escalation-timeeescalation-policy. - Garanta que cada nível tenha
notifyChannelscom nomes que existem em uma NotificationPolicy habilitada. - Procure
escalation initiated,escalation advancedeno escalation policy found for issuenos logs do operator. - Uma Issue reconhecida não avança, e uma em snooze segura o nível até
aiops.chatcli.io/snoozed-until.
Webhook retorna erro de assinatura
Webhook retorna erro de assinatura
- Leia a assinatura do header
X-Signature-256 - Confirme que o
secretno 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 (porta8080, 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