Remove notifier module duplication (#10051)
This commit is contained in:
@ -12,14 +12,13 @@ homepage = "https://solana.com/"
|
||||
clap = "2.33.1"
|
||||
log = "0.4.8"
|
||||
humantime = "2.0.0"
|
||||
reqwest = { version = "0.10.4", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||
serde_json = "1.0"
|
||||
solana-clap-utils = { path = "../clap-utils", version = "1.2.0" }
|
||||
solana-cli-config = { path = "../cli-config", version = "1.2.0" }
|
||||
solana-cli = { path = "../cli", version = "1.2.0" }
|
||||
solana-client = { path = "../client", version = "1.2.0" }
|
||||
solana-logger = { path = "../logger", version = "1.2.0" }
|
||||
solana-metrics = { path = "../metrics", version = "1.2.0" }
|
||||
solana-notifier = { path = "../notifier", version = "1.2.0" }
|
||||
solana-sdk = { path = "../sdk", version = "1.2.0" }
|
||||
solana-transaction-status = { path = "../transaction-status", version = "1.2.0" }
|
||||
solana-version = { path = "../version", version = "1.2.0" }
|
||||
|
@ -23,25 +23,3 @@ On failure this data point contains details about the specific test that failed
|
||||
the following fields:
|
||||
* `test`: name of the sanity test that failed
|
||||
* `err`: exact sanity failure message
|
||||
|
||||
|
||||
### Sanity failure push notification
|
||||
To receive a Slack, Discord and/or Telegram notification on sanity failure,
|
||||
define environment variables before running `solana-watchtower`:
|
||||
```
|
||||
export SLACK_WEBHOOK=...
|
||||
export DISCORD_WEBHOOK=...
|
||||
```
|
||||
|
||||
Telegram requires the following two variables:
|
||||
```
|
||||
export TELEGRAM_BOT_TOKEN=...
|
||||
export TELEGRAM_CHAT_ID=...
|
||||
```
|
||||
|
||||
To receive a Twilio SMS notification on failure, having a Twilio account,
|
||||
and a sending number owned by that account,
|
||||
define environment variable before running `solana-watchtower`:
|
||||
```
|
||||
export TWILIO_CONFIG='ACCOUNT=<account>,TOKEN=<securityToken>,TO=<receivingNumber>,FROM=<sendingNumber>'
|
||||
```
|
||||
|
@ -1,8 +1,5 @@
|
||||
//! A command-line executable for monitoring the health of a cluster
|
||||
|
||||
mod notifier;
|
||||
|
||||
use crate::notifier::Notifier;
|
||||
use clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg};
|
||||
use log::*;
|
||||
use solana_clap_utils::{
|
||||
@ -13,6 +10,7 @@ use solana_client::{
|
||||
client_error::Result as ClientResult, rpc_client::RpcClient, rpc_response::RpcVoteAccountStatus,
|
||||
};
|
||||
use solana_metrics::{datapoint_error, datapoint_info};
|
||||
use solana_notifier::Notifier;
|
||||
use solana_sdk::{
|
||||
clock::Slot, hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
|
||||
pubkey::Pubkey,
|
||||
@ -232,7 +230,7 @@ fn load_blocks(
|
||||
}
|
||||
|
||||
fn transaction_monitor(rpc_client: RpcClient) {
|
||||
let notifier = Notifier::new_with_env_prefix("TRANSACTION_NOTIFIER_");
|
||||
let notifier = Notifier::new("TRANSACTION_NOTIFIER_");
|
||||
let mut start_slot = loop {
|
||||
match rpc_client.get_slot() {
|
||||
Ok(slot) => break slot,
|
||||
@ -303,7 +301,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
};
|
||||
|
||||
let rpc_client = RpcClient::new(config.json_rpc_url.clone());
|
||||
let notifier = Notifier::new();
|
||||
let notifier = Notifier::default();
|
||||
let mut last_transaction_count = 0;
|
||||
let mut last_recent_blockhash = Hash::default();
|
||||
let mut last_notification_msg = "".into();
|
||||
|
@ -1,149 +0,0 @@
|
||||
use log::*;
|
||||
use reqwest::blocking::Client;
|
||||
use serde_json::json;
|
||||
use std::env;
|
||||
|
||||
struct TelegramWebHook {
|
||||
bot_token: String,
|
||||
chat_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct TwilioWebHook {
|
||||
account: String,
|
||||
token: String,
|
||||
to: String,
|
||||
from: String,
|
||||
}
|
||||
|
||||
impl TwilioWebHook {
|
||||
fn complete(&self) -> bool {
|
||||
!(self.account.is_empty()
|
||||
|| self.token.is_empty()
|
||||
|| self.to.is_empty()
|
||||
|| self.from.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_twilio_config() -> Result<Option<TwilioWebHook>, String> {
|
||||
let config_var = env::var("TWILIO_CONFIG");
|
||||
|
||||
if config_var.is_err() {
|
||||
info!("Twilio notifications disabled");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut config = TwilioWebHook::default();
|
||||
|
||||
for pair in config_var.unwrap().split(',') {
|
||||
let nv: Vec<_> = pair.split('=').collect();
|
||||
if nv.len() != 2 {
|
||||
return Err(format!("TWILIO_CONFIG is invalid: '{}'", pair));
|
||||
}
|
||||
let v = nv[1].to_string();
|
||||
match nv[0] {
|
||||
"ACCOUNT" => config.account = v,
|
||||
"TOKEN" => config.token = v,
|
||||
"TO" => config.to = v,
|
||||
"FROM" => config.from = v,
|
||||
_ => return Err(format!("TWILIO_CONFIG is invalid: '{}'", pair)),
|
||||
}
|
||||
}
|
||||
|
||||
if !config.complete() {
|
||||
return Err("TWILIO_CONFIG is incomplete".to_string());
|
||||
}
|
||||
Ok(Some(config))
|
||||
}
|
||||
|
||||
pub struct Notifier {
|
||||
client: Client,
|
||||
discord_webhook: Option<String>,
|
||||
slack_webhook: Option<String>,
|
||||
telegram_webhook: Option<TelegramWebHook>,
|
||||
twilio_webhook: Option<TwilioWebHook>,
|
||||
}
|
||||
|
||||
impl Notifier {
|
||||
pub fn new() -> Self {
|
||||
Self::new_with_env_prefix("")
|
||||
}
|
||||
|
||||
pub fn new_with_env_prefix(env_prefix: &str) -> Self {
|
||||
info!("Initializing {}Notifier", env_prefix);
|
||||
|
||||
let discord_webhook = env::var(format!("{}DISCORD_WEBHOOK", env_prefix))
|
||||
.map_err(|_| {
|
||||
info!("Discord notifications disabled");
|
||||
})
|
||||
.ok();
|
||||
let slack_webhook = env::var(format!("{}SLACK_WEBHOOK", env_prefix))
|
||||
.map_err(|_| {
|
||||
info!("Slack notifications disabled");
|
||||
})
|
||||
.ok();
|
||||
|
||||
let telegram_webhook = if let (Ok(bot_token), Ok(chat_id)) = (
|
||||
env::var(format!("{}TELEGRAM_BOT_TOKEN", env_prefix)),
|
||||
env::var(format!("{}TELEGRAM_CHAT_ID", env_prefix)),
|
||||
) {
|
||||
Some(TelegramWebHook { bot_token, chat_id })
|
||||
} else {
|
||||
info!("Telegram notifications disabled");
|
||||
None
|
||||
};
|
||||
let twilio_webhook = get_twilio_config()
|
||||
.map_err(|err| panic!("Twilio config error: {}", err))
|
||||
.unwrap();
|
||||
|
||||
Notifier {
|
||||
client: Client::new(),
|
||||
discord_webhook,
|
||||
slack_webhook,
|
||||
telegram_webhook,
|
||||
twilio_webhook,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, msg: &str) {
|
||||
if let Some(webhook) = &self.discord_webhook {
|
||||
let data = json!({ "content": msg });
|
||||
if let Err(err) = self.client.post(webhook).json(&data).send() {
|
||||
warn!("Failed to send Discord message: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(webhook) = &self.slack_webhook {
|
||||
let data = json!({ "text": msg });
|
||||
if let Err(err) = self.client.post(webhook).json(&data).send() {
|
||||
warn!("Failed to send Slack message: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(TelegramWebHook { chat_id, bot_token }) = &self.telegram_webhook {
|
||||
let data = json!({ "chat_id": chat_id, "text": msg });
|
||||
let url = format!("https://api.telegram.org/bot{}/sendMessage", bot_token);
|
||||
|
||||
if let Err(err) = self.client.post(&url).json(&data).send() {
|
||||
warn!("Failed to send Telegram message: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(TwilioWebHook {
|
||||
account,
|
||||
token,
|
||||
to,
|
||||
from,
|
||||
}) = &self.twilio_webhook
|
||||
{
|
||||
let url = format!(
|
||||
"https://{}:{}@api.twilio.com/2010-04-01/Accounts/{}/Messages.json",
|
||||
account, token, account
|
||||
);
|
||||
let params = [("To", to), ("From", from), ("Body", &msg.to_string())];
|
||||
if let Err(err) = self.client.post(&url).form(¶ms).send() {
|
||||
warn!("Failed to send Twilio message: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user