Configuring replication

Learn how to configure replication.

About this task

This script must be run on a Linux® host with the following tools installed (the tools are preinstalled or available on RHEL 8 hosts):
  • Bash
  • Curl
  • Jq

Procedure

  • Save the script as couchdbReplication.sh on the local disk and set the executable part as chmod u+x couchdbReplication.sh.
    #!/bin/bash
    #/************************************************* {COPYRIGHT-TOP} ****
    #* Licensed Materials - Property of IBM
    #*
    #* "Restricted Materials of IBM"
    #*#*
    #* © Copyright IBM Corp. 2021  All Rights Reserved.
    #*
    #* US Government Users Restricted Rights - Use, duplication, or
    #* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
    #************************************************** {COPYRIGHT-END} ****/
    # This script can be used to configure a bidirectional replication between two sides of RBA.
    # If variables are exported and valid, the script will not prompt for values, otherwise an
    # interactive wizard will prompt for missing values.
    # Credentials can be defined individually per side, if they change, the setup needs to be repeated.
    
    # Headless mode:
    # export RBA_DB_URL_SIDE_A="https://rba-geo-1.company.com:6984"
    # export RBA_DB_USER_SIDE_A="xxx"
    # export RBA_DB_PW_SIDE_A="xxx"
    # export RBA_DB_URL_SIDE_B="https://rba-geo-2.company.com:6984"
    # export RBA_DB_USER_SIDE_B="xxx"
    # export RBA_DB_PW_SIDE_B="xxx"
    # ./couchdbReplication.sh setup|delete
    
    ACTION="${1}"
    
    # ensure only allowed actions are defined
    if [[ "${ACTION}" != "setup" ]] && [[ "${ACTION}" != "delete" ]]; then
        echo "Usage: ./couchdbReplication.sh setup|delete"
        exit 1
    fi
    
    set -e
    echo "================ RBA Replication Setup ================"
    echo "Running in ${ACTION} mode"
    
    # validate that prerequisites are available
    if ! command -v jq &> /dev/null; then
        echo "jq could not be found"
        exit
    fi
    
    if ! command -v curl &> /dev/null; then
        echo "curl could not be found"
        exit
    fi
    
    ######################################################################
    # side A config setup
    while true; do
        if [[ -z "${RBA_DB_URL_SIDE_A}" ]]; then
            echo -n "CouchDB URL side A: "
            read -r RBA_DB_URL_SIDE_A
            if [[ -z "${RBA_DB_URL_SIDE_A}" ]]; then
                echo "CouchDB URL cannot be empty"
                continue
            fi
        fi
    
        if [[ -z "${RBA_DB_USER_SIDE_A}" ]]; then
            echo -n "CouchDB username side A: "
            read -r RBA_DB_USER_SIDE_A
            if [[ -z "${RBA_DB_USER_SIDE_A}" ]]; then
                echo "CouchDB username cannot be empty"
                continue
            fi
        fi
    
        if [[ -z "${RBA_DB_PW_SIDE_A}" ]]; then
            echo -n "CouchDB password side A: "
            read -rs RBA_DB_PW_SIDE_A
            echo ""
            if [[ -z "${RBA_DB_PW_SIDE_A}" ]]; then
                echo "CouchDB password cannot be emtpy"
                continue
            fi
        fi
    
        # side A config validation
        set +e
        RBA_COUCHDB_STATUS=$(curl -k -sL -w "%{http_code}\\n" -u "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" "${RBA_DB_URL_SIDE_A}" -o /dev/null)
        set -e
        if [[ "200" == "${RBA_COUCHDB_STATUS}" ]]; then
            echo "CouchDB on side A is accessible"
    
            # the check if databases are initialized is only important to setup a replication, not to delete it
            if [[ "${ACTION}" == "setup" ]] ; then
                echo "Detecting runbook automation databases"
                RBA_COUCHDB_ALL_DBS=$(curl -k -s -u "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" "${RBA_DB_URL_SIDE_A}/_all_dbs" | jq -r '.[]')
                # only include dbs with the string rba (excludes _global_changes, _replicator and _users or other potential non-rba dbs)
                # RBA_DB_NAMES=$(echo "${RBA_COUCHDB_ALL_DBS}" | jq -r '.[] | select( . | test("(rba)"))')
                RBA_DB_NAMES=""
                for CURRENT_DB_NAME in ${RBA_COUCHDB_ALL_DBS}; do
                    if [[ "${CURRENT_DB_NAME}" == *"rba"* ]] && [[ "${CURRENT_DB_NAME}" != "rba-pdoc" ]]; then
                        echo "replicate: ${CURRENT_DB_NAME}"
                        RBA_DB_NAMES="${RBA_DB_NAMES} ${CURRENT_DB_NAME}"
                    else
                        echo "skip: ${CURRENT_DB_NAME}"
                    fi
                done
    
                for CURRENT_DB_NAME in ${RBA_DB_NAMES}; do
                    echo "RBA db detected: ${CURRENT_DB_NAME}"
                    set +e
                    RBA_DESIGN_DOC_STATUS=$(curl -k -sL -w "%{http_code}\\n" -u "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" "${RBA_DB_URL_SIDE_A}/${CURRENT_DB_NAME}/_design/georedundancy" -o /dev/null)
                    set -e
                    if [[ "200" == "${RBA_DESIGN_DOC_STATUS}" ]]; then
                        echo "CouchDB design doc ${RBA_DB_URL_SIDE_A}/${CURRENT_DB_NAME}/_design/georedundancy is accessible"
                    else
                        echo "CouchDB design doc ${RBA_DB_URL_SIDE_A}/${CURRENT_DB_NAME}/_design/georedundancy is not accessible"
                        echo "Please ensure that the IBM Runbook Automation database is initialized on side A and rerun this script"
                        exit 1
                    fi
                done
            fi
            break;
        else
            echo "CouchDB could not be accessed: ${RBA_COUCHDB_STATUS}"
            # at least one of the following variables are incorrect,
            # resetting them to trigger new prompt on next loop execution
            unset RBA_DB_URL_SIDE_A RBA_DB_USER_SIDE_A RBA_DB_PW_SIDE_A
        fi
    done
    
    ######################################################################
    # side B config setup
    while true; do
        if [[ -z "${RBA_DB_URL_SIDE_B}" ]]; then
            echo -n "CouchDB URL side B: "
            read -r RBA_DB_URL_SIDE_B
            if [[ -z "${RBA_DB_URL_SIDE_B}" ]]; then
                echo "CouchDB URL cannot be emtpy"
                continue
            fi
        fi
    
        if [[ -z "${RBA_DB_USER_SIDE_B}" ]]; then
            echo -n "CouchDB username side B: "
            read -r RBA_DB_USER_SIDE_B
            if [[ -z "${RBA_DB_USER_SIDE_B}" ]]; then
                echo "CouchDB username cannot be emtpy"
                continue
            fi
        fi
    
        if [[ -z "${RBA_DB_PW_SIDE_B}" ]]; then
            echo -n "CouchDB password side B: "
            read -rs RBA_DB_PW_SIDE_B
            echo ""
            if [[ -z "${RBA_DB_PW_SIDE_B}" ]]; then
                echo "CouchDB password cannot be emtpy"
                continue
            fi
        fi
    
        # side B config validation
        set +e
        RBA_COUCHDB_STATUS=$(curl -k -sL -w "%{http_code}\\n" -u "${RBA_DB_USER_SIDE_B}:${RBA_DB_PW_SIDE_B}" "${RBA_DB_URL_SIDE_B}" -o /dev/null)
        set -e
        if [[ "200" == "${RBA_COUCHDB_STATUS}" ]]; then
            echo "CouchDB on side B is accessible"
            # Do not check if side B is initialized as the replication can create targets if necessary.
            # This will simplify the setup after a disaster.
            break;
        else
            echo "CouchDB could not be accessed: ${RBA_COUCHDB_STATUS}"
            # at least one of the following variables are incorrect,
            # resetting them to trigger new prompt on next loop execution
            unset RBA_DB_URL_SIDE_B RBA_DB_USER_SIDE_B RBA_DB_PW_SIDE_B
        fi
    done
    
    
    if [[ "${ACTION}" == "setup" ]] ; then
        ######################################################################
        # computing basic auth headers required for replication documents
        AUTH_HEADER_SIDE_A="Basic $(echo -ne "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" | base64)"
        AUTH_HEADER_SIDE_B="Basic $(echo -ne "${RBA_DB_USER_SIDE_B}:${RBA_DB_PW_SIDE_B}" | base64)"
    
        ######################################################################
        echo "Creating replication for Runbook Service Database"
    
        for CURRENT_DB_NAME in ${RBA_DB_NAMES}; do
            echo "Setting up replication: ${RBA_DB_URL_SIDE_A}/${CURRENT_DB_NAME} -> ${RBA_DB_URL_SIDE_B}/${CURRENT_DB_NAME}"
            echo "Deleting old replication if present, continuing if missing"
            # get old rev to delete document
            OLD_REV=$(curl \
                -k \
                -s \
                -X GET \
                -u "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" \
                "${RBA_DB_URL_SIDE_A}/_replicator/${CURRENT_DB_NAME}-georedundancy-replication" | jq -r "._rev")
    
            # delete document
            curl \
                -k \
                -s \
                -X DELETE \
                -u "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" \
                "${RBA_DB_URL_SIDE_A}/_replicator/${CURRENT_DB_NAME}-georedundancy-replication?rev=${OLD_REV}"
    
            # create document on side A pushing docs to side B
            echo "Creating replication"
            CREATE_REPLICATION_RBA_A_TO_B=$(curl \
                -k \
                -s \
                -X POST \
                -u "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" \
                -H "Content-Type: application/json" \
                "${RBA_DB_URL_SIDE_A}/_replicator" -d '
            {
                "_id": "'"${CURRENT_DB_NAME}"'-georedundancy-replication",
                "source": {
                    "url": "'"${RBA_DB_URL_SIDE_A}"'/'"${CURRENT_DB_NAME}"'",
                    "headers": {
                        "Authorization": "'"${AUTH_HEADER_SIDE_A}"'"
                    }
                },
                "target": {
                    "url": "'"${RBA_DB_URL_SIDE_B}"'/'"${CURRENT_DB_NAME}"'",
                    "headers": {
                        "Authorization": "'"${AUTH_HEADER_SIDE_B}"'"
                    }
                },
                "filter": "georedundancy/standard",
                "create_target": true,
                "continuous": true
            }')
    
            # expected result: {"ok":true,"id":"rba-georedundancy-replication","rev":"1-9c73161d3485230f84ec12f0c922f5a3"}
            echo "${CREATE_REPLICATION_RBA_A_TO_B}"
            if [[ "$(echo "${CREATE_REPLICATION_RBA_A_TO_B}" | jq ".ok")" ]] ; then
                echo "Replication for ${CURRENT_DB_NAME} from side A to B was configured successfully"
            else
                echo "Failed to setup replication for ${CURRENT_DB_NAME} from side A to B"
                exit 1
            fi
    
            ######################################################################
            echo "${RBA_DB_URL_SIDE_B}/${CURRENT_DB_NAME} -> ${RBA_DB_URL_SIDE_A}/${CURRENT_DB_NAME}"
            echo "Deleting old replication if present, continuing if missing"
            # get old rev to delete document
            OLD_REV=$(curl \
                -k \
                -s \
                -X GET \
                -u "${RBA_DB_USER_SIDE_B}:${RBA_DB_PW_SIDE_B}" \
                "${RBA_DB_URL_SIDE_B}/_replicator/${CURRENT_DB_NAME}-georedundancy-replication" | jq -r "._rev")
    
            # delete document
            curl \
                -k \
                -s \
                -X DELETE \
                -u "${RBA_DB_USER_SIDE_B}:${RBA_DB_PW_SIDE_B}" \
                "${RBA_DB_URL_SIDE_B}/_replicator/${CURRENT_DB_NAME}-georedundancy-replication?rev=${OLD_REV}"
    
            # create document on side B pushing docs to side A
            echo "Creating replication document"
            CREATE_REPLICATION_RBA_B_TO_A=$(curl \
                -k \
                -s \
                -X POST \
                -u "${RBA_DB_USER_SIDE_B}:${RBA_DB_PW_SIDE_B}" \
                -H "Content-Type: application/json" \
                "${RBA_DB_URL_SIDE_B}/_replicator" -d '
            {
                "_id": "'"${CURRENT_DB_NAME}"'-georedundancy-replication",
                "source": {
                    "url": "'"${RBA_DB_URL_SIDE_B}"'/'"${CURRENT_DB_NAME}"'",
                    "headers": {
                        "Authorization": "'"${AUTH_HEADER_SIDE_B}"'"
                    }
                },
                "target": {
                    "url": "'"${RBA_DB_URL_SIDE_A}"'/'"${CURRENT_DB_NAME}"'",
                    "headers": {
                        "Authorization": "'"${AUTH_HEADER_SIDE_A}"'"
                    }
                },
                "filter": "georedundancy/standard",
                "create_target": true,
                "continuous": true
            }')
            echo "${CREATE_REPLICATION_RBA_B_TO_A}"
    
            # expected result: {"ok":true,"id":"rba-georedundancy-replication","rev":"1-9c73161d3485230f84ec12f0c922f5a3"}
            echo "${CREATE_REPLICATION_RBA_B_TO_A}"
            if [[ "$(echo "${CREATE_REPLICATION_RBA_B_TO_A}" | jq ".ok")" ]] ; then
                echo "Replication for ${CURRENT_DB_NAME} from side B to A was configured successfully"
            else
                echo "Failed to setup replication for ${CURRENT_DB_NAME} from side B to A"
                exit 1
            fi
        done
    
        echo "Replication setup completed, displaying replication status"
    else
        function deleteRbaReplications {
            CURRENT_DB_SERVER=${1}
            CURRENT_DB_USER=${2}
            CURRENT_DB_PW=${3}
            echo "Detecting runbook automation replications on ${CURRENT_DB_SERVER}"
            COUCHDB_REPLICATIONS=$(curl -k -s -u "${CURRENT_DB_USER}:${CURRENT_DB_PW}" "${CURRENT_DB_SERVER}/_replicator/_all_docs")
            # check for rba and georedundancy-replication in the doc id to delete
            # potential doc names would be 
            # bmstage-30363937666435352d393238372d343836382d383365362d353832393337313031313137-rba-as-georedundancy-replication
            # bmstage-30363937666435352d393238372d343836382d383365362d353832393337313031313137-rba-rbs-georedundancy-replication
            # rba-as-georedundancy-replication
            # rba-georedundancy-replication
            RBA_COUCHDB_REPLICATION_DOCS=$(echo "${COUCHDB_REPLICATIONS}" | jq -r '.rows[].id | select( . | test("(rba.*georedundancy-replication)"))')
            if [[ "${RBA_COUCHDB_REPLICATION_DOCS}" == "" ]]; then
                echo "No RBA replications were detected on ${CURRENT_DB_SERVER}, skipping deletion"
                return
            fi
    
            for CURRENT_DOC_TO_DELETE in ${RBA_COUCHDB_REPLICATION_DOCS}; do
                echo "Deleting replication doc ${CURRENT_DOC_TO_DELETE} on ${CURRENT_DB_SERVER}"
    
                # fetch rev required to delete replication doc
                CURRENT_DOC_REV=$(curl \
                    -k \
                    -s \
                    -X GET \
                    -u "${CURRENT_DB_USER}:${CURRENT_DB_PW}" \
                    "${CURRENT_DB_SERVER}/_replicator/${CURRENT_DOC_TO_DELETE}" | jq -r "._rev")
                
                # delete replication document
                DELETE_REPLICATION_DOC=$(curl \
                    -k \
                    -s \
                    -X DELETE \
                    -u "${CURRENT_DB_USER}:${CURRENT_DB_PW}" \
                    "${CURRENT_DB_SERVER}/_replicator/${CURRENT_DOC_TO_DELETE}?rev=${CURRENT_DOC_REV}")
    
                echo "${DELETE_REPLICATION_DOC}"
                if [[ "$(echo "${DELETE_REPLICATION_DOC}" | jq ".ok")" ]] ; then
                    echo "Replication ${CURRENT_DOC_TO_DELETE} on ${CURRENT_DB_SERVER} was delete successfully"
                else
                    echo "Failed to delete replication doc ${CURRENT_DOC_TO_DELETE} on ${CURRENT_DB_SERVER}"
                    exit 1
                fi
            done
        }
    
        deleteRbaReplications "${RBA_DB_URL_SIDE_A}" "${RBA_DB_USER_SIDE_A}" "${RBA_DB_PW_SIDE_A}"
        deleteRbaReplications "${RBA_DB_URL_SIDE_B}" "${RBA_DB_USER_SIDE_B}" "${RBA_DB_PW_SIDE_B}"
    fi
    
    echo "Showing current CouchDB scheduler jobs"
    echo "Side A:"
    curl \
        -k \
        -s \
        -X GET \
        -u "${RBA_DB_USER_SIDE_A}:${RBA_DB_PW_SIDE_A}" \
        "${RBA_DB_URL_SIDE_A}/_scheduler/jobs" | jq "."
    
    echo "Side B:"
    curl \
        -k \
        -s \
        -X GET \
        -u "${RBA_DB_USER_SIDE_B}:${RBA_DB_PW_SIDE_B}" \
        "${RBA_DB_URL_SIDE_B}/_scheduler/jobs" | jq "."
    
  • To setup the replication, run the following command and enter the prompted values:
    $ ./couchdbReplication.sh
    Usage: ./couchdbReplication.sh setup|delete
    
    Example:
    $ ./couchdbReplication.sh setup
    ================ RBA Replication Setup ================
    Running in setup mode
    CouchDB URL side A: https://couchdb.apps.noi-side-a.company.com
    CouchDB username side A: root
    CouchDB password side A: 
    CouchDB on side A is accessible
    Detecting runbook automation databases
    skip: _global_changes
    skip: _replicator
    skip: _users
    skip: collabopsuser
    skip: emailrecipients
    skip: genericproperties
    replicate: icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as
    replicate: icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs
    skip: incidentprocessorcfd95b7e-3bc7-4006-a4a8-a73a79c71255
    skip: integration
    skip: noi-drdb
    skip: noi-osregdb
    skip: osb-map
    skip: otc_omaas_broker
    skip: rba-pdoc
    skip: schedule
    skip: tenant
    skip: trainingjob
    RBA db detected: icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as
    CouchDB design doc https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as/_design/georedundancy is accessible
    RBA db detected: icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs
    CouchDB design doc https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs/_design/georedundancy is accessible
    CouchDB URL side B: https://couchdb.apps.noi-side-b.company.com
    CouchDB username side B: root
    CouchDB password side B: 
    CouchDB on side B is accessible
    Creating replication for Runbook Service Database
    Setting up replication: https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as -> https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as
    Deleting old replication if present, continuing if missing
    {"error":"not_found","reason":"deleted"}
    Creating replication
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication","rev":"9-6717a9fabfd77d2664066bdd6898f605"}
    Replication for icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as from side A to B was configured successfully
    https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as -> https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as
    Deleting old replication if present, continuing if missing
    {"error":"not_found","reason":"deleted"}
    Creating replication document
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication","rev":"5-7ab7eed4dc8cdf84610b7d64f0982929"}
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication","rev":"5-7ab7eed4dc8cdf84610b7d64f0982929"}
    Replication for icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as from side B to A was configured successfully
    Setting up replication: https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs -> https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs
    Deleting old replication if present, continuing if missing
    {"error":"not_found","reason":"deleted"}
    Creating replication
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication","rev":"9-0baaa632372a8dcaf588daf0d1230a9c"}
    Replication for icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs from side A to B was configured successfully
    https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs -> https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs
    Deleting old replication if present, continuing if missing
    {"error":"not_found","reason":"deleted"}
    Creating replication document
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication","rev":"5-068dabe643c2f8cb1a6eb510d2b4bcaa"}
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication","rev":"5-068dabe643c2f8cb1a6eb510d2b4bcaa"}
    Replication for icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs from side B to A was configured successfully
    Replication setup completed, displaying replication status
    Showing current CouchDB scheduler jobs
    Side A:
    {
      "total_rows": 2,
      "offset": 0,
      "jobs": [
        {
          "database": "_replicator",
          "id": "270a93d419a145d75cf310b3eea3637d+continuous+create_target",
          "pid": "<0.15361.337>",
          "source": "https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs/",
          "target": "https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs/",
          "user": null,
          "doc_id": "icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication",
          "history": [
            {
              "timestamp": "2021-09-30T10:16:46Z",
              "type": "started"
            },
            {
              "timestamp": "2021-09-30T10:16:46Z",
              "type": "added"
            }
          ],
          "node": "couchdb@geo66-couchdb-0.geo66-couchdb.backup66.svc.cluster.local",
          "start_time": "2021-09-30T10:16:46Z"
        },
        {
          "database": "_replicator",
          "id": "68b5cb66e11652098dc49c800d93db4a+continuous+create_target",
          "pid": "<0.12902.337>",
          "source": "https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as/",
          "target": "https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as/",
          "user": null,
          "doc_id": "icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication",
          "history": [
            {
              "timestamp": "2021-09-30T10:16:41Z",
              "type": "started"
            },
            {
              "timestamp": "2021-09-30T10:16:41Z",
              "type": "added"
            }
          ],
          "node": "couchdb@geo66-couchdb-0.geo66-couchdb.backup66.svc.cluster.local",
          "start_time": "2021-09-30T10:16:41Z"
        }
      ]
    }
    Side B:
    {
      "total_rows": 0,
      "offset": 0,
      "jobs": []
    }
    
    Alternatively, you can export variables to start the script in noninteractive mode. This step is useful when starting the script by automation:
    $ export RBA_DB_URL_SIDE_A="https://couchdb.apps.noi-side-a.company.com"
    $ export RBA_DB_USER_SIDE_A="usera"
    $ export RBA_DB_PW_SIDE_A="xxx"
    $ export RBA_DB_URL_SIDE_B="https://couchdb.apps.noi-side-b.company.com"
    $ export RBA_DB_USER_SIDE_B="userb"
    $ export RBA_DB_PW_SIDE_B="xxx"
    $ ./couchdbReplication.sh setup
    
  • To stop the replication between sides, use the same script with the delete command (the example uses the noninteractive mode):
    $ ./couchdbReplication.sh delete
    ================ RBA Replication Setup ================
    Running in delete mode
    CouchDB on side A is accessible
    CouchDB on side B is accessible
    Detecting runbook automation replications on https://couchdb.apps.noi-side-a.company.com
    Deleting replication doc icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication on https://couchdb.apps.noi-side-a.company.com
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication","rev":"10-4d14f022b02c8fd6f116f74cf463572a"}
    Replication icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication on https://couchdb.apps.noi-side-a.company.com was delete successfully
    Deleting replication doc icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication on https://couchdb.apps.noi-side-a.company.com
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication","rev":"10-286548f1f99210c89ff1edfd547ef317"}
    Replication icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication on https://couchdb.apps.noi-side-a.company.com was delete successfully
    Detecting runbook automation replications on https://couchdb.apps.noi-side-b.company.com
    Deleting replication doc icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication on https://couchdb.apps.noi-side-b.company.com
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication","rev":"6-4ca916e83431cf2a7318d4347fdbe421"}
    Replication icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication on https://couchdb.apps.noi-side-b.company.com was delete successfully
    Deleting replication doc icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication on https://couchdb.apps.noi-side-b.company.com
    {"ok":true,"id":"icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication","rev":"6-894c0282ebaf098d434fff550086dbb4"}
    Replication icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication on https://couchdb.apps.noi-side-b.company.com was delete successfully
    Showing current CouchDB scheduler jobs
    Side A:
    {
      "total_rows": 0,
      "offset": 0,
      "jobs": []
    }
    Side B:
    {
      "total_rows": 0,
      "offset": 0,
      "jobs": []
    }
    
    Note: If one side becomes unavailable for a short time, for example due to Kubernetes rescheduling actions or a router restart, the replication resumes automatically. If there is a longer outage, resume replication manually by running the replication setup again. The step deletes existing replication records and creates them again, which triggers a new replication on CouchDB instantaneously.
  • To verify whether the replication is completed, run the following command against both sides:
    $ curl -sku xxx:xxx https://couchdb.apps.noi-side-a.company.com/_active_tasks | jq "."
    Example output:
    
    [
      {
        "node": "couchdb@geo66-couchdb-0.geo66-couchdb.backup66.svc.cluster.local",
        "pid": "<0.1145.0>",
        "changes_pending": 0,
        "checkpoint_interval": 30000,
        "checkpointed_source_seq": "48-g1AAAAUzeJzN0ksOgjAQBuDGd-Ih9AI0gJTHRr2JttMqmiIGxMSV3kRvojfRm2CxJOpaF93MZGYx-fJnJEKoFzc5GkNaQMzZdClSYtWDZePPEW-zVUKzA8H5HjDIIt-JDMsUqJTqToMiNijLch03aT9Ri64XcAbC-_n6v4BsqCqb1Ma2NhIGdmibY5xWxllt7L2MYcQC3wnMMc4r4_ErR0E9vhi5xhg3LVXRSTXFPFfOzssZAQEwznnRzus7T-Y6lI7M-UvtvGnnvXK29G86kedzMMz50M7y7fQF4RH5Pc_1Ew38wpQ",
        "continuous": true,
        "database": "shards/00000000-1fffffff/_replicator.1633015915",
        "doc_id": "icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as-georedundancy-replication",
        "doc_write_failures": 0,
        "docs_read": 0,
        "docs_written": 0,
        "missing_revisions_found": 0,
        "replication_id": "c51067ba96d5707fbe636743f0efe835+continuous",
        "revisions_checked": 24,
        "source": "https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as/",
        "source_seq": "48-g1AAAAUzeJzN0ksOgjAQBuDGd-Ih9AI0gJTHRr2JttMqmiIGxMSV3kRvojfRm2CxJOpaF93MZGYx-fJnJEKoFzc5GkNaQMzZdClSYtWDZePPEW-zVUKzA8H5HjDIIt-JDMsUqJTqToMiNijLch03aT9Ri64XcAbC-_n6v4BsqCqb1Ma2NhIGdmibY5xWxllt7L2MYcQC3wnMMc4r4_ErR0E9vhi5xhg3LVXRSTXFPFfOzssZAQEwznnRzus7T-Y6lI7M-UvtvGnnvXK29G86kedzMMz50M7y7fQF4RH5Pc_1Ew38wpQ",
        "started_on": 1633347279,
        "target": "https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-as/",
        "through_seq": "48-g1AAAAUzeJzN0ksOgjAQBuDGd-Ih9AI0gJTHRr2JttMqmiIGxMSV3kRvojfRm2CxJOpaF93MZGYx-fJnJEKoFzc5GkNaQMzZdClSYtWDZePPEW-zVUKzA8H5HjDIIt-JDMsUqJTqToMiNijLch03aT9Ri64XcAbC-_n6v4BsqCqb1Ma2NhIGdmibY5xWxllt7L2MYcQC3wnMMc4r4_ErR0E9vhi5xhg3LVXRSTXFPFfOzssZAQEwznnRzus7T-Y6lI7M-UvtvGnnvXK29G86kedzMMz50M7y7fQF4RH5Pc_1Ew38wpQ",
        "type": "replication",
        "updated_on": 1633504493,
        "user": null
      },
      {
        "node": "couchdb@geo66-couchdb-0.geo66-couchdb.backup66.svc.cluster.local",
        "pid": "<0.4215.0>",
        "changes_pending": 0,
        "checkpoint_interval": 30000,
        "checkpointed_source_seq": "114-g1AAAAUzeJzN1EsOAUEQANAOEt9I7Oy4wHTamG5scBP6F0OakfFJrLgJN-Em3GT0ZxasWfSmKlWLykulUgoAUImLAox5cuCxYNOFTHCQFwGCnyXcpss1TU8Y7o4ccnXY7WUKVcKpUnpOgQLWybJsFRdpda0bZYYRiiT9efq_gKyrI5vkxpYzkhFBkvhjnBrj7MvYw4xopD_GuTGec2PNGvUaccRDb4ybko7gopNmXo2zbp2jKJThAHvmvDnn3Tib7i6pGHLZ98z5cM6ncbatExFJQtnzzPlyTnufDevEiIlI_P6LVm-JSMKf",
        "continuous": true,
        "database": "shards/e0000000-ffffffff/_replicator.1633015915",
        "doc_id": "icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs-georedundancy-replication",
        "doc_write_failures": 0,
        "docs_read": 3,
        "docs_written": 3,
        "missing_revisions_found": 3,
        "replication_id": "412c029073c1eb39e0d443a525cd0f85+continuous",
        "revisions_checked": 79,
        "source": "https://couchdb.apps.noi-side-a.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs/",
        "source_seq": "114-g1AAAAUzeJzN1EsOAUEQANAOEt9I7Oy4wHTamG5scBP6F0OakfFJrLgJN-Em3GT0ZxasWfSmKlWLykulUgoAUImLAox5cuCxYNOFTHCQFwGCnyXcpss1TU8Y7o4ccnXY7WUKVcKpUnpOgQLWybJsFRdpda0bZYYRiiT9efq_gKyrI5vkxpYzkhFBkvhjnBrj7MvYw4xopD_GuTGec2PNGvUaccRDb4ybko7gopNmXo2zbp2jKJThAHvmvDnn3Tib7i6pGHLZ98z5cM6ncbatExFJQtnzzPlyTnufDevEiIlI_P6LVm-JSMKf",
        "started_on": 1633347375,
        "target": "https://couchdb.apps.noi-side-b.company.com/icp-63666439356237652d336263372d343030362d613461382d613733613739633731323535-rba-rbs/",
        "through_seq": "114-g1AAAAUzeJzN1EsOAUEQANAOEt9I7Oy4wHTamG5scBP6F0OakfFJrLgJN-Em3GT0ZxasWfSmKlWLykulUgoAUImLAox5cuCxYNOFTHCQFwGCnyXcpss1TU8Y7o4ccnXY7WUKVcKpUnpOgQLWybJsFRdpda0bZYYRiiT9efq_gKyrI5vkxpYzkhFBkvhjnBrj7MvYw4xopD_GuTGec2PNGvUaccRDb4ybko7gopNmXo2zbp2jKJThAHvmvDnn3Tib7i6pGHLZ98z5cM6ncbatExFJQtnzzPlyTnufDevEiIlI_P6LVm-JSMKf",
        "type": "replication",
        "updated_on": 1633504494,
        "user": null
      }
    ]
    
    Both sides are in sync when all replications state "changes_pending": 0 or "changes_pending": null.
  • In the case of database migrations, it is recommended to disable replication, upgrade both sides, and then reactivate replication again. For more information, see Upgrading Runbook Automation in replicated environments.