Browse Source

first

master
david 3 years ago
commit
693934ed65
  1. 5
      .dockerignore
  2. 5
      .gitignore
  3. 10
      Dockerfile
  4. 23
      README.md
  5. 17
      database.js
  6. 36
      index.js
  7. 181
      netmon.py
  8. 11875
      package-lock.json
  9. 26
      package.json
  10. 6
      postcss.config.js
  11. 3
      public/styles/tailwind.css
  12. 36
      serviceWrapper.bash
  13. 12
      tailwind.config.js
  14. 27
      views/Card.jsx
  15. 88
      views/DiffCard.jsx
  16. 16
      views/Title.jsx
  17. 33
      views/index.jsx

5
.dockerignore

@ -0,0 +1,5 @@
node_modules/
rubbish/
db.sqlite3
data.csv
public/styles/style.css

5
.gitignore vendored

@ -0,0 +1,5 @@
node_modules/
rubbish/
db.sqlite3
data.csv
public/styles/style.css

10
Dockerfile

@ -0,0 +1,10 @@
FROM nikolaik/python-nodejs:python3.9-nodejs16-alpine
ENV PYTHONUNBUFFERED=1 NODE_ENV=production
WORKDIR /app
COPY ./netmon.py ./
CMD [ "python", "./netmon.py" , "monitor" ]
# copy index/views/public/pkg.json/postcss/tailwind configs
#npm i
#build css
#run supervisord or wrapper

23
README.md

@ -0,0 +1,23 @@
# netmon
bunch of misc cmds
```
docker run --rm -it --name pls -w /app -p 3000:3000 -p 5000:5000 -e dstHost=localhost -e dstPort=8000 -e TZ=Australia/Sydney -v /home/blender/projects/netmon:/app nikolaik/python-nodejs:python3.9-nodejs16-alpine sh
docker exec -it pls sh
apk add sqlite
npm install -g nodemon
npm install express sqlite
python -m http.server 8000
export dstHost=localhost dstPort=8000
python netmon.py monitor
sqlite3 db.sqlite3
.headers on
.mode column
`SELECT * FROM netmonResults;`
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest postcss-cli
npm install tailwindcss postcss autoprefixer postcss-cli
```

17
database.js

@ -0,0 +1,17 @@
var sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database('db.sqlite3', (err) => {
if (err) {
console.error(err.message);
throw err;
} else {
console.log('Connected to the SQLite database.');
db.run(
`CREATE TABLE IF NOT EXISTS netmonResults (id integer PRIMARY KEY,
timestamp text,
status integer)`
);
}
});
module.exports = db;

36
index.js

@ -0,0 +1,36 @@
const express = require('express');
const app = express();
const port = 3000;
const path = require('path');
require('dotenv').config();
app.set('views', __dirname + '/views');
app.set('view engine', 'jsx');
app.engine('jsx', require('express-react-views').createEngine());
app.use(express.static(path.join(__dirname, '/public')));
const db = require('./database.js');
async function db_all(query) {
return new Promise(function (resolve, reject) {
db.all(query, function (err, rows) {
if (err) {
return reject(err);
}
resolve(rows);
});
});
}
app.get('/', async (req, res) => {
const sql = `SELECT * FROM netmonResults`;
const dbdata = await db_all(sql);
res.render('index', { dbdata });
});
app.listen(port, () => {
console.log(
`app listening at http://localhost:${port} in ${app.settings.env} mode. netmon is monitoring ${process.env.dstHost}`
);
});

181
netmon.py

@ -0,0 +1,181 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import csv
import sys
import time
import socket
import datetime
import sqlite3
from pathlib import Path
path = Path(__file__).resolve().parent
def update_db(payload):
conn = None
try:
db = (str(path) + "/db.sqlite3")
conn = sqlite3.connect(db)
c = conn.cursor()
c.execute(
'''
CREATE TABLE IF NOT EXISTS netmonResults (
id integer PRIMARY KEY,
timestamp text,
status integer
)
'''
)
c.execute(
'''
INSERT OR REPLACE into netmonResults (
timestamp, status
)
VALUES (?, ?)
''',
(payload)
)
conn.commit()
print (f"db update successful")
except Exception as ex:
print(ex)
print (f"db operation failed")
finally:
if conn:
conn.close()
def internet(dstHost, dstPort, timeout=3):
""" Generates a new request"""
try:
socket.setdefaulttimeout(timeout)
socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((dstHost, int(dstPort)))
return True
except Exception as ex:
# print(ex)
return False
def current_timestamp():
""" Get Current timestamp string """
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def str_to_date(timestamp):
""" Convert timestamp string to date object """
return datetime.datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
def secs_to_HMS(secs):
""" Convert seconds to second and minutes
Format : HH:MM:SS
"""
return str(datetime.timedelta(seconds=secs));
def record_file_exist():
""" Check if records file exist """
return os.path.isfile('data.csv')
def create_record_file():
""" Create a new record file """
with open('data.csv', 'a') as csvfile:
columns = ['timestamp', 'status']
writer = csv.DictWriter(csvfile, fieldnames=columns)
writer.writeheader()
def last_record_status():
""" Get last record """
result = None
with open('data.csv', 'r') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
result = row
return None if result is None else result['status']
def write_record(status):
""" Create a new record """
with open('data.csv', 'a') as csvfile:
columns = ['timestamp', 'status']
writer = csv.DictWriter(csvfile, fieldnames=columns)
writer.writerow({'timestamp': str(current_timestamp()), 'status': status})
def get_total_downtime():
""" Calculate downtime """
seconds = 0
down = None
up = None
with open('data.csv', 'r') as csvfile:
reader = csv.DictReader(csvfile)
for record in reader:
try:
if record['status'] == '0':
print('Went Down at : ', record['timestamp'])
down = str_to_date(record['timestamp'])
next_record = next(reader)
up = str_to_date(next_record['timestamp'])
seconds += (up - down).total_seconds()
print('Went up at : ', next_record['timestamp'])
except Exception as ex:
print('\nCurrent Status : Still Down')
seconds += (str_to_date(current_timestamp()) - down).total_seconds()
return secs_to_HMS(seconds);
def monitor_connection(sleep_time):
try:
dstHost = os.getenv('dstHost')
dstPort = os.getenv('dstPort')
if dstHost is None or dstPort is None:
raise Exception('vars are fucked')
except Exception as error:
print('Caught this error: ' + repr(error))
print ("""
pls set vars
eg;
for host:
export dstHost=localhost dstPort=8000
for docker:
-e dstHost=localhost -e dstPort=8000
""")
sys.exit(1)
""" Start monitoring """
print('Monitoring your connection for ' + dstHost)
while True:
last_record = last_record_status()
if not internet(dstHost, dstPort):
if last_record == '1' or last_record is None:
print('Internet went down')
write_record(0)
update_db((str(current_timestamp()), '0'))
else:
if last_record == '0' or last_record is None:
print('Internet is up')
write_record(1)
update_db((str(current_timestamp()), '1'))
time.sleep(sleep_time)
def args_error():
print('Please provide an argument\nOptions\n./internet.py monitor\n./internet.py downtime')
args = sys.argv
if not len(args) > 1:
args_error()
elif args[1] == 'monitor':
if not record_file_exist():
create_record_file()
monitor_connection(1)
elif args[1] == 'downtime':
print('\nRemained down for : ', get_total_downtime(), ' HH:MM:SS ')

11875
package-lock.json generated

File diff suppressed because it is too large Load Diff

26
package.json

@ -0,0 +1,26 @@
{
"dependencies": {
"dayjs": "^1.10.6",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"express-react-views": "^0.11.0",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"sqlite3": "^5.0.2"
},
"devDependencies": {
"autoprefixer": "^10.3.1",
"nodemon": "^2.0.12",
"postcss": "^8.3.6",
"postcss-cli": "^8.3.1",
"tailwindcss": "^2.2.7"
},
"scripts": {
"start": "NODE_ENV=development node index.js",
"build:css": "postcss public/styles/tailwind.css -o public/styles/style.css",
"dev": "npm run build:css && nodemon index.js",
"testHost": "python -m http.server 8000",
"netmon": "python netmon.py monitor",
"prod": "NODE_ENV=production node index.js "
}
}

6
postcss.config.js

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
},
};

3
public/styles/tailwind.css

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

36
serviceWrapper.bash

@ -0,0 +1,36 @@
#!/bin/bash
# Start the first process
./my_first_process -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_first_process: $status"
exit $status
fi
# Start the second process
./my_second_process -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_second_process: $status"
exit $status
fi
# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container exits with an error
# if it detects that either of the processes has exited.
# Otherwise it loops forever, waking up every 60 seconds
while sleep 60; do
ps aux |grep my_first_process |grep -q -v grep
PROCESS_1_STATUS=$?
ps aux |grep my_second_process |grep -q -v grep
PROCESS_2_STATUS=$?
# If the greps above find anything, they exit with 0 status
# If they are not both 0, then something is wrong
if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
echo "One of the processes has already exited."
exit 1
fi
done

12
tailwind.config.js

@ -0,0 +1,12 @@
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
purge: ['./public/**/*.html', './views/*.{js,jsx,ts,tsx,vue}', '.index.js'],
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [require('tailwindcss'), require('autoprefixer')],
};

27
views/Card.jsx

@ -0,0 +1,27 @@
const React = require('react');
import { TimeBetweenRows } from './DiffCard';
export const Card = ({ dbdata }) => {
return dbdata.reverse().map((row, index) => {
const nextRow = dbdata[index + 1];
return (
<div className="grid grid-cols-1 px-2">
<div
className={`shadow-md p-1 flex items-center justify-between ${
row.status === 1 ? 'bg-green-50' : 'bg-red-50'
} `}
>
<div className="flex-grow pl-2">{row.timestamp}</div>
<div className="p-1 pr-2">{row.status === 1 ? '🟢' : '🔴'}</div>
</div>
{!!nextRow ? (
<div className="flex justify-center items-center py-1 text-gray-400">
<TimeBetweenRows row={row} nextRow={nextRow} />
</div>
) : null}
</div>
);
});
};

88
views/DiffCard.jsx

@ -0,0 +1,88 @@
const React = require('react');
const dayjs = require('dayjs');
export const TimeBetweenRows = ({ row, nextRow }) => {
if (nextRow) {
const firstDate = dayjs(row.timestamp);
const secondDate = dayjs(nextRow.timestamp);
const theDiff = firstDate.diff(secondDate);
const theSeconds = theDiff / 1000;
const theMinutes = theSeconds / 60;
const theHours = theMinutes / 60;
const theDays = theHours / 24;
// console.log(theDiff, theSeconds, theMinutes, theHours, theDays);
const renderSecs = <>{theSeconds === 1 ? 'sec' : 'secs'}</>;
const renderMins = <>{theMinutes === 1 ? 'min ' : 'mins '}</>;
const renderHrs = <>{theHours === 1 ? 'hr ' : 'hrs '}</>;
const renderDays = <>{theDays === 1 ? 'day ' : 'days '}</>;
return (
<>
{/* secs */}
{theSeconds < 60 ? (
<>
{Math.round(theSeconds)}
{renderSecs}
</>
) : null}
{/* mins secs */}
{theMinutes > 1 && theMinutes < 60 ? (
<>
<>
{Math.round(theMinutes)}
{renderMins}
</>
<>
{Math.round((theMinutes % 1) * 60)}
{renderSecs}
</>
</>
) : null}
{/* hrs mins secs */}
{theHours > 1 && theHours < 24 ? (
<>
<>
{Math.round(theHours)}
{renderHrs}
</>
<>
{Math.round((theHours % 1) * 60)}
{renderMins}
</>
<>
{Math.round((theMinutes % 1) * 60)}
{renderSecs}
</>
</>
) : null}
{/* days hrs mins secs */}
{theDays > 1 ? (
<>
<>
{Math.round(theDays)}
{renderDays}
</>
<>
{Math.round((theDays % 1) * 24)}
{renderHrs}
</>
<>
{Math.round((theHours % 1) * 60)}
{renderMins}
</>
<>
{Math.round((theMinutes % 1) * 60)}
{renderSecs}
</>
</>
) : null}
</>
);
}
return false;
};

16
views/Title.jsx

@ -0,0 +1,16 @@
const React = require('react');
export const Title = ({ dbdata }) => {
const statusCheck = dbdata?.slice(-1)[0].status === 1;
return (
<div className="text-xl p-2 pb-4">
<div>
Everything looks {statusCheck ? 'AMAZING 🔥🔥🔥' : 'HORRIFIC 💀💀💀'}
</div>
<div className="text-xs text-gray-400 pt-1">
Monitoring {process.env.dstHost}
</div>
</div>
);
};

33
views/index.jsx

@ -0,0 +1,33 @@
const React = require('react');
import { Title } from './Title';
import { Card } from './Card';
function App({ dbdata }) {
return (
<html lang="en">
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/styles/style.css" />
</head>
<title>netmon</title>
<body className="bg-indigo-50 max-w-sm antialiased tracking-wide leading-relaxed container mx-auto">
<div className="shadow-2xl my-8 rounded p-2">
{dbdata.length ? (
<div>
<Title dbdata={dbdata} />
<Card dbdata={dbdata} />
</div>
) : (
<div className="flex justify-center items-center ">
no information from the db was loaded, sad
</div>
)}
</div>
</body>
</html>
);
}
module.exports = App;
Loading…
Cancel
Save