#!/bin/bash

# Copyright: 2023 Virtuozzo International GmbH

# 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.

inherit os net;
include log virtuozzo vzexec;

DESCRIPTION="Manipulate NFS authentication inside container";
VERSION="1"
DEFAULT_ACTION="Usage";

declare -l ATYPE;
declare DESTINATION;
declare -a IPLIST;
declare -i CTID;
declare FALSE=1
declare TRUE=0
declare _BACKUP_COUNT=5
VERBOSE=1

EXPORTS_PATH="/etc/exports"
EXPORTS_EXT=""
CONTAINER_EXPORTS_FILE="${EXPORTS_PATH}${EXPORTS_EXT}"
NFS_CONFIG_DIR="/etc"
DEFAULTEXPORTOPT="async,rw,no_subtree_check,no_root_squash"
NFS_BACKEND="Native"
STORAGE_BACKEND="nfs" # nfs | gluster
_NFS_VERSION=3
MOUNTPROG="/sbin/unfsd"
MOUNTPACKAGE="/var/lib/jelastic/packages/jelastic-nfs-server.tar.gz"
METAINFOFILE="/etc/jelastic/metainf.conf"
CLIENTSPATH="/etc/jelastic/clients"
CLIENTS=""

$PROGRAM "tar"
VZ_TYPE=0

function doUsage() {
    showUsageMessage
}

function onModLoadCallback() {
    log "Preload callback";

    ## TODO: remove "params" garbarge option
    local temp=`getopt -o t:,l:,p:,c:,r: -l list:,clients:,type:,path:,ctid:,uuid:,vtype:,readonly:,version: -- params "$@" 2>/dev/null` oldifs;
    [[ $? != 0 ]] && die -q "Terminating...";
    eval set -- "$temp";

    while true ; do
        case "$1" in
            -t | --type)
                shift
                ATYPE=${1,,}
                shift
                ;;
            -l | --list )
                shift
                oldifs=$IFS
                IFS=';'
                IPLIST=(${1})
                IFS=${oldifs}
                shift
                ;;
            -p | --path )
                shift
                DESTINATION=${1}
                shift
                ;;
            -c | --ctid )
                shift
                CTID=$1
                vzexecSetCTID $CTID
                shift
                ;;
            --uuid)
                shift;
                _UUID=$1
                UUID=$1
                shift;
                ;;
            --vtype)
                shift;
                VTYPE=$1
                shift;
                ;;
            --clients )
                shift
                CLIENTS="$1"
                shift
                ;;
            --version )
                shift
                case ${1^^} in
                    NFS | NFS3 )
                        _NFS_VERSION=3
                        ;;
                    NFS4 )
                        _NFS_VERSION=4
                        ;;
                    GLUSTER )
                        STORAGE_BACKEND="gluster"
                        ;;
                esac
                shift
                ;;
            --)
                shift
                break
                ;;
        esac;
    done;
    [[ ! -z "${CTID}" ]] && {
        populateVEVarsVZ $CTID
        res=$?
        if [[ "$res" -eq 3 ]] ; then
            writeJSONResponseErr "result=>4003" "message=>ctid $CTID not found"
            die -q;
        fi

        VZ_CTID_ROOT=$VZ_VEID_ROOT
        NFS_CONFIG_DIR="$(vzctPath $VZ_VEID_ROOT /etc)"
        NFS_CONFIG_FILE="$(vzctPath $VZ_VEID_ROOT /etc/exports)"
        EXPORTS_FILE="$(vzctPath $VZ_VEID_ROOT $CONTAINER_EXPORTS_FILE)"

        if vzexecRun "sed -rne '/JELASTIC_CHECK_MOUNT=/{s/JELASTIC_CHECK_MOUNT=([0-9])/\1/g;p}' /.jelenv" ; then
            res=$(vzexecGetLastStdOut)
            [ -n "$res" ] && JELASTIC_CHECK_MOUNT=$res
        fi

        if vzexecRun "sed -rne '/VAP_FIREWALL_BACKEND=/{s/VAP_FIREWALL_BACKEND=(nftables|iptables)/\1/g;p}' /etc/jelastic/metainf.conf" ; then
            res=$(vzexecGetLastStdOut)
            [ -n "$res" ] && VAP_FIREWALL_BACKEND=$res
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - Firewall backend from metainf is $VAP_FIREWALL_BACKEND" >> $JEM_CALLS_LOG
        fi


        vzexecRun "[ ! -d $CLIENTSPATH ] && mkdir -p $CLIENTSPATH"
        VZ_TYPE=$(set +f; cat /etc/*release /etc/issue | grep -i "virtuozzo\|parallels" | awk '{ for (i=1; i<NF; i++ ) {if ($i ~ "release" ) print $(i+1) }}' | awk -F'.' '{print $1}' | head -n 1)
    }

    if [ -z "$VAP_FIREWALL_BACKEND" ] ; then
        local issue_file="$(vzctPath $VZ_VEID_ROOT /etc/issue )"
        local release_files="$(vzctPath $VZ_VEID_ROOT /etc/)/*-release"
        issue_string=$(set +f; cat $release_files $issue_file 2>/dev/null);

        VAP_FIREWALL_BACKEND=$( detectFirewallBackend "$issue_string" )
    fi
}

function dosetupUtils() {

    if [[ "x$CTID" == "x" ]] ; then
        writeJSONResponseErr "result=>4140" "message=>Failed to install packages: CTID is required"
        return 1
    fi

    if isContainerRunning $CTID ; then

        if [ -z "$_metainf" ] ; then
            _metainf="$(vzctPath $VZ_CTID_ROOT $METAINFOFILE)"
        fi

        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - Looking COMPUTE_TYPE in $_metainf" >> $JEM_CALLS_LOG
        local computetype="$( [ -e "$_metainf" ] && $SED -nre '/COMPUTE_TYPE=/{s/COMPUTE_TYPE=(\S+)/\1/g;p}' "$_metainf")"

        if [[ "xstorage" == "x$computetype" ]] ; then
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - The node is a shared storage. Enabling nfs server" >> $JEM_CALLS_LOG
            vzexecRun "systemctl enable nfs-server"
            return 0
        fi
    fi

    if [[ ! -e "$MOUNTPACKAGE" ]] ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - error installing unfsd. $MOUNTPACKAGE not found" >> $JEM_CALLS_LOG
        return 1
    fi
    local proxy_env="export http_proxy=\"$(printenv http_proxy)\"; export https_proxy=\"$(printenv https_proxy)\"; export ftp_proxy=\"$(printenv ftp_proxy)\"; export no_proxy=\"$(printenv no_proxy)\"";
    local addPackages=""

    #install nfs-utils
    case $VZ_VEID_OS in
        almalinux|centos|fedora|vzlinux )

            if [ "x$VZ_VEID_OS" == "xcentos" -a "$VZ_VEID_OS_VER" -eq 5 ] ; then
                writeJSONResponseErr "result=>4112" "message=>NFS: CentOS 5 is not supported"
                return 1
            fi
            if [ "x$VZ_VEID_OS" == "xcentos" -a "$VZ_VEID_OS_VER" -eq 6 ] ; then
                writeJSONResponseErr "result=>4112" "message=>NFS: CentOS 6 is not supported"
                return 1
            fi

            addPackages="libtirpc"

            if [ "$VZ_VEID_OS_VER" -eq 7 -o "x$VZ_VEID_OS" == "xvzlinux" ]; then
                addPackages="$addPackages nfs-utils"
            fi

            #perform repos update
            local repo="updates,base"

            [[ "${VZ_VEID_OS_VER/.*}" == "9" ]] && repo="appstream"
            vzexecRun "$proxy_env; yum update -y ca-certificates --disablerepo=* --enablerepo=$repo"
            ;;

        debian|ubuntu )

            if [ "x$VZ_VEID_OS" == "xdebian" -a "$VZ_VEID_OS_VER" -eq 6 ] ; then
                writeJSONResponseErr "result=>4112" "message=>NFS: Debian 6 is not supported"
                return 1
            fi

            addPackages="libtirpc1 nfs-common"
            case $VZ_VEID_OS_VER in
                10|11|12|20|22)
                    addPackages="libtirpc-common nfs-common"
                    ;;
            esac

            waitCounter=90
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - waiting until dpkg lock is released" >> $JEM_CALLS_LOG;
            for apt_lock_file in "/var/lib/dpkg/lock" "/var/lib/dpkg/lock-frontend"; do
                if [ -f "$(vzctPath $VZ_VEID_ROOT $apt_lock_file)" ]; then
                    while [ -n "$(vzexecRun "pgrep 'apt|dpkg' | tr '[:cntrl:]' ' '"; vzexecGetLastStdOut;)" ]; do
                        waitCounter=$((waitCounter-1));
                        [[ $waitCounter -eq 0 ]] && break
                        sleep 3;
                    done
                    rm -f "$(vzctPath $VZ_VEID_ROOT $apt_lock_file)"
                fi
            done

            case $VZ_VEID_OS_VER in
                10|11)
                    ric="--allow-releaseinfo-change"
                    ;;
                *)
                    ric=""
                    ;;
            esac

            #perform repos update
            vzexecRun "$proxy_env; apt-get $ric update -y"
            ;;
        alpine)
            writeJSONResponseErr "result=>4112" "message=>NFS: Alpine Linux is not supported"
            return 1
            ;;
    esac

    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - installing rpcbind $addPackages" >> $JEM_CALLS_LOG
    installCmd=$(installPackageCmd $VZ_VEID_OS install rpcbind $addPackages)
    checkCmd=$(checkPackageCmd $VZ_VEID_OS rpcbind )

    #the installFromTAR indicates whether unfsd will be unpacked from TAR or we use package
    installFromTAR=1
    case $VZ_VEID_OS in
        ubuntu)
            if [ $VZ_VEID_OS_VER -ge 22 ] ; then
                installFromTAR=0

                dc=3
                de=0
                packageName="unfsd_0.9.23.deb"

                while [[ $dc -gt 0 ]] ; do
                    VEDownloadFileWMD5 "http://repository.jelastic.com/pub/unfsd/deb/22.04/$packageName"
                    de=$?
                    dc=$((dc-1))
                done

                if [[ $de -ne 0 ]] ; then
                    writeJSONResponseErr "result=>4140" "message=>Failed to install following packages: $packageName. Downloading error!"
                fi
            fi
            ;;
        debian)
            if [ $VZ_VEID_OS_VER -ge 12 ] ; then
                installFromTAR=0

                dc=3
                de=0
                packageName="unfsd_0.9.23.deb"

                while [[ $dc -gt 0 ]] ; do
                    VEDownloadFileWMD5 "http://repository.jelastic.com/pub/unfsd/deb/22.04/$packageName"
                    de=$?
                    dc=$((dc-1))
                done

                if [[ $de -ne 0 ]] ; then
                    writeJSONResponseErr "result=>4140" "message=>Failed to install following packages: $packageName. Downloading error!"
                fi
            fi
            ;;
        almalinux)
            if [ $VZ_VEID_OS_VER -ge 9 ] ; then
                installFromTAR=0

                dc=3
                de=0
                packageName="unfsd-0.9.23-1.el9.x86_64.rpm"

                while [[ $dc -gt 0 ]] ; do
                    VEDownloadFileWMD5 "http://repository.jelastic.com/pub/unfsd/rpm/$packageName"
                    de=$?
                    dc=$((dc-1))
                done

                if [[ $de -ne 0 ]] ; then
                    writeJSONResponseErr "result=>4140" "message=>Failed to install following packages: $packageName. Downloading error!"
                fi
            fi
            ;;
    esac

    if [[ $installFromTAR -eq 1 ]] ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - unpacking $MOUNTPACKAGE" >> $JEM_CALLS_LOG
        $TAR hzxf "$MOUNTPACKAGE" -C "$VZ_VEID_ROOT/"
    fi


    # install systemD unit
    [[ -d "$(vzctPath $VZ_VEID_ROOT /lib/systemd/system)" ]] && echo "$SystemDUnit" > "$(vzctPath $VZ_VEID_ROOT /lib/systemd/system/unfsd.service)"

    isContainerRunning $CTID && {
        vzexecRun "$installCmd"

        #log output from package manager
        echo "CTID:$CTID Detected OS: $VZ_VEID_OS package manager response: $(vzexecGetLastStdOut) $(vzexecGetLastStdErr)" >> $ACTIONS_LOG

        # if not installed from TAR-package use the package manager
        if [[ $installFromTAR -eq 0 ]] ; then
            PMInstallCmd=""
            case $VZ_VEID_OS in
                debian|ubuntu)
                    PMInstallCmd="dpkg --install ./unfsd_0.9.23.deb && rm ./unfsd_0.9.23.deb"
                ;;
                almalinux)
                    PMInstallCmd="rpm -i ./unfsd-0.9.23-1.el9.x86_64.rpm && rm ./unfsd-0.9.23-1.el9.x86_64.rpm"
                ;;
            esac

            if ! VEExecRun "$PMInstallCmd" ; then
                stdout=$(vzexecGetLastStdOut)
                writeJSONResponseErr "result=>4140" "message=>Failed to install following packages: $stdout"
                return 1
            fi
        fi

        vzexecRun "eval $checkCmd"
        stdout=$(vzexecGetLastStdOut)
        if [[ -n "$stdout" ]] ; then
            writeJSONResponseErr "result=>4140" "message=>Failed to install following packages: $stdout"
            return 1
        fi


        if [ "x$VZ_VEID_OS" == "xubuntu" -o "x$VZ_VEID_OS" == "xdebian" -o "x$VZ_VEID_OS" == "xsuse" ] ; then
            vzexecRun '[ -d /etc/conf.d1 ] && ln -s "/etc/rc.d/init.d/unfsd.jelastic" "/etc/init.d/unfsd.jelastic"'
        fi

        if [ "x$VZ_VEID_OS" == "xubuntu" -o "x$VZ_VEID_OS" == "xdebian" ] ; then
            vzexecRun 'update-rc.d unfsd.jelastic defaults'
            if [ "x$VZ_VEID_OS" == "xdebian" ] ; then
                if [ "$VZ_VEID_OS_VER" -ge "8" ] ; then
                    vzexecRun "systemctl enable unfsd"
                else
                    vzexecRun 'sed -i -r "/^#/!s/exit\s+0/service rpcbind start;\n\/etc\/init.d\/unfsd.jelastic start;\nexit 0/g" /etc/rc.local'
                fi
            fi
        fi


        if ! vzexecRun "$_INSTALLUNFSDCMD" ; then
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - error installing unfsd." >> $JEM_CALLS_LOG
            return 1
        fi
    }
    return 0
}

function gatherCTInfo() {
    isContainerRunning $CTID || {
        echo "Container $CTID is not running"
    }


    _ctExportsFile="$(vzexecRun "[[ -e $CONTAINER_EXPORTS_FILE ]] && cat $CONTAINER_EXPORTS_FILE || echo \"$CONTAINER_EXPORTS_FILE not found\""; vzexecGetLastStdOut)"
    if [ "x$VAP_FIREWALL_BACKEND" == "xiptables" ] ; then
        _ctFirewallRules="$(vzexecRun "iptables -S"; vzexecGetLastStdOut)"
    else
        _ctFirewallRules="$(vzexecRun "nft list ruleset"; vzexecGetLastStdOut)"
    fi
    _ctIpInfo="$(vzexecRun "ip a l; ip r l" ; vzexecGetLastStdOut)"

    echo -e "\n`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID \n=====\nContainer $CTID Info:\nexports:\n$_ctExportsFile\nip info:\n$_ctIpInfo\niptables:\n$_ctFirewallRules\n=====\n"
}

function _adjustFirewall() {
    if isFunction "_adjust${STORAGE_BACKEND^^}Firewall" ; then
        "_adjust${STORAGE_BACKEND^^}Firewall" "$@"
    fi
}

function _adjustNFSFirewall() {
    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID _adjustNFSFirewall started" >> $JEM_CALLS_LOG
    isContainerRunning ${CTID} || return $FALSE;

    vzexecRun "jem firewall isEnabled"
    fwstatus=$(vzexecGetLastErrCode)
    if [[ "$fwstatus" -gt 0 ]] ; then
        #firewall is not running in container (or old jem inside)
        set -f
        [ -e "$(vzctPath $VZ_CTID_ROOT /etc/exports)" ] && NFSIPS=($($SED -re 's/.+(\s|\t)+((\*)|([0-9]+\.){3}[0-9]+(\/[0-9]{0,2})?).*/\2/g' -e '/#/d' "$(vzctPath $VZ_CTID_ROOT /etc/exports)" | sort | uniq | $SED -e '/^$/d' -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'))

        if [ "x$VAP_FIREWALL_BACKEND" == "xiptables" ] ; then
            local __allnetwork=0
            IPT="iptables"

            if [[ "${#NFSIPS[@]}" -gt 0 ]] ; then
                for nfsip in ${NFSIPS[@]} ; do
                    if [ "$nfsip" == "*" ] ; then
                        # whole network requested
                        vzexecRun "$IPT -D INPUT -p tcp -m multiport --dports 111,2049 -j ACCEPT; $IPT -D INPUT -p udp -m multiport --dports 111,2049 -j ACCEPT; $IPT -I INPUT -p tcp -m multiport --dports 111,2049 -j ACCEPT; $IPT -I INPUT -p udp -m multiport --dports 111,2049 -j ACCEPT"

                        #all network exported
                        __allnetwork=1
                        break
                    else
                        #remove rule if already exists
                        vzexecRun "$IPT -D INPUT -p tcp -m multiport --dports 111,2049 -s $nfsip -j ACCEPT; $IPT -D INPUT -p udp -m multiport --dports 111,2049 -s $nfsip -j ACCEPT"
                        #add new rule for selected IP
                        vzexecRun "$IPT -I INPUT -p tcp -m multiport --dports 111,2049 -s $nfsip -j ACCEPT; $IPT -I INPUT -p udp -m multiport --dports 111,2049 -s $nfsip -j ACCEPT"
                    fi
                done
            fi
            vzexecRun "$IPT -D INPUT -i lo -j ACCEPT; $IPT -I INPUT -i lo -j ACCEPT"

            if [[ "$__allnetwork" -eq 0 ]] ; then
                #DROP ALL OTHER SOURCES
                vzexecRun "$IPT -D INPUT -p udp -m multiport --dports 111,2049 -j DROP; $IPT -D INPUT -p tcp -m multiport --dports 111,2049 -j DROP"
                vzexecRun "$IPT -A INPUT -p udp -m multiport --dports 111,2049 -j DROP; $IPT -A INPUT -p tcp -m multiport --dports 111,2049 -j DROP"
            fi

            vzexecRun "service iptables save"
            #JE-26417
            vzexecRun "[ -x /etc/init.d/iptables-persistent ] && /etc/init.d/iptables-persistent save ; [ -x /etc/init.d/netfilter-persistent ] && /etc/init.d/netfilter-persistent save"

        else
            inherit nftables
            local __allnetwork=0

            for nfsip in ${NFSIPS[@]} ; do
                if [[ "${#NFSPort}" -gt 0 ]] ; then
                    if [ "$nfsip" == "*" ] ; then
                        vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol tcp ip daddr $ip tcp dport { $NFSPort} counter accept" 2>>$JEM_CALLS_LOG
                        vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol udp ip daddr $ip udp dport { $NFSPort} counter accept" 2>>$JEM_CALLS_LOG
                        __allnetwork=1
                    else
                        if [[ "$__allnetwork" -eq 0 ]] ; then
                            vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol tcp ip saddr $nfsip ip daddr $ip tcp dport { $NFSPort} counter accept" 2>>$JEM_CALLS_LOG
                            vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol udp ip saddr $nfsip ip daddr $ip udp dport { $NFSPort} counter accept" 2>>$JEM_CALLS_LOG
                        fi
                    fi
                fi
                if [[ "${#RPCPort}" -gt 0 ]] ; then
                    if [ "$nfsip" == "*" ] ; then
                        vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol tcp ip daddr $ip tcp dport { $RPCPort} counter accept" 2>>$JEM_CALLS_LOG
                        vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol udp ip daddr $ip udp dport { $RPCPort} counter accept" 2>>$JEM_CALLS_LOG
                        __allnetwork=1
                    else
                        if [[ "$__allnetwork" -eq 0 ]] ; then
                            vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol tcp ip saddr $nfsip ip daddr $ip tcp dport { $RPCPort} counter accept" 2>>$JEM_CALLS_LOG
                            vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN ip protocol udp ip saddr $nfsip ip daddr $ip udp dport { $RPCPort} counter accept" 2>>$JEM_CALLS_LOG
                        fi
                    fi
                fi
            done

            vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_TABLE_NAME $FW_FILTER_INPUT_CHAIN iifname \"lo\" accept"

            if [[ "$__allnetwork" -eq 0 ]] ; then
                #DROP ALL OTHER SOURCES

                #UDP
                vzexecRun "nft -a list ruleset | sed -rne '/udp.+111,\s*2049.*drop.*/{s/.*handle\s([0-9]+)$/\1/g;p}'"
                h="$(vzexecGetLastStdOut)"
                if [ -n $h ] ; then
                    vzexecRun "nft delete rule ip filter INPUT handle $h"
                fi

                #TCP
                vzexecRun "nft -a list ruleset | sed -rne '/tcp.+111,\s*2049.*drop.*/{s/.*handle\s([0-9]+)$/\1/g;p}'"
                h="$(vzexecGetLastStdOut)"
                if [ -n $h ] ; then
                    vzexecRun "nft delete rule ip filter INPUT handle $h"
                fi

                vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_FILTER_TABLE_NAME $FW_FILTER_INPUT_CHAIN  ip protocol ip udp dport { 111,2049} counter accept"
                vzexecRun "nft add rule $FW_DEFAULT_TABLE_TYPE $FW_FILTER_TABLE_NAME $FW_FILTER_INPUT_CHAIN  ip protocol ip tcp dport { 111,2049} counter accept"
            fi

            vzexecRun "nft -s list ruleset >> \"$FW_RULESET_FILE\" 2>> $JEM_CALLS_LOG"

        fi

        set +f
    else
        #firewall is enabled, so call reconfiguration method
        vzexecRun "jem firewall FWReconfigure"
    fi
}

function validateExports() {
    : ${1:?"Missing param: file to check"};
    OIFS=$IFS;IFS=$'\n'
    dd=($(getExportedDirList $1));
    #IFS=$OIFS
    if [[ $? -eq 0 ]] ; then
        for (( i = 0; i < ${#dd[@]}; i++)) ; do
            isValidShare ${dd[$i]} $1 "$VZ_CTID_ROOT" || invalidExports=("${invalidExports[@]}" "${dd[$i]}")
        done
        local backup="$1.backup-$(date +%d-%m-%Y.%H:%M:%S.%N)"
        cp -f "$1" "$backup" > /dev/null 2>&1

        keeplist=$(mktemp)
        fulllist=$(mktemp)
        find $NFS_CONFIG_DIR -name exports.backup-??-??-????.??:??:??.* -printf '%T@ %p\n' 2>/dev/null | sort -k 1nr | sed 's/^[^ ]* //' | head -n $_BACKUP_COUNT > $keeplist 2>/dev/null
        find $NFS_CONFIG_DIR -name exports.backup-??-??-????.??:??:??.* -printf '%T@ %p\n' 2>/dev/null | sort -k 1nr | sed 's/^[^ ]* //' > $fulllist 2>/dev/null
        comm -13 --nocheck-order $keeplist $fulllist 2>/dev/null | while read f ; do
            echo "removing backup file $f " >> $ACTIONS_LOG
            rm $f 2>/dev/null
        done
        /bin/rm -f $keeplist 2>/dev/null
        /bin/rm -f $fulllist 2>/dev/null

        for (( i = 0; i < ${#invalidExports[@]}; i++)) ; do
            lineToComment="/$(sed -re 's/\//\\\//g' <<< $(sed -re 's/\^/\\^/g' -e 's/\$/\\$/g' -e 's/(\+\{|\}|\[|\]|\(|\))/\\\1/g'  -e 's/\s/(\\\\040|\\s)/g' <<< "${invalidExports[$i]}"))/ s/^#*/#/"
            sed -i -re "$lineToComment" "$1"
        done
    else
        IFS=$OIFS
        return 1
    fi
    IFS=$OIFS
    local tmpfile=$( mktemp -p /tmp )
    $AWK '!seen[$0]++' "$1" > "$tmpfile" 2>/dev/null && sed -i -re '/^".*"\s*$/d' -e '/^[^\s]+\s?$/d' $tmpfile && mv -f "$tmpfile" "$1" >/dev/null 2>&1
    chmod 666 "$1"
    return 0
}


function _checkConfigs() {
    local UNFSDBIN='/sbin/unfsd'
    local _metainf="$(vzctPath $VZ_CTID_ROOT $METAINFOFILE)"

    vzexecRun "[[ ! -e '/etc/exports' ]]" && return 1
    validateExports "$(vzctPath $VZ_CTID_ROOT /etc/exports)" || return 1

    isContainerRunning $CTID && {
        local computetype="$( [ -e "$_metainf" ] && $SED -nre '/COMPUTE_TYPE=/{s/COMPUTE_TYPE=(\S+)/\1/g;p}' "$_metainf")"
        if [[ "xstorage" == "x$computetype" ]] ; then
            vzexecRun "[[ ! -e $MOUNTPROG ]]" && return 0
        fi

        vzexecRun "$UNFSDBIN -T"
        errCode=$(vzexecGetLastErrCode)
        [[ "$errCode" -ne 0 ]] && return 1
    }
    return 0
}

function _nfsReexport() {
    local _metainf="$(vzctPath $VZ_CTID_ROOT $METAINFOFILE)"
    log "ReExporting shares"
    _checkConfigs || {
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID _nfsReexport: Cannot add client configuration. $(gatherCTInfo)" >> ${JEM_CALLS_LOG}
        return 1
    }
    _adjustFirewall >> ${JEM_CALLS_LOG}

    isContainerRunning ${CTID} && {
        local computetype="$( [ -e "$_metainf" ] && $SED -nre '/COMPUTE_TYPE=/{s/COMPUTE_TYPE=(\S+)/\1/g;p}' "$_metainf")"
        if [[ "xstorage" == "x$computetype" ]] ; then
            if vzexecRun "[[ ! -e $MOUNTPROG ]]" ; then
                vzexecRun "exportfs -ra"
                local err=$(vzexecGetLastStdErr)
                [[ -z "${err// }" ]] && return $TRUE

                echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID _nfsReexport: Cannot add client configuration. exports:$(gatherCTInfo) | $err " >> ${JEM_CALLS_LOG}
                return 1
            fi
        fi
    }

    PID=$(vzctl exec ${CTID} pgrep unfsd)
    if [[ ! -z "${PID}" ]] ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - Reloading unfsd with PID: $PID" >> ${JEM_CALLS_LOG}
        vzctl exec ${CTID} kill -HUP $PID > /dev/null 2>&1; res=$?
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - Reloading done, exit result is $res" >> ${JEM_CALLS_LOG}
    fi
    return 0
}

function doRestart() {
    if [[ "x$STORAGE_BACKEND" == "xnfs" ]] ; then
        if ! _nfsReexport ; then
            writeJSONResponseErr "result=>4113" "message=>NFS: Cannot verify client configuration"
            return 1
        fi
    fi
    writeJSONResponseOut "result=>0" "message=>Success"
    return 0
}

function _addNativeip() {
    if [[ -z "${IPLIST[*]}" ]] ; then
        log "ADD: Empty ip list. Nothing to do. Exiting";
        return;
    fi

    eval "$($SED -re "/^r[ow]:.*/{s/^((ro|rw):)?(\/?.*)/accessMode='\2'\ndestinationPath='\3'/g;ta};s/^(\/.*)/destinationPath='\1'/g;ta;s/(.*)/errValue='\1'/;q1;:a;q0;" <<< "$DESTINATION" |  $SED -re "s/='(.*?)'.*/=\1/g" | $SED -re "s/('|\"|\`)/\\\\\1/g" | $SED -re 's/(.*)=(.*)/\1="\2"/g')"
    [[ -z "$destinationPath" ]] && {
        writeJSONResponseErr "result=>4066" "message=>Wrong param. DESTINATION required" ;
        return 1;
    }

    if [[ "x$STORAGE_BACKEND" == "xgluster" ]] ; then
        _addGlusterShare || return 1
        return 0
    fi

    local aCurrentIPs=()
    local running
    local _createPath=1
    local _isFUSE=0
    local _done=0
    local _version=$_NFS_VERSION
    local _metainf="$(vzctPath $VZ_CTID_ROOT $METAINFOFILE)"

    isContainerRunning ${CTID} ; running=$?
    if [[ $running -ne 0 ]] ; then
        $VZCTL mount $CTID > /dev/null 2>&1
        EXPORTS_FILE="$(vzctPath $VZ_CTID_ROOT $CONTAINER_EXPORTS_FILE)"
    else
        if ! vzexecRun "which rpcbind showmount" ; then
            dosetupUtils $CTID || return 1
        fi

        if [[ ! -e "${VZ_CTID_ROOT}${MOUNTPROG}" ]] ; then
            dosetupUtils $CTID || return 1
        fi
    fi

    local computetype="$( [ -e "$_metainf" ] && $SED -nre '/COMPUTE_TYPE=/{s/COMPUTE_TYPE=(\S+)/\1/g;p}' "$_metainf")"
    if [[ "xstorage" == "x$computetype" ]] ; then
        _version=4
        if isContainerRunning ${CTID} ; then
            if vzexecRun "grep -q \" $destinationPath fuse\" /proc/mounts" ; then
                _createPath=0
                _isFUSE=1
            elif vzexecRun "fuse_avail=\$(grep \"fuse\" /proc/mounts | awk '{print \$2}'); [ -n \"\$fuse_avail\" ] &&  grep -q \$fuse_avail <<< \"$destinationPath\"" ; then
                vzexecRun "[ ! -e \"${destinationPath}\" ]" && _createPath=1 || _createPath=0
                _isFUSE=1
            fi
        else
            _createPath=0
        fi
    fi

    [ "$VZ_TYPE" -eq 6 ] && _version=3

    if [ -e "${EXPORTS_FILE}" ] ; then
        dPath="\\\"?$($SED -re 's/(\[|\]|\*|\(|\)|\$|\?|\|)/\\\1/g' <<< $destinationPath)\\\"?\s+"
        if [[ $running -eq 0 ]] ; then
            if vzexecRun "grep -E \"$dPath\" \"$CONTAINER_EXPORTS_FILE\"" ; then
                aCurrentIPs=($(vzexecGetLastStdOut | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/[0-9]{2})?'))
            fi
        else
            aCurrentIPs=($(grep -E "$dPath" "$EXPORTS_FILE" | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])(\/[0-9]{2})?'))
        fi
    fi

    log "Adding IPs to exports file (${EXPORTS_FILE})"
    for i in "${IPLIST[@]}" ; do
        isValidIP $i || continue

        if [[ $running -ne 0 ]] ; then
            # container is mounted, but not running. Try to perform operations directly on mounted fs
            # ---------------------------------------------------------------------------------------
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - container is not running." >> ${JEM_CALLS_LOG}

            if [[ -f "$(vzctPath $VZ_CTID_ROOT ${destinationPath})" ]] ; then
                writeJSONResponseOut "result=>4150" "message=>Exporting regular files via NFS is not supported. Please export directory" ;
                return $FALSE
            fi

            [[ ! -d "$(vzctPath $VZ_CTID_ROOT ${destinationPath})" ]] && [ ! -L "${VZ_CTID_ROOT}${destinationPath}" ] && {
                if [[ $_createPath -eq 1 ]] ; then
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - creating directory ${VZ_CTID_ROOT}${destinationPath} " >> ${JEM_CALLS_LOG}
                    mkdir -p "${VZ_CTID_ROOT}${destinationPath}"
                    chmod 0777 "${VZ_CTID_ROOT}${destinationPath}"
                fi
            }

        else
            # container is running. use vzctl
            # ---------------------------------------------------------------------------------------
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - container is running. Performing all operations via vzctl" >> ${JEM_CALLS_LOG}
            if vzexecRun "[[ -f \"$destinationPath\" ]]" ; then
                writeJSONResponseOut "result=>4150" "message=>Exporting regular files via NFS is not supported. Please export directory" ;
                return $FALSE
            fi

            if vzexecRun "[[ ! -d \"$destinationPath\" ]] && [ ! -L \"$destinationPath\" ]" ; then
                if [[ $_createPath -eq 1 ]] ; then
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - creating directory $destinationPath" >> ${JEM_CALLS_LOG}
                    if ! vzexecRun "mkdir -p \"$destinationPath\" && chmod 0777 \"$destinationPath\"" ; then
                        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - Error creating directory: $(vzexecGetLastStdErr; vzexecGetLastStdOut)" >> ${JEM_CALLS_LOG}
                    fi
                fi
            fi
        fi

        if [[ -z $(indexOf "${aCurrentIPs[*]}" "$i") ]] ; then
            log "${DESTINATION}\t${i}${DEFAULTEXPORTOPT}"
            [[ "x${accessMode}" == "xro" ]] && DEFAULTEXPORTOPT=$($SED -re 's/,rw,/,ro,/g' <<< $DEFAULTEXPORTOPT)
            _opts="$DEFAULTEXPORTOPT"
            if [[ $_version -eq 4 ]] ; then
                if [ -z "$_UUID" ] ; then
                    local pathID=$(md5sum <<< "$i:$destinationPath" | cut -d' ' -f1 ) # md5sum of <ipaddress of client>:<path>
                    _UUID="${pathID::8}-${pathID:8:4}-${pathID:12:4}-${pathID:16:4}-${pathID:20:12}"
                fi
                _opts="$DEFAULTEXPORTOPT,fsid=$_UUID"
            fi

            if [[ $running -ne 0 ]] ; then
                echo -e "\"${destinationPath}\"\t$i($_opts)" >> "${EXPORTS_FILE}"
            else
                if ! vzexecRun "echo -e \"\\\"${destinationPath}\\\"\t$i($_opts)\">> $CONTAINER_EXPORTS_FILE" ; then
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - error adding entry. Error: $(vzexecGetLastStdErr; vzexecGetLastStdOut). $(gatherCTInfo)" >> ${JEM_CALLS_LOG}
                fi
            fi

            _done=1
        else
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - entry for $i already exists" >> ${JEM_CALLS_LOG}
            _done=1
        fi
    done

    if [[ $running -ne 0 ]] ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - umounting container" >> ${JEM_CALLS_LOG}
        $VZCTL umount $CTID > /dev/null 2>&1
    else
        if [[ $_done -eq 1 ]] ; then
            if ! _nfsReexport ; then
                echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - ReExporting data fail. $(gatherCTInfo)" >> ${JEM_CALLS_LOG}

                _removeNativeip
                writeJSONResponseErr "result=>4113" "message=>NFS: Cannot add client configuration"
                return 1
            fi

            if [ -z "$JELASTIC_CHECK_MOUNT" ]; then
                if ! vzexecRun "rpcinfo -p $1 | grep -q mountd" ; then
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - mountd procedures not found on RPC server. Checking remote share will be disabled" >> ${JEM_CALLS_LOG}
                    JELASTIC_CHECK_MOUNT=0
                fi
                JELASTIC_CHECK_MOUNT=1
            fi

            case "$JELASTIC_CHECK_MOUNT" in
                false|0)
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - remote server checking disabled" >> ${JEM_CALLS_LOG}
                    return 0
                    ;;
                true|1)
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - remote server checking enabled" >> ${JEM_CALLS_LOG}
                    ;;
            esac

            retries=5
            vzexecRun "showmount -e 127.0.0.1 | grep -qP \"$IPLIST\""
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID - showmount $(vzexecGetLastStdErr; vzexecGetLastStdOut)" >> ${JEM_CALLS_LOG}

            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID: checking exports" >> ${JEM_CALLS_LOG};
            while [[ $retries -gt 0 ]] ; do
                if [[ "$(vzexecGetLastErrCode)" -gt 0 ]]; then
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID: $(vzexecGetLastStdOut)" >> ${JEM_CALLS_LOG};
                    sleep 4
                    vzexecRun "showmount -e 127.0.0.1 | grep -qP \"$IPLIST\""
                    retries=$((retries-1))
                else
                    [[ $_isFUSE -eq 1 ]] && _isFUSE="true" || _isFUSE="false"
                    writeJSONResponseOut "result=>0" "message=>Client configuration has been changed" "version=>NFS$_version" "fuse=>$_isFUSE" "UUID=>$_UUID"
                    return $(vzexecGetLastErrCode)
                fi
            done
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID: timeout has elapsed" >> ${JEM_CALLS_LOG};
            lasterr=$(vzexecGetLastErrCode)
            if [[ "$lasterr" -ne 0 ]] ; then
                echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID showmount fails. $(gatherCTInfo) | $err " >> ${JEM_CALLS_LOG}
                writeJSONResponseErr "result=>4113" "message=>NFS: Cannot add client configuration"
            fi
            return $lasterr
        else
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID Error adding export entry. $(gatherCTInfo) | $err " >> ${JEM_CALLS_LOG}
            writeJSONResponseErr "result=>4113" "message=>NFS: Cannot add client configuration"
        fi
    fi
    return $?
}

function _addGlusterShare() {
    if ! isContainerRunning $CTID ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID Container is not running. Skipping with OK " >> ${JEM_CALLS_LOG}
        writeJSONResponseOut "result=>0" "message=>Operation was skipped due container is stopped" "version=>GLUSTER"
        return 0
    fi

    if ! vzexecRun "command -v gluster &>/dev/null" ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID gluster command not found " >> ${JEM_CALLS_LOG}
        writeJSONResponseErr "result=>4208" "message=>GlusterFS cluster is not available"
        return 1
    fi

    local volumeName=$(sed 's/\///g' <<< $destinationPath)
    if ! vzexecRun "gluster volume list | grep $volumeName" ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID gluster volume $volumeName not found " >> ${JEM_CALLS_LOG}
        writeJSONResponseErr "result=>4209" "message=>Volume $volumeName is not found"
        return 1
    fi

    vzexecRun "gluster volume get $volumeName auth.allow 2>/dev/null | tail -n 1 | tr -s ' ' | cut -d ' ' -f2 | tr ',' ' '"
    local aCurrentIPs=($(vzexecGetLastStdOut))
    #explicit remove '*' from a list of allowed IPs
    aCurrentIPs=(${aCurrentIPs[*]/'*'})
    local aNewIPs=("${aCurrentIPs[*]}")
    local setNewList=0

    for i in "${IPLIST[@]}" ; do
        isValidIP $i || continue

        if [[ -z "$(indexOf "${aCurrentIPs[*]}" "$i")" ]] ; then
            aNewIPs=("${aNewIPs[@]}" "$i")
            setNewList=1
        fi
    done

    #explicit add localhost if not presnt
    if [[ -z "$(indexOf "${aCurrentIPs[*]}" "127.0.0.1")" ]] ; then
        aNewIPs=("${aNewIPs[@]}" "127.0.0.1")
        setNewList=1
    fi

    if [[ $setNewList -eq 1 ]] ; then
        _ipstr="${aNewIPs[@]}"
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID setting $volumeName auth.allow to ${_ipstr// /,}" >> ${JEM_CALLS_LOG}
        vzexecRun "gluster volume set $volumeName auth.allow ${_ipstr// /,}" || return 1
        vzexecRun "[[ -d $CLIENTSPATH ]] && echo \"$_ipstr\" | sed -r -e 's/  / /g' -e 's/^ //g' -e 's/ $//g' -e 's/\*//g' > $CLIENTSPATH/$volumeName"
    else
        #JE-59318
        _ipstr="${aCurrentIPs[@]}"
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID saving client list for $volumeName: ${_ipstr// /,}" >> ${JEM_CALLS_LOG}
        vzexecRun "[[ -d $CLIENTSPATH ]] && echo \"$_ipstr\" | sed -r -e 's/  / /g' -e 's/^ //g' -e 's/ $//g' -e 's/\*//g' > $CLIENTSPATH/$volumeName"
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID auth.allow not changed" >> ${JEM_CALLS_LOG}
    fi

    writeJSONResponseOut "result=>0" "message=>Client configuration has been changed" "version=>GLUSTER"
    return 0
}

function _removeNativeip() {
    if [[ -z "${IPLIST[*]}" ]] ; then
        log "REMOVE: Empty ip list. Nothing to do. Exiting";
        return;
    fi

    [[ "${DESTINATION:0:1}" != '/' ]] && STORAGE_BACKEND="gluster"

    if [[ "x$STORAGE_BACKEND" == "xgluster" ]] ; then
        _removeGlusterShare || return 1
        return 0
    fi

    isContainerRunning ${CTID} ; running=$?
    if [[ $running -ne 0 ]] ; then
        $VZCTL mount $CTID > /dev/null 2>&1
        EXPORTS_FILE="$(vzctPath $VZ_CTID_ROOT $CONTAINER_EXPORTS_FILE)"
    fi

    _checkConfigs || {
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID _checkConfigs failed. $(gatherCTInfo) | $err " >> ${JEM_CALLS_LOG}
        writeJSONResponseErr "result=>4113" "message=>NFS: Cannot add client configuration"
        return $FALSE
    }

    DESTINATION=${DESTINATION//\//\\/}
    DESTINATION=${DESTINATION//\+/\\+}
    if [[ $running -eq 0 ]] ; then

        if [ "x$VAP_FIREWALL_BACKEND" == "xiptables" ] ; then
           for i in "${IPLIST[@]}" ; do
                isValidIP $i || continue
                echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID removing $i | $err " >> ${JEM_CALLS_LOG}
                if ! vzexecRun "sed -i -re \"/\\\"?$DESTINATION\\\"?\s+${i//./\\.}/{/${i//./\\.}[\(| ]/{s/(${i//./\\.}(\([^\)]*\))?)\s?.*//g}}\" $CONTAINER_EXPORTS_FILE" ; then
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID error removing $i " >> ${JEM_CALLS_LOG}
                fi
                vzexecRun "$IPT -D INPUT -p udp -m multiport --dports 111,2049 -s $i -j ACCEPT; $IPT -D INPUT -p tcp -m multiport --dports 111,2049 -s $i -j ACCEPT"
            done
        else
            for i in "${IPLIST[@]}" ; do
                isValidIP $i || continue
                echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID removing $i | $err " >> ${JEM_CALLS_LOG}
                if ! vzexecRun "sed -i -re \"/\\\"?$DESTINATION\\\"?\s+${i//./\\.}/{/${i//./\\.}[\(| ]/{s/(${i//./\\.}(\([^\)]*\))?)\s?.*//g}}\" $CONTAINER_EXPORTS_FILE" ; then
                    echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID error removing $i " >> ${JEM_CALLS_LOG}
                fi

                vzexecRun "nft -a list ruleset | sed -rne '/8\.8\.8\.8.*udp dport \{ 111, 2049 \}/{s/.*handle\s([0-9]+)$/\1/g;p}'"
                h="$(vzexecGetLastStdOut)"
                if [ -n $h ] ; then
                    vzexecRun "nft delete rule ip filter INPUT handle $h"
                fi

                #TCP
                vzexecRun "nft -a list ruleset | sed -rne '/8\.8\.8\.8.*tcp dport \{ 111, 2049 \}/{s/.*handle\s([0-9]+)$/\1/g;p}'"
                h="$(vzexecGetLastStdOut)"
                if [ -n $h ] ; then
                    vzexecRun "nft delete rule ip filter INPUT handle $h"
                fi
            done
        fi

        #JE-26420
        vzexecRun "jem firewall isEnabled"
        fwstatus=$(vzexecGetLastErrCode)
        if [[ "$fwstatus" -gt 1 ]] ; then
            vzexecRun "jem firewall FWReconfigure"
        fi
    else
        for i in "${IPLIST[@]}" ; do
            isValidIP $i || continue
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID removing $i | $err " >> ${JEM_CALLS_LOG}
            $SED -i -re "/\"?$DESTINATION\"?\s+/{/${i//./\\.}[\(| ]/{s/(${i//./\\.}(\([^\)]*\))?)\s?.*//g}}" "${EXPORTS_FILE}"
        done
    fi

    # clean up the exports file
    $SED -i -re '/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/!d' "${EXPORTS_FILE}"

    if [[ $running -ne 0 ]] ; then
        $VZCTL umount $CTID > /dev/null 2>&1
    else
        _nfsReexport
    fi
    return $?
}

function _removeGlusterShare() {
    if ! isContainerRunning $CTID ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID Container is not running. Skipping with OK " >> ${JEM_CALLS_LOG}
        writeJSONResponseOut "result=>0" "message=>Operation was skipped due container is stopped" "version=>GLUSTER"
        return 0
    fi

    if ! vzexecRun "command -v gluster &>/dev/null" ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID gluster command not found " >> $JEM_CALLS_LOG
        writeJSONResponseErr "result=>4208" "message=>GlusterFS cluster is not available"
        return 1
    fi

    local volumeName=$(sed 's/\///g' <<< $DESTINATION)
    if ! vzexecRun "gluster volume list | grep $volumeName" ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID gluster volume $volumeName not found " >> $JEM_CALLS_LOG
        writeJSONResponseErr "result=>4209" "message=>Volume $volumeName is not found"
        return 1
    fi

    vzexecRun "gluster volume get $volumeName auth.allow 2>/dev/null | tail -n 1 | tr -s ' ' | cut -d ' ' -f2 | tr ',' ' '"
    local aCurrentIPs=($(vzexecGetLastStdOut))
    #explicit remove '*' from a list of allowed IPs
    aCurrentIPs=(${aCurrentIPs[*]/'*'})
    local aNewIPs=("${aCurrentIPs[*]}")

    for i in "${IPLIST[@]}" ; do
        isValidIP $i || continue

        if [[ ! -z "$(indexOf "${aCurrentIPs[*]}" "$i")" ]] ; then
            echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID removing $i from auth.allow " >> $JEM_CALLS_LOG
            aNewIPs=("${aNewIPs[@]/$i}")
            vzexecRun "[ -e $CLIENTSPATH/$volumeName ] && sed -i -re 's/\b$i\b//g' -e 's/  +/ /g'  -e 's/^ | $//g' $CLIENTSPATH/$volumeName"
            setNewList=1
        fi
    done

    if [[ $setNewList -eq 1 ]] ; then
        _ipstr=${aNewIPs[@]}
        #do not remove localhost
        [[ -z "$_ipstr" ]] && _ipstr="127.0.0.1"
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID setting $volumeName auth.allow to ${_ipstr// /,}" >> $JEM_CALLS_LOG
        vzexecRun "gluster volume set $volumeName auth.allow ${_ipstr// /,}" || return 1
    else
        #JE-59318
        _ipstr="${aCurrentIPs[@]}"
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID saving client list for $volumeName: ${_ipstr// /,}" >> ${JEM_CALLS_LOG}
        vzexecRun "[[ -d $CLIENTSPATH ]] && echo \"$_ipstr\" | sed -r -e 's/  / /g' -e 's/^ //g' -e 's/ $//g' -e 's/\*//g' > $CLIENTSPATH/$volumeName"
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID auth.allow not changed" >> $JEM_CALLS_LOG
    fi

    writeJSONResponseOut "result=>0" "message=>Client configuration has been changed" "version=>GLUSTER"
    return 0
}

function _cleanNativeip() {
    if [[ -z "${IPLIST[*]}" ]] ; then
        log "ADD: Empty ip list. Cleaning all";


        if [[ "x$STORAGE_BACKEND" == "xgluster" ]] ; then
            _cleanGlusterAuth || return 1
            return 0
        fi

        isContainerRunning ${CTID} ; running=$?
        if [[ $running -ne 0 ]] ; then
            $VZCTL mount $CTID > /dev/null 2>&1
        fi

        echo "" > "${EXPORTS_FILE}"

        if [[ $running -ne 0 ]] ; then
            $VZCTL umount $CTID > /dev/null 2>&1
        else
            _nfsReexport
        fi
        return;
    fi
    return 0
}

function _cleanGlusterAuth() {
    if ! vzexecRun "command -v gluster &>/dev/null" ; then
        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID gluster command not found " >> ${JEM_CALLS_LOG}
        return 1
    fi
    vzexecRun "gluster volume set data auth.allow 127.0.0.1"
    vzexecRun "gluster volume reset data auth.reject"
}

function _cleanip() {
    return 0
}

function doAdjustFirewall() {
    if ! _adjustFirewall ; then
        PUBLISH_ERROR=1
        writeJSONResponseErr "result=>4068" "message=>Firewall reconfiguration error"
        return 1
    else
        writeJSONResponseOut "result=>0" "message=>Firewall reconfigured successfully"
        return 0
    fi
}

function doAdd() {
    local requiredParqams=("CTID" "DESTINATION" "IPLIST" "TYPE")
    local msg=$(checkParams ${requiredParqams[@]})
    [[ ! -z "${msg}" ]] && { writeJSONResponseErr "result=>4099" "message=>Missing param $msg" ; return 99; }
    _add${NFS_BACKEND}${ATYPE};
}

function doRemove() {
    local requiredParqams=("CTID" "DESTINATION" "IPLIST" "TYPE")
    local msg=$(checkParams ${requiredParqams[@]})
    [[ ! -z "${msg}" ]] && { writeJSONResponseErr "result=>4099" "message=>Missing param $msg" ; return 99; }
    _remove${NFS_BACKEND}${ATYPE};
    return $?
}

function doList() {
    local _first=0
    if [ ! -e "${EXPORTS_FILE}" ] ; then
        echo '{"result":"4099", "message":"'${EXPORTS_FILE}' not found!"}'
        return 1
    fi

    echo '{"result":"0", "shares":['
    while read l ; do
        [[ $_first -eq 0 ]] && _first=1  || echo ","
        echo -n "{"
        sed -re 's/^"(.*)"\s+.*fsid=([^,\)]+).*/"name":"\1","fsid":"\2"/' <<< $l | \
        sed -re'/root"$/{s/.*"root"/\0,"fuse":"false"/;q}' -e 's/.*/\0,"fuse":"true"/'
        echo -n "}"
    done < "${EXPORTS_FILE}"
    echo "]}"
}

function doClean() {
    _clean${NFS_BACKEND}${ATYPE};
    return $?
}

function doSet() {
    OIFS=$IFS;IFS=";" clist=($CLIENTS);IFS=$OIFS
    volumes=()

    re='(.*):(.*):(.*)'
    for e in ${clist[@]}; do
        if [[ $e =~ $re ]] ; then
            volName=${BASH_REMATCH[3]}
            ipa=${BASH_REMATCH[1]}

            if [[ ! " ${volumes[@]} " =~ " clp$volName " ]]; then
                volumes+=("clp$volName")
                eval "clp${volName}=()"
            fi
            eval "clp${volName}+=($ipa)"
        fi
    done

    if ! vzexecRun "gluster volume list" ; then
        writeJSONResponseErr "result=>4208" "message=>GlusterFS cluster is not available"
        return 1
    fi
    cVols=($(vzexecGetLastStdOut))

    for v in ${cVols[@]} ; do
        if ! vzexecRun "gluster volume get $v auth.allow 2>/dev/null | tail -n 1 | tr -s ' ' | cut -d ' ' -f2 | tr ',' ' '" ; then
            writeJSONResponseErr "result=>4210" "message=>Cannot get volume auth list for $v"
            return 1
        fi
        eval "clc$v=($(vzexecGetLastStdOut))"
        vzexecRun "[ -e $CLIENTSPATH/$v ] && cat $CLIENTSPATH/$v"
        eval "clf$v=($(vzexecGetLastStdOut))"

        aList=clc$v[@]
        bList=clf$v[@]
        pList=clp$v[@]
        rList=()

        FVol=" ${!bList} "
        for i in "${!aList}" ; do
            [[ $FVol =~ " $i " ]]  || rList+=($i)
        done

        rList+=(${!pList})
        #explicit add localhost if not presnt
        if [[ -z "$(indexOf "${rList[*]}" "127.0.0.1")" ]] ; then
            rList=("${rList[@]}" "127.0.0.1")
        fi

        rList=$(tr ' ' '\n' <<< "${rList[@]}" | sort -u | tr '\n' ' ')

        if ! vzexecRun "gluster volume set $v auth.allow ${rList// /,}" ; then
            writeJSONResponseErr "result=>4210" "message=>Cannot set volume auth list for $v"
            return 1
        fi

        echo "`date +%D.%k:%M:%S.%N`:   $action:$subaction CTID:$CTID saving client list for $v: ${rList// /,}" >> ${JEM_CALLS_LOG}
        vzexecRun "[[ -d $CLIENTSPATH ]] && echo \"$rList\" | sed -r -e 's/  / /g' -e 's/^ //g' -e 's/ $//g' -e 's/\*//g' > $CLIENTSPATH/$v"
    done

    writeJSONResponseOut "result=>0" "message=>Clients set successfully"
    return 0
}

defineBigInline SystemDUnit << 'EOF'
[Unit]
Description=Jelastic UNFSD
Requires=rpcbind.target rpcbind.service

[Service]
Type=forking
ExecStart=/sbin/unfsd -i /var/run/unfsd.pid
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=unfsd.service
EOF

defineBigInline _INSTALLUNFSDCMD <<'EOF'
if [ -d /run/systemd/system ] ; then
    systemctl restart rpcbind
    systemctl restart rpcbind.socket
    systemctl enable unfsd
    systemctl start unfsd
else
    [ -f /etc/init.d/rpcbind ] && /etc/init.d/rpcbind restart
    sed -i "s/\/usr\/sbin\/unfsd/\/sbin\/unfsd/g" /etc/init.d/unfsd.jelastic
    sed -i "s/\/usr\/sbin\/unfsd/\/sbin\/unfsd/g" /etc/rc.d/init.d/unfsd.jelastic
    chkconfig --level 345 rpcbind on
    chkconfig --level 345 unfsd.jelastic on
    /etc/init.d/unfsd.jelastic start
fi
EOF
