Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/configuration/sinks/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ Click a sink for setup instructions.
:link: pushover
:link-type: doc

.. grid-item-card:: :octicon:`cpu;1em;` Plivo
:class-card: sd-bg-light sd-bg-text-light
:link: plivo
:link-type: doc

.. grid-item-card:: :octicon:`cpu;1em;` ServiceNow
:class-card: sd-bg-light sd-bg-text-light
:link: ServiceNow
Expand Down
51 changes: 51 additions & 0 deletions docs/configuration/sinks/plivo.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Plivo
#################

.. admonition:: This page documents a legacy sink in Robusta classic
:class: warning

For new setups, we recommend `HolmesGPT <https://holmesgpt.dev/>`_ instead.

HolmesGPT triages your alerts instead of just forwarding them. Sinks are deterministic: they send every notification, unchanged, to a fixed destination, leaving you to read and prioritize each one yourself.

HolmesGPT instead uses AI to investigate each alert, surface the likely root cause, and escalate only what needs attention — so you get fewer, more actionable notifications. Set this up with `Alerts Triage <https://platform.robusta.dev/holmes/alerts-triage>`_ for alerts, or :ref:`Triggered Workflows <defining-playbooks>` for custom events.


Robusta can send SMS notifications about issues and events in your Kubernetes cluster to a phone number using Plivo.

Getting your Auth ID and Auth Token
------------------------------------------------
Log in to the Plivo console at `cx.plivo.com <https://cx.plivo.com>`_. Your Auth ID and Auth Token are shown on the dashboard.

Getting a sender number
------------------------------------------------
You need an SMS enabled Plivo phone number to send from. Buy or view your numbers in the Plivo console under Phone Numbers.

Configuring the Plivo sink
------------------------------------------------
Now we're ready to configure the Plivo sink.

.. admonition:: Add this to your generated_values.yaml

.. code-block:: yaml

sinksConfig:
- plivo_sink:
name: plivo_sink
auth_id: <YOUR_PLIVO_AUTH_ID>
auth_token: <YOUR_PLIVO_AUTH_TOKEN>
from_number: <YOUR_PLIVO_NUMBER> # E.164 format, e.g. +14155551234
to_number: <DESTINATION_NUMBER> # E.164 format; for several recipients join them with '<'

.. note::

Numbers use E.164 format. To send to more than one recipient, join the numbers with ``<`` (for example ``+14155551234<+14155555678``).

Save the file and run

.. code-block:: bash
:name: cb-add-plivo-sink

helm upgrade robusta robusta/robusta --values=generated_values.yaml

You should now get playbook results as SMS messages from Plivo.
2 changes: 2 additions & 0 deletions src/robusta/core/model/runner_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from robusta.core.sinks.webex.webex_sink_params import WebexSinkConfigWrapper
from robusta.core.sinks.webhook.webhook_sink_params import WebhookSinkConfigWrapper
from robusta.core.sinks.yamessenger.yamessenger_sink_params import YaMessengerSinkConfigWrapper
from robusta.core.sinks.plivo.plivo_sink_params import PlivoSinkConfigWrapper
from robusta.core.sinks.pushover.pushover_sink_params import PushoverSinkConfigWrapper
from robusta.core.sinks.zulip.zulip_sink_params import ZulipSinkConfigWrapper
from robusta.model.alert_relabel_config import AlertRelabel
Expand Down Expand Up @@ -74,6 +75,7 @@ class RunnerConfig(BaseModel):
FileSinkConfigWrapper,
MailSinkConfigWrapper,
PushoverSinkConfigWrapper,
PlivoSinkConfigWrapper,
GoogleChatSinkConfigWrapper,
ServiceNowSinkConfigWrapper,
ZulipSinkConfigWrapper,
Expand Down
2 changes: 2 additions & 0 deletions src/robusta/core/sinks/plivo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from robusta.core.sinks.plivo.plivo_sink import PlivoSink
from robusta.core.sinks.plivo.plivo_sink_params import PlivoSinkConfigWrapper, PlivoSinkParams
26 changes: 26 additions & 0 deletions src/robusta/core/sinks/plivo/plivo_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import logging

import requests

PLIVO_API_BASE = "https://api.plivo.com/v1/Account"


class PlivoClient:
def __init__(self, auth_id: str, auth_token: str):
self.auth_id = str(auth_id)
self.auth_token = str(auth_token)

def send_message(self, src: str, dst: str, text: str):
url = f"{PLIVO_API_BASE}/{self.auth_id}/Message/"
payload = {"src": src, "dst": dst, "text": text, "type": "sms"}

try:
response = requests.post(
url, json=payload, auth=(self.auth_id, self.auth_token), timeout=(5, 15)
)
if not response.ok:
logging.error(
f"Failed to send Plivo SMS to {dst}: {response.status_code} {response.reason} {response.text}"
)
except Exception as e:
logging.error(f"Error sending Plivo SMS to {dst}: {e}", exc_info=True)
38 changes: 38 additions & 0 deletions src/robusta/core/sinks/plivo/plivo_sink.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from typing import List

from robusta.core.reporting.base import Finding
from robusta.core.sinks.plivo.plivo_client import PlivoClient
from robusta.core.sinks.plivo.plivo_sink_params import PlivoSinkConfigWrapper
from robusta.core.sinks.sink_base import SinkBase

MAX_SMS_LENGTH = 1600


class PlivoSink(SinkBase):
def __init__(self, sink_config: PlivoSinkConfigWrapper, registry):
super().__init__(sink_config.plivo_sink, registry)

self.client = PlivoClient(
sink_config.plivo_sink.auth_id,
sink_config.plivo_sink.auth_token.get_secret_value(),
)
self.from_number = sink_config.plivo_sink.from_number
self.to_number = sink_config.plivo_sink.to_number

def write_finding(self, finding: Finding, platform_enabled: bool):
message = self.__build_message(finding, platform_enabled)
self.client.send_message(src=self.from_number, dst=self.to_number, text=message)

def __build_message(self, finding: Finding, platform_enabled: bool) -> str:
lines: List[str] = [f"{finding.severity.name} - {finding.title}"]

if platform_enabled:
lines.append(f"Investigate: {finding.get_investigate_uri(self.account_id, self.cluster_name)}")

lines.append(f"Source: {self.cluster_name}")

if finding.description:
lines.append(finding.description)

message = "\n".join(line for line in lines if line)
return message[:MAX_SMS_LENGTH]
22 changes: 22 additions & 0 deletions src/robusta/core/sinks/plivo/plivo_sink_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from pydantic import SecretStr

from robusta.core.sinks.sink_base_params import SinkBaseParams
from robusta.core.sinks.sink_config import SinkConfigBase


class PlivoSinkParams(SinkBaseParams):
auth_id: str
auth_token: SecretStr
from_number: str
to_number: str

@classmethod
def _get_sink_type(cls):
return "plivo"


class PlivoSinkConfigWrapper(SinkConfigBase):
plivo_sink: PlivoSinkParams

def get_params(self) -> SinkBaseParams:
return self.plivo_sink
2 changes: 2 additions & 0 deletions src/robusta/core/sinks/sink_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from robusta.core.sinks.webex import WebexSink, WebexSinkConfigWrapper
from robusta.core.sinks.webhook import WebhookSink, WebhookSinkConfigWrapper
from robusta.core.sinks.yamessenger import YaMessengerSink, YaMessengerSinkConfigWrapper
from robusta.core.sinks.plivo import PlivoSink, PlivoSinkConfigWrapper
from robusta.core.sinks.pushover import PushoverSink, PushoverSinkConfigWrapper
from robusta.core.sinks.zulip import ZulipSink, ZulipSinkConfigWrapper
from robusta.core.sinks.incidentio.incidentio_sink import IncidentioSink
Expand Down Expand Up @@ -56,6 +57,7 @@ class SinkFactory:
FileSinkConfigWrapper: FileSink,
MailSinkConfigWrapper: MailSink,
PushoverSinkConfigWrapper: PushoverSink,
PlivoSinkConfigWrapper: PlivoSink,
GoogleChatSinkConfigWrapper: GoogleChatSink,
ServiceNowSinkConfigWrapper: ServiceNowSink,
ZulipSinkConfigWrapper: ZulipSink,
Expand Down