-
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.
Final (general) approach, still needs some tweaing and validation though
- Loading branch information
1 parent
0050603
commit ef07154
Showing
5 changed files
with
67 additions
and
12 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 |
---|---|---|
@@ -1,3 +1,5 @@ | ||
.idea | ||
|
||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
|
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 |
---|---|---|
@@ -1,2 +1,20 @@ | ||
# network-device-offline-monitor | ||
A simple way of getting notified by email if a "always online" network device goes offline for any reason | ||
A simple way of getting notified by email if one or more local network devices go offline for any reason. | ||
|
||
This will scan any IP ranges specified in config.ini (see `IpRangesToScan`) and checks that any IPs mentioned in `RequiredIps` are online. If they aren't, it will send an email to the specified notification email. | ||
|
||
This script is designed for Linux since it uses nmap, however it might be possible to run it on a Windows OS as long as nmap is installed (https://nmap.org/book/inst-windows.html) and available on the `PATH`. I haven't tested this though. | ||
|
||
## How To Run | ||
|
||
This uses the Mailersend API to send emails (although naturally you can use your own provider or approach by modifying `send_email_notification()`). | ||
|
||
The Mailersend API key can only be specified by an environment variable: `MAILERSEND_API_KEY` | ||
|
||
So you can run this script by modifying `config.ini` as required, and then running something like: | ||
|
||
> MAILERSEND_API_KEY='changeme' python3 main.py | ||
You can also change the logging level by adding a `--loglevel` param, for example by running: | ||
|
||
> MAILERSEND_API_KEY='changeme' python3 main.py --loglevel debug |
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 |
---|---|---|
|
@@ -3,9 +3,8 @@ IpRangesToScan = | |
192.168.4.0/24 | ||
192.168.6.0/24 | ||
192.168.7.0/24 | ||
OfflineNotificationName = Tristan Perry | ||
OfflineNotificationEmail = [email protected] | ||
RequiredIps = | ||
192.168.7.254 | ||
192.168.7.0 | ||
192.168.4.27 | ||
Blah = Test |
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 |
---|---|---|
|
@@ -2,6 +2,9 @@ | |
import argparse | ||
import logging | ||
import nmap3 | ||
import os | ||
|
||
from mailersend import emails | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -11,18 +14,19 @@ def to_list(string: str) -> list: | |
return list(filter(None, split)) | ||
|
||
|
||
def load_config_values() -> tuple[list, str, list]: | ||
def load_config_values() -> tuple[list, str, str, list]: | ||
config = configparser.ConfigParser() | ||
config.read('config.ini') | ||
|
||
to_scan = config['DEFAULT']['IpRangesToScan'] | ||
notification_name = config['DEFAULT']['OfflineNotificationName'] | ||
notification_email = config['DEFAULT']['OfflineNotificationEmail'] | ||
required_ips = config['DEFAULT']['RequiredIps'] | ||
logger.debug('Config loaded. (to_scan) %s, (email) %s, (ips) %s', to_scan, notification_email, required_ips) | ||
|
||
# TODO validate | ||
|
||
return to_list(to_scan), notification_email, to_list(required_ips) | ||
return to_list(to_scan), notification_name, notification_email, to_list(required_ips) | ||
|
||
|
||
def get_active_local_ips(to_scan: list) -> list: | ||
|
@@ -36,7 +40,8 @@ def get_active_local_ips(to_scan: list) -> list: | |
logger.debug('Results for host range %s', host) | ||
logger.debug(results) | ||
|
||
up_ips = {ip: result for ip, result in results.items() if 'state' in result and result['state']['state'] == 'up'} | ||
up_ips = {ip: result for ip, result in results.items() if | ||
'state' in result and result['state']['state'] == 'up'} | ||
|
||
up_ips_list = list(up_ips.keys()) | ||
logger.debug('%s IPs are UP for host range %s', up_ips_list, host) | ||
|
@@ -45,8 +50,40 @@ def get_active_local_ips(to_scan: list) -> list: | |
return active_ips_in_range | ||
|
||
|
||
def send_email_notification(error_ips: list, notification_email: str) -> None: | ||
def send_email_notification(error_ips: list, notification_name: str, notification_email: str) -> None: | ||
logger.error('IP(s) %s are offline, sending email to %s', error_ips, notification_email) | ||
mailer = emails.NewEmail(os.getenv('MAILERSEND_API_KEY')) | ||
|
||
mail_body = {} | ||
|
||
mail_from = { | ||
"name": "Offline Notifier", | ||
"email": "[email protected]", | ||
} | ||
|
||
recipients = [ | ||
{ | ||
"name": notification_name, | ||
"email": notification_email, | ||
} | ||
] | ||
|
||
reply_to = [ | ||
{ | ||
"name": "No Reply", | ||
"email": "[email protected]", | ||
} | ||
] | ||
|
||
mailer.set_mail_from(mail_from, mail_body) | ||
mailer.set_mail_to(recipients, mail_body) | ||
mailer.set_reply_to(reply_to, mail_body) | ||
mailer.set_subject("Network Device(s) Offline", mail_body) | ||
mailer.set_plaintext_content("Warning: the following required IP addresses are offline: " + ', '.join(error_ips), | ||
mail_body) | ||
|
||
response = mailer.send(mail_body) | ||
logger.debug("Email response: %s", response) | ||
|
||
|
||
if __name__ == '__main__': | ||
|
@@ -59,14 +96,12 @@ def send_email_notification(error_ips: list, notification_email: str) -> None: | |
logging.basicConfig(level=args.loglevel.upper()) | ||
logging.info('Logging setup') | ||
|
||
ip_ranges_to_scan, email, required_ips = load_config_values() | ||
ip_ranges_to_scan, name, email, required_ips = load_config_values() | ||
all_active_ips = get_active_local_ips(ip_ranges_to_scan) | ||
logger.info('All active IPs: %s', all_active_ips) | ||
|
||
offline_ips = list(set(required_ips) - set(all_active_ips)) | ||
logger.info('Offline IPs %s', offline_ips) | ||
|
||
if offline_ips: | ||
send_email_notification(offline_ips) | ||
|
||
# See PyCharm help at https://www.jetbrains.com/help/pycharm/ | ||
send_email_notification(offline_ips, name, email) |
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 |
---|---|---|
@@ -1,2 +1,3 @@ | ||
configparser~=6.0.1 | ||
python3-nmap~=1.6.0 | ||
python3-nmap~=1.6.0 | ||
mailersend~=0.5.6 |