#!/usr/bin/python3

# Copyright (C) 2011 Oracle. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, version 2.  This program is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the GNU
# General Public License along with this program; if not, write to the Free
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 021110-1307, USA.

### BEGIN PLUGIN INFO
# name: network
# configure: 50
# cleanup: 50
# description: Script to configure template network.
### END PLUGIN INFO

import glob
import json
import os

from templateconfig import netutils
from templateconfig.cli import main
from templateconfig.common import shell_cmd, get_entry_list


def do_enumerate(target):
    param = []
    if target == 'configure':
        param += [{'key': 'com.oracle.linux.network.hostname',
                   'description': 'System host name, e.g., "localhost.localdomain".'},
                  {'key': 'com.oracle.linux.network.host.0',
                   'description': 'Hostname entry for /etc/hosts, e.g., '
                                  '"127.0.0.1 localhost localhost.localdomain".',
                   'hidden': True}]
        for (index, _) in enumerate(netutils.getPhysicalDevices()):
            dev_params = [
                {'key': 'com.oracle.linux.network.device.%s' % index,
                 'description': 'Network device to configure, e.g., "eth0".'},
                {'key': 'com.oracle.linux.network.hwaddr.%s' % index,
                 'description': 'Network device hardware address, e.g., "00:16:3E:28:0F:4E".',
                 'depends': 'com.oracle.linux.network.device.%s' % index,
                 'hidden': True},
                {'key': 'com.oracle.linux.network.mtu.%s' % index,
                 'description': 'Network device MTU, e.g., "1500".',
                 'depends': 'com.oracle.linux.network.device.%s' % index,
                 'hidden': True},
                {'key': 'com.oracle.linux.network.onboot.%s' % index,
                 'description': 'Activate interface on system boot: yes or no.',
                 'choices': ['yes', 'no'],
                 'depends': 'com.oracle.linux.network.device.%s' % index},
                {'key': 'com.oracle.linux.network.bootproto.%s' % index,
                 'description': 'Boot protocol: dhcp or none(for static).',
                 'choices': ['dhcp', 'none'],
                 'depends': 'com.oracle.linux.network.device.%s' % index},
                {'key': 'com.oracle.linux.network.ipaddr.%s' % index,
                 'description': 'IP address of the interface.',
                 'depends': 'com.oracle.linux.network.bootproto.%s' % index,
                 'requires': ('com.oracle.linux.network.bootproto.%s' % index, ('static', 'none', None))},
                {'key': 'com.oracle.linux.network.netmask.%s' % index,
                 'description': 'Netmask of the interface.',
                 'depends': 'com.oracle.linux.network.bootproto.%s' % index,
                 'requires': ('com.oracle.linux.network.bootproto.%s' % index, ('static', 'none', None))},
                {'key': 'com.oracle.linux.network.gateway.%s' % index,
                 'description': 'Gateway IP address.',
                 'depends': 'com.oracle.linux.network.bootproto.%s' % index,
                 'requires': ('com.oracle.linux.network.bootproto.%s' % index, ('static', 'none', None))},
                {'key': 'com.oracle.linux.network.dns-servers.%s' % index,
                 'description': 'DNS servers separated by comma, e.g., "8.8.8.8,8.8.4.4".',
                 'depends': 'com.oracle.linux.network.bootproto.%s' % index,
                 'requires': ('com.oracle.linux.network.bootproto.%s' % index, ('static', 'none', None))},
                {'key': 'com.oracle.linux.network.dns-search-domains.%s' % index,
                 'description': 'DNS search domains separated by comma, e.g., '
                                '"us.example.com,cn.example.com".',
                 'hidden': True}]
            # Only show one device in console input screen: hide all others.
            if index > 0:
                for dev_param in dev_params:
                    dev_param['hidden'] = True
            param += dev_params
    return json.dumps(param)


def do_configure(param):
    param = json.loads(param)
    netutils.ifupDevice('lo')
    hostname = param.get('com.oracle.linux.network.hostname')
    if hostname:
        netutils.setHostname(hostname)
    for (device, index) in get_entry_list(param, 'com.oracle.linux.network.device'):
        if device not in netutils.getPhysicalDevices():
            continue
        config = netutils.ConfDevice(device)
        config.clear()
        config['DEVICE'] = device
        config['NM_CONTROLLED'] = 'yes'
        onboot = param.get('com.oracle.linux.network.onboot.%s' % index, 'no')
        config['ONBOOT'] = onboot
        if onboot == 'yes':
            bootproto = param.get('com.oracle.linux.network.bootproto.%s' % index, 'none')
            if bootproto not in ['dhcp', 'none', 'static']:
                raise Exception('Unknown boot protocol: %s. Should be dhcp, none or static' % bootproto)
            config['BOOTPROTO'] = bootproto
            if bootproto in ['none', 'static']:
                ipaddr = param.get('com.oracle.linux.network.ipaddr.%s' % index)
                if ipaddr:
                    netmask = param.get('com.oracle.linux.network.netmask.%s' % index)
                    if not netmask:
                        raise Exception('Netmask is required when IP address is provided.')
                    config['IPADDR'] = ipaddr
                    config['NETMASK'] = netmask
            gateway = param.get('com.oracle.linux.network.gateway.%s' % index)
            if gateway:
                config['GATEWAY'] = gateway
            dns_servers = param.get('com.oracle.linux.network.dns-servers.%s' % index, '')
            if dns_servers:
                dns_server_count = 1
                for dns_server in dns_servers.split(','):
                    config['DNS%s' % dns_server_count] = dns_server.strip()
                    dns_server_count += 1
            else:
                if bootproto != 'dhcp':
                    config['PEERDNS'] = 'no'
            dns_search_domains = param.get('com.oracle.linux.network.dns-search-domains.%s' % index)
            if dns_search_domains:
                config['DOMAIN'] = dns_search_domains.replace(',', ' ')
            hwaddr = param.get('com.oracle.linux.network.hwaddr.%s' % index)
            if hwaddr:
                config['HWADDR'] = hwaddr.upper()
            mtu = param.get('com.oracle.linux.network.mtu.%s' % index)
            if mtu:
                config['MTU'] = mtu
            config.write()
            netutils.ifdownDevice(device)
            netutils.ifupDevice(device)
            shell_cmd('systemctl restart NetworkManager')
            shell_cmd('nmcli network off && nmcli network on')
        else:
            config['DEVICE'] = device
            config['BOOTPROTO'] = 'none'
            config['PEERDNS'] = 'no'
            config.write()
            netutils.ifdownDevice(device)

        # update ipaddr and netmask
        addr = netutils.getAddr(device)
        if addr:
            param['com.oracle.linux.network.ipaddr.%s' % index] = addr[0]
            param['com.oracle.linux.network.netmask.%s' % index] = addr[1]

    for (host, _) in get_entry_list(param, 'com.oracle.linux.network.host'):
        fields = host.split()
        if len(fields) >= 2:
            netutils.setHosts(*fields)
    return json.dumps(param)


def do_cleanup(param):
    param = json.loads(param)
    netutils.setHostname('localhost.localdomain')
    for ifcfg in glob.glob('/etc/sysconfig/network-scripts/ifcfg-*'):
        if ifcfg.endswith('ifcfg-lo'):
            continue
        os.unlink(ifcfg)
    with open('/etc/hosts', 'w') as hosts:
        hosts.write('127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4\n')
        hosts.write('::1         localhost localhost.localdomain localhost6 localhost6.localdomain6\n')
    open('/etc/resolv.conf', 'w').close()
    shell_cmd('rm -f /var/lib/dhclient/*')
    shell_cmd('rm -f /etc/udev/rules.d/70-persistent-net.rules')
    shell_cmd('rm -f /var/log/dnf.rpm.log')
    shell_cmd('rm -f /var/log/hawkey.log')
    shell_cmd('rm -f /var/log/dnf.librepo.log*')
    shell_cmd('rm -f /var/log/dnf.log')
    shell_cmd('systemctl restart NetworkManager')
    return json.dumps(param)


if __name__ == '__main__':
    main(do_enumerate, {'configure': do_configure, 'cleanup': do_cleanup})
