#!/bin/bash


# cleanup_opendaylight() - Remove residual data files, anything left over
# from previous runs that a clean run would need to clean up
function cleanup_opendaylight {
    # Wipe out the data, journal and snapshots directories ... grumble grumble grumble
    rm -rf $ODL_DIR/$ODL_NAME/{data,journal,snapshots}

    # Remove existing logfiles
    if [[ -n "$LOGDIR" ]]; then
        rm -f "$LOGDIR/$ODL_KARAF_LOG_BASE*"
    fi
    if [[ -n "$SCREEN_LOGDIR" ]]; then
        rm -f "$SCREEN_LOGDIR/$ODL_KARAF_LOG_BASE*"
    fi
    rm -f "$DEST/logs/$ODL_KARAF_LOG_BASE*"

    move_interface_addresses "outof_bridge"

    unbind_opendaylight_controller
}


# configure_opendaylight() - Set config files, create data dirs, etc
function configure_opendaylight {
    echo "Configuring OpenDaylight"

    # The logging config file in ODL
    local ODL_LOGGING_CONFIG=${ODL_DIR}/${ODL_NAME}/etc/org.ops4j.pax.logging.cfg

    # Add netvirt feature in Karaf, if it's not already there
    local ODLFEATUREMATCH=$(cat $ODL_DIR/$ODL_NAME/etc/org.apache.karaf.features.cfg | \
                            grep featuresBoot= | grep $ODL_NETVIRT_KARAF_FEATURE)
    if [ "$ODLFEATUREMATCH" == "" ]; then
        sed -i "/^featuresBoot=/ s/$/,$ODL_NETVIRT_KARAF_FEATURE/" \
               $ODL_DIR/$ODL_NAME/etc/org.apache.karaf.features.cfg
    fi

    if [[ "$ODL_RELEASE" =~ "helium" ]]; then
        # Move Tomcat to $ODL_PORT
        local _ODLPORT=$(cat $ODL_DIR/$ODL_NAME/configuration/tomcat-server.xml | \
                         grep $ODL_PORT)
        if [ "$_ODLPORT" == "" ]; then
            sed -i "/\<Connector port/ s/808./$ODL_PORT/" \
                   $ODL_DIR/$ODL_NAME/configuration/tomcat-server.xml
        fi
    else
        # Move Jetty to $ODL_PORT
        local _ODLPORT=$(cat $ODL_DIR/$ODL_NAME/etc/jetty.xml | grep $ODL_PORT)
        if [ "$_ODLPORT" == "" ]; then
            sed -i "/\<Property name\=\"jetty\.port/ s/808./$ODL_PORT/" \
                   $ODL_DIR/$ODL_NAME/etc/jetty.xml
        fi
    fi

    # Configure L3 if the user wants it
    if [ "${ODL_L3}" == "True" ]; then
        # Configure L3 FWD if it's not there
        local L3FWD=$(cat $ODL_DIR/$ODL_NAME/etc/custom.properties | \
                      grep ^ovsdb.l3.fwd.enabled)
        if [ "$L3FWD" == "" ]; then
            echo "ovsdb.l3.fwd.enabled=yes" >> $ODL_DIR/$ODL_NAME/etc/custom.properties
        fi

        # Configure L3 GW MAC if it's not there
        local L3GW_MAC=$(cat $ODL_DIR/$ODL_NAME/etc/custom.properties | \
                         grep ^ovsdb.l3gateway.mac)
        if [[ -z "$L3GW_MAC" && -n "$ODL_L3GW_MAC" ]]; then
            echo "ovsdb.l3gateway.mac=$ODL_L3GW_MAC" >> $ODL_DIR/$ODL_NAME/etc/custom.properties
        fi
    fi

    # Remove existing logfiles
    local ODL_LOGDIR=$DEST/logs
    if [[ -n "$LOGDIR" ]]; then
        ODL_LOGDIR=$LOGDIR
    fi

    rm -f "$ODL_LOGDIR/$ODL_KARAF_LOG_BASE*"
    # Log karaf output to a file
    _LF=$ODL_LOGDIR/$ODL_KARAF_LOG_NAME
    LF=$(echo $_LF | sed 's/\//\\\//g')
    # Soft link for easy consumption
    sudo mkdir -p "$ODL_LOGDIR"
    ln -sf $_LF "$ODL_LOGDIR/screen-karaf.log"
    if [[ -n $SCREEN_LOGDIR ]]; then
        ln -sf $_LF "$SCREEN_LOGDIR/screen-karaf.log"
    fi

    # Change the karaf logfile
    # disable log rotation by setting max fiel size large enough
    sed -i -e "/^log4j\.appender\.out\.file/ s/.*/log4j\.appender\.out\.file\=$LF/" \
           -e "/^log4j\.appender\.out\.maxFileSize/ s/.*/log4j\.appender\.out\.maxFileSize\=1024GB/" \
    $ODL_DIR/$ODL_NAME/etc/org.ops4j.pax.logging.cfg

    # Configure DEBUG logs for network virtualization in odl, if the user wants it
    if [ "${ODL_NETVIRT_DEBUG_LOGS}" == "True" ]; then
        local OVSDB_DEBUG_LOGS=$(cat $ODL_LOGGING_CONFIG | grep ^log4j.logger.org.opendaylight.ovsdb)
        if [ "${OVSDB_DEBUG_LOGS}" == "" ]; then
            echo 'log4j.logger.org.opendaylight.ovsdb = TRACE, out' >> $ODL_LOGGING_CONFIG
            echo 'log4j.logger.org.opendaylight.ovsdb.lib = INFO, out' >> $ODL_LOGGING_CONFIG
            echo 'log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.impl.NeutronL3Adapter = DEBUG, out' >> $ODL_LOGGING_CONFIG
            echo 'log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.impl.TenantNetworkManagerImpl = DEBUG, out' >> $ODL_LOGGING_CONFIG
            echo 'log4j.logger.org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services.arp.GatewayMacResolverService = DEBUG, out' >> $ODL_LOGGING_CONFIG
            echo 'log4j.logger.org.opendaylight.ovsdb.plugin.md.OvsdbInventoryManager = INFO, out' >> $ODL_LOGGING_CONFIG
        fi
        if [[ "$ODL_RELEASE" =~ "helium" ]]; then
            local ODL_NEUTRON_DEBUG_LOGS=$(cat $ODL_LOGGING_CONFIG | \
                        grep ^log4j.logger.org.opendaylight.controller.networkconfig.neutron)
            if [ "${ODL_NEUTRON_DEBUG_LOGS}" == "" ]; then
                echo 'log4j.logger.org.opendaylight.controller.networkconfig.neutron = TRACE, out' >> $ODL_LOGGING_CONFIG
            fi
        else
            local ODL_NEUTRON_DEBUG_LOGS=$(cat $ODL_LOGGING_CONFIG | \
                        grep ^log4j.logger.org.opendaylight.neutron)
            if [ "${ODL_NEUTRON_DEBUG_LOGS}" == "" ]; then
                echo 'log4j.logger.org.opendaylight.neutron = TRACE, out' >> $ODL_LOGGING_CONFIG
            fi
        fi
    fi
}

# configure_neutron_opendaylight() - Set Neutron config files according to ODL settings
function configure_neutron_odl {
    echo "Configuring ML2 for OpenDaylight"
    populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_odl url=$ODL_ENDPOINT
    populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_odl username=$ODL_USERNAME
    populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_odl password=$ODL_PASSWORD
    populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_odl port_binding_controller=$ODL_PORT_BINDING_CONTROLLER
}

function configure_neutron_odl_lightweight_testing {
    echo "Configuring lightweight testing for OpenDaylight"
    populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_odl enable_lightweight_testing=True
}

# init_opendaylight() - Initialize databases, etc.
function init_opendaylight {
    # clean up from previous (possibly aborted) runs
    # create required data files
    :
}


# install_opendaylight() - Collect source and prepare
function install_opendaylight {
    echo "Installing OpenDaylight and dependent packages"
    if [[ "$ODL_USING_EXISTING_JAVA" != "True" ]]
    then
        if ! setup_java "${ODL_REQUIRED_JAVA_VERSION:-7}"; then
            exit 1
        fi
    fi

    install_opendaylight_neutron_thin_ml2_driver

    # Download OpenDaylight
    cd $ODL_DIR

    if [[ "$OFFLINE" != "True" ]]; then
        wget -N $ODL_URL/$ODL_PKG
    fi
    unzip -u -o $ODL_PKG
}


# install_opendaylight_neutron_thin_ml2_driver() - Install the ML2 driver
function install_opendaylight_neutron_thin_ml2_driver {
    echo "Installing the Networking-ODL driver for OpenDaylight"
    setup_develop $NETWORKING_ODL_DIR
}


# install_opendaylight_compute() - Make sure OVS is installed
function install_opendaylight_compute {
    if [[ "$SKIP_OVS_INSTALL" = "True" ]]; then
        echo "Skipping OVS installation."
    else
        # packages are the same as for Neutron OVS agent
        _neutron_ovs_base_install_agent_packages
    fi
}


# start_opendaylight() - Start running processes, including screen
function start_opendaylight {
    echo "Starting OpenDaylight"

    # Wipe out the data and journal directories ... grumble grumble grumble
    rm -rf $ODL_DIR/$ODL_NAME/{data,journal}

    # The following variables are needed by the running karaf process.
    # See the "bin/setenv" file in the OpenDaylight distribution for
    # their individual meaning.
    setup_java_env
    export JAVA_MIN_MEM=$ODL_JAVA_MIN_MEM
    export JAVA_MAX_MEM=$ODL_JAVA_MAX_MEM
    export JAVA_MAX_PERM_MEM=$ODL_JAVA_MAX_PERM_MEM
    run_process odl-server "$ODL_DIR/$ODL_NAME/bin/start"

    if [ -n "$ODL_BOOT_WAIT_URL" ]; then
        echo "Waiting for Opendaylight to start via $ODL_BOOT_WAIT_URL ..."
        # Probe ODL restconf for netvirt until it is operational
        local testcmd="curl -o /dev/null --fail --silent --head -u \
              ${ODL_USERNAME}:${ODL_PASSWORD} http://${ODL_MGR_IP}:${ODL_PORT}/${ODL_BOOT_WAIT_URL}"
        test_with_retry "$testcmd" "Opendaylight did not start after $ODL_BOOT_WAIT" \
              $ODL_BOOT_WAIT $ODL_RETRY_SLEEP_INTERVAL
    else
        echo "Waiting for Opendaylight to start ..."
        # Sleep a bit to let OpenDaylight finish starting up
        sleep $ODL_BOOT_WAIT
    fi
}


# stop_opendaylight() - Stop running processes (non-screen)
function stop_opendaylight {
    # Stop the karaf container
    $ODL_DIR/$ODL_NAME/bin/stop
    stop_process odl-server
}


# cleanup_opendaylight_compute() - Remove all OVS ports, bridges and disconnects
# controller from switch
function cleanup_opendaylight_compute {
    # Remove the patch ports
    for port in $(sudo ovs-vsctl show | grep Port | awk '{print $2}'  | cut -d '"' -f 2 | grep patch); do
        sudo ovs-vsctl del-port ${port}
    done

    # remove all OVS ports that look like Neutron created ports
    for port in $(sudo ovs-vsctl list port | grep -o -e tap[0-9a-f\-]* -e q[rg]-[0-9a-f\-]*); do
        sudo ovs-vsctl del-port ${port}
    done

    # Remove all the vxlan ports
    for port in $(sudo ovs-vsctl list port | grep name | grep vxlan | awk '{print $3}'  | cut -d '"' -f 2); do
        sudo ovs-vsctl del-port ${port}
    done

    # Disconnect controller from switch
    unbind_opendaylight_controller

    # remove all OVS bridges created by ODL
    for bridge in $(sudo ovs-vsctl list-br | grep -o -e ${OVS_BR} -e ${PUBLIC_BRIDGE}); do
        sudo ovs-vsctl del-br ${bridge}
    done
}


# bind_opendaylight_controller() - set control manager to OVS
function bind_opendaylight_controller {
    echo_summary "Initializing OpenDaylight"
    ODL_LOCAL_IP=${ODL_LOCAL_IP:-$HOST_IP}
    ODL_MGR_PORT=${ODL_MGR_PORT:-6640}
    ODL_OVS_MANAGERS=${ODL_OVS_MANAGERS:-$ODL_MGR_IP}
    read ovstbl <<< $(sudo ovs-vsctl get Open_vSwitch . _uuid)
    local ODL_MANAGERS_PARAM=()
    for manager in $(echo $ODL_OVS_MANAGERS | tr "," "\n"); do
        ODL_MANAGERS_PARAM=( "${ODL_MANAGERS_PARAM[@]}" "tcp:$manager:$ODL_MGR_PORT" )
    done
    sudo ovs-vsctl set-manager ${ODL_MANAGERS_PARAM[@]}
    if [[ -n "$ODL_PROVIDER_MAPPINGS" ]]; then
        sudo ovs-vsctl set Open_vSwitch $ovstbl \
            other_config:provider_mappings=$ODL_PROVIDER_MAPPINGS
    fi
    sudo ovs-vsctl set Open_vSwitch $ovstbl other_config:local_ip=$ODL_LOCAL_IP
}


# unbind_opendaylight_controller() - disconnect controller from switch and clear bridges
function unbind_opendaylight_controller {
    sudo ovs-vsctl del-manager
    BRIDGES=$(sudo ovs-vsctl list-br)
    for bridge in $BRIDGES ; do
        sudo ovs-vsctl del-controller $bridge
     done
}


# configure_opendaylight_l3() - configure bridges for OpenDaylight L3 forwarding
function configure_opendaylight_l3 {
    wait_for_active_bridge $PUBLIC_BRIDGE $ODL_RETRY_SLEEP_INTERVAL $ODL_BOOT_WAIT

    # Note: as of Lithium-SR3 and Beryllium releases, ODL will add the OVS port(s)
    #       to the external bridge via the ODL_PROVIDER_MAPPINGS method. Being so,
    #       the usage of PUBLIC_INTERFACE is no longer necessary in ODL devstack.

    # DEPRECATED: Add public interface to public bridge, if needed
    if [[ -n "$PUBLIC_INTERFACE" && "$PUBLIC_INTERFACE" != "br100" ]]; then
        deprecated "Adding $PUBLIC_INTERFACE to $PUBLIC_BRIDGE."
        deprecated "Use ODL_PROVIDER_MAPPINGS instead of PUBLIC_INTERFACE."
        sudo ovs-vsctl --no-wait -- --may-exist add-port $PUBLIC_BRIDGE $PUBLIC_INTERFACE
        sudo ip link set $PUBLIC_INTERFACE up
    fi

    move_interface_addresses "into_bridge"
}