#!/usr/bin/python
"""Wait until VDSM devices get their IPv4 addresses

Wait up to 10 seconds for vdsm-controlled interfaces with static IP to obtain
their address. It should be called because `service network restart` may return
asynchronously, before addresses have been applied to devices.
"""

from os import listdir
from os.path import isfile, join
import sys

from vdsm.network.configurators.ifcfg import NET_CONF_DIR
from vdsm.network.configurators.ifcfg import ConfigWriter
from vdsm.network.netinfo.addresses import getIpInfo
from vdsm.network.netlink import monitor


def _get_vdsm_ip_onboot_devs():
    """Return set of VDSM devices with assigned IPv4 and ONBOOT=yes"""
    vdsm_ip_onboot_devs = set()
    ifcfgs = [f for f in listdir(NET_CONF_DIR)
              if (isfile(join(NET_CONF_DIR, f)) and f.startswith('ifcfg-'))]
    for ifcfg in ifcfgs:
        with open(join(NET_CONF_DIR, ifcfg)) as f:
            config = f.read()
            if (config.startswith(ConfigWriter.CONFFILE_HEADER_BASE) and
                    '\nONBOOT=yes\n' in config and '\nIPADDR=' in config):
                vdsm_ip_onboot_devs.add(ifcfg[6:])
    return vdsm_ip_onboot_devs


def _get_ipless_devs(devs):
    """Return set of IPless devices filtered out of devs"""
    return set(dev for dev in devs if getIpInfo(dev)[0] == '')


def _wait_for_ipv4(devs):
    """Wait for devs to get their IPv4 addresses with netlink Monitor"""
    try:
        with monitor.Monitor(groups=('ipv4-ifaddr',), timeout=10) as mon:
            ipless_devs = _get_ipless_devs(devs)
            if not ipless_devs:
                mon.stop()
            for event in mon:
                dev_name = event.get('label')
                if (dev_name in ipless_devs and
                        event.get('event') == 'new_addr' and
                        event.get('scope') == 'global'):
                    ipless_devs.remove(dev_name)
                if not ipless_devs:
                    mon.stop()
    except monitor.MonitorError as e:
        if e[0] == monitor.E_TIMEOUT:
            sys.stderr.write('IP addresses has not been caught within the '
                             'given timeout.\n')
        else:
            raise


if __name__ == '__main__':
    devs = _get_vdsm_ip_onboot_devs()
    _wait_for_ipv4(devs)
