This is an automated email from the ASF dual-hosted git repository.
gongchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new 9fd58ced4a [feature] add twilio sms client support (#3159)
9fd58ced4a is described below
commit 9fd58ced4a0371eb0ab73f248f857e5add83c175
Author: Sarthak Arora <[email protected]>
AuthorDate: Sat Mar 22 11:42:32 2025 +0530
[feature] add twilio sms client support (#3159)
Co-authored-by: yunfan24 <[email protected]>
Co-authored-by: tomsun28 <[email protected]>
---
.../apache/hertzbeat/alert/config/SmsConfig.java | 6 +
.../{SmsConfig.java => TwilioSmsProperties.java} | 44 ++----
.../hertzbeat/alert/service/SmsClientFactory.java | 7 +-
.../alert/service/impl/TwilioSmsClientImpl.java | 171 +++++++++++++++++++++
.../alert/service/TwilioSmsClientImplTest.java | 64 ++++++++
.../hertzbeat/common/constants/SmsConstants.java | 3 +
.../src/main/resources/application.yml | 4 +
home/docs/help/alert_sms.md | 46 ++++++
script/application.yml | 4 +
.../hertzbeat-mysql-iotdb/conf/application.yml | 4 +
.../hertzbeat-mysql-tdengine/conf/application.yml | 4 +
.../conf/application.yml | 4 +
.../conf/application.yml | 4 +
web-app/src/app/pojo/SmsNoticeSender.ts | 2 +
.../{enums/sms-type.enum.ts => TwilioSmsConfig.ts} | 15 +-
web-app/src/app/pojo/enums/sms-type.enum.ts | 3 +-
.../message-server/message-server.component.html | 48 ++++++
.../message-server/message-server.component.ts | 8 +-
web-app/src/assets/i18n/en-US.json | 4 +
web-app/src/assets/i18n/ja-JP.json | 4 +
web-app/src/assets/i18n/zh-CN.json | 4 +
web-app/src/assets/i18n/zh-TW.json | 3 +
22 files changed, 408 insertions(+), 48 deletions(-)
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/SmsConfig.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/SmsConfig.java
index ded6348674..3ceb6deb78 100644
---
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/SmsConfig.java
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/SmsConfig.java
@@ -64,6 +64,12 @@ public class SmsConfig {
* Aws configuration
*/
private AwsSmsProperties aws;
+
+ /**
+ * Twilio SMS configuration
+ */
+ private TwilioSmsProperties twilio;
+
/**
* Smslocal SMS configuration
*/
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/SmsConfig.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/TwilioSmsProperties.java
similarity index 56%
copy from
hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/SmsConfig.java
copy to
hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/TwilioSmsProperties.java
index ded6348674..26c74bfd9b 100644
---
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/SmsConfig.java
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/config/TwilioSmsProperties.java
@@ -21,51 +21,29 @@ import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
/**
- * SMS configuration
+ * Twilio SMS configuration properties
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
-@Component
-@ConfigurationProperties(prefix = "alerter.sms")
-public class SmsConfig {
-
- /**
- * whether to enable SMS, default is false
- */
- private boolean enable = false;
-
- /**
- * sms service provider
- */
- @NotBlank(message = "Type cannot be empty")
- private String type;
-
- /**
- * Tencent cloud SMS configuration
- */
- private TencentSmsProperties tencent;
-
+public class TwilioSmsProperties {
/**
- * Aliyun SMS configuration
+ * Twilio Account SID
*/
- private AlibabaSmsProperties alibaba;
+ @NotBlank(message = "Account SID cannot be empty")
+ private String accountSid;
/**
- * UniSMS configuration
+ * Twilio Auth Token
*/
- private UniSmsProperties unisms;
+ @NotBlank(message = "Auth Token cannot be empty")
+ private String authToken;
/**
- * Aws configuration
- */
- private AwsSmsProperties aws;
- /**
- * Smslocal SMS configuration
+ * Twilio Issued Phone Number
*/
- private SmslocalSmsProperties smslocal;
+ @NotBlank(message = "Twilio Phone Number cannot be empty")
+ private String twilioPhoneNumber;
}
\ No newline at end of file
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/SmsClientFactory.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/SmsClientFactory.java
index 1e42299ea6..50aebbf9dc 100644
---
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/SmsClientFactory.java
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/SmsClientFactory.java
@@ -23,6 +23,7 @@ import org.apache.hertzbeat.alert.config.SmsConfig;
import org.apache.hertzbeat.alert.service.impl.SmsLocalSmsClientImpl;
import org.apache.hertzbeat.alert.service.impl.AwsSmsClientImpl;
import org.apache.hertzbeat.alert.service.impl.TencentSmsClientImpl;
+import org.apache.hertzbeat.alert.service.impl.TwilioSmsClientImpl;
import org.apache.hertzbeat.alert.service.impl.UniSmsClientImpl;
import org.apache.hertzbeat.alert.service.impl.AlibabaSmsClientImpl;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
@@ -35,6 +36,7 @@ import org.springframework.stereotype.Component;
import static org.apache.hertzbeat.common.constants.SmsConstants.ALIBABA;
import static org.apache.hertzbeat.common.constants.SmsConstants.AWS;
import static org.apache.hertzbeat.common.constants.SmsConstants.TENCENT;
+import static org.apache.hertzbeat.common.constants.SmsConstants.TWILIO;
import static org.apache.hertzbeat.common.constants.SmsConstants.UNISMS;
import static org.apache.hertzbeat.common.constants.SmsConstants.SMSLOCAL;
@@ -141,9 +143,12 @@ public class SmsClientFactory {
case AWS:
currentSmsClient = new AwsSmsClientImpl(smsConfig.getAws());
break;
+ case TWILIO:
+ currentSmsClient = new
TwilioSmsClientImpl(smsConfig.getTwilio());
+ break;
default:
log.warn("[SmsClientFactory] Unsupported SMS provider type:
{}", smsConfig.getType());
break;
}
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git
a/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/TwilioSmsClientImpl.java
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/TwilioSmsClientImpl.java
new file mode 100644
index 0000000000..5a6ba033f6
--- /dev/null
+++
b/hertzbeat-alerter/src/main/java/org/apache/hertzbeat/alert/service/impl/TwilioSmsClientImpl.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.hertzbeat.alert.service.impl;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hertzbeat.alert.config.TwilioSmsProperties;
+import org.apache.hertzbeat.alert.service.SmsClient;
+import org.apache.hertzbeat.common.entity.alerter.GroupAlert;
+import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
+import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
+import org.apache.hertzbeat.common.support.exception.SendMessageException;
+import org.apache.hertzbeat.common.util.JsonUtil;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+
+import static org.apache.hertzbeat.common.constants.SmsConstants.TWILIO;
+
+/**
+ * Twilio SMS Client Implementation<br>
+ * API doc: <a href=
+ *
"https://www.twilio.com/docs/sms/api">https://www.twilio.com/docs/sms/api</a>
+ */
+@Slf4j
+public class TwilioSmsClientImpl implements SmsClient {
+
+ private static final String API_URL_FORMAT =
"https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json";
+ private static final String MESSAGE_TEMPLATE = "Instance: %s, Priority:
%s, Content: %s";
+
+ private final String accountSid;
+ private final String authToken;
+ private final String twilioPhoneNumber;
+
+ public TwilioSmsClientImpl(TwilioSmsProperties config) {
+ if (config != null) {
+ this.accountSid = config.getAccountSid();
+ this.authToken = config.getAuthToken();
+ this.twilioPhoneNumber = config.getTwilioPhoneNumber();
+ } else {
+ this.accountSid = "";
+ this.authToken = "";
+ this.twilioPhoneNumber = "";
+ }
+ }
+
+ @Override
+ public void sendMessage(NoticeReceiver receiver, NoticeTemplate
noticeTemplate, GroupAlert alert) {
+ String instance = null;
+ String priority = null;
+ String content = null;
+ if (alert.getCommonLabels() != null) {
+ instance = alert.getCommonLabels().get("instance") == null ?
alert.getGroupKey()
+ : alert.getCommonLabels().get("instance");
+ priority = alert.getCommonLabels().get("priority") == null ?
"unknown"
+ : alert.getCommonLabels().get("priority");
+ content = alert.getCommonAnnotations().get("summary");
+ content = content == null ?
alert.getCommonAnnotations().get("description") : content;
+ if (content == null) {
+ content =
alert.getCommonAnnotations().values().stream().findFirst().orElse(null);
+ }
+ }
+ this.send(receiver.getPhone(), createMessage(instance, priority,
content));
+ }
+
+ private String createMessage(String instance, String priority, String
content) {
+ return String.format(MESSAGE_TEMPLATE, instance, priority, content);
+ }
+
+ private void send(String phoneNumber, String message) {
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ String endpoint = String.format(API_URL_FORMAT, accountSid);
+ URI requestUri = new URI(endpoint);
+
+ HttpPost httpPost = createHttpPost(requestUri, phoneNumber,
message);
+ log.info("Sending Twilio SMS request to {}", requestUri);
+ executeRequest(httpClient, httpPost, phoneNumber);
+ } catch (Exception e) {
+ log.warn("Failed to send SMS: {}", e.getMessage());
+ throw new SendMessageException(e.getMessage());
+ }
+ }
+
+ private HttpPost createHttpPost(URI requestUri, String toNumber, String
message) {
+ HttpPost httpPost = new HttpPost(requestUri);
+
+ String auth = accountSid + ":" + authToken;
+ String encodedAuth =
Base64.getEncoder().encodeToString(auth.getBytes());
+ httpPost.setHeader("Authorization", "Basic " + encodedAuth);
+
+ List<BasicNameValuePair> parameters = new ArrayList<>();
+ parameters.add(new BasicNameValuePair("To", toNumber));
+ parameters.add(new BasicNameValuePair("From", twilioPhoneNumber));
+ parameters.add(new BasicNameValuePair("Body", message));
+
+ try {
+ httpPost.setEntity(new UrlEncodedFormEntity(parameters));
+ return httpPost;
+ } catch (Exception e) {
+ log.error("Failed to create HTTP request: {}", e.getMessage());
+ throw new SendMessageException(e.getMessage());
+ }
+ }
+
+ private void executeRequest(CloseableHttpClient httpClient, HttpPost
httpPost, String phoneNumber)
+ throws Exception {
+ try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+ int statusCode = response.getStatusLine().getStatusCode();
+ String responseBody = EntityUtils.toString(response.getEntity());
+ log.info("SMS response status: {}, body: {}", statusCode,
responseBody);
+
+ if (statusCode < 200 || statusCode >= 300) {
+
+ if (responseBody.contains("21608")) {
+ throw new SendMessageException(
+ "The Twilio trial account can only send SMS to
verified phone numbers");
+ } else {
+ throw new SendMessageException(
+ "HTTP request failed with status code: " +
statusCode + ", response: " + responseBody);
+ }
+ }
+
+ JsonNode jsonResponse = JsonUtil.fromJson(responseBody);
+ if (jsonResponse == null) {
+ throw new SendMessageException(statusCode + ":" +
responseBody);
+ }
+
+ JsonNode sidNode = jsonResponse.get("sid");
+ if (sidNode == null) {
+ throw new SendMessageException(statusCode + ":" +
responseBody);
+ }
+
+ String sid = sidNode.asText();
+ log.info("Successfully sent SMS to phone: {}, sid: {}",
phoneNumber, sid);
+ }
+ }
+
+ @Override
+ public String getType() {
+ return TWILIO;
+ }
+
+ @Override
+ public boolean checkConfig() {
+ return !(accountSid.isBlank() || authToken.isBlank() ||
twilioPhoneNumber.isBlank());
+ }
+}
\ No newline at end of file
diff --git
a/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/TwilioSmsClientImplTest.java
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/TwilioSmsClientImplTest.java
new file mode 100644
index 0000000000..2c32417ea8
--- /dev/null
+++
b/hertzbeat-alerter/src/test/java/org/apache/hertzbeat/alert/service/TwilioSmsClientImplTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.hertzbeat.alert.service;
+
+import org.apache.hertzbeat.alert.config.TwilioSmsProperties;
+import org.apache.hertzbeat.alert.service.impl.TwilioSmsClientImpl;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Test case for {@link TwilioSmsClientImpl}
+ */
+class TwilioSmsClientImplTest {
+
+ @Test
+ void getType() {
+ TwilioSmsProperties twilioSmsProperties = new TwilioSmsProperties();
+ twilioSmsProperties.setAccountSid("accountSid");
+ twilioSmsProperties.setAuthToken("authToken");
+ twilioSmsProperties.setTwilioPhoneNumber("twilioPhoneNumber");
+ TwilioSmsClientImpl twilioSmsClient = new
TwilioSmsClientImpl(twilioSmsProperties);
+
+ assertEquals("twilio", twilioSmsClient.getType());
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ "accountSid, authToken, twilioPhoneNumber, true",
+ "accountSid, authToken, '', false",
+ "accountSid, '', twilioPhoneNumber, false",
+ "accountSid, '', '', false",
+ "'', authToken, twilioPhoneNumber, false",
+ "'', authToken, '', false",
+ "'', '', twilioPhoneNumber, false",
+ "'', '', '', false",
+ })
+ void checkConfig(String accountSid, String authToken, String
twilioPhoneNumber, boolean expected) {
+ TwilioSmsProperties twilioSmsProperties = new TwilioSmsProperties();
+ twilioSmsProperties.setAccountSid(accountSid);
+ twilioSmsProperties.setAuthToken(authToken);
+ twilioSmsProperties.setTwilioPhoneNumber(twilioPhoneNumber);
+ TwilioSmsClientImpl twilioSmsClient = new
TwilioSmsClientImpl(twilioSmsProperties);
+
+ assertEquals(expected, twilioSmsClient.checkConfig());
+ }
+}
\ No newline at end of file
diff --git
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/SmsConstants.java
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/SmsConstants.java
index 16e0234a86..7929035562 100644
---
a/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/SmsConstants.java
+++
b/hertzbeat-common/src/main/java/org/apache/hertzbeat/common/constants/SmsConstants.java
@@ -35,4 +35,7 @@ public interface SmsConstants {
// Aws cloud SMS
String AWS = "aws";
+
+ // Twilio SMS
+ String TWILIO = "twilio";
}
diff --git a/hertzbeat-manager/src/main/resources/application.yml
b/hertzbeat-manager/src/main/resources/application.yml
index 10341c84ab..5839bf6dda 100644
--- a/hertzbeat-manager/src/main/resources/application.yml
+++ b/hertzbeat-manager/src/main/resources/application.yml
@@ -231,6 +231,10 @@ alerter:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
+ twilio:
+ account-sid: YOUR_ACCOUNT_SID
+ auth-token: YOUR_AUTH_TOKEN
+ twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
diff --git a/home/docs/help/alert_sms.md b/home/docs/help/alert_sms.md
index 63fc55400a..317cd9e322 100644
--- a/home/docs/help/alert_sms.md
+++ b/home/docs/help/alert_sms.md
@@ -225,6 +225,52 @@ alerter:
Now you can configure this information in your hertzbeat application.
+### Twilio SMS Configuration
+
+To activate and use the Twilio SMS service, refer to the official Twilio
documentation: [SMS Getting Started
Guide](https://www.twilio.com/docs/sms/quickstart)
+
+You can configure the Twilio SMS service either through the graphical
interface or in the `application.yml` file.
+To use `application.yml`, add/fill in the following Twilio SMS configuration
(replace parameters with your own SMS server configuration):
+
+```yaml
+alerter:
+ sms:
+ enable: true # Whether to enable
+ type: twilio # SMS provider type, supports "twilio"
+ twilio: # Twilio SMS configuration
+ account-sid: # Your Twilio Account SID
+ auth-token: # Your Twilio Auth Token
+ twilio-phone-number: # Your Twilio Phone Number
+```
+
+1. Create a Twilio account
+
+ - If you don't have a Twilio account, sign up at [Twilio
Console](https://www.twilio.com/console)
+ - You'll get a free trial account that allows you to test the SMS service
+
+2. Obtain Twilio credentials
+
+ - After signing in, locate your Account SID and Auth Token on the
dashboard
+ - These credentials will be used to authenticate API requests
+
+3. Get a Twilio Phone Number
+
+ - In the Twilio Console, navigate to "Phone Numbers" > "Manage" >
"Active Numbers"
+ - Click "Buy a Number" or use the trial number provided by Twilio
+ - Make sure the number has SMS capabilities enabled
+ - This number will be used as the sender for your SMS alerts
+ - A phone number is required for the Twilio SMS service to work
+
+4. Testing Your Configuration on Twilio
+
+ - Twilio provides a sandbox environment for testing
+ - If you are in the trial period, you will only be able to send SMS to
verified phone numbers
+ - To verify a phone number, add it to your verified phone numbers list
in the Twilio Console
+
+ > The message follows the format: "Instance: {}, Priority: {}, Content:
{}"
+
+ This information can be configured in the Hertzbeat application.
+
## Operation steps
1. **【Alarm notification】->【Add new recipient】 ->【Select SMS notification
method】**
diff --git a/script/application.yml b/script/application.yml
index e79f661b46..b52a1b4d22 100644
--- a/script/application.yml
+++ b/script/application.yml
@@ -230,6 +230,10 @@ alerter:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
+ twilio:
+ account-sid: YOUR_ACCOUNT_SID
+ auth-token: YOUR_AUTH_TOKEN
+ twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
diff --git a/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
b/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
index 4e46efaf4f..e0f4787cf6 100644
--- a/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
+++ b/script/docker-compose/hertzbeat-mysql-iotdb/conf/application.yml
@@ -197,6 +197,10 @@ alerter:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
+ twilio:
+ account-sid: YOUR_ACCOUNT_SID
+ auth-token: YOUR_AUTH_TOKEN
+ twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
diff --git
a/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
b/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
index 7fa65f3159..5552637a1b 100644
--- a/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
+++ b/script/docker-compose/hertzbeat-mysql-tdengine/conf/application.yml
@@ -193,6 +193,10 @@ alerter:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
+ twilio:
+ account-sid: YOUR_ACCOUNT_SID
+ auth-token: YOUR_AUTH_TOKEN
+ twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
diff --git
a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
index 249af2cdc0..bb09bf75d1 100644
---
a/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
+++
b/script/docker-compose/hertzbeat-mysql-victoria-metrics/conf/application.yml
@@ -191,6 +191,10 @@ alerter:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
+ twilio:
+ account-sid: YOUR_ACCOUNT_SID
+ auth-token: YOUR_AUTH_TOKEN
+ twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
diff --git
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
index 9388e078b7..647ad882d8 100644
---
a/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
+++
b/script/docker-compose/hertzbeat-postgresql-victoria-metrics/conf/application.yml
@@ -190,6 +190,10 @@ alerter:
access-key-id: YOUR_ACCESS_KEY_ID
access-key-secret: YOUR_ACCESS_KEY_SECRET
region: AWS_REGION_FOR_END_USER_MESSAGING
+ twilio:
+ account-sid: YOUR_ACCOUNT_SID
+ auth-token: YOUR_AUTH_TOKEN
+ twilio-phone-number: YOUR_TWILIO_PHONE_NUMBER
scheduler:
server:
enabled: true
diff --git a/web-app/src/app/pojo/SmsNoticeSender.ts
b/web-app/src/app/pojo/SmsNoticeSender.ts
index d3d4f2c049..759502b2aa 100644
--- a/web-app/src/app/pojo/SmsNoticeSender.ts
+++ b/web-app/src/app/pojo/SmsNoticeSender.ts
@@ -21,6 +21,7 @@ import { AlibabaSmsConfig } from './AlibabaSmsConfig';
import { AwsSmsConfig } from './AwsSmsConfig';
import { SmslocalSmsConfig } from './SmslocalSmsConfig';
import { TencentSmsConfig } from './TencentSmsConfig';
+import { TwilioSmsConfig } from './TwilioSmsConfig';
import { UniSmsConfig } from './UniSmsConfig';
import { SmsType } from './enums/sms-type.enum';
@@ -32,6 +33,7 @@ export class SmsNoticeSender {
unisms: UniSmsConfig = new UniSmsConfig();
smslocal: SmslocalSmsConfig = new SmslocalSmsConfig();
aws: AwsSmsConfig = new AwsSmsConfig();
+ twilio: TwilioSmsConfig = new TwilioSmsConfig();
enable: boolean = false;
creator!: string;
modifier!: string;
diff --git a/web-app/src/app/pojo/enums/sms-type.enum.ts
b/web-app/src/app/pojo/TwilioSmsConfig.ts
similarity index 80%
copy from web-app/src/app/pojo/enums/sms-type.enum.ts
copy to web-app/src/app/pojo/TwilioSmsConfig.ts
index f62f40a0e1..4735885aa5 100644
--- a/web-app/src/app/pojo/enums/sms-type.enum.ts
+++ b/web-app/src/app/pojo/TwilioSmsConfig.ts
@@ -17,15 +17,8 @@
* under the License.
*/
-export enum SmsType {
- TENCENT = 'tencent',
- ALIBABA = 'alibaba',
- UNISMS = 'unisms',
- SMSLOCAL = 'smslocal',
- AWS = 'aws'
-}
-
-export enum UniSmsAuthMode {
- HMAC = 'hmac',
- SIMPLE = 'simple'
+export class TwilioSmsConfig {
+ accountSid!: string;
+ authToken!: string;
+ twilioPhoneNumber!: string;
}
diff --git a/web-app/src/app/pojo/enums/sms-type.enum.ts
b/web-app/src/app/pojo/enums/sms-type.enum.ts
index f62f40a0e1..95dba15349 100644
--- a/web-app/src/app/pojo/enums/sms-type.enum.ts
+++ b/web-app/src/app/pojo/enums/sms-type.enum.ts
@@ -22,7 +22,8 @@ export enum SmsType {
ALIBABA = 'alibaba',
UNISMS = 'unisms',
SMSLOCAL = 'smslocal',
- AWS = 'aws'
+ AWS = 'aws',
+ TWILIO = 'twilio'
}
export enum UniSmsAuthMode {
diff --git
a/web-app/src/app/routes/setting/settings/message-server/message-server.component.html
b/web-app/src/app/routes/setting/settings/message-server/message-server.component.html
index ad2db43370..a804f51547 100644
---
a/web-app/src/app/routes/setting/settings/message-server/message-server.component.html
+++
b/web-app/src/app/routes/setting/settings/message-server/message-server.component.html
@@ -72,6 +72,11 @@
<br />
{{ 'alert.notice.sender.sms.unisms.authMode' | i18n }}: {{
smsNoticeSender.unisms.authMode }}
</ng-container>
+ <ng-container *ngSwitchCase="SmsType.TWILIO">
+ {{ 'alert.notice.sender.sms.twilio.accountSid' | i18n }}: {{
smsNoticeSender.twilio.accountSid }}
+ <br />
+ {{ 'alert.notice.sender.sms.twilio.twilioPhoneNumber' | i18n }}:
{{ smsNoticeSender.twilio.twilioPhoneNumber }}
+ </ng-container>
</ng-container>
<br />
{{ 'common.enable' | i18n }}: {{ smsNoticeSender.enable ?
('common.yes' | i18n) : ('common.no' | i18n) }}
@@ -160,6 +165,7 @@
<nz-option [nzValue]="SmsType.UNISMS" nzLabel="{{
'alert.notice.sender.sms.type.unisms' | i18n }}"></nz-option>
<nz-option [nzValue]="SmsType.SMSLOCAL" nzLabel="{{
'alert.notice.sender.sms.type.smslocal' | i18n }}"></nz-option>
<nz-option [nzValue]="SmsType.AWS" nzLabel="{{
'alert.notice.sender.sms.type.aws' | i18n }}"></nz-option>
+ <nz-option [nzValue]="SmsType.TWILIO" nzLabel="{{
'alert.notice.sender.sms.type.twilio' | i18n }}"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
@@ -373,6 +379,48 @@
</nz-form-item>
</ng-container>
+ <!-- Twilio SMS -->
+ <ng-container *ngIf="smsType === SmsType.TWILIO">
+ <nz-form-item>
+ <nz-form-label [nzSpan]="7" nzFor="accountSid" nzRequired="true">
+ {{ 'alert.notice.sender.sms.twilio.accountSid' | i18n }}
+ </nz-form-label>
+ <nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' |
i18n">
+ <input
+ [(ngModel)]="smsNoticeSender.twilio.accountSid"
+ nz-input
+ required
+ name="accountSid"
+ type="password"
+ id="twilioAccountSid"
+ />
+ </nz-form-control>
+ </nz-form-item>
+ <nz-form-item>
+ <nz-form-label [nzSpan]="7" nzFor="authToken" nzRequired="true">
+ {{ 'alert.notice.sender.sms.twilio.authToken' | i18n }}
+ </nz-form-label>
+ <nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' |
i18n">
+ <input [(ngModel)]="smsNoticeSender.twilio.authToken" nz-input
required name="authToken" type="password" id="twilioAuthToken" />
+ </nz-form-control>
+ </nz-form-item>
+ <nz-form-item>
+ <nz-form-label [nzSpan]="7" nzFor="twilioPhoneNumber"
nzRequired="true">
+ {{ 'alert.notice.sender.sms.twilio.twilioPhoneNumber' | i18n }}
+ </nz-form-label>
+ <nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' |
i18n">
+ <input
+ [(ngModel)]="smsNoticeSender.twilio.twilioPhoneNumber"
+ nz-input
+ required
+ name="twilioPhoneNumber"
+ type="text"
+ id="twilioPhoneNumber"
+ />
+ </nz-form-control>
+ </nz-form-item>
+ </ng-container>
+
<nz-form-item>
<nz-form-label nzSpan="7" nzFor="smsEnable" nzRequired="true">{{
'common.enable' | i18n }}</nz-form-label>
<nz-form-control nzSpan="12">
diff --git
a/web-app/src/app/routes/setting/settings/message-server/message-server.component.ts
b/web-app/src/app/routes/setting/settings/message-server/message-server.component.ts
index 3989d14f21..c20b89cf68 100644
---
a/web-app/src/app/routes/setting/settings/message-server/message-server.component.ts
+++
b/web-app/src/app/routes/setting/settings/message-server/message-server.component.ts
@@ -33,6 +33,7 @@ import { SmsType, UniSmsAuthMode } from
'src/app/pojo/enums/sms-type.enum';
import { AwsSmsConfig } from '../../../../pojo/AwsSmsConfig';
import { EmailNoticeSender } from '../../../../pojo/EmailNoticeSender';
import { SmslocalSmsConfig } from '../../../../pojo/SmslocalSmsConfig';
+import { TwilioSmsConfig } from '../../../../pojo/TwilioSmsConfig';
import { GeneralConfigService } from
'../../../../service/general-config.service';
@Component({
@@ -146,6 +147,7 @@ export class MessageServerComponent implements OnInit {
this.smsNoticeSender.unisms = { ...new UniSmsConfig(),
...message.data.unisms };
this.smsNoticeSender.smslocal = { ...new SmslocalSmsConfig(),
...message.data.smslocal };
this.smsNoticeSender.aws = { ...new AwsSmsConfig(),
...message.data.aws };
+ this.smsNoticeSender.twilio = { ...new TwilioSmsConfig(),
...message.data.twilio };
this.smsType = message.data.type || 'tencent';
} else {
this.smsNoticeSender = new SmsNoticeSender();
@@ -171,7 +173,8 @@ export class MessageServerComponent implements OnInit {
alibaba: { ...this.smsNoticeSender.alibaba },
unisms: { ...this.smsNoticeSender.unisms },
smslocal: { ...this.smsNoticeSender.smslocal },
- aws: { ...this.smsNoticeSender.aws }
+ aws: { ...this.smsNoticeSender.aws },
+ twilio: { ...this.smsNoticeSender.twilio }
};
this.isSmsServerModalVisible = true;
}
@@ -184,7 +187,8 @@ export class MessageServerComponent implements OnInit {
alibaba: { ...this.tempSmsNoticeSender.alibaba },
unisms: { ...this.tempSmsNoticeSender.unisms },
smslocal: { ...this.tempSmsNoticeSender.smslocal },
- aws: { ...this.tempSmsNoticeSender.aws }
+ aws: { ...this.tempSmsNoticeSender.aws },
+ twilio: { ...this.tempSmsNoticeSender.twilio }
};
this.isSmsServerModalVisible = false;
}
diff --git a/web-app/src/assets/i18n/en-US.json
b/web-app/src/assets/i18n/en-US.json
index 8553bdfe31..f6b128fa39 100644
--- a/web-app/src/assets/i18n/en-US.json
+++ b/web-app/src/assets/i18n/en-US.json
@@ -158,12 +158,16 @@
"alert.notice.sender.sms.aws.accessKeyId": "Aws SMS AccessKeyId",
"alert.notice.sender.sms.aws.accessKeySecret": "Aws SMS AccessKeySecret",
"alert.notice.sender.sms.aws.region": "Aws Region",
+ "alert.notice.sender.sms.twilio.accountSid": "Twilio Account SID",
+ "alert.notice.sender.sms.twilio.authToken": "Twilio Auth Token",
+ "alert.notice.sender.sms.twilio.twilioPhoneNumber": "Twilio Phone Number",
"alert.notice.sender.sms.type": "Sms Type",
"alert.notice.sender.sms.type.alibaba": "Alibaba Sms",
"alert.notice.sender.sms.type.tencent": "Tencent Sms",
"alert.notice.sender.sms.type.unisms": "UniSMS",
"alert.notice.sender.sms.type.smslocal": "Smslocal Sms",
"alert.notice.sender.sms.type.aws": "Aws Sms",
+ "alert.notice.sender.sms.type.twilio": "Twilio Sms",
"alert.notice.template": "Notice Template",
"alert.notice.template.content": "Template Content",
"alert.notice.template.delete": "Delete Template",
diff --git a/web-app/src/assets/i18n/ja-JP.json
b/web-app/src/assets/i18n/ja-JP.json
index 3a849708fe..4f5df70163 100644
--- a/web-app/src/assets/i18n/ja-JP.json
+++ b/web-app/src/assets/i18n/ja-JP.json
@@ -158,12 +158,16 @@
"alert.notice.sender.sms.aws.accessKeyId": "Aws SMS AccessKeyId",
"alert.notice.sender.sms.aws.accessKeySecret": "Aws SMS AccessKeySecret",
"alert.notice.sender.sms.aws.region": "Aws Region",
+ "alert.notice.sender.sms.twilio.accountSid": "Twilio Account SID",
+ "alert.notice.sender.sms.twilio.authToken": "Twilio Auth Token",
+ "alert.notice.sender.sms.twilio.twilioPhoneNumber": "Twilio Phone Number",
"alert.notice.sender.sms.type": "SMSタイプ",
"alert.notice.sender.sms.type.alibaba": "Alibaba Sms",
"alert.notice.sender.sms.type.tencent": "Tencent Sms",
"alert.notice.sender.sms.type.unisms": "UniSMS",
"alert.notice.sender.sms.type.smslocal": "Smslocal Sms",
"alert.notice.sender.sms.type.aws": "Aws Sms",
+ "alert.notice.sender.sms.type.twilio": "Twilio Sms",
"alert.notice.template": "通知テンプレート",
"alert.notice.template.content": "テンプレート内容",
"alert.notice.template.delete": "テンプレートを削除",
diff --git a/web-app/src/assets/i18n/zh-CN.json
b/web-app/src/assets/i18n/zh-CN.json
index 4b24ed798d..bb382f071d 100644
--- a/web-app/src/assets/i18n/zh-CN.json
+++ b/web-app/src/assets/i18n/zh-CN.json
@@ -158,12 +158,16 @@
"alert.notice.sender.sms.aws.accessKeyId": "Aws SMS AccessKeyId",
"alert.notice.sender.sms.aws.accessKeySecret": "Aws SMS AccessKeySecret",
"alert.notice.sender.sms.aws.region": "Aws Region",
+ "alert.notice.sender.sms.twilio.accountSid": "Twilio Account SID",
+ "alert.notice.sender.sms.twilio.authToken": "Twilio Auth Token",
+ "alert.notice.sender.sms.twilio.twilioPhoneNumber": "Twilio Phone Number",
"alert.notice.sender.sms.type": "短信类型",
"alert.notice.sender.sms.type.alibaba": "阿里短信",
"alert.notice.sender.sms.type.tencent": "腾讯短信",
"alert.notice.sender.sms.type.unisms": "合一短信(UniSMS)",
"alert.notice.sender.sms.type.smslocal": "当地短信(Smslocal)",
"alert.notice.sender.sms.type.aws": "Aws Sms",
+ "alert.notice.sender.sms.type.twilio": "Twilio Sms",
"alert.notice.template": "通知模板",
"alert.notice.template.content": "模板内容",
"alert.notice.template.delete": "删除通知模板",
diff --git a/web-app/src/assets/i18n/zh-TW.json
b/web-app/src/assets/i18n/zh-TW.json
index 0dd6edc967..433274d281 100644
--- a/web-app/src/assets/i18n/zh-TW.json
+++ b/web-app/src/assets/i18n/zh-TW.json
@@ -158,6 +158,9 @@
"alert.notice.sender.sms.aws.accessKeyId": "Aws SMS AccessKeyId",
"alert.notice.sender.sms.aws.accessKeySecret": "Aws SMS AccessKeySecret",
"alert.notice.sender.sms.aws.region": "Aws Region",
+ "alert.notice.sender.sms.twilio.accountSid": "Twilio Account SID",
+ "alert.notice.sender.sms.twilio.authToken": "Twilio Auth Token",
+ "alert.notice.sender.sms.twilio.twilioPhoneNumber": "Twilio Phone Number",
"alert.notice.sender.sms.type": "騰訊類型",
"alert.notice.sender.sms.type.alibaba": "阿裏短訊",
"alert.notice.sender.sms.type.tencent": "騰訊短訊",
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]