Skip to content
This repository has been archived by the owner on Feb 3, 2022. It is now read-only.

Commit

Permalink
- Update Dockerfile & requirements.txt
Browse files Browse the repository at this point in the history
- Create dependabot.yml
- Update workflows
- Modify except statements to handle Exception subclass instead of BaseException
- Remove/rename some constants in main.py
- Update copyright statements in LICENSE
  • Loading branch information
TheCatLady committed Jan 20, 2021
1 parent 42641fc commit f0fc339
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 88 deletions.
23 changes: 23 additions & 0 deletions .github/dependabot.yml
@@ -0,0 +1,23 @@
version: 2
updates:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
labels:
- "馃З dependencies"
- "馃 bot"
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
labels:
- "馃З dependencies"
- "馃 bot"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
labels:
- "馃З dependencies"
- "馃 bot"
1 change: 0 additions & 1 deletion .github/workflows/codeql-analysis.yml
Expand Up @@ -15,7 +15,6 @@ on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '15 18 * * 4'
Expand Down
15 changes: 13 additions & 2 deletions .github/workflows/docker-publish.yml
Expand Up @@ -3,12 +3,23 @@ name: Docker
on:
push:
branches: [ main ]
tags: [ v* ]
pull_request:
branches: [ main ]

env:
IMAGE_NAME: qnap-pushover

jobs:
build:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'

steps:
- uses: actions/checkout@v2

- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME

build-and-push:
runs-on: ubuntu-latest
if: github.event_name == 'push'
Expand Down Expand Up @@ -42,4 +53,4 @@ jobs:
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION
2 changes: 1 addition & 1 deletion Dockerfile
@@ -1,4 +1,4 @@
FROM python:alpine
FROM python:3.9.1-alpine3.12
COPY requirements.txt /
RUN pip install -r requirements.txt
COPY main.py /
Expand Down
4 changes: 3 additions & 1 deletion LICENSE
@@ -1,6 +1,8 @@
MIT License

Copyright (c) 2018 Vincent Cox
Copyright 漏 2021 TheCatLady
Copyright 漏 2019 M. T. Lott
Copyright 漏 2018 Vincent Cox

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
75 changes: 34 additions & 41 deletions README.md
@@ -1,17 +1,17 @@
# `qnap-pushover` 🔔

[![Python](https://img.shields.io/github/languages/top/TheCatLady/docker-qnap-pushover?logo=python&style=flat-square)](https://github.com/TheCatLady/docker-qnap-pushover)
[![Docker Image Size](https://img.shields.io/docker/image-size/thecatlady/qnap-pushover/latest?style=flat-square&logo=docker&label=docker%20image%20size)](https://hub.docker.com/r/thecatlady/qnap-pushover)
[![Docker Hub Pulls](https://img.shields.io/docker/pulls/thecatlady/qnap-pushover?style=flat-square&label=docker%20hub%20pulls&logo=docker)](https://hub.docker.com/r/thecatlady/qnap-pushover)
[![GitHub Repo Stars](https://img.shields.io/github/stars/TheCatLady/docker-qnap-pushover?label=github%20stars&logo=github&style=flat-square)](https://github.com/TheCatLady/docker-qnap-pushover/stargazers)<br/>
[![Last Commit](https://img.shields.io/github/last-commit/TheCatLady/docker-qnap-pushover?style=flat-square&logo=git)](https://github.com/TheCatLady/docker-qnap-pushover)
[![GitHub Container Registry Build Status](https://img.shields.io/github/workflow/status/TheCatLady/docker-qnap-pushover/Docker?label=github%20container%20registry%20build&logo=github&style=flat-square)](https://github.com/TheCatLady/docker-qnap-pushover)
[![Docker Hub Build Status](https://img.shields.io/docker/cloud/build/thecatlady/qnap-pushover?style=flat-square&label=docker%20hub%20build&logo=docker)](https://hub.docker.com/r/thecatlady/qnap-pushover)<br/>
[![License](https://img.shields.io/github/license/TheCatLady/docker-qnap-pushover?logo=open%20source%20initiative&style=flat-square)](https://github.com/TheCatLady/docker-qnap-pushover/blob/main/LICENSE)
[![Python](https://img.shields.io/github/languages/top/TheCatLady/docker-qnap-pushover?style=flat-square&logoColor=white&logo=python)](https://github.com/TheCatLady/docker-qnap-pushover)
[![Code Quality](https://img.shields.io/lgtm/grade/python/github/TheCatLady/docker-qnap-pushover?style=flat-square&logoColor=white&logo=lgtm&label=code%20quality)](https://lgtm.com/projects/g/TheCatLady/docker-qnap-pushover/)
[![Image Size](https://img.shields.io/docker/image-size/thecatlady/qnap-pushover/latest?style=flat-square&logoColor=white&logo=docker&label=image%20size)](https://hub.docker.com/r/thecatlady/qnap-pushover)
[![Docker Hub Pulls](https://img.shields.io/docker/pulls/thecatlady/qnap-pushover?style=flat-square&logoColor=white&logo=docker&label=docker%20hub%20pulls)](https://hub.docker.com/r/thecatlady/qnap-pushover)<br/>
[![Last Commit](https://img.shields.io/github/last-commit/TheCatLady/docker-qnap-pushover?style=flat-square&logoColor=white&logo=git)](https://github.com/TheCatLady/docker-qnap-pushover)
[![GitHub Container Registry Build Status](https://img.shields.io/github/workflow/status/TheCatLady/docker-qnap-pushover/Docker?style=flat-square&logoColor=white&logo=github&label=github%20container%20registry%20build)](https://github.com/TheCatLady/docker-qnap-pushover)
[![Docker Hub Build Status](https://img.shields.io/docker/cloud/build/thecatlady/qnap-pushover?style=flat-square&logoColor=white&logo=docker&label=docker%20hub%20build)](https://hub.docker.com/r/thecatlady/qnap-pushover)<br/>
[![License](https://img.shields.io/github/license/TheCatLady/docker-qnap-pushover?style=flat-square&logoColor=white&logo=open%20source%20initiative)](https://github.com/TheCatLady/docker-qnap-pushover/blob/main/LICENSE)
[![Become a GitHub Sponsor](https://img.shields.io/badge/github%20sponsors-become%20a%20sponsor-ff69b4?style=flat-square&logo=github%20sponsors)](https://github.com/sponsors/TheCatLady)
[![Donate via PayPal](https://img.shields.io/badge/paypal-make%20a%20donation-blue?style=flat-square&logo=paypal)](http://paypal.me/DHoung)

[Pushover](https://pushover.net/) notifications for [QNAP](https://www.qnap.com/) NAS system events via `python-pushover`
[Pushover](https://pushover.net/) notifications for [QNAP](https://www.qnap.com/) NAS system events via [`python-pushover`](https://github.com/Thibauth/python-pushover)

## Usage

Expand All @@ -21,7 +21,7 @@ If you would prefer to pull from GHCR, simply replace `thecatlady/qnap-pushover`

### Docker Compose (recommended)

Add the following volume and service definitions to a `docker-compose.yaml` file:
Add the following volume and service definitions to a `docker-compose.yml` file:

```yaml
volumes:
Expand All @@ -46,20 +46,12 @@ services:
restart: always
```

Then, run the following command from the directory containing your `docker-compose.yaml` file:
Then, run the following command from the directory containing your `docker-compose.yml` file:

```bash
docker-compose up -d
```

To update the container when a new image is available, run the following:

```bash
docker-compose pull qnap-pushover
docker-compose up -d
docker image prune
```

### Docker CLI

Run the following command to create the required named volume:
Expand Down Expand Up @@ -88,7 +80,23 @@ docker run -d \
thecatlady/qnap-pushover
```

To update the container when a new image is available, run the commands below followed by your `docker run` command:
## Updating

The process to update the container when a new image is available is dependent on how you set it up initially.

### Docker Compose

Run the following commands from the directory containing your `docker-compose.yml` file:

```bash
docker-compose pull qnap-pushover
docker-compose up -d
docker image prune
```

### Docker CLI

Run the commands below, followed by your original `docker run` command:

```bash
docker stop qnap-pushover
Expand All @@ -107,8 +115,8 @@ The container image is configured using the following parameters passed at runti
|`-e LOG_LEVEL=`|Container logging level; `DEBUG` < `INFO` < `WARN` < `ERROR` < `CRITICAL`|`WARN`|no|
|`-e NOTIFY_LEVEL=`|Minimum system event type to generate a notification; `INFO` < `WARN` < `ERROR`|`WARN`|no|
|`-e POLL_INTERVAL=`|Poll interval in seconds|`10`|no|
|`-e INCLUDE=`|List of keywords which must be present in the event description to trigger a notification (comma-delimited)||no|
|`-e EXCLUDE=`|List of keywords which must _not_ be present in the event description to trigger a notification (comma-delimited)||no|
|`-e INCLUDE=`|List of keywords which _must_ be present in the event description to trigger a notification (comma-delimited)||no|
|`-e EXCLUDE=`|List of keywords which _must not_ be present in the event description to trigger a notification (comma-delimited)||no|
|`-e TESTING_MODE=`|Testing mode (`true` or `false`); if set to `true`, will re-queue the last 10 system log events at _every_ container start and result in duplicate notifications|`false`|no|
|`-e PUSHOVER_TOKEN=`|[Pushover application API token](https://pushover.net/api#registration); e.g., `azGDORePK8gMaC0QOYAMyEEuzJnyUi`||**yes**|
|`-e PUSHOVER_RECIPIENT=`|[Pushover user and/or group key(s)](https://pushover.net/api#identifiers); e.g., `uQiRzpo4DXghDmr9QzzfQu27cmVRsG` or `gznej3rKEVAvPUxu9vvNnqpmZpokzF` (up to 50, comma-delimited)||**yes**|
Expand All @@ -118,31 +126,16 @@ The container image is configured using the following parameters passed at runti

## Building Locally

If you would like to make modifications to the code, you can build the Docker image yourself instead of pulling the pre-built image available from [GitHub Container Registry (GHCR)](https://github.com/users/TheCatLady/packages/container/package/qnap-pushover) or [Docker Hub](https://hub.docker.com/r/thecatlady/qnap-pushover).
If you would like to make modifications to the code, you can build the Docker image yourself instead of pulling the pre-built image available from [GitHub Container Registry (GHCR)](https://github.com/users/TheCatLady/packages/container/package/qnap-pushover) and [Docker Hub](https://hub.docker.com/r/thecatlady/qnap-pushover).

```bash
git clone https://github.com/TheCatLady/docker-qnap-pushover.git
cd docker-qnap-pushover
docker build \
--no-cache \
--pull \
-t thecatlady/qnap-pushover .
docker volume create qnap-pushover
docker run -d \
--name=qnap-pushover \
-e TZ=America/New_York `#optional` \
-e LOG_LEVEL=WARN `#optional` \
-e NOTIFY_LEVEL=WARN `#optional` \
-e POLL_INTERVAL=10 `#optional` \
-e TESTING_MODE=false `#optional` \
-e PUSHOVER_TOKEN=<Pushover application API token> \
-e PUSHOVER_RECIPIENT=<Pushover user and/or group key(s)> \
-v qnap-pushover:/data \
-v /etc/logs/event.log:/event.log:ro \
--restart always \
thecatlady/qnap-pushover
docker build --no-cache --pull -t thecatlady/qnap-pushover .
```

Once the image has been built, follow the directions in the "Usage" section above to start the container.

## How to Contribute

Show your support by starring this project! &#x1F31F; Pull requests, bug reports, and feature requests are also welcome!
Expand Down
71 changes: 30 additions & 41 deletions main.py
Expand Up @@ -6,17 +6,18 @@
import sqlite3
import time

EVENT_ID_FILE = "last_event_id.txt"
DB_FILE = "event.log"
DB_NAME = "NASLOG_EVENT"
ID_COL = "event_id"
TYPE_COL = "event_type"
DESC_COL = "event_desc"
DATE_COL = "event_date"
TIME_COL = "event_time"
USER_COL = "event_user"
IP_COL = "event_ip"
COLOR = ["grey", "#ffc311", "#ca414b"]
EVENT_LOG_PATH = "/event.log"
EVENT_ID_PATH = "/data/last_event_id.txt"
FONT_COLOR = ["grey", "#ffc311", "#ca414b"]

LOGGING_LEVEL = {
'critical': logging.CRITICAL,
'error': logging.ERROR,
'warn': logging.WARNING,
'warning': logging.WARNING,
'info': logging.INFO,
'debug': logging.DEBUG
}

# Banner
print('''
Expand All @@ -27,16 +28,7 @@
https://github.com/TheCatLady/docker-qnap-pushover
''')

LOGGING_LEVELS = {
'critical': logging.CRITICAL,
'error': logging.ERROR,
'warn': logging.WARNING,
'warning': logging.WARNING,
'info': logging.INFO,
'debug': logging.DEBUG
}

logging_level = LOGGING_LEVELS.get(os.environ['LOG_LEVEL'].lower())
logging_level = LOGGING_LEVEL.get(os.environ['LOG_LEVEL'].lower())

if logging_level is None:
logging_level = logging.WARNING
Expand All @@ -50,7 +42,7 @@
NOTIFY_TYPE = 1
else:
NOTIFY_TYPE = 2
except:
except Exception:
NOTIFY_TYPE = 1
finally:
if NOTIFY_TYPE == 0:
Expand All @@ -65,14 +57,14 @@

try:
POLL_INTERVAL = int(os.environ['POLL_INTERVAL'])
except:
except Exception:
POLL_INTERVAL = 10
finally:
logging.info(f"Poll interval is set to {POLL_INTERVAL} seconds.")

try:
INCLUDE = list(filter(str.strip, os.environ['INCLUDE'].lower().split(',')))
except:
except Exception:
INCLUDE = []
finally:
if len(INCLUDE) > 0:
Expand All @@ -82,7 +74,7 @@

try:
EXCLUDE = list(filter(str.strip, os.environ['EXCLUDE'].lower().split(',')))
except:
except Exception:
EXCLUDE = []
finally:
if len(EXCLUDE) > 0:
Expand All @@ -92,7 +84,7 @@

try:
TESTING_MODE = bool(os.getenv('TESTING_MODE', 'false').lower().strip() in ['true', '1'])
except:
except Exception:
TESTING_MODE = False
finally:
if TESTING_MODE:
Expand All @@ -106,44 +98,41 @@
pushover_client = pushover.Client(PUSHOVER_RECIPIENT, api_token=PUSHOVER_TOKEN)
logging.info(f"Using Pushover application API token {PUSHOVER_TOKEN} and recipient user/group key(s) {PUSHOVER_RECIPIENT}.")

log_path = os.path.abspath(DB_FILE)
event_id_path = os.path.abspath(os.path.join("data", EVENT_ID_FILE))

if os.path.isfile(log_path):
db_conn = sqlite3.connect(log_path) # event.log is not a text file, but a SQLite database
if os.path.isfile(EVENT_LOG_PATH):
db_conn = sqlite3.connect(EVENT_LOG_PATH) # event.log is not a text file, but a SQLite database

try:
with open(event_id_path, "r") as f:
with open(EVENT_ID_PATH, "r") as f:
last_event_id = int(f.readline()) # read the last-processed event ID from a file if it exists
logging.info(f"Read the last-processed event ID from the data file. ({last_event_id})")
except (FileNotFoundError, ValueError):
last_event_id = 0

if last_event_id == 0: # set the last-processed event ID to the newest event ID if we weren't able to read it from a file
cursor = db_conn.cursor()
cursor.execute(f"SELECT {ID_COL} FROM {DB_NAME} ORDER BY {ID_COL} DESC LIMIT 1;")
cursor.execute(f"SELECT event_id FROM NASLOG_EVENT ORDER BY event_id DESC LIMIT 1;")
last_event_id = cursor.fetchone()[0]
logging.info(f"Setting the last-processed event ID to the newest event ID in the database. ({last_event_id})")

if TESTING_MODE:
last_event_id -= 10 # for testing, re-queue the previous 10 events
logging.info("Testing mode is enabled. Re-queuing last 10 system log events for processing.")
else:
raise Exception(f"Unable to open {DB_FILE}. Was the log file mounted to the container?")
raise Exception(f"Unable to open {EVENT_LOG_PATH}. Was the log file mounted to the container?")

while True:
cursor = db_conn.cursor()
cursor.execute(f"SELECT {ID_COL} FROM {DB_NAME} ORDER BY {ID_COL} DESC LIMIT 1;")
cursor.execute(f"SELECT event_id FROM NASLOG_EVENT ORDER BY event_id DESC LIMIT 1;")
newest_event_id = cursor.fetchone()[0]

if newest_event_id > last_event_id:
new_event_count = newest_event_id - last_event_id
logging.info(f"{new_event_count} new system log events detected in {DB_FILE}.")
logging.info(f"{new_event_count} new system log events detected in {EVENT_LOG_PATH}.")

try:
for i in range(new_event_count):
cursor = db_conn.cursor()
cursor.execute(f"SELECT {TYPE_COL}, {DESC_COL}, {DATE_COL}, {TIME_COL}, {USER_COL}, {IP_COL} FROM {DB_NAME} WHERE {ID_COL}={last_event_id + 1 + i};")
cursor.execute(f"SELECT event_type, event_desc, event_date, event_time, event_user, event_ip FROM NASLOG_EVENT WHERE event_id={last_event_id + 1 + i};")
event = cursor.fetchone()
event_type = event[0]
event_desc = event[1].strip()
Expand Down Expand Up @@ -190,7 +179,7 @@

if quotes % 2 == 0:
if first_line:
message = f"<font color=\"{COLOR[event_type]}\"><b>{prev}{s}</b></font><small>";
message = f"<font color=\"{FONT_COLOR[event_type]}\"><b>{prev}{s}</b></font><small>";
first_line = False
else:
message += f"<br/>{prev}{s}"
Expand All @@ -200,7 +189,7 @@
else:
prev += f"{s}. "
else:
message = f"<font color=\"{COLOR[event_type]}\"><b>{message}</b></font><small>"
message = f"<font color=\"{FONT_COLOR[event_type]}\"><b>{message}</b></font><small>"

message_details = ""

Expand Down Expand Up @@ -242,9 +231,9 @@
f"Only {i} of {new_event_count} new system log events were processed successfully. " \
f"Re-queuing the remaining {new_event_count - i} unprocessed events.")
else:
logging.info(f"No new system log events detected in {DB_FILE}.")
logging.info(f"No new system log events detected in {EVENT_LOG_PATH}.")

with open(event_id_path, "w+") as f:
with open(EVENT_ID_PATH, "w+") as f:
f.write(str(last_event_id))
f.truncate()
logging.info(f"Wrote the last-processed event ID to the data file. ({last_event_id})")
Expand Down
7 changes: 6 additions & 1 deletion requirements.txt
@@ -1 +1,6 @@
python-pushover
certifi==2020.12.5
chardet==4.0.0
idna==2.10
python-pushover==0.4
requests==2.25.1
urllib3==1.26.2

0 comments on commit f0fc339

Please sign in to comment.