#!/bin/bash
datetime=$(date +%Y%m%d-%H:%M:%S)
log_file=/var/log/dhcp_fix_${datetime}.log
do_fix=false
lft_threshold=252288000 # 8 years secs


function do_log() {
    local color=$1
    local level=$2
    shift
    shift
    local msg=$@
    local prefix=""

    if [[ $color -gt 30 ]]; then
        prefix="\033[1;$color;40m[$level]\033[0m"
    else
        prefix="[$level]"
    fi
	echo -e "$prefix [`date +'%Y-%m-%d %H:%M:%S'`] $msg" | tee -a $log_file
}

function log_info() {
    local msg=$@
    do_log 0 INFO $msg
}

function log_warn() {
    local msg=$@
    do_log 33 WARN $msg
}

function log_error() {
    local msg=$@
    do_log 31 ERROR $msg
}

function log_success() {
    local msg=$@
    do_log 32 SUCCESS $msg
}

function check_dhclient() {
    # dhclient is running -> 0
    # otherwise -> 1
    local interface=$1
    if   ps aux | grep -v grep | grep -q "dhclient -v" ; then # by dhclient -v
        return 0
    elif ps aux | grep -v grep | grep -q "dhclient $interface\$" ; then # by dhclient ethX
        return 0
    elif ps aux | grep -v grep | grep '/sbin/dhclient' | grep -q "$interface\$" ; then # by ifup ethX
        return 0
    fi
    return 1
}

function check_interface() {
    # don't need fix -> 0
    # need fix -> 1
    local interface=$1
    log_info "start checking $interface"

    local if_state=`cat /sys/class/net/$interface/operstate`
    log_info "$interface state is $if_state"

    if [[ $if_state == down ]]; then
        log_info "no need fix, $interface is link down"
        return 0
    fi

    log_info "ip a show dev $interface"
    ip a show dev $interface >> $log_file

    local valid_lft=$(ip a show dev $interface | awk '/valid_lft/ {print $2}')
    valid_lft=${valid_lft%sec}
    log_info "$interface valid_lft $valid_lft"

    if [[ -z $valid_lft ]]; then
        log_warn "$interface valid_lft is empty, skip it"
        return 0
    fi

    # interface is link up and the valid_lft of `ip a show dev $interface` could be:
    # if configured with dhcp -> valid_lft ${num}sec
    # if configured with static -> valid_lft forever

    if [[ $valid_lft == forever ]]; then
        log_info "no need fix, $interface is configured statically"
        return 0
    fi

    if check_dhclient $interface ; then
        log_info "no need fix, dhclient $interface is running"
        return 0
    else
        log_warn "dhclient $interface not running"
    fi

    log_warn "need fixing $interface"
    return 1
}

function fix_interface() {
    # fixed ok -> 0
    # fixed error -> 1
    local interface=$1
    log_info "start fixing $interface"
    log_info "ip a show dev $interface"
    ip a show dev $interface >> $log_file

    local ifcfg=/etc/sysconfig/network-scripts/ifcfg-$interface

    if [[ ! -f $ifcfg ]]; then
        log_warn "not find $ifcfg, please fixing manually"
        return 1
    fi

    if [[ $interface != eth0 ]] && ! grep -q 'DEFROUTE=no' $ifcfg ; then
        log_warn "$interface is set as linked to default route, please fixing manually"
        return 1
    fi

    log_info "$ifcfg content"
    cat $ifcfg >> $log_file

    if ! grep -q "BOOTPROTO=dhcp" $ifcfg ; then
        log_warn "$ifcfg not configured dhcp, skip"
        return 0
    fi

    log_info "ifup $interface"
    /usr/sbin/ifup $interface >> $log_file

    log_info "ip a show dev $interface"
    ip a show dev $interface >> $log_file

    if check_dhclient $interface ; then
        log_info "ok, dhclient $interface is running now"
        return 0
    else
        log_warn "dhclient $interface still not running !"
        return 1
    fi
}

function fix_net_hotplug() {
    base64_path=`command -v base64`
    gzip_path=`command -v gzip`

    if [[ -z $base64_path ]]; then
        log_warn "not find base64 command"
        return 1
    elif [[ -z $gzip_path ]]; then
        log_warn "not find gzip command"
        return 1
    fi

    net_hotplug_encoding="H4sIAKR0xFwAA7VV30/bMBB+rv+KI1RsdCsZr0N9QAwG0lTQ1D0hFLnJJbEItmU7pdXK/75zfjQpa9E0iT60tu/77j7ffUkPD8K5kKHNGTu06GC8pAV8U/KDg0QBlyuXC5mBSMHlCBLdszKPICxYp7TGhFHkHg5gnEK44CYsVPwY2nJuVzZs0Q9nniwZ0AeXwsEXloqa6GkJLsITISOiCEnRB9iJZ1aVJkYI0cUhShGVThTWr8Y5FhoNYzfT2eXPq/OLy+jidnoV3Z3PricVnFLHSqYiazWNbWyEdpZ5GQfg0xUqg4DCJ7lyuiizr3Tq0EDvKHgt7LQSdgLD3ztKv2yKpaWMnVCyLncPwXADD2AygSDY9GiwW4rwUlJO16fWy7IoAkJ2CmJuEYbnF7Ob2ylhGU+StcFMWGIdMzao45uiHjIYHHZZLRXnDrhBmBtVZrmDUgO3wEFz40ClUPevNNxfhNha69Fa1N82kaO1LgStC0V7k/DROimfnlYeYjEerV1JEMf16Ji4g2aqtDo726ukvQAmVWt6yohS56k9RJ7QRsW+3eGi4DLsjeOl6+xWXepatdeKrnczja5vZ3c/fn2fnHZplxBa/3CIlHrRz0LdNZPhxwxdlD/7TX/+L5WwJoWkUXtAsMUfyLqZTY56E81XXTb/0yQaNGkaDmWCoyPYlJu0gQpc32qPh3jlwdYmn3ue6tnxDT4uMe635C/W3njXcD9utDxmfsUMPqkFrkvZefV/rJqoZ+nN2lo1wfc0a3v4T86ppG058P1HU9V8czivEPvG429av2TAb6sA2y2gQL7ArVdl84fyacn+AIuYGhVkBgAA"
    echo $net_hotplug_encoding | $base64_path -d | $gzip_path -d > /etc/eni_utils/net.hotplug
}

function work() {
    local interface=
    local ret=0
    for i in /sys/class/net/eth* ; do
        interface=${i#/sys/class/net/}
        if ! check_interface $interface ; then
            if $do_fix ; then
                if ! fix_interface $interface ; then
                    ret=1
                fi
            else
                ret=1
            fi
        fi
    done
    fix_net_hotplug
    return $ret
}

function check_eni_utils() {
    # centos7 with eni_utils
    if [[ -f /etc/eni_utils/net.hotplug && -d /var/run/systemd/ ]]; then
        return 0
    fi
    return 1
}

function main() {
    if [[ $1 == fix ]] ; then
        do_fix=true
        action="check and fix"
    else
        do_fix=false
        action="check"
    fi

    log_info "start $action"
    log_info "log file $log_file"

    if ! check_eni_utils ; then
        log_info "no need fix"
        log_success "$action success"
        log_success "return code: 0"
        return 0
    fi

    if work ; then
        log_success "$action success"
        log_success "return code: 0"
        return 0
    else
        log_error "$action failed"
        log_error "return code: 1"
        return 1
    fi
}

main fix