#!/bin/bash # -*- coding:utf-8 -*- ############################################################################# # Copyright (c): 2021, Huawei Tech. Co., Ltd. # FileName : install.sh # Version : V1.0.0 # Date : 2021-03-15 # Description : the script used to install the single cluster on one machine ######################################### function usage() { echo " Usage: sh $0 -w password Arguments: -w login password -p datanode port, default 5432 -e netinterface, default gateway Iface --multinode if specify, will install master_slave cluster. default install single node. -h, --help Show this help, then exit " } function info() { echo -e "\033[32m$1\033[0m" } function error() { echo -e "\033[31m$1\033[0m" } function check_param() { if [ X$password == X'' ]; then error "ERROR: The parameter '-w' can not be empty\n" usage exit 1 fi local -i num=0 if [ -n "$(echo $password | grep -E --color '^(.*[a-z]+).*$')" ]; then let num=$num+1 fi if [ -n "$(echo $password | grep -E --color '^(.*[A-Z]).*$')" ]; then let num=$num+1 fi if [ -n "$(echo $password | grep -E --color '^(.*\W).*$')" ]; then let num=$num+1 fi if [ -n "$(echo $password | grep -E --color '^(.*[0-9]).*$')" ]; then let num=$num+1 fi if [ ${#password} -lt 8 ] || [ $num -lt 3 ] then error "password must be at least 8 character and at least three kinds" exit 1 fi if [ X$user == X"root" ]; then error "Error: can not install openGauss with root" exit 1 fi if [ X$port == X"" ]; then port=$default_port fi if [ X$mode == X"master_standby" ]; then let slave_port=$port+200 fi } function check_install_env() { # check pgxc path if [ X$mode == X"single" ] then if [ -d "$app/data/single_node" ] && [ X"$(ls -A $app/data/single_node)" != X"" ] then error "ERROR: the directory $app/data/single_node must be dir and empty" exit 1 fi else for pgxc in $(echo "master slave" | awk '{print $1,$2}') do if [ -d "$app/data/$pgxc" ] && [ X"$(ls -A $app/data/$pgxc)" != X"" ] then error "ERROR: the directory $app/data/master or $app/data/slave must be dir and empty" exit 1 fi done fi # check pid port and lock file portlist=($(netstat -nutl | grep $port)) i=3 while ((i < ${#portlist[*]})) do listen_addr=${portlist[((i))]} p=${listen_addr##*:} echo $p if [ X"$p" == X"$port" ]; then error "Error: The port $port has been occupied, please use -p to set a new port." exit 1 fi ((i += 6)) done local delete_slave_lock="" local delete_master_lock="" if [ X$slave_port != X"0" ]; then slave_occupied=$(netstat -ntul | grep $slave_port) delete_slave_lock=$(rm -rf /tmp/.s.PGSQL.$slvae_port* 2>&1) if [ X"$slave_occupied" != X"" ]; then error "Error: The slave port $slave_port has been occupied, please use -p to set a new port." exit 1 fi fi delete_master_lock=$(rm -rf /tmp/.s.PGSQL.$port* 2>&1) if [[ $delete_master_lock == *"Operation not permitted"* ]] || [[ $delete_slave_lock == *"Operation not permitted"* ]]; then error "Error: not have permitted to delete /tmp/.s.PGSQL.* file, you should delete it or change port." exit 1 fi } function check_os() { # check shm local shared_buffers=1073741824 # 1G local shmmax=$(cat /proc/sys/kernel/shmmax) env test $shared_buffers -gt $shmmax && echo "Shared_buffers must be less than shmmax. Please check it." && exit 1 local shmall=$(cat /proc/sys/kernel/shmall) local pagesize=$(getconf PAGESIZE) if [ $(($shmall/1024/1024/1024*$pagesize)) -ne 0 ]; then if [ $(($shared_buffers/1024/1024/1024-$shmall/1024/1024/1024*$pagesize)) -gt 0 ]; then echo "The usage of the device [Shared_buffers] space cannot be greater than shmall*PAGESIZE." && exit 1 fi fi # check sem local -a sem local -i index=0 local max_connection=5000 local conn_floor for line in $(cat /proc/sys/kernel/sem) do sem[index]=$line let index=$index+1 done if [ ${sem[0]} -lt 17 ] then info "On systemwide basis, the maximum number of SEMMSL is not correct. the current SEMMSL value is: ${sem[0]}. Please check it." info "The required value should be greater than 17. You can modify it in file '/etc/sysctl.conf'." exit 1 fi let conn_floor=($max_connection+150)/16 if [ ${sem[3]} -lt $conn_floor ] then info "On systemwide basis, the maximum number of SEMMNI is not correct. the current SEMMNI value is: ${sem[3]}. Please check it." info "The required value should be greater than ${conn_floor}. You can modify it in file '/etc/sysctl.conf'." exit 1 fi let conn_floor=$conn_floor*17 if [ ${sem[1]} -lt $conn_floor ] then info "On systemwide basis, the maximum number of SEMMNS is not correct. the current SEMMNS value is: ${sem[1]}. Please check it." info "The required value should be greater than ${conn_floor}. You can modify it in file '/etc/sysctl.conf'." exit 1 fi # check cpu instruction CPU_BIT=$(uname -m) if [ X"$CPU_BIT" == X"x86_64" ]; then if [ X"$(cat /proc/cpuinfo | grep rdtscp | uniq)" == X"" ]; then echo "The cpu instruction rdtscp is missing." && exit 1 fi fi } function change_gausshome_owner() { mkdir_file=$(chown $user:$group $app 2>&1) if [[ $mkdir_file == *"Permission denied"* ]]; then error "Error: $user not have permission to change $app owner and group. please fix the permission manually." exit 1 fi chmod 700 $app } function set_environment() { local path_env='export PATH=$GAUSSHOME/bin:$PATH' local ld_env='export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH' local insert_line=2 sed -i "/^\\s*export\\s*GAUSSHOME=/d" ~/.bashrc # set PATH and LD_LIBRARY_PATH if [ X"$(grep 'export PATH=$GAUSSHOME/bin:$PATH' ~/.bashrc)" == X"" ] then echo $path_env >> ~/.bashrc fi if [ X"$(grep 'export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH' ~/.bashrc)" == X"" ] then echo $ld_env >> ~/.bashrc fi if [ X"$(grep 'export GS_CLUSTER_NAME=dbCluster' ~/.bashrc)" == X"" ] then echo 'export GS_CLUSTER_NAME=dbCluster' >> ~/.bashrc fi if [ X"$(grep 'ulimit -n 1000000' ~/.bashrc)" == X"" ] then echo 'ulimit -n 1000000' >> ~/.bashrc fi # set GAUSSHOME path_env_line=$(cat ~/.bashrc | grep -n 'export PATH=$GAUSSHOME/bin:$PATH' | awk -F ':' '{print $1}') ld_env_line=$(grep -n 'export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH' ~/.bashrc | awk -F ':' '{print $1}') echo if [ $path_env_line -gt $ld_env_line ] then let insert_line=$ld_env_line else let insert_line=$path_env_line fi sed -i "$insert_line i\export GAUSSHOME=$app" ~/.bashrc source ~/.bashrc } function single_install() { info "[step 6]: init datanode" gs_initdb -w $password -D $app/data/single_node --nodename "sgnode" --locale="en_US.UTF-8" if [ X$port != X$default_port ] then sed -i "/^#port =/c\port = $port" $app/data/single_node/postgresql.conf fi info "[step 7]: start datanode" gs_ctl start -D $app/data/single_node -Z single_node } function init_db() { info "[init primary datanode.]" gs_initdb -D $app/data/master --nodename=datanode1 -E UTF-8 --locale=en_US.UTF-8 -U $user -w $password info "[init slave datanode.]" gs_initdb -D $app/data/slave --nodename=datanode2 -E UTF-8 --locale=en_US.UTF-8 -U $user -w $password } function config_db() { info "[config datanode.]" ip_arr=$(/sbin/ifconfig ${netinterface_arr[0]}|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:") sed -i "/^#listen_addresses/c\listen_addresses = 'localhost,${ip_arr}'" $app/data/master/postgresql.conf sed -i "/^#listen_addresses/c\listen_addresses = 'localhost,${ip_arr}'" $app/data/slave/postgresql.conf sed -i "/^#port/c\port = $port" $app/data/master/postgresql.conf sed -i "/^#port/c\port = $slave_port" $app/data/slave/postgresql.conf sed -i "/^#replconninfo1/c\replconninfo1 = 'localhost=${ip_arr} localport=$(($port+1)) localheartbeatport=$(($port+5)) localservice=$(($port+4)) remotehost=${ip_arr} remoteport=$(($slave_port+1)) remoteheartbeatport=$(($slave_port+5)) remoteservice=$(($slave_port+4))'" $app/data/master/postgresql.conf sed -i "/^#replconninfo1/c\replconninfo1 = 'localhost=${ip_arr} localport=$(($slave_port+1)) localheartbeatport=$(($slave_port+5)) localservice=$(($slave_port+4)) remotehost=${ip_arr} remoteport=$(($port+1)) remoteheartbeatport=$(($port+5)) remoteservice=$(($port+4))'" $app/data/slave/postgresql.conf echo "remote_read_mode = non_authentication" | tee -a $app/data/master/postgresql.conf $app/data/slave/postgresql.conf echo "host all all ${ip_arr}/32 trust" | tee -a $app/data/master/pg_hba.conf $app/data/slave/pg_hba.conf } function start_db() { info "[start primary datanode.]" gs_ctl start -D $app/data/master -M primary info "[build and start slave datanode.]" gs_ctl build -D $app/data/slave -b full } function master_standby_install() { init_db config_db start_db } declare default_port=5432 declare user=$(whoami) declare group=$(id -gn $user) declare shell_path=$(cd `dirname $0`;pwd) declare app=$(dirname $shell_path) declare mode="single" declare -i port declare -i slave_port=0 declare -a netinterface_arr declare -i index=0 # Exclude docker* netInterface for i in $(/sbin/route -n | grep "UG" | awk '{print $8}'); do if [[ $i != docker* ]]; then netinterface_arr[index]=$i index=$index+1 fi done function get_param() { ARGS=$(getopt -a -o w:p:e:h -l multinode,help -- "$@") [ $? -ne 0 ] && usage eval set -- "${ARGS}" while [ $# -gt 0 ] do case "$1" in -w) password="$2" shift ;; -p) port="$2" shift ;; -e) netinterface_arr[0]=$(echo "$2") shift ;; --multinode) mode="master_standby" ;; -h|--help) usage exit ;; --) shift break ;; esac shift done } function end_help() { if [ X$mode == X"single" ] then echo -e '[complete successfully]: You can start or stop the database server using: gs_ctl start|stop|restart -D $GAUSSHOME/data/single_node -Z single_node\n' else echo -e '[complete successfully]: You can start or stop the database server using: primary: gs_ctl start|stop|restart -D $GAUSSHOME/data/master -M primary standby: gs_ctl start|stop|restart -D $GAUSSHOME/data/slave -M standby\n' fi } function fn_load_demoDB() { cd $shell_path gsql -d postgres -p $port -f school.sql gsql -d postgres -p $port -f finance.sql } function fn_check_demoDB() { cd $shell_path if [ "`cat load.log | grep ROLLBACK`" != "" ] then return 1 elif [ "`cat load.log | grep '\[GAUSS-[0-9]*\]'`" != "" ] then return 1 elif [ "`cat load.log | grep ERROR`" != "" ] then return 1 elif [ "`cat load.log | grep Unknown`" != "" ] then return 1 fi return 0 } function fn_install_demoDB() { input=$1 if [ "$input"X = X ] then read -p "Would you like to create a demo database (yes/no)? " input fi if [ "$input"X == "yes"X ] then fn_load_demoDB 1>$shell_path/load.log 2>&1 fn_check_demoDB elif [ "$input"X == "no"X ] then return 2 else read -p "Please type 'yes' or 'no': " input fn_install_demoDB $input fi return $? } function import_sql() { fn_install_demoDB local returnFlag=$? if [ $returnFlag -eq 0 ] then info "Load demoDB [school,finance] success." return 0 elif [ $returnFlag -eq 1 ] then error "Load demoDB failed, you can check load.log for more details." else info "Input no, operation skip." fi return 1 } function main() { get_param $@ info "[step 1]: check parameter" check_param info "[step 2]: check install env and os setting" check_install_env check_os info "[step 3]: change_gausshome_owner" change_gausshome_owner info "[step 4]: set environment variables" set_environment if [ X$mode == X"single" ] then single_install else master_standby_install fi info "import sql file" import_sql if [ $? -eq 0 ] then end_help exit 0 else exit 1 fi } main $@