-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
last_commit:50f1df9c67467914f1f5267cc92f48472e2001e6
- Loading branch information
GVE Devnet Admin
committed
Mar 8, 2024
0 parents
commit 50159f8
Showing
15 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
LINE_CHANNEL_ACCESS_TOKEN=12345678 | ||
LINE_CHANNEL_SECRET=12345678 | ||
CERTIFICATE=/path/to/fullchain.pem | ||
PRIVATE_KEY=/path/to/privkey.pem |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
name: Docker Build & Publish | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
- master | ||
tags: | ||
- '*' | ||
|
||
env: | ||
REGISTRY: ghcr.io | ||
IMAGE_NAME: ${{ github.repository }} | ||
|
||
|
||
jobs: | ||
push: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
packages: write | ||
contents: read | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v3 | ||
|
||
- name: Setup Docker buildx | ||
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf | ||
|
||
- name: Log into registry ${{ env.REGISTRY }} | ||
if: github.event_name != 'pull_request' | ||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c | ||
with: | ||
registry: ${{ env.REGISTRY }} | ||
username: ${{ github.actor }} | ||
password: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Extract Docker metadata | ||
id: meta | ||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 | ||
with: | ||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | ||
|
||
- name: Build and push Docker image | ||
id: build-and-push | ||
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a | ||
with: | ||
context: . | ||
push: ${{ github.event_name != 'pull_request' }} | ||
tags: ${{ steps.meta.outputs.tags }} | ||
labels: ${{ steps.meta.outputs.labels }} | ||
cache-from: type=gha | ||
cache-to: type=gha,mode=max |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.env | ||
*.pem | ||
telinebotvenv/ | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
FROM python:3.9-slim-buster | ||
WORKDIR /app | ||
COPY ./requirements.txt /app | ||
|
||
# Modify the example paths to pem files for setting up SSL | ||
COPY ${CERTIFICATE} /var/servercredentials/ | ||
COPY ${PRIVATE_KEY} /var/servercredentials/ | ||
ENV CERTIFICATE=/var/servercredentials/fullchain.pem | ||
ENV PRIVATE_KEY=/var/servercredentials/privkey.pem | ||
|
||
RUN pip install -r requirements.txt | ||
COPY . . | ||
EXPOSE 5000 | ||
CMD ["python", "./bot_line.py"] |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# gve_devnet_thousandeyes_line_bot | ||
This repo is a flask server that receives ThousandEyes webhook alerts and re-format them to be sent to users via an official account on LINE. | ||
|
||
|
||
## Contacts | ||
* Kevin Chen | ||
|
||
## Solution Components | ||
* ThousandEyes | ||
|
||
|
||
## Installation/Configuration | ||
1. [Sign up](https://developers.line.biz/en/docs/basics/channel-access-token/) to LINE business account and acquire a channel access token and channel secret. | ||
2. Acquire an SSL certificate to enable HTTPS connection. LINE requires HTTPS for programatic access to its APIs. You can use a certificate from any Certificate Authority, for example [Let's Encrypt](https://letsencrypt.org/getting-started/) and save the certificate and private key files. | ||
3. Configure the environment variables shown below | ||
```python | ||
# Set environment variable in a .env file (see .env example) | ||
LINE_CHANNEL_ACCESS_TOKEN=12345678 | ||
LINE_CHANNEL_SECRET=12345678 | ||
CERTIFICATE=/path/to/fullchain.pem | ||
PRIVATE_KEY=/path/to/privkey.pem | ||
``` | ||
4. Set up a virtual environment and install dependencies | ||
``` | ||
python -m venv myvenv | ||
pip install -r requirements.txt | ||
``` | ||
5. Configure ThousandEyes webhook integration | ||
From your ThousandEyes dashboard, access the integrations page via the left nagivation pane. | ||
![navigation_pane.png](/IMAGES/TE_sidebar_scaled.png) | ||
|
||
Create a new integration by presseing the "New Integration" button. | ||
![navigation_pane.png](/IMAGES/TEdashboard.png) | ||
Select Custom Webhook and you can now configure the integration to point to your bot server. Put in the URL associated with your server and optionally select a preset configuration (generic is used for this example). | ||
|
||
![navigation_pane.png](/IMAGES/TEwebhookconfig.png) | ||
|
||
A basic configuration is shown in the screenshot above. The URL of the webhook server should be the IP address of your bot server or your custom domain. Select the generic preset and the following fields would be auto-filled with example headers and body. | ||
|
||
## Usage | ||
|
||
Run the app: | ||
|
||
``` | ||
python bot_line.py | ||
``` | ||
NOTE: the app may require sudo permissions to run | ||
|
||
Once the server is running, to register for an alert from ThousandEyes, the user must first add the official account created above, and send a message to the bot. The bot will inform the user that they are now subscribed to ThousandEyes alerts. Now all future ThousandEyes alerts will be forwarded to that user. Multiple users can be added at the same time, however if the server is restarted, the users must re-register with the bot by sending a new subscribe message. | ||
![chat_demo.png](IMAGES/chat_demo.png) | ||
# Screenshots | ||
|
||
The bot requires channel access token to authenticate with LINE's servers. | ||
![line_app_diagram.png](IMAGES/line_app_diagram.png) | ||
|
||
# Docker | ||
This repo contains a dockerfile, which can be used to create an image to run this app in a Docker container. Please provide the full path to fullchain.pem and privkey.pem in the .env file before running the dockerfile. | ||
|
||
### LICENSE | ||
|
||
Provided under Cisco Sample Code License, for details see [LICENSE](LICENSE.md) | ||
|
||
### CODE_OF_CONDUCT | ||
|
||
Our code of conduct is available [here](CODE_OF_CONDUCT.md) | ||
|
||
### CONTRIBUTING | ||
|
||
See our contributing guidelines [here](CONTRIBUTING.md) | ||
|
||
#### DISCLAIMER: | ||
<b>Please note:</b> This script is meant for demo purposes only. All tools/ scripts in this repo are released for use "AS IS" without any warranties of any kind, including, but not limited to their installation, use, or performance. Any use of these scripts and tools is at your own risk. There is no guarantee that they have been through thorough testing in a comparable environment and we are not responsible for any damage or data loss incurred with their use. | ||
You are responsible for reviewing and testing any scripts you run thoroughly before use in any non-testing environment. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
""" | ||
Copyright (c) 2024 Cisco and/or its affiliates. | ||
This software is licensed to you under the terms of the Cisco Sample | ||
Code License, Version 1.1 (the "License"). You may obtain a copy of the | ||
License at | ||
https://developer.cisco.com/docs/licenses | ||
All use of the material herein must be in accordance with the terms of | ||
the License. All rights not expressly granted by the License are | ||
reserved. Unless required by applicable law or agreed to separately 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. | ||
""" | ||
|
||
|
||
import os | ||
import sys | ||
import json | ||
from argparse import ArgumentParser | ||
|
||
from flask import Flask, request, abort | ||
from linebot.v3 import ( | ||
WebhookHandler | ||
) | ||
from linebot.v3.exceptions import ( | ||
InvalidSignatureError | ||
) | ||
from linebot.v3.webhooks import ( | ||
MessageEvent, | ||
TextMessageContent, | ||
) | ||
from linebot.v3.messaging import ( | ||
Configuration, | ||
ApiClient, | ||
MessagingApi, | ||
ReplyMessageRequest, | ||
TextMessage, | ||
PushMessageRequest | ||
) | ||
|
||
from dotenv import load_dotenv | ||
|
||
load_dotenv() | ||
user_ids = [] | ||
|
||
app = Flask(__name__) | ||
|
||
# get channel_secret and channel_access_token from your environment variable | ||
channel_secret = os.environ.get('LINE_CHANNEL_SECRET') | ||
channel_access_token = os.environ.get('LINE_CHANNEL_ACCESS_TOKEN') | ||
if channel_secret is None: | ||
print('Specify LINE_CHANNEL_SECRET as environment variable.') | ||
sys.exit(1) | ||
if channel_access_token is None: | ||
print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.') | ||
sys.exit(1) | ||
|
||
handler = WebhookHandler(channel_secret) | ||
|
||
configuration = Configuration( | ||
access_token=channel_access_token | ||
) | ||
|
||
|
||
def parse_alert(alert_body): | ||
alert_id = alert_body['alert']['id'] | ||
alert_name = alert_body['alert']['test']['name'] | ||
alert_domain = alert_body['alert']['targets'] | ||
alert_rule = alert_body['alert']["rule"]["expression"] | ||
alert_details = len(alert_body["alert"]["details"]) | ||
alert_message = "alert id: " + \ | ||
str(alert_id) + "\nalert name: " + str(alert_name) + "\nalert domain: " + str(alert_domain) + \ | ||
"\nalert rule: " + str(alert_rule) + \ | ||
"\nalert details: " + str(alert_details) | ||
return alert_message | ||
|
||
|
||
@app.route("/", methods=['POST']) | ||
def verifyServer(): | ||
# test webhook endpoint | ||
return 'OK' | ||
|
||
|
||
@app.route("/te_alerts", methods=['POST']) | ||
def receive_te_alerts(): | ||
alert_body = request.get_json() | ||
alert_message = parse_alert(alert_body) | ||
print("received webhook from TE.") | ||
for user in user_ids: | ||
with ApiClient(configuration) as api_client: | ||
line_bot_api = MessagingApi(api_client) | ||
line_bot_api.push_message(PushMessageRequest( | ||
to=str(user), messages=[TextMessage(text=alert_message)])) | ||
|
||
return 'OK' | ||
|
||
|
||
@ app.route("/callback", methods=['POST']) | ||
def callback(): | ||
# get X-Line-Signature header value | ||
signature = request.headers['X-Line-Signature'] | ||
|
||
# get request body as text | ||
body = request.get_data(as_text=True) | ||
app.logger.info("Request body: " + body) | ||
print(body) | ||
|
||
# handle webhook body | ||
try: | ||
handler.handle(body, signature) | ||
except InvalidSignatureError: | ||
abort(400) | ||
|
||
return 'OK' | ||
|
||
|
||
@ handler.add(MessageEvent, message=TextMessageContent) | ||
def message_text(event): | ||
with ApiClient(configuration) as api_client: | ||
line_bot_api = MessagingApi(api_client) | ||
line_bot_api.reply_message_with_http_info( | ||
ReplyMessageRequest( | ||
reply_token=event.reply_token, | ||
messages=[TextMessage( | ||
text="you are now subscribed to ThousandEyes Alert")] | ||
) | ||
) | ||
user_ids.append(event.source.user_id) | ||
# line_bot_api.push_message(PushMessageRequest( | ||
# to=event.source.user_id, messages=[TextMessage(text="TE Alerts")])) | ||
|
||
|
||
if __name__ == "__main__": | ||
arg_parser = ArgumentParser( | ||
usage='Usage: python ' + __file__ + ' [--port <port>] [--help]' | ||
) | ||
arg_parser.add_argument('-p', '--port', default=5100, help='port') | ||
arg_parser.add_argument('-d', '--debug', default=False, help='debug') | ||
options = arg_parser.parse_args() | ||
|
||
app.run(host='0.0.0.0', debug=options.debug, port=options.port, ssl_context=( | ||
os.environ.get("CERTIFICATE"), os.environ.get("PRIVATE_KEY"))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
version: "3.5" | ||
|
||
services: | ||
line-bot: | ||
container_name: line_bot_server | ||
# environment: | ||
volumes: | ||
- /usr/src/app | ||
command: python bot_line.py | ||
build: | ||
context: . | ||
|
||
restart: "always" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
aenum==3.1.15 | ||
aiohttp==3.9.1 | ||
aiosignal==1.3.1 | ||
annotated-types==0.6.0 | ||
async-timeout==4.0.3 | ||
attrs==23.2.0 | ||
autopep8==2.0.4 | ||
blinker==1.7.0 | ||
certifi==2023.11.17 | ||
chardet==3.0.4 | ||
charset-normalizer==3.3.2 | ||
click==8.1.7 | ||
colorful==0.5.6 | ||
Deprecated==1.2.14 | ||
Flask==3.0.1 | ||
frozenlist==1.4.1 | ||
future==0.18.3 | ||
gunicorn==20.0.4 | ||
idna==2.10 | ||
itsdangerous==2.1.2 | ||
Jinja2==3.1.3 | ||
line-bot-sdk==3.7.0 | ||
MarkupSafe==2.1.4 | ||
multidict==6.0.4 | ||
pi==0.1.2 | ||
prettyprinter==0.18.0 | ||
pycodestyle==2.11.1 | ||
pydantic==2.5.3 | ||
pydantic_core==2.14.6 | ||
Pygments==2.17.2 | ||
PyJWT==2.8.0 | ||
python-dateutil==2.8.2 | ||
python-dotenv==1.0.1 | ||
PyYAML==5.3.1 | ||
requests==2.31.0 | ||
requests-toolbelt==1.0.0 | ||
six==1.16.0 | ||
tomli==2.0.1 | ||
typing_extensions==4.9.0 | ||
urllib3==2.1.0 | ||
webexteamssdk==1.6 | ||
Werkzeug==3.0.1 | ||
wrapt==1.16.0 | ||
yarl==1.9.4 |