#! /usr/bin/python3
# coding=utf-8


import time
import paramiko
import MySQLdb
import json


q1c = "SELECT REPLACE(hw_addr, ':','') as hw_addr, " \
      "serial, " \
      "net_num " \
      "FROM dhcp4.1c_import " \
      "where imported = 0;"

qleases4 = "SELECT INET_NTOA(address) as ip4, " \
           "HEX(hwaddr)as hw_addr, hostname, " \
           "expire, " \
           "valid_lifetime " \
           "FROM lease4 " \
           "where INET_NTOA(address) like '10.%s.0%';"

qhosts_ip = "SELECT " \
         "INET_NTOA(ipv4_address) AS ipv4_address " \
         "FROM dhcp4.hosts;"

qinsert_hosts = "START TRANSACTION; " \
                "SET @ipv4_reservation='%s'; " \
                "SET @hostname = '%s'; " \
                "SET @identifier_type='hw-address'; " \
                "SET @identifier_value='%s'; " \
                "SET @dhcp4_subnet_id=1024; " \
                "INSERT INTO hosts ( dhcp_identifier, " \
                "  dhcp_identifier_type, " \
                "  dhcp4_subnet_id, " \
                "  ipv4_address, " \
                "  hostname) " \
                "VALUES ( " \
                "UNHEX(@identifier_value)," \
                "  (SELECT type FROM host_identifier_type WHERE name=@identifier_type)," \
                "  @dhcp4_subnet_id," \
                "  INET_ATON(@ipv4_reservation)," \
                "  @hostname); " \
                "COMMIT;"

qupdate_1c = "update 1c_import set imported = 1 where serial = '%s';"


def send_data(user, password, name, host):
    errorcode = ''
#    work = True
    commands = []
#    commands.append("hostname %s" % name)
#    commands.append("echo '%s' > /etc/hostname" % name)
#    commands.append("echo 'hostname=%s' > /etc/network.conf.factory" % name)
#    commands.append("echo 'dhcp=true' >> /etc/network.conf.factory")
#    commands.append("echo 'hostname=%s' > /config/network.conf" % name)
#    commands.append("echo 'dhcp=true' >> /config/network.conf")
#    commands.append("sync")
    commands.append("/sbin/reboot \n")
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())  # если нет хоста - добавляем
    try:
        client.connect(hostname=host, username=user, password=password, look_for_keys=False,
                       allow_agent=False)   # пытаемся подключиться, look_for_keys=False, allow_agent=False - зачем-то
        #                                     нужны циске.
    except Exception as exept:  # в случае исключения -
        errorcode = exept  # возвращаем код и описание исключения
    else:  # усли все в порядке
        conn = client.invoke_shell()  # врубаем интерактивный шелл - с цисками только так.
        time.sleep(1)  # задержка
        conn.recv(1000)  # хаваем все, что выплюнула, дабы не отсвечивало (ограничиваю 1000 строк)
        # conn.send("head -n 1 /config/network.conf\n")
        # time.sleep(1)
        # h = conn.recv(100)
        # if "hostname=" + name in h:
        #     work = False
        work = True  # ЗАГЛУШКА!!! В данном случае условия не проверяются.
        if work:
            print(name, host, "will reboot")
            for command in commands:  # Читаем и исполняем команды
                conn.send(command + '\n')  # засылаем команду
                time.sleep(0.1)  # ждем указанный таймаут
                conn.recv(99999999999)  # хаваем его в никуда
            else:
                print("nothing to do")
    finally:  # по окончании всех процедур
        client.close()  # закрываем коннектий
    return errorcode  # Вертаем все, что наковыряли


def read_table(sql, dbhost, dbuser, dbpass, dbbase):
    try:
        conn = MySQLdb.connect(host=dbhost, user=dbuser,
                               passwd=dbpass, db=dbbase)
    except MySQLdb.Error as err:
        print("Connection error: {}".format(err))
        conn.close()
    try:
        cur = conn.cursor(MySQLdb.cursors.DictCursor)
        cur.execute(sql)
        data = cur.fetchall()
    except MySQLdb.Error as err:
        print("Query error: {}".format(err))
    conn.close()
    return data


def first_free_ip(ips, ip_pool, octet1, octet2, octet3):
    locked_ip = []
    octet4 = ''
    set_octets = False
    for ip in ips:
        octets = ip['ipv4_address'].split('.')
        if not set_octets:
            octet1 = octets[0]
            octet2 = octets[1]
            set_octets = True
        if octets[2] == str(octet3):
            locked_ip.append(octets[3])
    i = int(ip_pool[0])
    while i < int(ip_pool[1]):
        if not str(i) in locked_ip:
            octet4 = str(i)
            break
        i = i + 1
    if octet4 == '':
        return ''
    else:
        return "%s.%s.%s.%s" % (octet1, octet2, octet3, octet4)


def make_hosts(sql, ip, hostname, hw_addr, dbhost, dbuser, dbpass, dbbase):
    try:
        conn = MySQLdb.connect(host=dbhost, user=dbuser,
                               passwd=dbpass, db=dbbase)
    except MySQLdb.Error as err:
        print("Connection error: {}".format(err))
        conn.close()
    try:
        cur = conn.cursor(MySQLdb.cursors.DictCursor)
        cur.execute(sql % (ip, hostname, hw_addr))
        data = cur.fetchall()
        cur.close()
    except MySQLdb.Error as err:
        print("Query error: {}".format(err))
    try:
        cur = conn.cursor(MySQLdb.cursors.DictCursor)
        print(qupdate_1c % hostname)
        cur.execute(qupdate_1c % hostname)
        data = cur.fetchall()
        cur.close()
    except MySQLdb.Error as err:
        print("Query error: {}".format(err))
    conn.commit()
    conn.close()
    return data


def read_conf():
    conf = json.load(open('config.json'))
    return conf


def main():
    conf = read_conf()
    dbconf = [conf['dbhost'], conf['dbuser'], conf['dbpass'], conf['dbbase']]
    data_1c = read_table(q1c, *dbconf)
    data_leases = read_table(qleases4 % conf['ip_oct2'], *dbconf)

    for line in data_1c:
        set_ip = first_free_ip(read_table(qhosts_ip, *dbconf),
                               conf['ippool'], conf['ip_oct1'], conf['ip_oct2'], line['net_num'])
        set_hw_addr = line['hw_addr']
        set_host = line['serial']
        make_hosts(qinsert_hosts, set_ip, set_host, set_hw_addr,
                   *dbconf)
        print('host built name %s, mac %s, ip %s' % (set_host, set_hw_addr, set_ip))
    for line in data_1c:
        for lease in data_leases:
            if line['hw_addr'] == lease['hw_addr']:
                send_data(conf['sshuser'], conf['sshpass'], line['serial'], lease['ip4'])


if __name__ == '__main__':
    main()
