Hype/hype.py

882 lines
43 KiB
Python

#!/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='<p id="alert" style="color:green"><b>'+item+'</b> had been deleted !</p>'
else:
resultats='<p id="alert" style="color:red"><b>'+item+'</b> could not been deleted !</p>'
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='<p id="alert" style="color:red"><b>'+cont+'</b>'+lang_console2+'</p>'
else:
item=request.form['restore']
item=item.split('_')[2]
out=ct.snapshot_restore(item)
if out:
resultats='<p id="alert" style="color:green"><b>'+item+'</b> had been restored !</p>'
else:
resultats='<p id="alert" style="color:red"><b>'+item+'</b> could not been restored !</p>'
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='<p id="alert" style="color:green"><b>'+item+'</b> had been deleted !</p>'
else:
resultats='<p id="alert" style="color:red"><b>'+item+'</b> 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', '<br>')
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 = """ <disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='""" + diskFile + """'/>
<target dev='""" + target_dev + """' bus='""" + target_bus + """'/>
<address type='""" + address_type + """' controller='""" + address_controller + """' bus='""" + address_bus + """' target='""" + address_target + """' unit='""" + address_unit + """'/>
</disk>"""
dom.updateDeviceFlags(diskXML, 0)
def check_iso_is_mounted(VM):
dom = conn.lookupByName(VM)
raw_xml = dom.XMLDesc()
xml = minidom.parseString(raw_xml)
diskTypes = xml.getElementsByTagName('disk')
for disk_xml in diskTypes:
disk = None
source = disk_xml.getElementsByTagName('source')
if disk_xml.getAttribute('device') == 'cdrom':
try:
gotdata= source[0].getAttribute('file')
if source[0].getAttribute('file'):
state = 1
else:
state = 0
except IndexError:
state = 0
#Return 1 if mounted or 0 if not mounted
return state
@app.route("/mountiso", methods=['POST'])
def mountiso():
VM=request.form['vm']
ISO=iso_path+request.form['iso']
mount_iso(VM,ISO)
resultats='<p id="alert" style="color:green">ISO mounted !</p>'
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='<p id="alert" style="color:green">ISO had been ejected !</p>'
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Containers</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Servers</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
def get_vm_devices(VM):
xml = get_xml(VM)
diskTypes = xml.getElementsByTagName("disk")
full_list=[]
for diskType in diskTypes:
list_vm=[]
list_vm.append(diskType.getAttribute("device"))
diskNodes = diskType.childNodes
for diskNode in diskNodes:
if diskNode.nodeName[0:1] != "#":
if diskNode.nodeName=='source':
for attr in diskNode.attributes.keys():
list_vm.append(diskNode.attributes[attr].value)
full_list.append(list_vm)
full_list.reverse()
return full_list
@app.route('/devicelist', methods = ['POST'])
def get_devices():
list_devices=[]
full_vm_list=list_activ_vm()+list_inactiv_vm()
for vm_name in full_vm_list:
list_vm=get_vm_devices(vm_name)
list_vm.insert(0, vm_name)
list_devices.append(list_vm)
return list_devices
def storage_get_pool():
pool_html='<table class="table table-responsive table-condensed align-middle mb-0"><tr>'
##Cleaning Pool cache to avoid error due to deleted entries
for refresh_pool in conn.listAllStoragePools():
refresh_pool.refresh(0)
for pools in conn.listStoragePools():
pool = conn.storagePoolLookupByName(pools)
info = pool.info()
if info[1]==0:
pool_used=0
else:
pool_used=round((info[2]*100)/info[1],2)
pool_free=100-pool_used
graf_pool=pygal.Pie(value_font_size=25,half_pie = True,fill=True, interpolate='cubic', style=dark_lighten_style, legend_at_bottom=True,show_legend=False)
graf_pool.add("Used",pool_used)
graf_pool.add("Free",pool_free)
graf_pool=graf_pool.render_data_uri()
pool_html=pool_html+"<td><img src='"+graf_pool+"' style='width:200px'><br>Pool: <b>"+pool.name()+"</b><br>UUID: "+pool.UUIDString()+"<br>Autostart: "+str(pool.autostart())+"<br>Is active: "+str(pool.isActive())+"<br>Is persistent: "+str(pool.isPersistent())+"<br>Num volumes: "+str(pool.numOfVolumes())+"<br>Pool state: "+str(info[0])+"<br>Capacity: "+str(convert_size(info[1]))+"<br>Allocation: "+str(convert_size(info[2]))+"<br>Available: "+str(convert_size(info[3]))+'</td>'
pool_html=pool_html+'</tr></table>'
return pool_html
@app.route('/delvol', methods = ['POST'])
def dellvol():
pool_item=request.form['pool']
volume_item=request.form['volume']
pools=conn.storagePoolLookupByName(pool_item)
vlm=pools.storageVolLookupByName(volume_item)
vlm.delete()
return redirect(url_for('pool'))
def storage_get_volumes():
volume_html='<table class="table table-responsive table-hover table-condensed align-middle mb-0 bg-white"><tr><th>Pool</th><th>Volume Name</th><th>Capacity</th><th>Allocation</th><th>Delete</th><th>Chart</th></tr>'
##Cleaning Pool cache to avoid error due to deleted entries
for refresh_pool in conn.listAllStoragePools():
refresh_pool.refresh(0)
for pools in conn.listStoragePools():
pool=conn.storagePoolLookupByName(pools)
for volume in pool.listVolumes():
vol = pool.storageVolLookupByName(volume)
info = vol.info()
if info[1]==0:
vol_used=0
else:
vol_used=round((info[2]*100)/info[1],2)
vol_free=100-vol_used
vol_graf=pygal.Pie(value_font_size=25,half_pie = True,fill=True, interpolate='cubic', style=dark_lighten_style, show_legend=False)
vol_graf.add("Used",vol_used)
vol_graf.add("Free",vol_free)
vol_graf=vol_graf.render_data_uri()
volume_html=volume_html+"<tr><td>"+pools+"</td><td>"+volume+"</td><td>"+str(convert_size(info[1]))+"</td><td>"+ str(convert_size(info[2]))+"</td><td>"
volume_html=volume_html+"<form action=\"/delvol\" method=\"post\"><input type=\"hidden\" name=\"pool\" value=\""+pools+"\"><button type=\"submit\" name=\"volume\" value=\""+volume+"\"><span class=\"fas fa-trash\"></span></button></form></td><td><img src='"+vol_graf+"' style='width:40px'></tr>"
volume_html=volume_html+"</table>"
return volume_html
def global_cpu_monit():
cpu_percent_used=psutil.cpu_percent()
cpu_percent_free=100-cpu_percent_used
cpu_usage=psutil.cpu_times_percent()
cpu_usage_html="Kernel: "+str(cpu_usage.system)+"%<br>User: "+str(cpu_usage.user)+"%<br>Idle: "+str(cpu_usage.idle)+"%<br>IO wait: "+str(cpu_usage.iowait)+"%<br>"
return cpu_usage_html, cpu_percent_used, cpu_percent_free
def global_mem_monit():
mem_percent_used=psutil.virtual_memory().percent
mem_percent_free=100-mem_percent_used
memory_usage= conn.getMemoryStats(libvirt.VIR_NODE_MEMORY_STATS_ALL_CELLS)
memory_usage_html="Total: "+str(convert_size(memory_usage['total']*1024))+"<br>Free: "+str(convert_size(memory_usage['free']*1024))+"<br>Buffers: "+str(convert_size(memory_usage['buffers']*1024))+"<br>Cached: "+str(convert_size(memory_usage['cached']*1024))+"<br>".format(**memory_usage)
return memory_usage_html, mem_percent_used, mem_percent_free
def vm_monit():
vm_monit_html='<table class="table table-responsive table-hover table-condensed align-middle mb-0"><tr><th>Nom</th><th>State</th></tr>'
full_vm_list=list_activ_vm()+list_inactiv_vm()
for vm_name in full_vm_list:
dom=conn.lookupByName(vm_name)
state, maxmem, mem, cpus, cput = dom.info()
if state==1:
state="RUNNING"
else:
state="STOPPED"
vm_monit_html=vm_monit_html+"<tr><td>"+dom.name()+"<td>"+str(state)+"<br>Max memory : "+ str(convert_size(maxmem*1024))+"<br>Memory : "+ str(convert_size(mem*1024))
vm_monit_html=vm_monit_html+"<br>CPU number : "+str(cpus)+"<br>CPU time : "+str(cput)+"</td></tr>"
vm_monit_html=vm_monit_html+"</table>"
return vm_monit_html
def lxc_monit():
ct_monit_html='<table class="table table-responsive table-hover table-condensed align-middle mb-0"><tr><th>Nom</th><th>State</th></tr>'
for lxc_name in get_lxc_list():
ct=lxc.Container(lxc_name)
if ct.state=='RUNNING':
p=psutil.Process(ct.init_pid)
ct_cpu=str(round(p.cpu_percent(), 2))
ct_meme=str(round(p.memory_percent(), 2))
else:
ct_meme='0'
ct_cpu='0'
ct_monit_html=ct_monit_html+"<tr><td>"+lxc_name+"<td>"+ct.state+"<br>Memory : "+ct_meme+"%"
ct_monit_html=ct_monit_html+"<br>CPU : "+ct_cpu+"%</td></tr>"
ct_monit_html=ct_monit_html+"</table>"
return ct_monit_html
def list_activ_vm():
list_run_id=conn.listDomainsID()
list_run=[]
for id in list_run_id:
dom=conn.lookupByID(id)
list_run.append(dom.name())
return list_run
def list_inactiv_vm():
list_vm=conn.listDefinedDomains()
return list_vm
def list_full_vm():
full_vm_list=list_activ_vm()+list_inactiv_vm()
return full_vm_list
def list_distrib():
link_list = ['debian','ubuntu','centos','busybox','ubuntu-cloud','cirros','sabayon']
name_list = ['Debian','Ubuntu','Centos','Busybox','Ubuntu-cloud','Cirros','Sabayon']
listd = zip(name_list, link_list)
return listd
def get_iso_list():
list_iso_path= []
list_iso_size= []
for x in os.listdir(iso_path):
if x.endswith(".iso"):
size=os.path.getsize(iso_path+x)
size=convert_size(size)
list_iso_size.append(str(size))
list_iso_path.append(str(x))
list_iso=zip(list_iso_path, list_iso_size)
return list_iso
def get_os_profile_list():
list_profile=[]
for profile in os.popen("osinfo-query os | awk '{ print $1 }' | awk 'NR > 2 { print }'"):
list_profile.append(str(profile))
return list_profile
def get_lxc_list():
liste_ct=lxc.list_containers()
return liste_ct
def get_lxc_activ():
activ_ct = 0
inactiv_ct = 0
for ct_name in get_lxc_list():
ct_state=lxc.Container(ct_name)
if ( ct_state.state == "RUNNING"):
activ_ct +=1
else:
inactiv_ct +=1
return activ_ct,inactiv_ct
def get_lxc_state():
out=''
for ct_name in get_lxc_list():
ct_state=lxc.Container(ct_name)
if ( ct_state.state == "RUNNING"):
color_ct_state='<p style="background-color:PaleGreen">'+ct_state.state+'</p>'
else:
color_ct_state='<p style="background-color:lightcoral">'+ct_state.state+'</p>'
out=out+'<tr><td>'+ct_name+'</td><td>'
out=out+color_ct_state+'</td><td><div id="action"><center><table class="tacs"><tr><td><form action="/startct" method="post"><button type="submit" value="'+ct_name+'" name="start" onclick="loading();">'
out=out+'<span class="fas fa-play"></span></button></form></td><td><form class="flotte" action="/stopct" method="post"><button type="submit" value="'+ct_name+'" name="stop" onclick="loading();">'
out=out+'<span class="fas fa-stop"></span></button></form></td><td><form class="flotte" action="/destroyct" method="post"><button type="submit" value="'+ct_name+'" name="destroy" onclick="loading();">'
out=out+'<span class="fas fa-trash"></span></button></form></td><td><form class="flotte" action="/console" method="post"><button type="submit" value="'+ct_name+'" name="console" onclick="loading();">'
out=out+'<span class="fas fa-terminal"></span></button></form></td></tr></table></center></div></td><td>'
out=out+str(ct_state.get_ips()).replace('(', '').replace(')', '').replace(',', '').replace('\'', '')+'</td></tr>'
out='<table class="table table-responsive table-hover table-condensed align-middle mb-0 bg-white"><tr><th>Name</th><th>State</th><th>Actions</th><th>IP</th></tr>'+out+'</table>'
return out
def get_snap_list_lxc(cont):
dom=lxc.Container(cont)
list_snap_lxc = dom.snapshot_list()
out=[]
for snap in list_snap_lxc:
nom_snap=snap[0]
date_snap=datetime.datetime.strptime(snap[2], '%Y:%m:%d %H:%M:%S')
date_snap=date_snap.strftime("%d%m%Y%H%M")
concat_name=dom.name+"_"+date_snap+"_"+nom_snap
out.append(concat_name)
return out
def get_snap_list_vm(cont):
dom=conn.lookupByName(cont)
list_snap_vm=dom.snapshotListNames()
list_snap_vm.reverse()
out=[]
for snap in list_snap_vm:
out.append(snap)
return out
def get_vm_ips(vm):
dom=conn.lookupByName(vm)
if not dom:
raise SystemExit("Failed to connect to Dom")
try:
ifaces = dom.interfaceAddresses(libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT)
except:
ifaces = None
result="--.--.--.--"
if ifaces is None:
result="--.--.--.--"
else:
for (name, val) in ifaces.items():
if val['addrs']:
for addr in val['addrs']:
if addr['addr']:
result=str(addr['addr'])+"/"+str(addr['prefix'])
break
else:
result="-"
return result
def get_vm_state():
out=''
for activ_vm in list_activ_vm():
disk_state=check_iso_is_mounted(activ_vm)
if disk_state == 1:
disk_color='<p style="color:black"><form class="flotte" action="/ejectiso" method="post"><span class="fas fa-compact-disc"></span></p></td><td><form class="flotte" action="/ejectiso" method="post"><button style="border:0" type="submit" value="'+activ_vm+'" name="ejectisovm" onclick="loading();"><span class="fas fa-eject"></span></button></form>'
else:
disk_color='<p style="color:LightGray"><span class="fas fa-compact-disc"></span></p></td><td>'
color_vm_state='<p style="background-color:PaleGreen">RUNNING</p>'
out=out+'<tr><td>'+activ_vm+'</td><td>'
out=out+color_vm_state+'</td><td><div id="action"><center><table class="tacs"><tr><td><form action="/startvm" method="post"><button type="submit" value="'+activ_vm+'" name="startvm" onclick="loading();">'
out=out+'<span class="fas fa-play"></span></button></form></td><td><form class="flotte" action="/stopvm" method="post"><button type="submit" value="'+activ_vm+'" name="stopvm" onclick="loading();">'
out=out+'<span class="fas fa-stop"></span></button></form></td><td><form class="flotte" action="/destroyvm" method="post"><button type="submit" value="'+activ_vm+'" name="destroyvm" onclick="loading();">'
out=out+'<span class="fas fa-trash"></span></button></form></td><td><form class="flotte" action="/consolevm" method="post"><button type="submit" value="'+activ_vm+'" name="consolevm" onclick="loading();">'
out=out+'<span class="fas fa-terminal"></span></button></form></td></tr></table></center></div></td><td>'
out=out+get_vm_ips(activ_vm)+'</td><td>'+disk_color+'</td></tr>'
for inactiv_vm in list_inactiv_vm():
color_vm_state='<p style="background-color:lightcoral">STOPPED</p>'
out=out+'<tr><td>'+inactiv_vm+'</td><td>'
out=out+color_vm_state+'</td><td><div id="action"><center><table class="tacs"><tr><td><form action="/startvm" method="post"><button type="submit" value="'+inactiv_vm+'" name="startvm" onclick="loading();">'
out=out+'<span class="fas fa-play"></span></button></form></td><td><form class="flotte" action="/stopvm" method="post"><button type="submit" value="'+inactiv_vm+'" name="stopvm" onclick="loading();">'
out=out+'<span class="fas fa-stop"></span></button></form></td><td><form class="flotte" action="/destroyvm" method="post"><button type="submit" value="'+inactiv_vm+'" name="destroyvm" onclick="loading();">'
out=out+'<span class="fas fa-trash"></span></button></form></td><td><form class="flotte" action="/consolevm" method="post"><button type="submit" value="'+inactiv_vm+'" name="consolevm" onclick="loading();">'
out=out+'<span class="fas fa-terminal"></span></button></form></td></tr></table></center></div></td><td>'
out=out+'IP</td><td></td></tr>'
out='<table class="table table-responsive table-hover table-condensed align-middle mb-0 bg-white"><tr><th>Name</th><th>State</th><th>Actions</th><th>IP</th><th>Disk</th></tr>'+out+'</table>'
return out
def mount_pts():
os.system('mount -o remount,rw /dev/pts')
@app.route('/state')
def state():
resultats=''
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Containers</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Servers</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route('/snap_vm', methods = ['POST'])
def create_snap():
nom = request.form['nom']
dom=conn.lookupByName(nom)
actual_date=datetime.datetime.now()
actual_date=actual_date.strftime("%d%m%Y%H%M")
snapshot_name= dom.name()+"_"+actual_date+"_snap"
SNAPSHOT_XML_TEMPLATE = """<domainsnapshot>
<name>{snapshot_name}</name>
</domainsnapshot>"""
dom.snapshotCreateXML(SNAPSHOT_XML_TEMPLATE.format(snapshot_name=snapshot_name),libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC)
if dom.snapshotCurrent().getName()==snapshot_name:
resultats='<p id="alert" style="color:green"><b>'+nom+'</b> '+lang_snapvm+'</p>'
else:
resultats='<p id="alert" style="color:red"><b>'+nom+'</b> '+lang_snapvm_failed+'</p>'
return render_template('backup.html',listlxc=list_snap_lxc,listvm=list_snap_vm,loguser=session['username'],alertmessage=resultats)
@app.route('/snap_lxc', methods = ['POST'])
def create_snap_lxc():
nom = request.form['nom']
cont=lxc.Container(nom)
if ( cont.state == "STOPPED"):
try:
snap=cont.snapshot()
resultats='<p id="alert" style="color:green"><b>'+nom+'</b> '+lang_snapvm+'</p>'
except:
resultats='<p id="alert" style="color:red"><b>'+nom+'</b> Snapshot Failed !</p>'
else:
resultats='<p id="alert" style="color:red"><b>'+nom+'</b> Should be stopped first !</p>'
full_snap_lxc=[]
full_snap_vm=[]
for int in get_lxc_list():
if get_snap_list_lxc(int):
full_snap_lxc.append(get_snap_list_lxc(int))
else:
full_snap_lxc.append('')
for ant in list_full_vm():
if get_snap_list_vm(ant):
full_snap_vm.append(get_snap_list_vm(ant))
else:
full_snap_vm.append('')
list_snap_lxc = zip(get_lxc_list(), full_snap_lxc)
list_snap_vm = zip(list_full_vm(), full_snap_vm)
return render_template('backup.html',listlxc=list_snap_lxc,listvm=list_snap_vm,loguser=session['username'],alertmessage=resultats)
@app.route('/backup')
def backup():
resultats=''
full_snap_lxc=[]
full_snap_vm=[]
for int in get_lxc_list():
if get_snap_list_lxc(int):
full_snap_lxc.append(get_snap_list_lxc(int))
else:
full_snap_lxc.append('')
for ant in list_full_vm():
if get_snap_list_vm(ant):
full_snap_vm.append(get_snap_list_vm(ant))
else:
full_snap_vm.append('')
list_snap_lxc = zip(get_lxc_list(), full_snap_lxc)
list_snap_vm = zip(list_full_vm(), full_snap_vm)
return render_template('backup.html',listlxc=list_snap_lxc,listvm=list_snap_vm,loguser=session['username'],alertmessage=resultats,title="Backups")
@app.route('/',methods = ['GET', 'POST'])
def index():
app.logger.info('Info level log')
app.logger.warning('Warning level log')
if 'username' in session:
resultats=''
global_cpu, cpu_percent_used, cpu_percent_free=global_cpu_monit()
global_ram, mem_percent_used, mem_percent_free=global_mem_monit()
activ_ct, inactiv_ct = get_lxc_activ()
host_disk_total, host_disk_used, host_disk_percent, host_disk_free, host_disk_free_percent = host_disk()
memory_usage= conn.getMemoryStats(libvirt.VIR_NODE_MEMORY_STATS_ALL_CELLS)
memory_total=convert_size(memory_usage['total']*1024)
memory_free=convert_size(memory_usage['free']*1024)
memory_buffers=convert_size(memory_usage['buffers']*1024)
memory_cached=convert_size(memory_usage['cached']*1024)
return render_template('index.html',host_disk_total=host_disk_total, host_disk_used=host_disk_used, host_disk_percent=host_disk_percent, host_disk_free=host_disk_free, host_disk_free_percent=host_disk_free_percent,hostname=conn.getHostname(),activ_vm=len(list_activ_vm()),inactiv_vm=len(list_inactiv_vm()),activ_ct=activ_ct,inactiv_ct=inactiv_ct,cpu_percent_used=cpu_percent_used,cpu_percent_free=cpu_percent_free,mem_percent_used=mem_percent_used,mem_percent_free=mem_percent_free,memory_total=memory_total,memory_free=memory_free,memory_buffers=memory_buffers,memory_cached=memory_cached,loguser=session['username'],title="Dashboard")
return render_template('login.html',title="Welcome")
@app.route('/upload', methods = ['GET', 'POST'])
def upload():
resultats=''
if request.method == 'POST':
f = request.files.get('file')
f.save(os.path.join(app.config['UPLOADED_PATH'],f.filename))
resultats='<p id="alert" style="color:green"><b>'+f.filename+'</b> '+lang_uploaded+'</p>'
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('/deliso', methods = ['POST'])
def delete_iso():
file=request.form['fichier']
location = app.config['UPLOADED_PATH']
path=os.path.join(location, file)
os.remove(path)
resultats='<p id="alert" style="color:green"><b>'+file+'</b> '+lang_deleted+'</p>'
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('/build')
def build():
if 'username' in session:
resultats=''
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())
return render_template('login.html')
@app.route('/monit')
def monit():
resultats=''
global_cpu, cpu_percent_used, cpu_percent_free=global_cpu_monit()
global_ram, mem_percent_used, mem_percent_free=global_mem_monit()
return render_template('monit.html',lxc_monit=lxc_monit(),vm_monit=vm_monit(),global_cpu=global_cpu,global_memory=global_ram,cpu_percent_used=cpu_percent_used,cpu_percent_free=cpu_percent_free, mem_percent_used=mem_percent_used,mem_percent_free=mem_percent_free,loguser=session['username'],alertmessage=resultats,title="Monitoring")
@app.route('/pool')
def pool():
resultats=''
return render_template('pool.html',volumes_det=storage_get_volumes(),pool_det=storage_get_pool(),loguser=session['username'],alertmessage=resultats,title="Pools")
@app.route("/creation", methods=['POST'])
def create_CT():
mount_pts()
nom = request.form['nom']
os = request.form['os']
ip = request.form['ip']
container=lxc.Container(nom)
resultats=container.create(os)
if request.form['ip']:
file_object = open('/var/lib/lxc/'+nom+'/config', 'a')
file_object.write('lxc.net.0.ipv4.address = '+ip+'\n')
file_object.write('lxc.net.0.ipv4.gateway = auto')
file_object.close()
if ( resultats == True ):
logging.info('CREATION - New contanier : '+nom+' - '+os+' ! ')
resultats='<p id="alert" style="color:green"><b>'+nom+'</b> '+lang_created+'</p>'
else:
if len(nom.split()) > 1:
logging.warning('CREATION FAILED - Too many word in <b>'+nom+'</b>, please use one word !')
resultats='<p id="alert" style="color:red">Too many word in <b>'+nom+'</b>, please use only one word !</p>'
else:
logging.warning('CREATION FAILED - Error on <b>'+nom+'</b> creation : '+os+' !')
resultats='<p id="alert" style="color:red">An Error append for <b>'+nom+'</b> !</p>'
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("/creationvm", methods=['POST'])
def create_VM():
nom = request.form['nom']
ram = request.form['ram']
cpu = request.form['cpu']
ose = request.form['os']
iso = request.form['iso']
iso = iso_path+iso
net = request.form['net']
disk = request.form['disk']
os.system('kill -9 $(ps -edf | grep pyxter | grep -v grep | awk \'{ print $2 }\')')
## VOIR TODO
##VERSION SERIE
# creationcmd='--name '+str(nom)+' --ram '+str(ram)+' --disk pool=default,size='+str(disk)+',bus=virtio,format=qcow2 --vcpus '+str(cpu)+' --os-type linux --os-variant '+str(ose)+' --network network:bridged --graphics none --console pty,target_type=serial --cdrom '+str(iso)+' --extra-args \'console=ttyS0,115200n8 serial\' --force --debug '
# os.system('/usr/bin/python3 -m pyxtermjs --command "virt-install" --host 0.0.0.0 --cmd-args "'+creationcmd+'" &')
##VERSION VNC
creationcmd='--name '+str(nom)+' --ram '+str(ram)+' --disk pool=default,size='+str(disk)+',bus=virtio,format=qcow2 --vcpus '+str(cpu)+' --os-type linux --os-variant '+str(ose)+' --network network:bridged --graphics vnc,listen=0.0.0.0 --noautoconsole --console pty,target_type=serial --cdrom '+str(iso)+' --force --debug '
os.system('virt-install'+creationcmd+'" &')
##
resultats='<p id="consolemessage" style="color:blue"><b>'+nom+'</b> '+lang_openconsole+'<button id="ModalBtn"><span class="fas fa-terminal"></span></button></p>'
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("/console",methods=['POST'])
def console():
mount_pts()
plx_console = request.form['console']
plx_console_state=lxc.Container(plx_console)
if ( plx_console_state.state == "STOPPED"):
resultats='<p id="alert" style="color:red"><b>'+plx_console+'</b> '+lang_console+' </p>'
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Container</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Server</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
os.system('kill -9 $(ps -edf | grep pyxter | grep -v grep | awk \'{ print $2 }\')')
os.system('/usr/bin/python3 -m pyxtermjs --command "lxc-attach" --cmd-args '+plx_console+' &')
time.sleep(2)
self_url=request.url_root
self_url=self_url.split(":")[1]
resultats='<p id="consolemessage" style="color:blue"><b>'+plx_console+'</b> '+lang_openconsole+'<button id="ModalBtn"><span class="fas fa-terminal"></span></button></p>'
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Container</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Server</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/consolevm",methods=['POST'])
def consolevm():
vm_console = request.form['consolevm']
dom=conn.lookupByName(vm_console)
if not conn:
raise SystemExit("Failed to open connection to Dom")
if dom.isActive():
os.system('kill -9 $(ps -edf | grep pyxter | grep -v grep | awk \'{ print $2 }\')')
os.system('/usr/bin/python3 -m pyxtermjs --command "virsh" --cmd-args "console '+vm_console+'" &')
time.sleep(2)
resultats='<p id="consolemessage" style="color:blue"><b>'+vm_console+'</b> '+lang_openconsole+'<button id="ModalBtn"><span class="fas fa-terminal"></span></button></p>'
else:
resultats='<p id="alert" style="color:red"><b>'+vm_console+'</b> '+lang_console+'</p>'
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Containers</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Servers</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/startct", methods=['POST'])
def start_ct():
mount_pts()
nom = request.form['start']
container=lxc.Container(nom)
if container.state=='RUNNING':
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_already_started+'</p>';
else:
container.start()
container.wait("RUNNING", 3)
logging.info('START - Started '+nom+' !')
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_started+'</p>';
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Containers</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Servers</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/stopct", methods=['POST'])
def stop_ct():
nom = request.form['stop']
container=lxc.Container(nom)
container.stop()
container.wait("STOPPED", 3)
logging.info('STOP - Stopped '+nom+' !')
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_stopped+'</p>';
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Containers</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Servers</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/startvm", methods=['POST'])
def start_vm():
nom=request.form['startvm']
dom=conn.lookupByName(nom)
if dom.isActive():
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_already_started+'</p>';
logging.info('START VM - Already tarted '+nom+' !')
else:
dom.create()
time.sleep(3)
alive=0
while alive < 3:
if dom.isActive():
alive=4
else:
logging.info('WAIT START VM - (TEST'+str(alive)+'/3)'+nom+' !')
time.sleep(3)
alive+=1
logging.info('START VM - Started '+nom+' !')
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_started+'</p>';
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Containers</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Servers</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/stopvm", methods=['POST'])
def stop_vm():
nom=request.form['stopvm']
dom=conn.lookupByName(nom)
dom.shutdown()
time.sleep(3)
alive=0
while alive < 5:
if dom.isActive():
logging.info('WAIT STOP VM - (TEST'+str(alive)+'/5)'+nom+' !')
time.sleep(3)
alive+=1
else:
alive=6
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_stopped+'</p>';
logging.info('STOP VM - Stopped'+nom+' !')
if dom.isActive():
#If not shutdown after 5 attempt, force stop (freeze VM, or OS not installed for example)
dom.destroy()
logging.info('ERROR STOP VM - Forced stopped'+nom+' !')
resultats='<p id="alert" style="color:red"><b>'+nom+'</b> '+lang_forced_stop+' </p>';
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all=get_lxc_state()+"<br>"+get_vm_state(),title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/destroyct", methods=['POST'])
def destroy_ct():
nom = request.form['destroy']
container=lxc.Container(nom)
if ( container.state == "RUNNING"):
resultats='<p id="alert" style="color:red"><b>'+nom+'</b> is running, stop it first !</p>';
else:
container.stop()
container.wait("STOPPED", 3)
container.destroy()
alive=0
while alive < 3:
if (nom in get_lxc_list()):
logging.info('WAIT DESTROY CT - (TEST'+str(alive)+'/3)'+nom+' !')
time.sleep(3)
alive+=1
logging.info('ERROR DESTROY CT - '+nom+' !')
resultats='<p id="alert" style="color:red"><b>'+nom+'</b> Error on Destroy </p>';
else:
alive=4
logging.info('DESTROY - Destroyed '+nom+' !')
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_destroyed+'</p>';
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all=get_lxc_state()+"<br>"+get_vm_state(),title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/destroyvm", methods=['POST'])
def destroy_vm():
nom=request.form['destroyvm']
dom=conn.lookupByName(nom)
if dom.isActive()==True:
resultats='<p id="alert" style="color:red"><b>'+nom+'</b> '+lang_console2+'</p>';
else:
dom.undefine()
time.sleep(3)
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> '+lang_destroyed+'</p>';
logging.info('DESTROY VM - Destoryed'+nom+' !')
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all='<div class="card"><div class="card-header">Containers</div><div class="card-body">'+get_lxc_state()+'</div></div><div class="card"><div class="card-header">Virtual Servers</div><div class="card-body">'+get_vm_state()+"</div></div>",title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route("/renamect", methods=['POST'])
def rename_ct():
mount_pts()
nom=request.form['nom']
newname=request.form['newname']
if len(newname.split()) > 1:
logging.warning('RENAME FAILED - Too many word in '+nom+', please use one word !')
resultats='<p id="alert" style="color:red">Too many word in <b>'+newname+'</b>, please use only one word !</p>'
else:
container=lxc.Container(nom)
container.stop()
container.wait("STOPPED", 3)
container.rename(newname)
logging.info('RENAME - '+nom+' is now known as '+newname+' !')
resultats='<p id="alert" style="color:blue"><b>'+nom+'</b> is known as <b>'+newname+'</b> ! </p>'
return render_template('state.html',loguser=session['username'],alertmessage=resultats,state_all=get_lxc_state()+"<br>"+get_vm_state(),title="State",listlxc=get_lxc_list(),listdistrib=list_distrib())
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if authenticate(str(username), str(password)):
session['username'] = request.form['username']
logging.info('AUTH LOG - New auth from '+username+' !')
return redirect(url_for('index'))
else:
resultats='<p id="alert" style="color:red">Invalid Username/Password ! </p>'
return render_template('login.html', alertmessage=resultats)
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('index'))
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
if __name__ == '__main__':
app.run(host=flask_host, port=flask_port, threaded=flask_thread, debug=flask_debug)