#!/bin/sh
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

case $0 in
    */*) dir0=`echo "$0" | sed 's,/[^/]*$,,'` ;;
    *) dir0=./ ;;
esac
. "$dir0/ovs-lib" || exit 1

for dir in "$sbindir" "$bindir" /sbin /bin /usr/sbin /usr/bin; do
    case :$PATH: in
        *:$dir:*) ;;
        *) PATH=$PATH:$dir ;;
    esac
done


ovnnb_active_conf_file="$etcdir/ovnnb-active.conf"
ovnsb_active_conf_file="$etcdir/ovnsb-active.conf"
ovn_northd_db_conf_file="$etcdir/ovn-northd-db-params.conf"
## ----- ##
## start ##
## ----- ##

pidfile_is_running () {
    pidfile=$1
    test -e "$pidfile" && pid=`cat "$pidfile"` && pid_exists "$pid"
} >/dev/null 2>&1

stop_nb_ovsdb() {
    if pidfile_is_running $DB_NB_PID; then
        ovs-appctl -t $rundir/ovnnb_db.ctl exit
    fi
}

stop_sb_ovsdb() {
    if pidfile_is_running $DB_SB_PID; then
        ovs-appctl -t $rundir/ovnsb_db.ctl exit
    fi
}

stop_ovsdb () {
    stop_nb_ovsdb
    stop_sb_ovsdb
}

demote_ovnnb() {
    if test ! -z "$DB_NB_SYNC_FROM_ADDR"; then
        echo "$DB_NB_SYNC_FROM_PROTO:$DB_NB_SYNC_FROM_ADDR:$DB_NB_SYNC_FROM_PORT" > $ovnnb_active_conf_file
    fi

    if test -e $ovnnb_active_conf_file; then
        ovs-appctl -t $rundir/ovnnb_db.ctl ovsdb-server/set-active-ovsdb-server `cat $ovnnb_active_conf_file`
        ovs-appctl -t $rundir/ovnnb_db.ctl ovsdb-server/connect-active-ovsdb-server
    else
        echo >&2 "$0: active server details not set"
        exit 1
    fi
}

demote_ovnsb() {
    if test ! -z "$DB_SB_SYNC_FROM_ADDR"; then
        echo "$DB_SB_SYNC_FROM_PROTO:$DB_SB_SYNC_FROM_ADDR:$DB_SB_SYNC_FROM_PORT" > $ovnsb_active_conf_file
    fi

    if test -e $ovnsb_active_conf_file; then
        ovs-appctl -t $rundir/ovnsb_db.ctl ovsdb-server/set-active-ovsdb-server `cat $ovnsb_active_conf_file`
        ovs-appctl -t $rundir/ovnsb_db.ctl ovsdb-server/connect-active-ovsdb-server
    else
        echo >&2 "$0: active server details not set"
        exit 1
    fi
}

promote_ovnnb() {
    rm -f $ovnnb_active_conf_file
    ovs-appctl -t $rundir/ovnnb_db.ctl ovsdb-server/disconnect-active-ovsdb-server
}

promote_ovnsb() {
    rm -f $ovnsb_active_conf_file
    ovs-appctl -t $rundir/ovnsb_db.ctl ovsdb-server/disconnect-active-ovsdb-server
}

start_nb_ovsdb() {
    # Check and eventually start ovsdb-server for Northbound DB
    if ! pidfile_is_running $DB_NB_PID; then
        upgrade_db "$DB_NB_FILE" "$DB_NB_SCHEMA" 1>/dev/null 2>/dev/null

        set ovsdb-server

        set "$@" --detach --monitor
        set "$@" $OVN_NB_LOG --log-file=$OVN_NB_LOGFILE
        set "$@" --remote=punix:$DB_NB_SOCK --pidfile=$DB_NB_PID
        set "$@" --remote=db:OVN_Northbound,NB_Global,connections
        set "$@" --unixctl=ovnnb_db.ctl
        set "$@" --private-key=db:OVN_Northbound,SSL,private_key
        set "$@" --certificate=db:OVN_Northbound,SSL,certificate
        set "$@" --ca-cert=db:OVN_Northbound,SSL,ca_cert
        set "$@" --ssl-protocols=db:OVN_Northbound,SSL,ssl_protocols
        set "$@" --ssl-ciphers=db:OVN_Northbound,SSL,ssl_ciphers

        if test X"$DB_NB_CREATE_INSECURE_REMOTE" = Xyes; then
            set "$@" --remote=ptcp:$DB_NB_PORT:$DB_NB_ADDR
        fi

        if test ! -z "$DB_NB_SYNC_FROM_ADDR"; then
            echo "$DB_NB_SYNC_FROM_PROTO:$DB_NB_SYNC_FROM_ADDR:$DB_NB_SYNC_FROM_PORT" > $ovnnb_active_conf_file
        fi

        if test -e $ovnnb_active_conf_file; then
            set "$@" --sync-from=`cat $ovnnb_active_conf_file`
        fi

        $@ $DB_NB_FILE
        ovn-nbctl init
    fi
}

start_sb_ovsdb() {
    # Check and eventually start ovsdb-server for Southbound DB
    if ! pidfile_is_running $DB_SB_PID; then
        upgrade_db "$DB_SB_FILE" "$DB_SB_SCHEMA" 1>/dev/null 2>/dev/null

        set ovsdb-server

        set "$@" --detach --monitor
        set "$@" $OVN_SB_LOG --log-file=$OVN_SB_LOGFILE
        set "$@" --remote=punix:$DB_SB_SOCK --pidfile=$DB_SB_PID
        set "$@" --remote=db:OVN_Southbound,SB_Global,connections
        set "$@" --unixctl=ovnsb_db.ctl
        set "$@" --private-key=db:OVN_Southbound,SSL,private_key
        set "$@" --certificate=db:OVN_Southbound,SSL,certificate
        set "$@" --ca-cert=db:OVN_Southbound,SSL,ca_cert
        set "$@" --ssl-protocols=db:OVN_Southbound,SSL,ssl_protocols
        set "$@" --ssl-ciphers=db:OVN_Southbound,SSL,ssl_ciphers

        if test X"$DB_SB_CREATE_INSECURE_REMOTE" = Xyes; then
            set "$@" --remote=ptcp:$DB_SB_PORT:$DB_SB_ADDR
        fi

        if test ! -z "$DB_SB_SYNC_FROM_ADDR"; then
            echo "$DB_SB_SYNC_FROM_PROTO:$DB_SB_SYNC_FROM_ADDR:$DB_SB_SYNC_FROM_PORT" > $ovnsb_active_conf_file
        fi

        if test -e $ovnsb_active_conf_file; then
            set "$@" --sync-from=`cat $ovnsb_active_conf_file`
        fi

        $@ $DB_SB_FILE
        ovn-sbctl init
    fi
}

start_ovsdb () {
    start_nb_ovsdb
    start_sb_ovsdb
}

sync_status() {
    ovs-appctl -t $rundir/ovn${1}_db.ctl ovsdb-server/sync-status | awk '{if(NR==1) print $2}'
}

status_ovnnb() {
    if ! pidfile_is_running $DB_NB_PID; then
        echo "not-running"
    else
        echo "running/$(sync_status nb)"
    fi
}

status_ovnsb() {
    if ! pidfile_is_running $DB_SB_PID; then
        echo "not-running"
    else
        echo "running/$(sync_status sb)"
    fi
}

status_ovsdb () {
  if ! pidfile_is_running $DB_NB_PID; then
      log_success_msg "OVN Northbound DB is not running"
  else
      log_success_msg "OVN Northbound DB is running"
  fi

  if ! pidfile_is_running $DB_SB_PID; then
      log_success_msg "OVN Southbound DB is not running"
  else
      log_success_msg "OVN Southbound DB is running"
  fi
}

start_northd () {
    if [ ! -e $ovn_northd_db_conf_file ]; then
        if test X"$OVN_MANAGE_OVSDB" = Xyes; then
            start_ovsdb

            if ! pidfile_is_running $DB_NB_PID; then
                log_failure_msg "OVN Northbound DB is not running"
                exit
            fi
            if ! pidfile_is_running $DB_SB_PID; then
                log_failure_msg "OVN Southbound DB is not running"
                exit
            fi
        fi
        ovn_northd_params="--ovnnb-db=unix:$DB_NB_SOCK --ovnsb-db=unix:$DB_SB_SOCK"
    else
        ovn_northd_params="`cat $ovn_northd_db_conf_file`"
    fi

    if daemon_is_running ovn-northd; then
        log_success_msg "ovn-northd is already running"
    else
        set ovn-northd
        if test X"$OVN_NORTHD_LOGFILE" != X; then
            set "$@" --log-file=$OVN_NORTHD_LOGFILE
        fi

        set "$@" $OVN_NORTHD_LOG $ovn_northd_params

        OVS_RUNDIR=${OVN_RUNDIR} start_daemon "$OVN_NORTHD_PRIORITY" "$OVN_NORTHD_WRAPPER" "$@"
    fi
}

start_controller () {
    set ovn-controller "unix:$DB_SOCK"
    set "$@" $OVN_CONTROLLER_LOG
    if test X"$OVN_CONTROLLER_SSL_KEY" != X; then
        set "$@" --private-key=$OVN_CONTROLLER_SSL_KEY
    fi
    if test X"$OVN_CONTROLLER_SSL_CERT" != X; then
        set "$@" --certificate=$OVN_CONTROLLER_SSL_CERT
    fi
    if test X"$OVN_CONTROLLER_SSL_CA_CERT" != X; then
        set "$@" --ca-cert=$OVN_CONTROLLER_SSL_CA_CERT
    fi
    if test X"$OVN_CONTROLLER_SSL_BOOTSTRAP_CA_CERT" != X; then
        set "$@" --bootstrap-ca-cert=$OVN_CONTROLLER_SSL_BOOTSTRAP_CA_CERT
    fi
    OVS_RUNDIR=${OVN_RUNDIR} start_daemon "$OVN_CONTROLLER_PRIORITY" "$OVN_CONTROLLER_WRAPPER" "$@"
}

start_controller_vtep () {
    set ovn-controller-vtep "unix:$DB_SOCK"
    set "$@" -vconsole:emer -vsyslog:err -vfile:info
    if test X"$OVN_CONTROLLER_SSL_KEY" != X; then
        set "$@" --private-key=$OVN_CONTROLLER_SSL_KEY
    fi
    if test X"$OVN_CONTROLLER_SSL_CERT" != X; then
        set "$@" --certificate=$OVN_CONTROLLER_SSL_CERT
    fi
    if test X"$OVN_CONTROLLER_SSL_CA_CERT" != X; then
        set "$@" --ca-cert=$OVN_CONTROLLER_SSL_CA_CERT
    fi
    if test X"$OVN_CONTROLLER_SSL_BOOTSTRAP_CA_CERT" != X; then
        set "$@" --bootstrap-ca-cert=$OVN_CONTROLLER_SSL_BOOTSTRAP_CA_CERT
    fi
    OVS_RUNDIR=${OVN_RUNDIR} start_daemon "$OVN_CONTROLLER_PRIORITY" "$OVN_CONTROLLER_WRAPPER" "$@"
}

## ---- ##
## stop ##
## ---- ##

stop_northd () {
    OVS_RUNDIR=${OVN_RUNDIR} stop_daemon ovn-northd

    if [ ! -e $ovn_northd_db_conf_file ]; then
        if test X"$OVN_MANAGE_OVSDB" = Xyes; then
            stop_ovsdb
        fi
    fi
}

stop_controller () {
    OVS_RUNDIR=${OVN_RUNDIR} stop_daemon ovn-controller
}

stop_controller_vtep () {
    OVS_RUNDIR=${OVN_RUNDIR} stop_daemon ovn-controller-vtep
}

## ------- ##
## restart ##
## ------- ##

restart_northd () {
    stop_northd
    start_northd
}

restart_controller () {
    stop_controller
    start_controller
}

restart_controller_vtep () {
    stop_controller_vtep
    start_controller_vtep
}

restart_ovsdb () {
    stop_ovsdb
    start_ovsdb
}

restart_nb_ovsdb () {
    stop_nb_ovsdb
    start_nb_ovsdb
}

restart_sb_ovsdb () {
    stop_sb_ovsdb
    start_sb_ovsdb
}

## ---- ##
## main ##
## ---- ##

set_defaults () {
    OVN_MANAGE_OVSDB=yes

    DB_NB_SOCK=$rundir/ovnnb_db.sock
    DB_NB_PID=$rundir/ovnnb_db.pid
    DB_NB_FILE=$dbdir/ovnnb_db.db
    DB_NB_ADDR=0.0.0.0
    DB_NB_PORT=6641
    DB_NB_SYNC_FROM_PROTO=tcp
    DB_NB_SYNC_FROM_ADDR=
    DB_NB_SYNC_FROM_PORT=6641

    DB_SB_SOCK=$rundir/ovnsb_db.sock
    DB_SB_PID=$rundir/ovnsb_db.pid
    DB_SB_FILE=$dbdir/ovnsb_db.db
    DB_SB_ADDR=0.0.0.0
    DB_SB_PORT=6642
    DB_SB_SYNC_FROM_PROTO=tcp
    DB_SB_SYNC_FROM_ADDR=
    DB_SB_SYNC_FROM_PORT=6642

    DB_NB_SCHEMA=$datadir/ovn-nb.ovsschema
    DB_SB_SCHEMA=$datadir/ovn-sb.ovsschema

    DB_SOCK=$rundir/db.sock
    DB_CONF_FILE=$dbdir/conf.db

    OVN_NORTHD_PRIORITY=-10
    OVN_NORTHD_WRAPPER=
    OVN_CONTROLLER_PRIORITY=-10
    OVN_CONTROLLER_WRAPPER=

    OVS_RUNDIR=${OVS_RUNDIR:-${rundir}}
    OVN_RUNDIR=${OVN_RUNDIR:-${OVS_RUNDIR}}

    OVN_CONTROLLER_LOG="-vconsole:emer -vsyslog:err -vfile:info"
    OVN_NORTHD_LOG="-vconsole:emer -vsyslog:err -vfile:info"
    OVN_NORTHD_LOGFILE=""
    OVN_NB_LOG="-vconsole:off"
    OVN_SB_LOG="-vconsole:off"
    OVN_NB_LOGFILE="$logdir/ovsdb-server-nb.log"
    OVN_SB_LOGFILE="$logdir/ovsdb-server-sb.log"

    OVN_CONTROLLER_SSL_KEY=""
    OVN_CONTROLLER_SSL_CERT=""
    OVN_CONTROLLER_SSL_CA_CERT=""
    OVN_CONTROLLER_SSL_BOOTSTRAP_CA_CERT=""

    DB_SB_CREATE_INSECURE_REMOTE="no"
    DB_NB_CREATE_INSECURE_REMOTE="no"

    MONITOR="yes"
}

set_option () {
    var=`echo "$option" | tr abcdefghijklmnopqrstuvwxyz- ABCDEFGHIJKLMNOPQRSTUVWXYZ_`
    eval set=\${$var+yes}
    eval old_value=\$$var
    if test X$set = X || \
        (test $type = bool && \
        test X"$old_value" != Xno && test X"$old_value" != Xyes); then
        echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
        return
    fi
    eval $var=\$value
}

usage () {
    set_defaults
    cat << EOF
$0: controls Open Virtual Network daemons
usage: $0 [OPTIONS] COMMAND

This program is intended to be invoked internally by Open Virtual Network
startup scripts.  System administrators should not normally invoke it directly.

Commands:
  start_northd                start ovn-northd
  start_ovsdb                 start ovn related ovsdb-server processes
  start_nb_ovsdb              start ovn northbound db ovsdb-server process
  start_sb_ovsdb              start ovn southbound db ovsdb-server process
  start_controller            start ovn-controller
  start_controller_vtep       start ovn-controller-vtep
  stop_northd                 stop ovn-northd
  stop_ovsdb                  stop ovn related ovsdb-server processes
  stop_nb_ovsdb               stop ovn northbound db ovsdb-server process
  stop_sb_ovsdb               stop ovn southbound db ovsdb-server process
  stop_controller             stop ovn-controller
  stop_controller_vtep        stop ovn-controller-vtep
  restart_northd              restart ovn-northd
  restart_ovsdb               restart ovn related ovsdb-server processes
  restart_nb_ovsdb            restart ovn northbound db ovsdb-server process
  restart_sb_ovsdb            restart ovn southbound db ovsdb-server process
  restart_controller          restart ovn-controller
  restart_controller_vtep     restart ovn-controller-vtep

Options:
  --ovn-northd-priority=NICE     set ovn-northd's niceness (default: $OVN_NORTHD_PRIORITY)
  --ovn-northd-wrapper=WRAPPER   run with a wrapper like valgrind for debugging
  --ovn-controller-priority=NICE     set ovn-controller's niceness (default: $OVN_CONTROLLER_PRIORITY)
  --ovn-controller-wrapper=WRAPPER   run with a wrapper like valgrind for debugging
  --ovn-controller-ssl-key=KEY OVN Southbound SSL private key file
  --ovn-controller-ssl-cert=CERT OVN Southbound SSL certificate file
  --ovn-controller-ssl-ca-cert=CERT OVN Southbound SSL CA certificate file
  --ovn-controller-ssl-bootstrap-ca-cert=CERT Bootstrapped OVN Southbound SSL CA certificate file
  --ovn-manage-ovsdb=yes|no        Whether or not the OVN databases should be
                                   automatically started and stopped along
                                   with ovn-northd. The default is "yes". If
                                   this is set to "no", the "start_ovsdb" and
                                   "stop_ovsdb" commands must be used to start
                                   and stop the OVN databases.
  --ovn-controller-log=STRING        ovn controller process logging params (default: $OVN_CONTROLLER_LOG)
  --ovn-northd-log=STRING            ovn northd process logging params (default: $OVN_NORTHD_LOG)
  --ovn-northd-logfile=STRING        ovn northd process log file (default: $OVN_NORTHD_LOGFILE)
  --ovn-nb-log=STRING             ovn NB ovsdb-server processes logging params (default: $OVN_NB_LOG)
  --ovn-sb-log=STRING             ovn SB ovsdb-server processes logging params (default: $OVN_SB_LOG)
  -h, --help                     display this help message

File location options:
  --db-sock=SOCKET     JSON-RPC socket name (default: $DB_SOCK)
  --db-nb-file=FILE    OVN_Northbound db file (default: $DB_NB_FILE)
  --db-sb-file=FILE    OVN_Southbound db file (default: $DB_SB_FILE)
  --db-nb-schema=FILE  OVN_Northbound db file (default: $DB_NB_SCHEMA)
  --db-sb-schema=FILE  OVN_Southbound db file (default: $DB_SB_SCHEMA)
  --db-nb-addr=ADDR    OVN Northbound db ptcp address (default: $DB_NB_ADDR)
  --db-nb-port=PORT    OVN Northbound db ptcp port (default: $DB_NB_PORT)
  --db-sb-addr=ADDR    OVN Southbound db ptcp address (default: $DB_SB_ADDR)
  --db-sb-port=PORT    OVN Southbound db ptcp port (default: $DB_SB_PORT)
  --ovn-nb-logfile=FILE OVN Northbound log file (default: $OVN_NB_LOGFILE)
  --ovn-sb-logfile=FILE OVN Southbound log file (default: $OVN_SB_LOGFILE)
  --db-nb-sync-from-addr=ADDR OVN Northbound active db tcp address (default: $DB_NB_SYNC_FROM_ADDR)
  --db-nb-sync-from-port=PORT OVN Northbound active db tcp port (default: $DB_NB_SYNC_FROM_PORT)
  --db-nb-sync-from-proto=PROTO OVN Northbound active db transport (default: $DB_NB_SYNC_FROM_PROTO)
  --db-nb-create-insecure-remote=yes|no Create ptcp OVN Northbound remote (default: $DB_NB_CREATE_INSECURE_REMOTE)
  --db-sb-sync-from-addr=ADDR OVN Southbound active db tcp address (default: $DB_SB_SYNC_FROM_ADDR)
  --db-sb-sync-from-port=ADDR OVN Southbound active db tcp port (default: $DB_SB_SYNC_FROM_PORT)
  --db-sb-sync-from-proto=PROTO OVN Southbound active db transport (default: $DB_SB_SYNC_FROM_PROTO)
  --db-sb-create-insecure-remote=yes|no Create ptcp OVN Southbound remote (default: $DB_SB_CREATE_INSECURE_REMOTE)

Default directories with "configure" option and environment variable override:
  logs: /usr/local/var/log/openvswitch (--with-logdir, OVS_LOGDIR)
  pidfiles and sockets: /usr/local/var/run/openvswitch (--with-rundir, OVS_RUNDIR)
  ovn-nb.db: /usr/local/etc/openvswitch (--with-dbdir, OVS_DBDIR)
  ovn-sb.db: /usr/local/etc/openvswitch (--with-dbdir, OVS_DBDIR)
  system configuration: /usr/local/etc (--sysconfdir, OVS_SYSCONFDIR)
  data files: /usr/local/share/openvswitch (--pkgdatadir, OVS_PKGDATADIR)
  user binaries: /usr/local/bin (--bindir, OVS_BINDIR)
  system binaries: /usr/local/sbin (--sbindir, OVS_SBINDIR)
EOF
}

set_defaults
command=
for arg
do
    case $arg in
        -h | --help)
            usage
            ;;
        --[a-z]*=*)
            option=`expr X"$arg" : 'X--\([^=]*\)'`
            value=`expr X"$arg" : 'X[^=]*=\(.*\)'`
            type=string
            set_option
            ;;
        --no-[a-z]*)
            option=`expr X"$arg" : 'X--no-\(.*\)'`
            value=no
            type=bool
            set_option
            ;;
        --[a-z]*)
            option=`expr X"$arg" : 'X--\(.*\)'`
            value=yes
            type=bool
            set_option
            ;;
        -*)
            echo >&2 "$0: unknown option \"$arg\" (use --help for help)"
            exit 1
            ;;
        *)
            if test X"$command" = X; then
                command=$arg
            else
                echo >&2 "$0: exactly one non-option argument required (use --help for help)"
                exit 1
            fi
            ;;
    esac
done
case $command in
    start_northd)
        start_northd
        ;;
    start_ovsdb)
        start_ovsdb
        ;;
    start_nb_ovsdb)
        start_nb_ovsdb
        ;;
    start_sb_ovsdb)
        start_sb_ovsdb
        ;;
    start_controller)
        start_controller
        ;;
    start_controller_vtep)
        start_controller_vtep
        ;;
    stop_northd)
        stop_northd
        ;;
    stop_ovsdb)
       stop_ovsdb
        ;;
    stop_nb_ovsdb)
       stop_nb_ovsdb
        ;;
    stop_sb_ovsdb)
       stop_sb_ovsdb
        ;;
    stop_controller)
        stop_controller
        ;;
    stop_controller)
        stop_controller
        ;;
    stop_controller_vtep)
        stop_controller_vtep
        ;;
    restart_northd)
        restart_northd
        ;;
    restart_ovsdb)
        restart_ovsdb
        ;;
    restart_nb_ovsdb)
        restart_nb_ovsdb
        ;;
    restart_sb_ovsdb)
        restart_sb_ovsdb
        ;;
    restart_controller)
        restart_controller
        ;;
    restart_controller_vtep)
        restart_controller_vtep
        ;;
    status_northd)
        daemon_status ovn-northd || exit 1
        ;;
    status_ovsdb)
        status_ovsdb
        ;;
    status_controller)
        daemon_status ovn-controller || exit 1
        ;;
    status_controller_vtep)
        daemon_status ovn-controller-vtep || exit 1
        ;;
    promote_ovnnb)
        promote_ovnnb
        ;;
    promote_ovnsb)
        promote_ovnsb
        ;;
    demote_ovnnb)
        demote_ovnnb
        ;;
    demote_ovnsb)
        demote_ovnsb
        ;;
    status_ovnnb)
        status_ovnnb
        ;;
    status_ovnsb)
        status_ovnsb
        ;;
    help)
        usage
        ;;
    preheat)
        echo >&2 "$0: preheating ovn to 350 degrees F."
        exit 1
        ;;
    '')
        echo >&2 "$0: missing command name (use --help for help)"
        exit 1
        ;;
    *)
        echo >&2 "$0: unknown command \"$command\" (use --help for help)"
        exit 1
        ;;
esac
