from json import load,dump
from genericpath import exists
from ovirtsdk.api import API
from threading import Thread
from time import sleep, time

PERIOD_TIME = 15  # time in seconds between measurements - for data integrity's sake, should match both the engine polling interval (determined by configuration values: NumberVmRefreshesBeforeSave * VdsRefreshRate) and the vdsm polling interval (vm_sample_net_interval in /etc/vdsm/vdsm.conf)
ENGINE_URL = 'http://localhost:8080/api'
USERNAME = 'admin@internal'
PASSWORD = 'foo'
PATHNAME = 'traffic.txt'

RX_ENTRY = 'rx'
TX_ENTRY = 'tx'

api = API(url=ENGINE_URL, username=USERNAME, password=PASSWORD)

def deserialize():
    if exists(PATHNAME):
        f = open(PATHNAME, 'r+')
        traffic = load(f)
        f.close()
    else:
        traffic = {}
    return traffic

def serialize(traffic):
    f = open(PATHNAME, 'w')
    dump(traffic, f)
    f.close()

# returns an up-to-date cumulative NIC network usage
# nicEntry := {'rx' : totalRxInBytes, 'tx' : totalTxInBytes}
def updateNic(nic, nicEntry):
    rx = nicEntry[RX_ENTRY] if (RX_ENTRY in nicEntry) else 0
    tx = nicEntry[TX_ENTRY] if (TX_ENTRY in nicEntry) else 0

    for statistic in nic.statistics.list():
        if statistic.get_name() == 'data.current.rx':
            rx += PERIOD_TIME * statistic.get_values().get_value().pop().get_datum()
        elif statistic.get_name() == 'data.current.tx':
            tx += PERIOD_TIME * statistic.get_values().get_value().pop().get_datum()

    nicEntry[RX_ENTRY] = rx
    nicEntry[TX_ENTRY] = tx

# returns the up-to-date cumulative network usage for all the NICs of a VM
# vmEntry := {nicName1 : nicEntry, nicName2 : nicEntry, ...}
# see nicEntry format in updateNic()
def updateVm(vm, vmEntry):
    for nic in vm.nics.list():
        nicName = nic.get_name()
        nicEntry = {}
        if nicName in vmEntry:
            nicEntry = vmEntry[nicName]
        updateNic(nic, nicEntry)
        vmEntry[nicName] = nicEntry

# returns the up-to-date cumulative network usage for all the NICs of all the VMs in the deployment
# traffic := {vmName1 : vmEntry, vmName2 : vmEntry, ...}
# see vmEntry format in updateVm
def updateAllVms():
    traffic = deserialize()
    for vm in api.vms.list():
        vmName = vm.get_name()
        vmEntry = {}
        if vmName in traffic:
            vmEntry = traffic[vmName]
        updateVm(vm, vmEntry)
        traffic[vmName] = vmEntry
    serialize(traffic)

while True:
    reference = time()
    thread = Thread(target=updateAllVms)
    thread.run()
    overhead = time() - reference
    sleep(PERIOD_TIME - overhead)  # for some reason initializing the thread takes non-negligible amount of time in Python, correct for it

api.disconnect()
