diff options
author | clarkzjw <[email protected]> | 2023-02-24 00:51:04 -0800 |
---|---|---|
committer | clarkzjw <[email protected]> | 2023-02-24 00:51:04 -0800 |
commit | 4bb5cbdc16ecf5f6e5961373816d4c741d54ee51 (patch) | |
tree | ea85f216881bacb54f579cae9814e2f85aa1abe5 | |
parent | a9fb6f252553ae49a2ba372434073824babe31e4 (diff) | |
parent | 391abe42adf3bf065d9543ada068b696b00efdcd (diff) | |
download | swarm2fediverse-4bb5cbdc16ecf5f6e5961373816d4c741d54ee51.tar.gz |
Merge branch 'deploy/cicd'
added Dockerfile and docker-compose.yaml with krakend api gateway and
monitoring using influxdb and grafana dashboard
-rw-r--r-- | .dockerignore | 3 | ||||
-rw-r--r-- | Dockerfile | 11 | ||||
-rw-r--r-- | bot.py | 10 | ||||
-rw-r--r-- | config.ini.example | 7 | ||||
-rw-r--r-- | config.py | 11 | ||||
-rw-r--r-- | contrib/docker-compose.yaml | 47 | ||||
-rwxr-xr-x | contrib/influx/initdb.sh | 16 | ||||
-rw-r--r-- | contrib/krakend.json | 84 | ||||
-rw-r--r-- | dbstore/peewee_store.py | 2 | ||||
-rw-r--r-- | requirements.txt | 8 |
10 files changed, 179 insertions, 20 deletions
diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8a229dd --- /dev/null +++ b/.dockerignore | |||
@@ -0,0 +1,3 @@ | |||
1 | .venv/ | ||
2 | *.db | ||
3 | *.ini | ||
@@ -1 +1,10 @@ | |||
1 | FROM python:3 | 1 | FROM python:3.10 |
2 | |||
3 | WORKDIR /usr/src/app | ||
4 | |||
5 | COPY requirements.txt ./ | ||
6 | RUN pip install --no-cache-dir -r requirements.txt | ||
7 | |||
8 | COPY . . | ||
9 | |||
10 | CMD [ "python", "./bot.py" ] | ||
@@ -8,7 +8,7 @@ from config import BOT_TOKEN, TELEGRAM_WEBHOOK_URL, HEALTHCHECK_URL, FEDI_LOGIN_ | |||
8 | import uvicorn | 8 | import uvicorn |
9 | from starlette.applications import Starlette | 9 | from starlette.applications import Starlette |
10 | from starlette.requests import Request | 10 | from starlette.requests import Request |
11 | from starlette.responses import PlainTextResponse, Response | 11 | from starlette.responses import PlainTextResponse, Response, JSONResponse |
12 | from starlette.routing import Route | 12 | from starlette.routing import Route |
13 | from telegram import Update | 13 | from telegram import Update |
14 | from telegram.ext import ( | 14 | from telegram.ext import ( |
@@ -188,12 +188,12 @@ async def main() -> None: | |||
188 | await application.bot.set_webhook(url=f"{BOT_DOMAIN}{TELEGRAM_WEBHOOK_URL}") | 188 | await application.bot.set_webhook(url=f"{BOT_DOMAIN}{TELEGRAM_WEBHOOK_URL}") |
189 | 189 | ||
190 | # Set up webserver | 190 | # Set up webserver |
191 | async def telegram_webhook(request: Request) -> Response: | 191 | async def telegram_webhook(request: Request) -> JSONResponse: |
192 | """Handle incoming Telegram updates by putting them into the `update_queue`""" | 192 | """Handle incoming Telegram updates by putting them into the `update_queue`""" |
193 | await application.update_queue.put( | 193 | await application.update_queue.put( |
194 | Update.de_json(data=await request.json(), bot=application.bot) | 194 | Update.de_json(data=await request.json(), bot=application.bot) |
195 | ) | 195 | ) |
196 | return Response() | 196 | return JSONResponse({'OK': 200}) |
197 | 197 | ||
198 | async def fedi_oauth_login_callback(request: Request) -> PlainTextResponse: | 198 | async def fedi_oauth_login_callback(request: Request) -> PlainTextResponse: |
199 | """ | 199 | """ |
@@ -221,7 +221,7 @@ async def main() -> None: | |||
221 | routes=[ | 221 | routes=[ |
222 | Route(TELEGRAM_WEBHOOK_URL, telegram_webhook, methods=["POST"]), | 222 | Route(TELEGRAM_WEBHOOK_URL, telegram_webhook, methods=["POST"]), |
223 | Route(HEALTHCHECK_URL, healthcheck, methods=["GET"]), | 223 | Route(HEALTHCHECK_URL, healthcheck, methods=["GET"]), |
224 | Route(FEDI_LOGIN_CALLBACK_URL, fedi_oauth_login_callback, methods=["POST", "GET"]), | 224 | Route(FEDI_LOGIN_CALLBACK_URL, fedi_oauth_login_callback, methods=["GET"]), |
225 | ] | 225 | ] |
226 | ) | 226 | ) |
227 | webserver = uvicorn.Server( | 227 | webserver = uvicorn.Server( |
@@ -229,7 +229,7 @@ async def main() -> None: | |||
229 | app=starlette_app, | 229 | app=starlette_app, |
230 | port=BOT_PORT, | 230 | port=BOT_PORT, |
231 | use_colors=False, | 231 | use_colors=False, |
232 | host="100.93.242.2", | 232 | host="0.0.0.0", |
233 | ) | 233 | ) |
234 | ) | 234 | ) |
235 | 235 | ||
diff --git a/config.ini.example b/config.ini.example index e3a9121..d52a4d1 100644 --- a/config.ini.example +++ b/config.ini.example | |||
@@ -2,3 +2,10 @@ | |||
2 | BOT_TOKEN = | 2 | BOT_TOKEN = |
3 | FOURSQUARE_API_KEY = | 3 | FOURSQUARE_API_KEY = |
4 | ENCRYPT_KEY = | 4 | ENCRYPT_KEY = |
5 | |||
6 | [API] | ||
7 | TELEGRAM_WEBHOOK_URL = "/checkinbot/webhook" | ||
8 | HEALTHCHECK_URL = "/checkinbot/healthcheck" | ||
9 | FEDI_LOGIN_CALLBACK_URL = "/checkinbot/fedi_login_callback" | ||
10 | BOT_DOMAIN = "https://" | ||
11 | BOT_PORT = 8080 | ||
@@ -10,6 +10,12 @@ BOT_TOKEN = config["DEFAULT"]["BOT_TOKEN"] | |||
10 | FSQ_API_KEY = config["DEFAULT"]["FOURSQUARE_API_KEY"] | 10 | FSQ_API_KEY = config["DEFAULT"]["FOURSQUARE_API_KEY"] |
11 | ENCRYPT_KEY = config["DEFAULT"]["ENCRYPT_KEY"] | 11 | ENCRYPT_KEY = config["DEFAULT"]["ENCRYPT_KEY"] |
12 | 12 | ||
13 | TELEGRAM_WEBHOOK_URL = config["API"]["TELEGRAM_WEBHOOK_URL"] | ||
14 | HEALTHCHECK_URL = config["API"]["HEALTHCHECK_URL"] | ||
15 | FEDI_LOGIN_CALLBACK_URL = config["API"]["FEDI_LOGIN_CALLBACK_URL"] | ||
16 | BOT_DOMAIN = config["API"]["BOT_DOMAIN"] | ||
17 | BOT_PORT = int(config["API"]["BOT_PORT"]) | ||
18 | |||
13 | MEDIA_GROUP_TIMEOUT = 3 | 19 | MEDIA_GROUP_TIMEOUT = 3 |
14 | 20 | ||
15 | FEDI_LOGIN, WAIT_VISIBILITY, WAIT_LOCATION, LOCATION_SEARCH_KEYWORD, LOCATION_CONFIRMATION, ADD_MEDIA, ADD_COMMENT = range(7) | 21 | FEDI_LOGIN, WAIT_VISIBILITY, WAIT_LOCATION, LOCATION_SEARCH_KEYWORD, LOCATION_CONFIRMATION, ADD_MEDIA, ADD_COMMENT = range(7) |
@@ -41,9 +47,4 @@ class MsgDict(TypedDict): | |||
41 | KEY_TOOT_STATUS_ID = "toot_status_id" | 47 | KEY_TOOT_STATUS_ID = "toot_status_id" |
42 | KEY_TOOT_STATUS_CONTENT = "toot_status_content" | 48 | KEY_TOOT_STATUS_CONTENT = "toot_status_content" |
43 | 49 | ||
44 | TELEGRAM_WEBHOOK_URL = "/checkinbot/webhook" | ||
45 | HEALTHCHECK_URL = "/checkinbot/healthcheck" | ||
46 | FEDI_LOGIN_CALLBACK_URL = "/checkinbot/fedi_login_callback" | ||
47 | BOT_DOMAIN = "https://zjw.social" | ||
48 | BOT_PORT = 30010 | ||
49 | BOT_SCOPE = ['read:accounts', 'write:media', 'write:statuses'] | 50 | BOT_SCOPE = ['read:accounts', 'write:media', 'write:statuses'] |
diff --git a/contrib/docker-compose.yaml b/contrib/docker-compose.yaml new file mode 100644 index 0000000..8aeaff8 --- /dev/null +++ b/contrib/docker-compose.yaml | |||
@@ -0,0 +1,47 @@ | |||
1 | version: '3' | ||
2 | services: | ||
3 | checkinbot: | ||
4 | image: "clarkzjw/checkin.bot:latest" | ||
5 | restart: always | ||
6 | volumes: | ||
7 | - "./config.ini:/usr/src/app/config.ini" | ||
8 | - sqlite3:/usr/src/app/database/ | ||
9 | ports: | ||
10 | - "8080:8080" | ||
11 | |||
12 | krakend: | ||
13 | image: "devopsfaith/krakend:2.2" | ||
14 | restart: always | ||
15 | ports: | ||
16 | - "8081:8080" | ||
17 | - "9091:9091" | ||
18 | volumes: | ||
19 | - "./krakend.json:/etc/krakend/krakend.json" | ||
20 | |||
21 | influx: | ||
22 | image: influxdb:2.6.1 | ||
23 | environment: | ||
24 | - "DOCKER_INFLUXDB_INIT_MODE=setup" | ||
25 | - "DOCKER_INFLUXDB_INIT_USERNAME=krakend" | ||
26 | - "DOCKER_INFLUXDB_INIT_PASSWORD=password" | ||
27 | - "DOCKER_INFLUXDB_INIT_ORG=my-org" | ||
28 | - "DOCKER_INFLUXDB_INIT_BUCKET=krakend" | ||
29 | - "DOCKER_INFLUXDB_INIT_RETENTION=1w" | ||
30 | - "DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=my-super-secret-auth-token" | ||
31 | ports: | ||
32 | - "8086:8086" | ||
33 | volumes: | ||
34 | - "./influx/initdb.sh:/docker-entrypoint-initdb.d/initdb.sh" | ||
35 | |||
36 | grafana: | ||
37 | image: "grafana/grafana:9.3.6" | ||
38 | restart: always | ||
39 | ports: | ||
40 | - "3000:3000" | ||
41 | volumes: | ||
42 | - grafana:/var/lib/grafana | ||
43 | |||
44 | volumes: | ||
45 | sqlite3: | ||
46 | grafana: | ||
47 | influxdb: | ||
diff --git a/contrib/influx/initdb.sh b/contrib/influx/initdb.sh new file mode 100755 index 0000000..b1d07af --- /dev/null +++ b/contrib/influx/initdb.sh | |||
@@ -0,0 +1,16 @@ | |||
1 | #!/bin/bash | ||
2 | # The following script creates the authentication for Grafana | ||
3 | # and is meant to be added to InfluxDB docker-compose.yml file. | ||
4 | # image: influxdb | ||
5 | # volumes: | ||
6 | # - "./config/influx:/docker-entrypoint-initdb.d" | ||
7 | set -e | ||
8 | |||
9 | # Retrieve the ID from the bucket created during setup | ||
10 | BUCKET_ID=$(influx bucket list | grep "$DOCKER_INFLUXDB_INIT_BUCKET" | awk '{print $1}') | ||
11 | |||
12 | influx v1 auth create \ | ||
13 | --username ${DOCKER_INFLUXDB_INIT_USERNAME} \ | ||
14 | --password ${DOCKER_INFLUXDB_INIT_PASSWORD} \ | ||
15 | --write-bucket ${BUCKET_ID} \ | ||
16 | --org ${DOCKER_INFLUXDB_INIT_ORG} | ||
diff --git a/contrib/krakend.json b/contrib/krakend.json new file mode 100644 index 0000000..2ed23d8 --- /dev/null +++ b/contrib/krakend.json | |||
@@ -0,0 +1,84 @@ | |||
1 | { | ||
2 | "$schema": "https://www.krakend.io/schema/v3.json", | ||
3 | "version": 3, | ||
4 | "name": "Checkin.bot API", | ||
5 | "extra_config": { | ||
6 | "telemetry/influx": { | ||
7 | "address": "http://influx:8086", | ||
8 | "ttl": "25s", | ||
9 | "buffer_size": 100, | ||
10 | "db": "krakend", | ||
11 | "username": "krakend", | ||
12 | "password": "password" | ||
13 | }, | ||
14 | "telemetry/metrics": { | ||
15 | "collection_time": "60s", | ||
16 | "proxy_disabled": false, | ||
17 | "router_disabled": false, | ||
18 | "backend_disabled": false, | ||
19 | "endpoint_disabled": false, | ||
20 | "listen_address": ":8090" | ||
21 | } | ||
22 | }, | ||
23 | "timeout": "3000ms", | ||
24 | "cache_ttl": "300s", | ||
25 | "output_encoding": "json", | ||
26 | "debug_endpoint": true, | ||
27 | "endpoints": [ | ||
28 | { | ||
29 | "endpoint": "/checkinbot/webhook", | ||
30 | "method": "POST", | ||
31 | "output_encoding": "json", | ||
32 | "backend": [ | ||
33 | { | ||
34 | "url_pattern": "/checkinbot/webhook", | ||
35 | "encoding": "json", | ||
36 | "sd": "static", | ||
37 | "method": "POST", | ||
38 | "host": [ | ||
39 | "http://checkinbot:8080" | ||
40 | ], | ||
41 | "disable_host_sanitize": false | ||
42 | } | ||
43 | ] | ||
44 | }, | ||
45 | { | ||
46 | "endpoint": "/checkinbot/healthcheck", | ||
47 | "method": "GET", | ||
48 | "output_encoding": "string", | ||
49 | "backend": [ | ||
50 | { | ||
51 | "url_pattern": "/checkinbot/healthcheck", | ||
52 | "encoding": "string", | ||
53 | "sd": "static", | ||
54 | "method": "GET", | ||
55 | "host": [ | ||
56 | "http://checkinbot:8080" | ||
57 | ], | ||
58 | "disable_host_sanitize": false | ||
59 | } | ||
60 | ] | ||
61 | }, | ||
62 | { | ||
63 | "endpoint": "/checkinbot/fedi_login_callback", | ||
64 | "method": "GET", | ||
65 | "output_encoding": "string", | ||
66 | "backend": [ | ||
67 | { | ||
68 | "url_pattern": "/checkinbot/fedi_login_callback", | ||
69 | "encoding": "string", | ||
70 | "sd": "static", | ||
71 | "method": "GET", | ||
72 | "disable_host_sanitize": false, | ||
73 | "host": [ | ||
74 | "http://checkinbot:8080" | ||
75 | ] | ||
76 | } | ||
77 | ], | ||
78 | "input_query_strings": [ | ||
79 | "code", | ||
80 | "state" | ||
81 | ] | ||
82 | } | ||
83 | ] | ||
84 | } \ No newline at end of file | ||
diff --git a/dbstore/peewee_store.py b/dbstore/peewee_store.py index c8d9c22..d05c642 100644 --- a/dbstore/peewee_store.py +++ b/dbstore/peewee_store.py | |||
@@ -5,7 +5,7 @@ TOOT_VISIBILITY_UNLISTED = "unlisted" | |||
5 | TOOT_VISIBILITY_PRIVATE = "private" | 5 | TOOT_VISIBILITY_PRIVATE = "private" |
6 | 6 | ||
7 | 7 | ||
8 | db = SqliteDatabase("checkinbot.db") | 8 | db = SqliteDatabase("database/checkinbot.db") |
9 | db.connect(reuse_if_open=True) | 9 | db.connect(reuse_if_open=True) |
10 | 10 | ||
11 | 11 | ||
diff --git a/requirements.txt b/requirements.txt index d1e0036..39887b9 100644 --- a/requirements.txt +++ b/requirements.txt | |||
@@ -1,12 +1,10 @@ | |||
1 | anyio==3.6.2 | 1 | anyio==3.6.2 |
2 | APScheduler==3.10.0 | 2 | APScheduler==3.10.0 |
3 | asgiref==3.6.0 | ||
4 | blurhash==1.1.4 | 3 | blurhash==1.1.4 |
5 | certifi==2022.12.7 | 4 | certifi==2022.12.7 |
6 | cffi==1.15.1 | 5 | cffi==1.15.1 |
7 | charset-normalizer==3.0.1 | 6 | charset-normalizer==3.0.1 |
8 | click==8.1.3 | 7 | click==8.1.3 |
9 | crypto==1.4.1 | ||
10 | cryptography==39.0.1 | 8 | cryptography==39.0.1 |
11 | decorator==5.1.1 | 9 | decorator==5.1.1 |
12 | greenlet==2.0.2 | 10 | greenlet==2.0.2 |
@@ -18,24 +16,18 @@ httpx==0.23.3 | |||
18 | hyperframe==6.0.1 | 16 | hyperframe==6.0.1 |
19 | idna==3.4 | 17 | idna==3.4 |
20 | Mastodon.py @ git+https://cgit.jinwei.me/clarkzjw/mastodon.py@503d58d226c52901532067d3dcb5a7814699f7fb | 18 | Mastodon.py @ git+https://cgit.jinwei.me/clarkzjw/mastodon.py@503d58d226c52901532067d3dcb5a7814699f7fb |
21 | Naked==0.1.32 | ||
22 | peewee==3.15.4 | 19 | peewee==3.15.4 |
23 | Pillow==9.4.0 | ||
24 | pycparser==2.21 | 20 | pycparser==2.21 |
25 | pycrypto==2.6.1 | ||
26 | python-dateutil==2.8.2 | 21 | python-dateutil==2.8.2 |
27 | python-magic==0.4.27 | 22 | python-magic==0.4.27 |
28 | python-telegram-bot==20.1 | 23 | python-telegram-bot==20.1 |
29 | pytz==2022.7.1 | 24 | pytz==2022.7.1 |
30 | pytz-deprecation-shim==0.1.0.post0 | 25 | pytz-deprecation-shim==0.1.0.post0 |
31 | PyYAML==6.0 | ||
32 | requests==2.28.2 | 26 | requests==2.28.2 |
33 | rfc3986==1.5.0 | 27 | rfc3986==1.5.0 |
34 | shellescape==3.8.1 | ||
35 | six==1.16.0 | 28 | six==1.16.0 |
36 | sniffio==1.3.0 | 29 | sniffio==1.3.0 |
37 | SQLAlchemy==2.0.4 | 30 | SQLAlchemy==2.0.4 |
38 | sqlparse==0.4.3 | ||
39 | starlette==0.25.0 | 31 | starlette==0.25.0 |
40 | typing_extensions==4.5.0 | 32 | typing_extensions==4.5.0 |
41 | tzdata==2022.7 | 33 | tzdata==2022.7 |