It works
parent
f8d5ed14e2
commit
119f049b48
@ -0,0 +1,3 @@
|
|||||||
|
flask==1.1.2
|
||||||
|
psutil==5.7.0
|
||||||
|
sh==1.13.1
|
@ -0,0 +1,11 @@
|
|||||||
|
from flask.blueprints import Blueprint
|
||||||
|
|
||||||
|
from .stats import get_stats
|
||||||
|
|
||||||
|
api_bp = Blueprint('api', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.route("/stats")
|
||||||
|
def stats():
|
||||||
|
"""Returns resource utilization statistics similar to `top`"""
|
||||||
|
return get_stats()
|
@ -0,0 +1,51 @@
|
|||||||
|
"""
|
||||||
|
Module contains all logic for retrieving CPU, Memory, and Disk stats.
|
||||||
|
"""
|
||||||
|
import psutil
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
|
from typing import Dict, Any
|
||||||
|
|
||||||
|
STATIC_STATS = {"cpu_count": psutil.cpu_count(logical=True),
|
||||||
|
"boot_time": dt.datetime.fromtimestamp(psutil.boot_time())}
|
||||||
|
|
||||||
|
|
||||||
|
def get_stats() -> Dict[str, Any]:
|
||||||
|
"""Main entrypoint for retrieving system stats."""
|
||||||
|
load_avg = [round(x / psutil.cpu_count(logical=True) * 100, 2) for x in psutil.getloadavg()]
|
||||||
|
mem = psutil.virtual_memory()
|
||||||
|
disk = psutil.disk_usage('/')
|
||||||
|
stats = {'load_avg': load_avg,
|
||||||
|
'mem': {
|
||||||
|
'total': mem.total,
|
||||||
|
'used': mem.used,
|
||||||
|
'free': mem.free,
|
||||||
|
'shared': mem.shared if hasattr(mem, 'shared') else None,
|
||||||
|
'buffers': mem.buffers if hasattr(mem, 'buffers') else None,
|
||||||
|
'cached': mem.cached if hasattr(mem, 'cached') else None,
|
||||||
|
'available': mem.available,
|
||||||
|
'percent': mem.percent,
|
||||||
|
},
|
||||||
|
'tasks': _get_tasks(),
|
||||||
|
}
|
||||||
|
stats.update(STATIC_STATS)
|
||||||
|
return stats
|
||||||
|
|
||||||
|
|
||||||
|
def _get_tasks() -> Dict[str, int]:
|
||||||
|
"""Retrieves a dictionary of task information."""
|
||||||
|
tasks = {
|
||||||
|
'total': 0,
|
||||||
|
'running': 0,
|
||||||
|
'sleeping': 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
for p in psutil.process_iter():
|
||||||
|
with p.oneshot():
|
||||||
|
if p.status() == psutil.STATUS_RUNNING:
|
||||||
|
tasks['running'] += 1
|
||||||
|
if p.status() == psutil.STATUS_SLEEPING:
|
||||||
|
tasks['sleeping'] += 1
|
||||||
|
tasks['total'] += 1
|
||||||
|
|
||||||
|
return tasks
|
@ -0,0 +1,8 @@
|
|||||||
|
from flask.app import Flask
|
||||||
|
from api.api import api_bp
|
||||||
|
from client.client import client_bp
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
|
||||||
|
app.register_blueprint(api_bp, url_prefix='/api_v1')
|
||||||
|
app.register_blueprint(client_bp)
|
@ -0,0 +1,13 @@
|
|||||||
|
from flask.blueprints import Blueprint
|
||||||
|
from flask.templating import render_template
|
||||||
|
|
||||||
|
client_bp = Blueprint('client', __name__,
|
||||||
|
template_folder='templates',
|
||||||
|
static_folder='static',
|
||||||
|
static_url_path='/client/static'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@client_bp.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('base.html')
|
@ -0,0 +1,15 @@
|
|||||||
|
const apiEndpoint = '/api_v1/';
|
||||||
|
|
||||||
|
const vm = new Vue({
|
||||||
|
el: '#vm',
|
||||||
|
delimiters: ['[[', ']]'],
|
||||||
|
data: {
|
||||||
|
greeting: 'Hello Vue!',
|
||||||
|
flaskStats: {}
|
||||||
|
},
|
||||||
|
created: async function(){
|
||||||
|
const gResponse = await fetch(apiEndpoint + 'stats');
|
||||||
|
const glObject = await gResponse.json()
|
||||||
|
this.flaskStats = glObject
|
||||||
|
}
|
||||||
|
})
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<title>Pupper ctl</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('client.static', filename='vendor/tailwind.min.css') }}">
|
||||||
|
<script src="{{ url_for('client.static', filename='vendor/vue.min.js') }}"></script>
|
||||||
|
</head>
|
||||||
|
<body class="font-sans">
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but real-world-vue doesn't work properly without JavaScript enabled. Please enable it to
|
||||||
|
continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<h1 class="text-6xl">Pupperctl</h1>
|
||||||
|
<div id="vm">
|
||||||
|
<p>[[ greeting ]]</p>
|
||||||
|
<p>[[ flaskStats.load_avg ]]</p>
|
||||||
|
</div>
|
||||||
|
<script src="{{ url_for('client.static', filename='app.js') }}" ></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue