import os
import json
import time
import threading
import configparser
import ovirtsdk4 as sdk
from pyzabbix import ZabbixMetric, ZabbixSender

ZABBIX_AGENT_CONF_PATH = '/etc/zabbix/zabbix_agentd.conf'
CONFIG_FILE = '/etc/zvirt-monitor/zvirt_monitor.conf'
USE_ZABBIX_CONF = True if os.path.isfile(ZABBIX_AGENT_CONF_PATH) else None


class requester_thread(threading.Thread):
    def __init__(self, name, config_list):
        threading.Thread.__init__(self)
        self.name = name
        self.config_list = config_list
        self.kill_received = False

    def run(self):
        while not self.kill_received:
            starttime = time.time()
            try:
                metrics = query_zvirt(self.config_list)
                send_to_Zabbix(self.config_list[4], metrics)
                # time.sleep(60)
                time.sleep(60.0 - ((time.time() - starttime) % 60.0))
            except:
                print("ERROR: Unable to connect to server")
                time.sleep(10)
   

def query_zvirt(config_list):
    connection = sdk.Connection(
        url=str(config_list[0]),
        username=str(config_list[1]), 
        password=str(config_list[2]), 
        ca_file=str(config_list[3]), 
    )

    system_service = connection.system_service()

    hosts_service = system_service.hosts_service()
    vms_service = system_service.vms_service()
    storage_domains_service = system_service.storage_domains_service()
    disks_service = system_service.disks_service()
    clusters_service = system_service.clusters_service()
    data_centers_service = system_service.data_centers_service()
    networks_service = system_service.networks_service()

    metrics = dict()

    api = system_service.get()
    api_data = {'name': api.product_info.name,
                'hosts': {'active': api.summary.hosts.active,
                        'total': api.summary.hosts.total},
                'storage_domains': {'active': api.summary.storage_domains.active,
                                    'total': api.summary.storage_domains.total},
                'users': {'active': api.summary.users.active,
                        'total': api.summary.users.total},
                'vms': {'active': api.summary.vms.active,
                        'total': api.summary.vms.total},
                'networks': {'total': sum(1 for network in networks_service.list())}
		}

    metrics['zvirt.api'] = json.dumps(api_data)

    hosts = hosts_service.list()
    hosts_data = []

    for host in hosts:
        host_stats = connection.follow_link(host.statistics)
        host_stats_data = dict()

        for stat in host_stats:
            if len(stat.values) != 0:
                host_stats_data[stat.name] = stat.values[0].datum

        host_data = {'name': host.name,
                    'id': host.id,
                    'external_status': host.external_status.value,
                    'hosts': {'active': host.summary.active,
                            'migrating': host.summary.migrating,
                            'total': host.summary.total},
                    'status': host.status.value,
                    'statistics': host_stats_data
                    }
        hosts_data.append(host_data)

    metrics['zvirt.hosts'] = json.dumps(hosts_data)

    vms = vms_service.list()
    vms_data = []

    for vm in vms:
        vm_stats = connection.follow_link(vm.statistics)
        vm_stats_data = dict()

        for stat in vm_stats:
            if len(stat.values) != 0:
                vm_stats_data[stat.name] = stat.values[0].datum

        vm_data = {'name': vm.name,
                'id': vm.id,
                'status': vm.status.value,
                'statistics': vm_stats_data
                }
        vms_data.append(vm_data)

    metrics['zvirt.vms'] = json.dumps(vms_data)

    storage_domains = storage_domains_service.list()
    storage_domains_data = []

    for storage_domain in storage_domains:
        if not storage_domain.status:
            status = 0
        else:
            status = storage_domain.status.value

        if not storage_domain.external_status:
            external_status = 0
        else:
            external_status = storage_domain.external_status.value

        storage_domain_data = {'name': storage_domain.name,
                            'id': storage_domain.id,
                            'status': status,
                            'external_status': external_status,
                            'available': storage_domain.available,
                            'committed': storage_domain.committed,
                            'critical_space_action_blocker': storage_domain.critical_space_action_blocker
                            }
        storage_domains_data.append(storage_domain_data)

    metrics['zvirt.storage_domains'] = json.dumps(storage_domains_data)

    disks = disks_service.list()
    disks_data = []

    for disk in disks:
        if not disk.status:
            status = 0
        else:
            status = disk.status.value

        disk_stats = connection.follow_link(disk.statistics)
        disk_stats_data = dict()

        for stat in disk_stats:
            if len(stat.values) != 0:
                disk_stats_data[stat.name] = stat.values[0].datum

        disk_data = {'name': disk.name,
                    'id': disk.id,
                    'status': status,
                    'statistics': disk_stats_data
                    }
        disks_data.append(disk_data)

    metrics['zvirt.disks'] = json.dumps(disks_data)

    data_centers = data_centers_service.list()
    data_centers_data = []
    for data_center in data_centers:
        data_center_data = {'name': data_center.name,
                        'id': data_center.id,
                        'status': data_center.status.value
                        }
        data_centers_data.append(data_center_data)

    metrics['zvirt.data_centers'] = json.dumps(data_centers_data)

    networks = networks_service.list()
    networks_data = []

    for network in networks:
        network_data = {'name': network.name,
		    'id': network.id,
		    'mtu': network.mtu,
		    'port_isolation': network.port_isolation
                    }
        networks_data.append(network_data)

    metrics['zvirt.networks'] = json.dumps(networks_data)
    

    connection.close()

    return metrics

def send_to_Zabbix(hostname, metrics):
    packet = [ZabbixMetric(hostname, key, value) for key, value in metrics.items()]
    ZabbixSender(use_config=USE_ZABBIX_CONF).send(packet)

def has_live_threads(threads):
    return True in [t.isAlive() for t in threads]

def main():
    if not os.path.isfile(CONFIG_FILE):
        print( '''Can't find config file''')
        exit()
    config = configparser.ConfigParser()
    config.read(CONFIG_FILE)

    threads = [
        requester_thread('T_' + zvirt, list(config[zvirt].values())
        ) for zvirt in config.sections()
    ]
    print(len(threads))
    for t in threads:
        t.start()
        print ('Thread', t.name, 'has started')

    while has_live_threads(threads):
        try:
            # synchronization timeout of threads kill
            [t.join(1) for t in threads
             if t is not None and t.isAlive()]
        except KeyboardInterrupt:
            # Ctrl-C handling and send kill to threads
            print('Sending kill to threads...')
            for t in threads:
                t.kill_received = True
                print('Thread', t.name, 'has started shutdown')

if __name__ == '__main__':
    main()
