#!/bin/bash
#
# Script to start docker daemon 
#
# June 2016, Lokheshvar Balakumar
# Copyright (c) 2016-2017, 2019, 2021 by Cisco Systems, Inc.
# All rights reserved.
#

# Check $VMTYPE and $VIRT_METHOD; 
# if in xr-vm and VIRT_METHOD is vm or
# if in host-os and VIR_METHOD is lxc; execute this script
# else exit

XR_DOCKER_LOG_FILE="/var/log/docker.log"
VMTYPE=`cat /proc/cmdline | sed 's/^.*vmtype=//' | cut -d" " -f1`
VIRT_METHOD=$(grep VIRT_METHOD /etc/init.d/calvados_bootstrap.cfg | awk -F '=' '{print $2}')

if [[ ! (("$VIRT_METHOD" == "lxc" && "$VMTYPE" == "hostos") || 
        ("$VIRT_METHOD" == "vm" && "$VMTYPE" == "xr-vm")) ]]; then
    echo "Virt_method: $VIRT_METHOD, VM_type: $VMTYPE - Script doesn't need to run" >> ${XR_DOCKER_LOG_FILE}
    exit 1
fi

if [[ "$app_hosting_cisco_docker_sourced" != true ]]; then
    app_hosting_cisco_docker_sourced=true

    if [[ -f /etc/rc.d/init.d/spirit_log.sh ]]; then
        source /etc/rc.d/init.d/spirit_log.sh
    fi

    if [[ -f /etc/sysconfig/docker ]]; then
        source /etc/sysconfig/docker
    fi

    if [[ -f /etc/sysconfig/cisco_docker ]]; then
        source /etc/sysconfig/cisco_docker
    fi

    if [[ -f /etc/init.d/operns-functions ]]; then
        source /etc/init.d/operns-functions
    fi
fi

XR_DOCKER_DAEMON_ALIVE_POLL_DELAY=10
XR_DOCKER_DAEMON_PID_PATTERN="[d]ocker daemon -D"
XR_DOCKER_PID=

if [[ -z "${DOCKER_VRF}" ]]; then
    DOCKER_VRF="global-vrf"
fi

function xr_docker_log
{
    local DATE=`date`
    echo "$DATE ($0): $*" >> ${XR_DOCKER_LOG_FILE}
}

function xr_docker_log_exec
{
    xr_docker_log "exec: $*"
    xr_docker_log "    : in cwd" `pwd`

    local PREFIX="`date -u`: -- "
    $* 2>&1 | sed "s/^/${PREFIX}/g" >>${XR_DOCKER_LOG_FILE} 2>&1

    return ${PIPESTATUS[0]}
}

#
# Remove the mounts used by system LXCs from docker daemon's 
# mount namespace
#
function docker_daemon_cleanup_bind_mounts()
{
    local check_lxcs=""

    #
    # Clean up is not required in platforms which run xr in a vm
    # Docker will run in the XR VM and will be shutdown on xr vm 
    # shutdown
    #
    if [[ "$VIRT_METHOD" == "vm" ]]; then
        return
    fi 

    check_lxcs=$(virsh -c lxc:/// list --name 2>/dev/null | egrep -w 'sysadmin|default-sdr--*')

    xr_docker_log "Remove mounts used by system LXCs from docker daemon's mount namespace"
    declare -F app_hosting_docker_daemon_cleanup_bind_mounts &>/dev/null &&
    app_hosting_docker_daemon_cleanup_bind_mounts "$check_lxcs"

    if [[ $? -ne 0 ]]; then
        xr_docker_log "Removal of one or more mounts may have failed. Check /var/log/platform.log"
        false
        return
    fi

    true
    return
}

function create_docker_mount()
{
    xr_docker_log_exec mkdir -p ${DOCKER_STORAGE_VOLUME}
    xr_docker_log_exec mkdir -p ${DOCKER_STORAGE_MOUNT}
    if [[ `grep -c $DOCKER_STORAGE_VOLUME /proc/mounts` -eq 0 ]]; then
        xr_docker_log_exec mount --bind ${DOCKER_STORAGE_MOUNT} ${DOCKER_STORAGE_VOLUME}
    fi
}

function ensure_docker_partition_size()
{
    xr_docker_log "Checking docker partition size mis-match (for upgrade)"
    cursize=$(df --output=size ${DOCKER_STORAGE_VOLUME} | awk 'NR==2 { print int($1/1024) }')
    xr_docker_log "PD Volume size=${DISK_TP_VOL_PART_SIZE} Current=${cursize}"

    if (( cursize > DISK_TP_VOL_PART_SIZE )); then
        xr_docker_log "Partition size mismatch. Don't start docker. Sleeping forever"
        sleep infinity
    fi
    xr_docker_log "Requested and physical Partition sizes match"
}

function docker_daemon_wait_initial_conditions()
{
    xr_docker_log "Docker daemon is waiting on initial conditions"

    while true
    do
        sleep $XR_DOCKER_DAEMON_ALIVE_POLL_DELAY

        ip netns exec ${DOCKER_VRF} ifconfig lo0 | grep -q "UP LOOPBACK RUNNING"
        if [[ $? -eq 0 ]]; then
            break
        fi
    done
}

function docker_daemon_launch()
{
    xr_docker_log "Starting the docker daemon"    

    (exec ip netns exec ${DOCKER_VRF} docker daemon $CISCO_DOCKER_OPTS $DOCKER_OPTS &>> ${XR_DOCKER_LOG_FILE}) &
}

function docker_daemon_get_pid()
{
    while true
    do
        docker_daemon_launch

        sleep $XR_DOCKER_DAEMON_ALIVE_POLL_DELAY

        XR_DOCKER_PID=$(ps aux | grep "$XR_DOCKER_DAEMON_PID_PATTERN" | awk "{print \$2}")
        if [[ $XR_DOCKER_PID != "" ]]; then
            xr_docker_log "Docker daemon pid $XR_DOCKER_PID is running"
            docker_daemon_cleanup_bind_mounts
            break
        fi
    done
}

function docker_daemon_wait_pid()
{
    local first_time=true

    while true
    do
        sleep $XR_DOCKER_DAEMON_ALIVE_POLL_DELAY

        ps p $XR_DOCKER_PID | grep -q "$XR_DOCKER_DAEMON_PID_PATTERN"
        if [[ $? -eq 0 ]]; then
            if [[ $first_time == true ]]; then
                first_time=false
                xr_docker_log "Verified the docker daemon is running"
            fi

            continue
        fi

        break
    done

    xr_docker_log "Docker daemon pid $XR_DOCKER_PID is no longer running"
}

function start_docker_daemon()
{
    xr_docker_log "Preparing to start the docker daemon"    

    while true
    do
        docker_daemon_wait_initial_conditions
        ensure_docker_partition_size
        docker_daemon_get_pid
        docker_daemon_wait_pid
    done
}

function main()
{
    create_docker_mount 

    start_docker_daemon $@
}

main $@
