#!/usr/bin/python3 import os import sys import lxc import time import datetime import math import pygal import psutil import logging import libvirt import collections collections.MutableSequence = collections.abc.MutableSequence collections.Iterable = collections.abc.Iterable from pygal.style import LightenStyle, LightColorizedStyle from flask import Flask, render_template, Response, request, redirect, url_for, session, escape from flask_fontawesome import FontAwesome from simplepam import authenticate from flask_navigation import Navigation from flask_dropzone import Dropzone from xml.dom import minidom #Flask config flask_port=5005 flask_host='0.0.0.0' flask_thread=True flask_debug=False #Other __version__ = "2.7" #path base for service lauch path = os.path.dirname(__file__) #iso path iso_path= path+'/storage/iso/' #Language lang_created='had been created !' lang_stopped='had been stopped !' lang_forced_stop='Error on Stop, stop had been forced !' lang_started='had been started !' lang_destroyed='had been destroyed !' lang_console='is stopped, please start it first !' lang_console2='is started, please stop it first !' lang_uploaded='had been uploaded !' lang_openconsole='console can be opened in a new tab' lang_already_started='is already started !' lang_deleted='had been deleted !' lang_snapvm='have a new snapshot !' lang_snapvm_failed='had met an error. Snapshot failed !' #Init logs logging.basicConfig(filename=path+'/log/Main-lxc.log', level=logging.DEBUG, format=f'%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s') logging.info('PROGRAM START') #Init Libvirt try: conn = libvirt.open("qemu:///system") except: exit(1) #Init Flask app = Flask(__name__,static_url_path='',static_folder='web/static',template_folder='web/templates') #Init FontAwsome fa = FontAwesome(app) #Init Nav nav = Navigation(app) #DropZone app.config.update( UPLOADED_PATH= iso_path, DROPZONE_MAX_FILE_SIZE = 10240, DROPZONE_TIMEOUT = 5*60*1000, DROPZONE_ALLOWED_FILE_CUSTOM = True, DROPZONE_ALLOWED_FILE_TYPE = '.iso') dropzone = Dropzone(app) #Menu nav.Bar('top', [ nav.Item('Dash', 'index'), nav.Item('State', 'state'), nav.Item('Build', 'build'), nav.Item('Storage','pool'), nav.Item('Monitoring','monit'), nav.Item('Backup','backup'), nav.Item('Host','host'), nav.Item('Logs','logs'), ]) #Graf Pantone dark_lighten_style = LightenStyle('#336676', base_style=LightColorizedStyle, step=2,value_font_size=25) dark_lighten_style.background = 'transparent' #Global fonctions def get_xml(VM): dom=conn.lookupByName(VM) raw_xml = dom.XMLDesc() xml = minidom.parseString(raw_xml) return xml ## @app.route('/del_snap_lxc', methods = ['POST']) def del_snap_lxc(): cont=request.form['cont'] conn=lxc.Container(cont) item=request.form['delete'] item=item.split('_')[2] out=conn.snapshot_destroy(item) if out: resultats='
'+item+' had been deleted !
' else: resultats=''+item+' could not been deleted !
' return render_template('backup.html',listlxc=get_lxc_list(),listvm=list_full_vm(),loguser=session['username'],alertmessage=resultats) @app.route('/rest_snap_lxc', methods = ['POST']) def rest_snap_lxc(): cont=request.form['cont'] ct=lxc.Container(cont) if ct.state=='RUNNING': resultats=''+cont+''+lang_console2+'
' else: item=request.form['restore'] item=item.split('_')[2] out=ct.snapshot_restore(item) if out: resultats=''+item+' had been restored !
' else: resultats=''+item+' could not been restored !
' return render_template('backup.html',listlxc=get_lxc_list(),listvm=list_full_vm(),loguser=session['username'],alertmessage=resultats) @app.route('/del_snap_vm', methods = ['POST']) def del_snap_vm(): item=request.form['delete'] cont=request.form['cont'] dom=conn.lookupByName(cont) snap_2del=dom.snapshotLookupByName(item) out=snap_2del.delete() if out: resultats=''+item+' had been deleted !
' else: resultats=''+item+' could not been deleted !>'
return render_template('backup.html',listlxc=get_lxc_list(),listvm=list_full_vm(),loguser=session['username'],alertmessage=resultats)
@app.route('/logs')
def logs():
if 'username' in session:
resultats=''
return render_template('logs.html',loguser=session['username'],alertmessage=resultats,state_all=get_lxc_state(),listlxc=get_lxc_list(),listdistrib=list_distrib())
return render_template('login.html',title="Logs")
@app.route('/stream')
def stream():
def generate():
with open(path+'/log/Main-lxc.log') as f:
while True:
yield f.read()
time.sleep(1)
return app.response_class(generate(), mimetype='text/plain')
@app.route('/host')
def host():
split_dec=conn.getSysinfo()
split_dec=split_dec.replace('\n', '
')
return render_template('host.html',loguser=session['username'],hostname=conn.getHostname(),hostlist=split_dec,title="Host")
def host_disk():
KB = 1024
MB = 1024 * KB
GB = 1024 * MB
host_disk_total = round(psutil.disk_usage('/').total / GB)
host_disk_used = round(psutil.disk_usage('/').used / GB)
host_disk_percent = psutil.disk_usage('/').percent
host_disk_free = host_disk_total - host_disk_used
host_disk_free_percent = round(100 - host_disk_percent,1)
return host_disk_total, host_disk_used, host_disk_percent, host_disk_free, host_disk_free_percent
def convert_size(bytes_size):
if bytes_size == 0:
return "0B"
size_name = ("B", "KB", "MB", "GB", "TB", "PB")
i = int(math.floor(math.log(bytes_size, 1024)))
p = math.pow(1024, i)
s = round(bytes_size / p, 2)
return"%s %s" % (s,size_name[i])
def get_cdrom_attribut(VM):
xml = get_xml(VM)
diskTypes = xml.getElementsByTagName('disk')
for disk_xml in diskTypes:
if disk_xml.getAttribute('device') == 'cdrom':
target_tag = disk_xml.getElementsByTagName('target')
address_tag = disk_xml.getElementsByTagName('address')
target_dev = target_tag[0].getAttribute('dev')
target_bus = target_tag[0].getAttribute('bus')
address_type = address_tag[0].getAttribute('type')
address_controller = address_tag[0].getAttribute('controller')
address_bus = address_tag[0].getAttribute('bus')
address_target = address_tag[0].getAttribute('target')
address_unit = address_tag[0].getAttribute('unit')
return target_dev, target_bus, address_type, address_controller, address_bus, address_target, address_unit
def mount_iso(VM,ISO):
dom = conn.lookupByName(VM)
target_dev, target_bus, address_type, address_controller, address_bus, address_target, address_unit = get_cdrom_attribut(VM)
diskFile = ISO
diskXML = """
ISO mounted !
' return render_template('build.html',listvm=list_activ_vm(),list_net=conn.listNetworks(),listvm_iso=get_iso_list(),list_profiles=get_os_profile_list(),list_iso=get_iso_list(),list_iso_mount=get_iso_list(),loguser=session['username'],alertmessage=resultats,state_all=get_vm_state(),title="Build",listlxc=get_lxc_list(),listdistrib=list_distrib()) @app.route('/ejectiso', methods = ['POST']) def eject_iso(): VM=request.form['ejectisovm'] state = check_iso_is_mounted(VM) while state != 0: ISO=''; mount_iso(VM,ISO) state = check_iso_is_mounted(VM) resultats='ISO had been ejected !
' return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='Pool: "+pool.name()+" UUID: "+pool.UUIDString()+" Autostart: "+str(pool.autostart())+" Is active: "+str(pool.isActive())+" Is persistent: "+str(pool.isPersistent())+" Num volumes: "+str(pool.numOfVolumes())+" Pool state: "+str(info[0])+" Capacity: "+str(convert_size(info[1]))+" Allocation: "+str(convert_size(info[2]))+" Available: "+str(convert_size(info[3]))+' | '
pool_html=pool_html+'
Pool | Volume Name | Capacity | Allocation | Delete | Chart |
---|---|---|---|---|---|
"+pools+" | "+volume+" | "+str(convert_size(info[1]))+" | "+ str(convert_size(info[2]))+" | " volume_html=volume_html+" |
Nom | State |
---|---|
"+dom.name()+" | "+str(state)+" Max memory : "+ str(convert_size(maxmem*1024))+" Memory : "+ str(convert_size(mem*1024)) vm_monit_html=vm_monit_html+" CPU number : "+str(cpus)+" CPU time : "+str(cput)+" |
Nom | State |
---|---|
"+lxc_name+" | "+ct.state+" Memory : "+ct_meme+"%" ct_monit_html=ct_monit_html+" CPU : "+ct_cpu+"% |
'+ct_state.state+'
' else: color_ct_state=''+ct_state.state+'
' out=out+'Name | State | Actions | IP |
---|