apiVersion: v1
kind: ConfigMap
metadata:
  name: cassandra-scripts
  labels:
    app: cassandra
    group: db
data:
  envVars.sh: |-
    #!/bin/bash

    export CLUSTER_DOMAIN=$(hostname -d | awk -F"." '{print $(NF-1),".",$NF}' | sed 's/ //g')
    export CASSANDRA_SEEDS=cassandra-0.cassandra.default.svc.$CLUSTER_DOMAIN,cassandra-1.cassandra.default.svc.$CLUSTER_DOMAIN
  jvm_options.sh: |-
    #!/bin/bash

    # Todo: avoid this and add manage it with run.sh
    echo "JVM_OPTS=\"\$JVM_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2\"" >> /etc/cassandra/cassandra-env.sh
  run_override.sh: |-
    #!/bin/bash

    source /usr/local/apache-cassandra/scripts/envVars.sh
    /usr/local/apache-cassandra/scripts/jvm_options.sh

    /run.sh
  postStart.sh: |-
    #!/bin/bash

    source /usr/local/apache-cassandra/scripts/envVars.sh

    echo "Wait 9042 port to be open"
    while [ $(ss -lnt | grep -c 9042) != 1 ] ; do
      sleep 5
    done

    until /ready-probe.sh ; do
      echo "Waiting node to be ready"
      sleep 1
    done
    exit 0
  preStop.sh: |-
    #!/bin/sh

    run_nodetool() {
      echo "Running: nodetool $1"
      /usr/local/apache-cassandra/bin/nodetool $1
      sleep 5
    }

    while [ $(/usr/local/apache-cassandra/bin/nodetool status | awk "/$CASSANDRA_RACK/{ print \$1,\$2 }" | grep -v $POD_IP | awk '{ print $1 }' | grep -v UN) -eq 0 ] ; do
      echo "Waiting all nodes to recover a correct status before draining this node"
      sleep 5
      pidof java || exit 1
    done

    run_nodetool disablethrift
    run_nodetool disablebinary
    run_nodetool disablegossip
    run_nodetool flush
    run_nodetool drain
    sleep 10
    run_nodetool stop
    run_nodetool stopdaemon

    exit 0
  snapshot2s3.sh: |-
    #!/bin/bash

    function alert_failure() {
      content=$1
      file="${CASSANDRA_CLUSTER_NAME}_$(hostname)"
      resource="/$AWS_BUCKET/failures/${file}"
      contentType="text/plain"
      dateValue=`date -R`
      stringToSign="PUT\n\n${contentType}\n${dateValue}\n${resource}"
      signature=`echo -en ${stringToSign} | openssl sha1 -hmac ${AWS_SECRET_ACCESS_KEY} -binary | base64`

      echo -e ${content} >> $file
      curl -X PUT -T "${file}" \
        -H "Host: ${AWS_BUCKET}.s3.amazonaws.com" \
        -H "Date: ${dateValue}" \
        -H "Content-Type: ${contentType}" \
        -H "Authorization: AWS ${AWS_ACCESS_KEY_ID}:${signature}" \
        https://${AWS_BUCKET}.s3-eu-west-1.amazonaws.com/failures/${file}
      rm -f $file
    }

    function clean() {
      echo "[+] Cleaning"
      /usr/local/apache-cassandra/bin/nodetool clearsnapshot
      rm -Rf /snap /tmp/snapshot2s3.log
    }

    # Create lock or stop if already present
    function create_lock() {
      if [ -f /tmp/snapshot2s3.lock ] ; then
        echo "Backup or restore is already in progress for $CLUSTER_DOMAIN/$CASSANDRA_CLUSTER_NAME/$(hostname)"
        exit 0
      fi
    }

    function release_lock() {
      rm -Rf /tmp/snapshot2s3.lock
    }

    function backup() {

      create_lock
      clean

      export LC_ALL=C
      snap_name="snapshot_$(date +%Y-%m-%d_%H-%M-%S)"

      # Create snapshot
      echo "[+] Starting Snapshot"
      /usr/local/apache-cassandra/bin/nodetool snapshot -t $snap_name > /tmp/snapshot2s3.log 2>&1
      if [ $? != 0 ] ; then
        echo "Error during snapshot, please check manually, cleaning before exit"
        alert_failure "Error during snaptshot:\n$(cat /tmp/snapshot2s3.log)"
        clean
        release_lock
        exit 1
      fi
      cat /tmp/snapshot2s3.log

      # Create temporary folder
      find /var/lib/cassandra/data -name $snap_name -exec mkdir -p /snap/{} \;

      # Make snapshot symlinks
      cd /snap
      for i in $(find . -name $snap_name | sed 's/^.\///') ; do
        rmdir /snap/$i
        ln -s /$i /snap/$i
      done

      # Dump schemas
      mkdir -p /snap/var/lib/cassandra/schemas
      for schema in $(cqlsh -e "select keyspace_name from system_schema.keyspaces;" | egrep "^\s+" | awk '{ print $1 }' | grep -v keyspace_name) ; do
        cqlsh -e "describe keyspace ${schema}" > /snap/var/lib/cassandra/schemas/${schema}.cql
        if [ $? != 0 ] ; then
          echo "Error while dumping schema ${schema}"
          alert_failure "Error while dumping ${schema} schema"
          clean
          release_lock
          exit 1
        fi
      done

      # Transfer with duplicity
      echo "[+] Running duplicity to transfer to AWS"
      duplicity --archive-dir /var/lib/cassandra/.duplicity --allow-source-mismatch --s3-european-buckets --s3-use-new-style --copy-links --num-retries 3 --s3-use-multiprocessing --s3-multipart-chunk-size 100 --volsize 1024 full . s3://s3-eu-west-1.amazonaws.com/${AWS_BUCKET}/$CLUSTER_DOMAIN/$CASSANDRA_CLUSTER_NAME/$(hostname) > /tmp/snapshot2s3.log 2>&1
      if [ $? != 0 ] ; then
        echo "Error while backuping $CLUSTER_DOMAIN/$CASSANDRA_CLUSTER_NAME/$(hostname)"
        alert_failure "Error with duplicity\n$(cat /tmp/snapshot2s3.log)"
      fi
      cat /tmp/snapshot2s3.log

      # Clean snapshot
      clean
      release_lock
    }

    function restore() {
      echo "Enter the cluster domain of cassandra, hit enter if you're ok with: $CLUSTER_DOMAIN"
      read clusterDomain
      test "$clusterDomain" != "" && CLUSTER_DOMAIN=$clusterDomain
      echo "Enter the cluster name of cassandra, hit enter if you're ok with: $CASSANDRA_CLUSTER_NAME"
      read clusterName
      test "$clusterName" != "" && CASSANDRA_CLUSTER_NAME=$clusterName
      NODE_NAME=$(hostname)
      echo "Enter the node name you want to restore, hit enter if you're ok with: $NODE_NAME"
      read nodeName
      test "$nodeName" != "" && NODE_NAME=$nodeName

      create_lock

      echo "[+] Running duplicity to restore from AWS"
      duplicity --archive-dir /var/lib/cassandra/.duplicity --allow-source-mismatch --s3-european-buckets --s3-use-new-style --copy-links --num-retries 3 --s3-use-multiprocessing --s3-multipart-chunk-size 100 --volsize 1024 --time $RESTORE_TIME s3://s3-eu-west-1.amazonaws.com/${AWS_BUCKET}/$CLUSTER_DOMAIN/$CASSANDRA_CLUSTER_NAME/$NODE_NAME /var/lib/cassandra/restore > /tmp/snapshot2s3.log 2>&1
      if [ $? != 0 ] ; then
        echo "Error while restoring $CLUSTER_DOMAIN/$CASSANDRA_CLUSTER_NAME/$NODE_NAME"
        alert_failure "Error with duplicity\n$(cat /tmp/snapshot2s3.log)"
      fi
      cat /tmp/snapshot2s3.log

      # Clean snapshot
      clean
      release_lock
    }

    function clean_old() {
      # Remove backups older than 3 months
      duplicity remove-older-than 3M --force s3://s3-eu-west-1.amazonaws.com/${AWS_BUCKET}/$CLUSTER_DOMAIN/$CASSANDRA_CLUSTER_NAME/$(hostname)
    }

    function list() {
      duplicity --archive-dir /var/lib/cassandra/.duplicity --allow-source-mismatch --s3-european-buckets --s3-use-new-style --copy-links --num-retries 3 --s3-use-multiprocessing --s3-multipart-chunk-size 100 --volsize 1024 collection-status s3://s3-eu-west-1.amazonaws.com/${AWS_BUCKET}/$CLUSTER_DOMAIN/$CASSANDRA_CLUSTER_NAME/$(hostname)
    }

    function help() {
      echo "Usage: $0 [backup|restore|list|clean_old] AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_PASSPHRASE AWS_BUCKET [RESTORE_TIME]"
      exit 1
    }

    # Check number of args
    test "$#" -lt 5 && help

    source /usr/local/apache-cassandra/scripts/envVars.sh
    export AWS_ACCESS_KEY_ID=$2
    export AWS_SECRET_ACCESS_KEY=$3
    export PASSPHRASE=$4
    export AWS_BUCKET=$5
    export RESTORE_TIME=$6

    if [ $1 == "backup" ] ; then
      backup
    elif [ $1 == "restore" ] ; then
      test "$#" -ne 6 && help
      restore
    elif [ $1 == "clean_old" ] ; then
      clean_old
    elif [ $1 == "list" ] ; then
      list
    else
      echo "Don't know what to do, please look help at ./$0"
    fi
  cassandra-restore.sh: |-
    #!/bin/bash

    function help() {
      echo "Usage: $0 <restore_data_folder> <keyspace> [<table>]"
      echo '* restore_data_folder: the data folder restored from snapshot2s3.sh script'
      echo '* keyspace: the keyspace to restore'
      echo '* table: (optional field) the table name to restore (without uuid). If not set, all tables from a keyspace will be restored'
      exit 1
    }

    function restore_table() {
      ks=$1
      tb=$2
      echo -e "\n[+] Restoring ${ks}/${tb}"
      /usr/local/apache-cassandra/bin/sstableloader -d $(hostname -A) ${ks}/${tb}
    }

    # Check number of args
    test "$1" == 'help' && help
    test "$#" -gt 1 || help

    source /usr/local/apache-cassandra/scripts/envVars.sh
    RESTORE_DATA_FOLDER=$1
    KEYSPACE=$2
    TABLE=$3

    # Ensure $RESTORE_DATA_FOLDER exist
    if [ ! -d $RESTORE_DATA_FOLDER ] ; then
      echo "$RESTORE_DATA_FOLDER doesn't exist, please check"
      exit 1
    fi
    cd $RESTORE_DATA_FOLDER

    # Ensure $KEYSPACE is present
    if [ ! -d $KEYSPACE ] ; then
      echo "$KEYSPACE is not found in $RESTORE_DATA_FOLDER folder, please ensure you've specified the data folder of the restore folder"
      exit 1
    fi

    # Restore schema ?
    echo 'Do you want to restore schema as well (y/n) ? (required for empty cassandra)'
    read restore_schema
    if [ "$restore_schema" != 'y' ] ; then
      echo 'You decided to not restore schema'
    else
      echo 'You decided to restore schema'
    fi

    echo -e "\n[+]You're going to restore $KEYSPACE keyspace"
    echo "Hit enter key when you're ready to proceed"
    read

    echo "[+] Flushing data to disk"
    /usr/local/apache-cassandra/bin/nodetool flush

    # Restore schema
    if [ "$restore_schema" == 'y' ] ; then
      if [ -f ../schemas/${KEYSPACE}.cql ] ; then
        echo "[+] Restoring schema ${KEYSPACE}"
        cqlsh < ../schemas/${KEYSPACE}.cql
      else
        echo "[+] SCHEMA ${KEYSPACE} MISSING !!! CAN'T RESTORE"
      fi
    fi

    # Prepare snapshot to make it usable with sstableloader
    for current_table in $(ls $KEYSPACE) ; do
      table_name_path="$(find ./${KEYSPACE}/$current_table -name "snapshot_*")"
      if [ "$(echo $table_name_path)" != "" ] ; then
        echo "[+] Preparing ${KEYSPACE}/${current_table}"
        table_name=$(echo $table_name_path | awk -F'/' '{ print $3 }' | sed -r 's/(\w+)-.*/\1/')
        table_name_uuid=$(echo $table_name_path | sed -r 's/(.+)\/snapshots\/.+/\1/')
        mv -v $table_name_path ${KEYSPACE}/$table_name
        rm -Rf $table_name_uuid
      fi
    done

    # Restore all tables or the desired one
    if [ "$TABLE" == '' ] ; then
      # Restore
      for table_name in $(ls $KEYSPACE) ; do
          restore_table $KEYSPACE $table_name
      done
    else
      restore_table $KEYSPACE $TABLE
    fi

    echo "[+] Restore finished"
  exporter_run_override.sh: |-
    #!/bin/bash
    cp -f /usr/local/apache-cassandra/scripts/exporter_config.yml /etc/cassandra_exporter/config.yml
    /run.sh
  reaper_ks_bootstrap.sh: |-
    #!/bin/bash
    echo "Create keyspace if it does not exist"
    if [ $(cqlsh -e 'DESC KEYSPACES' | grep -c reaper_db) == 0 ] ; then
        cqlsh -e "CREATE KEYSPACE reaper_db WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1': 3};"
    fi
