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