> #!/bin/bash
> # =============================================================================
> # oracle_deploy.sh v2.1
> # Oracle 一键部署:single(单实例/文件系统)| standalone(单实例+GI+ASM)| rac
> # 版本:11G / 12C(12.1) / 12.2 / 18C / 19C / 21C / 23AI
> # -----------------------------------------------------------------------------
> # 说明:
> # 1. 版本差异集中在 load_profile(),安装主流程与版本解耦;
> # 2. 参数支持任意顺序、-k=v 与 -k v 两种写法,并按模式校验必填项;
> # 3. OS 初始化脚本幂等,单机与 RAC 共用同一份;
> # 4. 响应文件统一由函数生成;
> # 5. 安装等待改为精确匹配+超时,避免死循环。
> # =============================================================================
> set -o pipefail
> SOFT_DIR=${SOFT_DIR:-/soft}
> ORA_BASE=/u01/app/oracle
> GRID_BASE=/u01/app/grid
> INVENTORY=/u01/app/oraInventory
> ASM_DISK_DIR=/dev/oracleasm/disks
> DB_TYPE=""; OP="install"; HA=""; VER=""
> PUBLIC_IP=""; NODE_NAME=""; ROOT_PWD=""; DB_PWD=""; DB_SID=""
> USE_CDB="false"; PDB_NAME=""; DB_CHARSET=""; DB_NCHARSET=""; YUM_SRC=""
> PUB1=""; PUB2=""; VIP1=""; VIP2=""; PRIV1=""; PRIV2=""; SCAN_IP=""
> PUB_IF=""; PRIV_IF=""; OCR_REDU=""; OCR_DISKS=""; DATA_REDU=""; DATA_DISKS=""
> DB_ZIP_OVERRIDE=""; GRID_ZIP_OVERRIDE=""
> ORA_NUMBER=""; ORA_NUMBER_S=""; ORACLE_HOME=""; GRID_HOME=""
> DB_ZIP=""; GRID_ZIP=""; DB_MEDIA_MODE=""; GRID_MEDIA_MODE=""
> AU_SIZE=""; SUPPORTS_CDB=0; CDB_REQUIRED=0
> RSP_DB_SCHEMA=""; RSP_GRID_SCHEMA=""; RSP_DBCA_SCHEMA=""
> MIN_MEM_SINGLE=""; MIN_MEM_RAC=""; IGNORE_FLAG=""; YUM_CMD=""
> PROG=$(basename "$0")
> LOG_FILE=${LOG_FILE:-/tmp/oracle_deploy_$(date +%Y%m%d_%H%M%S).log}
> START_TIME=$(date +%s)
> log(){
> local msg
> msg="$(date '+%F %T') $*"
> printf '%s\n' "$msg"
> printf '%s\n' "$msg" >>"$LOG_FILE" 2>/dev/null || true
> }
> die(){ log "ERROR: $*"; exit 1; }
> run_as(){ local u=$1; shift; su - "$u" -c "$(printf '%q ' "$@")"; }
> cidr24(){ echo "$1" | awk -F. '{print $1"."$2"."$3".0"}'; }
> cleanup(){
> local rc=$?
> if (( rc != 0 )); then
> log "脚本异常退出 (rc=$rc),日志: $LOG_FILE"
> else
> log "脚本执行完成,耗时 $(( $(date +%s) - START_TIME ))s,日志: $LOG_FILE"
> fi
> }
> trap cleanup EXIT
> # -----------------------------------------------------------------------------
> # 帮助
> # -----------------------------------------------------------------------------
> usage(){
> cat <<EOF
> Usage: ${PROG} -dt=oracle -op=install -ht=<mode> -v=<version> [options]
> ${PROG} -h | --help | -help | help
> -ht single 单实例(文件系统)
> standalone 单实例 + Grid Infrastructure + ASM(原 ha)
> rac 两节点 RAC
> -v 11G | 12C | 12.2 | 18C | 19C | 21C | 23AI
> 11G / 12C 使用解压式安装介质,12.2 及以上使用 image 方式
> 通用参数:
> -i <public_ip> 主机 IP
> -n <name> 主机名前缀(自动追加 db / db1、db2)
> -dp <password> oracle/grid 系统用户口令,SYS/SYSTEM 等口令
> -o <oracle_sid> 数据库 SID
> -cdb <true|false> 是否 CDB(11G 忽略;21C/23AI 强制 TRUE)
> -pdbname <name> PDB 名称(CDB 时默认 pdb)
> -cs <charset> 字符集,如 ZHS16GBK / AL32UTF8
> -ncs <ncharset> 国家字符集,如 AL16UTF16 / UTF8
> -yum </dev/cdrom|xxx.iso> 本地 yum 源
> RAC / standalone 专用:
> -rp <root_password> 节点 root 口令(用于配置互信,RAC 必填)
> -pu1/-pu2 <ip> node1/node2 公网 IP
> -vi1/-vi2 <ip> node1/node2 VIP(兼容旧写法 -vip1/-vip2)
> -pr1/-pr2 <ip> node1/node2 私网 IP
> -si <scan_ip> SCAN IP
> -puf <ifname> -prf <ifname> 公网/私网网卡名
> -or <HIGH|NORMAL|EXTERNAL> OCR 冗余
> -od </dev/sdb,...> OCR 磁盘
> -dr <HIGH|NORMAL|EXTERNAL> 数据盘冗余
> -dd </dev/sde,...> 数据磁盘
> 可选覆盖:
> -dbzip "a.zip b.zip" 覆盖默认数据库安装介质文件名
> -gridzip "g.zip" 覆盖默认 Grid 安装介质文件名
> 日志:
> 可通过环境变量 LOG_FILE 覆盖日志路径,默认 /tmp/oracle_deploy_<时间戳>.log
> 示例(19C 单实例):
> ./${PROG} -dt=oracle -op=install -ht=single -v=19C \\
> -i=192.168.220.100 -n=orcl -dp=Enmo_1234 -o=orcl \\
> -cdb=false -pdbname=pdb -cs=ZHS16GBK -ncs=AL16UTF16 -yum=/dev/cdrom
> 示例(19C RAC):
> ./${PROG} -dt=oracle -op=install -ht=rac -v=19C \\
> -i=192.168.220.100 -n=enmo -rp=123456 -dp=Enmo_1234 -o=orcl \\
> -cdb=true -pdbname=pdb -cs=ZHS16GBK -ncs=AL16UTF16 -yum=/dev/cdrom \\
> -pu1=192.168.220.100 -pu2=192.168.220.102 \\
> -vi1=192.168.220.103 -vi2=192.168.220.104 \\
> -pr1=192.168.220.100 -pr2=192.168.220.102 -si=192.168.220.240 \\
> -puf=eth0 -prf=eth1 -or=EXTERNAL -od=/dev/sdb,/dev/sdc \\
> -dr=EXTERNAL -dd=/dev/sde,/dev/sdf
> EOF
> }
> # -----------------------------------------------------------------------------
> # 参数解析
> # -----------------------------------------------------------------------------
> is_known_opt(){
> case $1 in
> -dt|--db-type|-op|--operation|-ht|--ha-type|-v|--version|-i|--ip|-n|--name|\
> -rp|-dp|-o|-cdb|-pdbname|-cs|-ncs|-yum|-pu1|-pu2|-vi1|-vi2|-vip1|-vip2|\
> -pr1|-pr2|-si|-scan|-puf|-prf|-or|-od|-dr|-dd|-dbzip|-gridzip|-h|--help|-help)
> return 0 ;;
> *) return 1 ;;
> esac
> }
> set_param(){
> local k=$1 v=$2
> case $k in
> -dt|--db-type) DB_TYPE=$v ;;
> -op|--operation) OP=$v ;;
> -ht|--ha-type) HA=$v ;;
> -v|--version) VER=$v ;;
> -i|--ip) PUBLIC_IP=$v ;;
> -n|--name) NODE_NAME=$v ;;
> -rp) ROOT_PWD=$v ;;
> -dp) DB_PWD=$v ;;
> -o) DB_SID=$v ;;
> -cdb) USE_CDB=$v ;;
> -pdbname) PDB_NAME=$v ;;
> -cs) DB_CHARSET=$v ;;
> -ncs) DB_NCHARSET=$v ;;
> -yum) YUM_SRC=$v ;;
> -pu1) PUB1=$v ;;
> -pu2) PUB2=$v ;;
> -vi1|-vip1) VIP1=$v ;;
> -vi2|-vip2) VIP2=$v ;;
> -pr1) PRIV1=$v ;;
> -pr2) PRIV2=$v ;;
> -si|-scan) SCAN_IP=$v ;;
> -puf) PUB_IF=$v ;;
> -prf) PRIV_IF=$v ;;
> -or) OCR_REDU=$v ;;
> -od) OCR_DISKS=$v ;;
> -dr) DATA_REDU=$v ;;
> -dd) DATA_DISKS=$v ;;
> -dbzip) DB_ZIP_OVERRIDE=$v ;;
> -gridzip) GRID_ZIP_OVERRIDE=$v ;;
> *) die "未知参数: $k" ;;
> esac
> }
> parse_args(){
> (( $# == 0 )) && { usage; exit 1; }
> while (( $# )); do
> case $1 in
> -h|--help|-help|help) usage; exit 0 ;;
> --) shift; break ;;
> -*=*)
> set_param "${1%%=*}" "${1#*=}"; shift ;;
> -*)
> (( $# >= 2 )) || die "参数 $1 缺少取值"
> is_known_opt "$2" && die "参数 $1 缺少取值(下一个是参数 $2)"
> set_param "$1" "$2"; shift 2 ;;
> *) die "无法识别的参数: $1" ;;
> esac
> done
> (( $# == 0 )) || die "存在无法解析的尾部参数: $*"
> }
> # -----------------------------------------------------------------------------
> # 参数规范化与校验
> # -----------------------------------------------------------------------------
> normalize_inputs(){
> DB_TYPE=${DB_TYPE,,}; OP=${OP,,}; HA=${HA,,}; VER=${VER^^}
> [[ -n $DB_TYPE ]] || { usage; die "必须指定 -dt=oracle"; }
> [[ $DB_TYPE == oracle ]] || die "本版本仅支持 -dt=oracle"
> [[ $OP == install ]] || die "当前仅支持 -op=install"
> case $HA in
> single) ;;
> standalone|ha) HA=standalone ;;
> rac) ;;
> *) die "-ht 仅支持 single / standalone / rac" ;;
> esac
> }
> load_profile(){
> case $VER in
> 11G|11.2|11.2.0|112)
> VER=11G
> ORA_NUMBER=11.2.0; ORA_NUMBER_S=11.2
> RSP_DB_SCHEMA=v11_2_0; RSP_GRID_SCHEMA=v11_2_0; RSP_DBCA_SCHEMA=11.2.0
> DB_MEDIA_MODE=extract; GRID_MEDIA_MODE=extract
> DB_ZIP="p13390677_112040_Linux-x86-64_1of7.zip p13390677_112040_Linux-x86-64_2of7.zip"
> GRID_ZIP="p13390677_112040_Linux-x86-64_3of7.zip"
> AU_SIZE=1; SUPPORTS_CDB=0; CDB_REQUIRED=0
> MIN_MEM_SINGLE=2048; MIN_MEM_RAC=2560
> IGNORE_FLAG="-ignoreSysPrereqs -ignorePrereq" ;;
> 12C|12.1|121)
> VER=12C
> ORA_NUMBER=12.1.0; ORA_NUMBER_S=12.1
> RSP_DB_SCHEMA=v12_1_0; RSP_GRID_SCHEMA=v12_1_0; RSP_DBCA_SCHEMA=12.1.0
> DB_MEDIA_MODE=extract; GRID_MEDIA_MODE=extract
> DB_ZIP="linuxamd64_12102_database_1of2.zip linuxamd64_12102_database_2of2.zip"
> GRID_ZIP="linuxamd64_12102_grid_1of2.zip linuxamd64_12102_grid_2of2.zip"
> AU_SIZE=4; SUPPORTS_CDB=1; CDB_REQUIRED=0
> MIN_MEM_SINGLE=2048; MIN_MEM_RAC=4096
> IGNORE_FLAG="-ignoreSysPrereqs -ignorePrereq" ;;
> 12.2|122)
> VER=12.2
> ORA_NUMBER=12.2.0; ORA_NUMBER_S=12.2
> RSP_DB_SCHEMA=v12_2_0; RSP_GRID_SCHEMA=v12_2_0; RSP_DBCA_SCHEMA=12.2.0
> DB_MEDIA_MODE=image; GRID_MEDIA_MODE=image
> DB_ZIP=LINUX.X64_122010_db_home.zip; GRID_ZIP=LINUX.X64_122010_grid_home.zip
> AU_SIZE=4; SUPPORTS_CDB=1; CDB_REQUIRED=0
> MIN_MEM_SINGLE=2048; MIN_MEM_RAC=4096
> IGNORE_FLAG="-ignorePrereqFailure" ;;
> 18C|18.0|18)
> VER=18C
> ORA_NUMBER=18.0.0; ORA_NUMBER_S=18.0
> RSP_DB_SCHEMA=v18.0.0; RSP_GRID_SCHEMA=v18.0.0; RSP_DBCA_SCHEMA=18.0.0
> DB_MEDIA_MODE=image; GRID_MEDIA_MODE=image
> DB_ZIP=LINUX.X64_180000_db_home.zip; GRID_ZIP=LINUX.X64_180000_grid_home.zip
> AU_SIZE=4; SUPPORTS_CDB=1; CDB_REQUIRED=0
> MIN_MEM_SINGLE=2048; MIN_MEM_RAC=8192
> IGNORE_FLAG="-ignorePrereqFailure" ;;
> 19C|19.0|19)
> VER=19C
> ORA_NUMBER=19.3.0; ORA_NUMBER_S=19.0
> RSP_DB_SCHEMA=v19.0.0; RSP_GRID_SCHEMA=v19.0.0; RSP_DBCA_SCHEMA=19.0.0
> DB_MEDIA_MODE=image; GRID_MEDIA_MODE=image
> DB_ZIP=LINUX.X64_193000_db_home.zip; GRID_ZIP=LINUX.X64_193000_grid_home.zip
> AU_SIZE=4; SUPPORTS_CDB=1; CDB_REQUIRED=0
> MIN_MEM_SINGLE=2048; MIN_MEM_RAC=8192
> IGNORE_FLAG="-ignorePrereqFailure" ;;
> 21C|21.0|21)
> VER=21C
> ORA_NUMBER=21.3.0; ORA_NUMBER_S=21.0
> RSP_DB_SCHEMA=v21.0.0; RSP_GRID_SCHEMA=v21.0.0; RSP_DBCA_SCHEMA=21.0.0
> DB_MEDIA_MODE=image; GRID_MEDIA_MODE=image
> DB_ZIP=LINUX.X64_213000_db_home.zip; GRID_ZIP=LINUX.X64_213000_grid_home.zip
> AU_SIZE=4; SUPPORTS_CDB=1; CDB_REQUIRED=1
> MIN_MEM_SINGLE=2048; MIN_MEM_RAC=8192
> IGNORE_FLAG="-ignorePrereqFailure" ;;
> 23AI|23C|23.0|23)
> VER=23AI
> ORA_NUMBER=23.0.0; ORA_NUMBER_S=23.0
> RSP_DB_SCHEMA=v23.0.0; RSP_GRID_SCHEMA=v23.0.0; RSP_DBCA_SCHEMA=23.0.0
> DB_MEDIA_MODE=image; GRID_MEDIA_MODE=image
> DB_ZIP=LINUX.X64_230000_db_home.zip; GRID_ZIP=LINUX.X64_230000_grid_home.zip
> AU_SIZE=4; SUPPORTS_CDB=1; CDB_REQUIRED=1
> MIN_MEM_SINGLE=2048; MIN_MEM_RAC=8192
> IGNORE_FLAG="-ignorePrereqFailure" ;;
> *) die "不支持的版本: $VER(支持 11G/12C/12.2/18C/19C/21C/23AI)" ;;
> esac
> [[ -n $DB_ZIP_OVERRIDE ]] && DB_ZIP=$DB_ZIP_OVERRIDE
> [[ -n $GRID_ZIP_OVERRIDE ]] && GRID_ZIP=$GRID_ZIP_OVERRIDE
> ORACLE_HOME=${ORA_BASE}/product/${ORA_NUMBER}/dbhome_1
> GRID_HOME=/u01/app/${ORA_NUMBER}/grid
> }
> require(){ [[ -n $2 ]] || die "缺少必填参数: $1"; }
> validate_params(){
> require "-i" "$PUBLIC_IP"
> require "-n" "$NODE_NAME"
> require "-dp" "$DB_PWD"
> require "-o" "$DB_SID"
> require "-cs" "$DB_CHARSET"
> require "-ncs" "$DB_NCHARSET"
> require "-yum" "$YUM_SRC"
> [[ $DB_SID =~ ^[A-Za-z][A-Za-z0-9_#$]{0,7}$ ]] || die "SID 非法: $DB_SID"
> [[ $NODE_NAME =~ ^[A-Za-z][A-Za-z0-9-]*$ ]] || die "主机名前缀非法: $NODE_NAME"
> if [[ $HA != single ]]; then
> require "-or" "$OCR_REDU"; require "-od" "$OCR_DISKS"
> require "-dr" "$DATA_REDU"; require "-dd" "$DATA_DISKS"
> fi
> if [[ $HA == rac ]]; then
> require "-rp" "$ROOT_PWD"
> require "-pu1" "$PUB1"; require "-pu2" "$PUB2"
> require "-vi1" "$VIP1"; require "-vi2" "$VIP2"
> require "-pr1" "$PRIV1"; require "-pr2" "$PRIV2"
> require "-si" "$SCAN_IP"
> require "-puf" "$PUB_IF"; require "-prf" "$PRIV_IF"
> [[ $NODE_NAME == *[0-9] ]] && log "WARN: -n 末尾含数字,RAC 主机名将拼接为 ${NODE_NAME}db1/${NODE_NAME}db2"
> fi
> if (( SUPPORTS_CDB == 0 )); then
> [[ ${USE_CDB,,} == true ]] && log "WARN: $VER 不支持 CDB,已强制 -cdb=false"
> USE_CDB=FALSE; PDB_NAME=""
> else
> case ${USE_CDB,,} in
> true|yes|1) USE_CDB=TRUE ;;
> *) USE_CDB=FALSE ;;
> esac
> (( CDB_REQUIRED == 1 )) && USE_CDB=TRUE
> if [[ $USE_CDB == TRUE ]]; then
> PDB_NAME=${PDB_NAME:-pdb}
> else
> PDB_NAME=""
> fi
> fi
> }
> resolve_yum_cmd(){
> case $YUM_SRC in
> /dev/cdrom) YUM_CMD="mount /dev/cdrom /mnt" ;;
> *.iso) [[ -f $YUM_SRC ]] || die "yum 镜像不存在: $YUM_SRC"
> YUM_CMD="mount -o loop $YUM_SRC /mnt" ;;
> *) die "-yum 仅支持 /dev/cdrom 或本地 iso 文件" ;;
> esac
> }
> # -----------------------------------------------------------------------------
> # 预检查
> # -----------------------------------------------------------------------------
> os_major(){
> if [[ -r /etc/redhat-release ]]; then
> grep -oE '[0-9]+' /etc/redhat-release | head -1
> elif [[ -r /etc/os-release ]]; then
> ( . /etc/os-release; echo "${VERSION_ID%%.*}" )
> else
> echo 0
> fi
> }
> precheck(){
> log "===== 环境预检查 ====="
> [[ $EUID -eq 0 ]] || die "请以 root 运行"
> [[ $NODE_NAME =~ ^localhost ]] && die "hostname 非法: $NODE_NAME"
> [[ $PUBLIC_IP == 127.0.0.1 ]] && die "IP 非法: $PUBLIC_IP"
> local major; major=$(os_major)
> case $major in
> 7|8|9) log "OS major version: $major" ;;
> *) die "仅支持 RHEL/OEL 7/8/9,当前: $major" ;;
> esac
> [[ $VER == 23AI && $major -lt 8 ]] && log "WARN: 23AI 建议部署在 OL8/OL9 上"
> local mem_mb; mem_mb=$(awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo)
> local need=$MIN_MEM_SINGLE
> [[ $HA == rac ]] && need=$MIN_MEM_RAC
> (( mem_mb >= need )) || die "内存不足: 需要 ${need}MB,当前 ${mem_mb}MB"
> if id oracle >/dev/null 2>&1; then die "oracle 用户已存在,疑似已安装"; fi
> [[ -d $ORA_BASE ]] && die "$ORA_BASE 已存在,疑似已安装"
> local tz; tz=$(timedatectl 2>/dev/null | awk -F': ' '/Time zone/{print $2}' | awk '{print $1}')
> [[ -n $tz && $tz != Asia/Shanghai ]] && die "时区为 $tz,请先设置为 Asia/Shanghai"
> mountpoint -q /mnt 2>/dev/null && umount /mnt >/dev/null 2>&1 || true
> eval "$YUM_CMD" >/dev/null 2>&1 || die "无法挂载 yum 源: $YUM_CMD"
> umount /mnt >/dev/null 2>&1 || true
> local f
> for f in $DB_ZIP; do
> [[ -f ${SOFT_DIR}/$f ]] || die "缺少数据库介质: ${SOFT_DIR}/$f"
> done
> if [[ $HA != single ]]; then
> for f in $GRID_ZIP; do
> [[ -f ${SOFT_DIR}/$f ]] || die "缺少 Grid 介质: ${SOFT_DIR}/$f"
> done
> fi
> log "预检查通过"
> }
> # -----------------------------------------------------------------------------
> # OS 初始化脚本(生成一次,单机/RAC 共用,幂等)
> # -----------------------------------------------------------------------------
> gen_setos(){
> cat > "${SOFT_DIR}/setos.sh" <<'EOS'
> #!/bin/bash
> # generated by oracle_deploy.sh -- 幂等 OS 初始化
> set -u
> say(){ echo "[setos] $*"; }
> : "${ROLE:=primary}"
> : "${NODE_SUFFIX:=1}"
> # 1. hosts
> if [[ "${HA}" == "rac" ]]; then
> sed -i '/^# >>> oradb hosts/,/^# <<< oradb hosts/d' /etc/hosts
> cat >> /etc/hosts <<EOF
> # >>> oradb hosts
> ${PUB1} ${NODE_NAME}db1
> ${PUB2} ${NODE_NAME}db2
> ${VIP1} ${NODE_NAME}db1-vip
> ${VIP2} ${NODE_NAME}db2-vip
> ${PRIV1} ${NODE_NAME}db1-priv
> ${PRIV2} ${NODE_NAME}db2-priv
> ${SCAN_IP} ${NODE_NAME}db-scan
> # <<< oradb hosts
> EOF
> else
> grep -qE "^${PUBLIC_IP}[[:space:]]+${NODE_NAME}db([[:space:]]|$)" /etc/hosts \
> || echo -e "${PUBLIC_IP}\t${NODE_NAME}db" >> /etc/hosts
> fi
> if [[ "${HA}" == "rac" ]]; then
> hostnamectl set-hostname "${NODE_NAME}db${NODE_SUFFIX}"
> else
> hostnamectl set-hostname "${NODE_NAME}db"
> fi
> # 2. yum
> mountpoint -q /mnt 2>/dev/null && umount /mnt >/dev/null 2>&1 || true
> eval "${YUM_CMD}" >/dev/null 2>&1 || { echo "ERROR: 挂载 yum 源失败: ${YUM_CMD}"; exit 1; }
> mkdir -p /etc/yum.repos.d/bak
> for r in /etc/yum.repos.d/*.repo; do [[ -e "${r}" ]] && mv -f "${r}" /etc/yum.repos.d/bak/ 2>/dev/null; done
> cat > /etc/yum.repos.d/oradb.repo <<EOF
> [oradb]
> name=oradb local
> baseurl=file:///mnt
> enabled=1
> gpgcheck=0
> EOF
> yum clean all >/dev/null 2>&1
> yum makecache >/dev/null 2>&1 || { echo "ERROR: yum 源不可用"; exit 1; }
> OS_MAJOR=$(grep -oE '[0-9]+' /etc/redhat-release 2>/dev/null | head -1)
> if [[ ${OS_MAJOR:-7} -ge 8 ]]; then
> PKGS="gcc gcc-c++ make binutils elfutils-libelf elfutils-libelf-devel glibc-devel \
> libaio libaio-devel libstdc++ libstdc++-devel ksh sysstat unixODBC unixODBC-devel libnsl \
> libXext libX11 libXau libXi libXtst libXrender xorg-x11-utils device-mapper-multipath \
> unzip zip net-tools lrzsz vim dstat bc tree nfs-utils expect psmisc \
> policycoreutils-python-utils smartmontools"
> else
> PKGS="gcc gcc-c++ make compat-gcc-34 compat-libstdc++-33 elfutils-libelf \
> elfutils-libelf-devel glibc-headers libaio libaio-devel libgcc libstdc++ libstdc++-devel \
> ksh sysstat unixODBC unixODBC-devel compat-libcap1 libXp libXi libXtst xorg-x11-utils \
> device-mapper-multipath unzip zip smartmontools net-tools lrzsz vim dstat libnsl \
> policycoreutils-python bc tree nfs-utils expect psmisc"
> fi
> for p in ${PKGS}; do
> rpm -q "${p}" >/dev/null 2>&1 || yum install -y "${p}" >/dev/null 2>&1 \
> || say "WARN: 软件包未安装: ${p}"
> done
> umount /mnt >/dev/null 2>&1 || true
> # 3. 关闭无关服务 / SELinux
> systemctl stop firewalld >/dev/null 2>&1 || true
> systemctl disable firewalld >/dev/null 2>&1 || true
> sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
> setenforce 0 >/dev/null 2>&1 || true
> for s in tuned ktune postfix avahi-daemon avahi-dnsconfd atd bluetooth wpa_supplicant \
> accounts-daemon ModemManager rtkit-daemon rpcbind rngd upower rhsmcertd mcelog colord \
> gdm libstoragemgmt ksmtuned brltty cups irqbalance; do
> systemctl stop "${s}" >/dev/null 2>&1 || true
> systemctl disable "${s}" >/dev/null 2>&1 || true
> done
> # 4. sysctl
> sed -i '/^# >>> oradb oracle sysctl/,/^# <<< oradb oracle sysctl/d' /etc/sysctl.conf
> mem_kb=$(awk '/MemTotal/{print $2}' /proc/meminfo)
> huge_pages=$(awk -v m="${mem_kb}" 'BEGIN{printf "%d", (m*0.75)/2048}')
> (( huge_pages < 256 )) && huge_pages=256
> cat >> /etc/sysctl.conf <<EOF
> # >>> oradb oracle sysctl
> kernel.shmall = ${mem_kb}
> kernel.shmmax = $(( mem_kb * 1024 ))
> kernel.shmmni = 4096
> kernel.sem = 250 32000 100 128
> fs.file-max = 6815744
> fs.aio-max-nr = 1048576
> net.ipv4.ip_local_port_range = 9000 65500
> net.core.rmem_default = 262144
> net.core.rmem_max = 4194304
> net.core.wmem_default = 262144
> net.core.wmem_max = 1048576
> net.ipv4.ipfrag_high_thresh = 4194304
> net.ipv4.ipfrag_low_thresh = 3145728
> vm.min_free_kbytes = 512000
> vm.vfs_cache_pressure = 200
> vm.swappiness = 20
> vm.nr_hugepages = ${huge_pages}
> # <<< oradb oracle sysctl
> EOF
> sysctl -p >/dev/null 2>&1 || sysctl --system >/dev/null 2>&1 || true
> # 5. limits
> sed -i '/^# >>> oradb limits/,/^# <<< oradb limits/d' /etc/security/limits.conf
> {
> echo "# >>> oradb limits"
> for u in oracle grid; do
> [[ ${u} == grid && ${HA} == single ]] && continue
> cat <<EOF
> ${u} soft nproc 16384
> ${u} hard nproc 16384
> ${u} soft nofile 10240
> ${u} hard nofile 65536
> ${u} soft stack 10240
> ${u} hard stack 32768
> ${u} soft memlock unlimited
> ${u} hard memlock unlimited
> ${u} soft core unlimited
> ${u} hard core unlimited
> EOF
> done
> echo "# <<< oradb limits"
> } >> /etc/security/limits.conf
> grep -q 'pam_limits.so' /etc/pam.d/login || echo 'session required pam_limits.so' >> /etc/pam.d/login
> # 6. 用户与组
> chattr -i /etc/passwd /etc/group /etc/gshadow >/dev/null 2>&1 || true
> add_group(){
> local g=$1 gid=$2
> getent group "$g" >/dev/null && return 0
> if getent group "$gid" >/dev/null; then groupadd "$g"; else groupadd -g "$gid" "$g"; fi
> }
> add_user(){
> local u=$1 uid=$2 grps=$3
> id "$u" >/dev/null 2>&1 && return 0
> if getent passwd "$uid" >/dev/null; then
> useradd -g oinstall -G "$grps" -m "$u"
> else
> useradd -u "$uid" -g oinstall -G "$grps" -m "$u"
> fi
> }
> add_group oinstall 54321
> add_group dba 54322
> if [[ "${HA}" != "single" ]]; then
> add_group oper 54323
> add_group asmadmin 54324
> add_group asmoper 54325
> add_group asmdba 54326
> add_group backupdba 54327
> add_group dgdba 54328
> add_group kmdba 54329
> add_group racdba 54330
> add_user oracle 54321 "dba,oper,asmdba,backupdba,dgdba,kmdba,racdba"
> add_user grid 54322 "dba,asmadmin,asmdba,asmoper"
> else
> add_user oracle 54321 "dba"
> fi
> echo "${DB_PWD}" | passwd --stdin oracle >/dev/null 2>&1
> [[ "${HA}" != "single" ]] && echo "${DB_PWD}" | passwd --stdin grid >/dev/null 2>&1
> # 7. 关闭透明大页
> chmod +x /etc/rc.d/rc.local >/dev/null 2>&1 || true
> for f in /sys/kernel/mm/transparent_hugepage/enabled /sys/kernel/mm/redhat_transparent_hugepage/enabled; do
> [[ -f "${f}" ]] && echo never > "${f}" || true
> done
> grep -q 'transparent_hugepage' /etc/rc.d/rc.local 2>/dev/null || cat >> /etc/rc.d/rc.local <<'EOF'
> if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
> echo never > /sys/kernel/mm/transparent_hugepage/enabled
> fi
> EOF
> # 8. 目录
> mkdir -p /u01/app /soft
> if [[ "${HA}" == "single" ]]; then
> mkdir -p "${ORA_BASE}" /oradata
> chown -R oracle:oinstall /u01 /oradata "${SOFT_DIR}"
> else
> mkdir -p "${GRID_BASE}" "${GRID_HOME}" "${ORA_BASE}"
> chown -R grid:oinstall /u01
> chown -R oracle:oinstall "${ORA_BASE}" "${SOFT_DIR}"
> fi
> chmod -R 775 /u01 "${SOFT_DIR}" 2>/dev/null || true
> # 9. 解压安装介质(仅主节点)
> if [[ "${ROLE}" == "primary" ]]; then
> if [[ "${DB_MEDIA_MODE}" == "image" ]]; then
> mkdir -p "${ORACLE_HOME}"
> chown -R oracle:oinstall "${ORACLE_HOME}"
> for z in ${DB_ZIP}; do
> su - oracle -c "unzip -oq ${SOFT_DIR}/${z} -d ${ORACLE_HOME}" \
> || { echo "ERROR: 解压 ${z} 失败"; exit 1; }
> done
> else
> for z in ${DB_ZIP}; do
> unzip -oq "${SOFT_DIR}/${z}" -d "${SOFT_DIR}" \
> || { echo "ERROR: 解压 ${z} 失败"; exit 1; }
> done
> chown -R oracle:oinstall "${SOFT_DIR}/database"
> fi
> if [[ "${HA}" != "single" ]]; then
> if [[ "${GRID_MEDIA_MODE}" == "image" ]]; then
> mkdir -p "${GRID_HOME}"
> chown -R grid:oinstall "${GRID_HOME}"
> for z in ${GRID_ZIP}; do
> su - grid -c "unzip -oq ${SOFT_DIR}/${z} -d ${GRID_HOME}" \
> || { echo "ERROR: 解压 ${z} 失败"; exit 1; }
> done
> else
> for z in ${GRID_ZIP}; do
> unzip -oq "${SOFT_DIR}/${z}" -d "${SOFT_DIR}" \
> || { echo "ERROR: 解压 ${z} 失败"; exit 1; }
> done
> chown -R grid:oinstall "${SOFT_DIR}/grid"
> fi
> fi
> fi
> # 10. 环境变量
> if [[ "${HA}" == "rac" ]]; then
> ORA_SID="${DB_SID}${NODE_SUFFIX}"
> ASM_SID="+ASM${NODE_SUFFIX}"
> else
> ORA_SID="${DB_SID}"
> ASM_SID="+ASM"
> fi
> sed -i '/^# >>> oradb oracle profile/,/^# <<< oradb oracle profile/d' /home/oracle/.bash_profile 2>/dev/null
> cat >> /home/oracle/.bash_profile <<EOF
> # >>> oradb oracle profile
> export TMP=/tmp
> export TMPDIR=\$TMP
> export ORACLE_SID=${ORA_SID}
> export ORACLE_BASE=${ORA_BASE}
> export ORACLE_HOME=${ORACLE_HOME}
> export ORACLE_TERM=xterm
> export PATH=/usr/sbin:\$PATH
> export PATH=\$ORACLE_HOME/bin:\$PATH
> export LD_LIBRARY_PATH=\$ORACLE_HOME/lib:/lib:/usr/lib
> export CLASSPATH=\$ORACLE_HOME/JRE:\$ORACLE_HOME/jlib:\$ORACLE_HOME/rdbms/jlib
> umask 022
> # <<< oradb oracle profile
> EOF
> chown oracle:oinstall /home/oracle/.bash_profile
> if [[ "${HA}" != "single" ]]; then
> sed -i '/^# >>> oradb grid profile/,/^# <<< oradb grid profile/d' /home/grid/.bash_profile 2>/dev/null
> cat >> /home/grid/.bash_profile <<EOF
> # >>> oradb grid profile
> export ORACLE_BASE=${GRID_BASE}
> export ORACLE_HOME=${GRID_HOME}
> export ORACLE_SID=${ASM_SID}
> export PATH=\$ORACLE_HOME/OPatch:\$ORACLE_HOME/bin:\$PATH
> umask 022
> # <<< oradb grid profile
> EOF
> chown grid:oinstall /home/grid/.bash_profile
> fi
> say "OS 初始化完成 (ROLE=${ROLE}, NODE_SUFFIX=${NODE_SUFFIX})"
> EOS
> chmod +x "${SOFT_DIR}/setos.sh"
> }
> gen_setos_env(){
> cat > "${SOFT_DIR}/setos.env" <<EOF
> export SOFT_DIR='${SOFT_DIR}'
> export HA='${HA}'
> export VER='${VER}'
> export ORA_NUMBER='${ORA_NUMBER}'
> export ORA_NUMBER_S='${ORA_NUMBER_S}'
> export NODE_NAME='${NODE_NAME}'
> export PUBLIC_IP='${PUBLIC_IP}'
> export PUB1='${PUB1}'
> export PUB2='${PUB2}'
> export VIP1='${VIP1}'
> export VIP2='${VIP2}'
> export PRIV1='${PRIV1}'
> export PRIV2='${PRIV2}'
> export SCAN_IP='${SCAN_IP}'
> export DB_PWD='${DB_PWD}'
> export DB_SID='${DB_SID}'
> export YUM_CMD='${YUM_CMD}'
> export DB_ZIP='${DB_ZIP}'
> export GRID_ZIP='${GRID_ZIP}'
> export DB_MEDIA_MODE='${DB_MEDIA_MODE}'
> export GRID_MEDIA_MODE='${GRID_MEDIA_MODE}'
> export ORACLE_HOME='${ORACLE_HOME}'
> export GRID_HOME='${GRID_HOME}'
> export ORA_BASE='${ORA_BASE}'
> export GRID_BASE='${GRID_BASE}'
> EOF
> chmod 600 "${SOFT_DIR}/setos.env"
> }
> run_setos_local(){
> gen_setos; gen_setos_env
> ( source "${SOFT_DIR}/setos.env"; export ROLE=primary NODE_SUFFIX=1; bash "${SOFT_DIR}/setos.sh" ) \
> || die "本机 OS 初始化失败"
> }
> run_setos_remote(){
> ssh "${NODE_NAME}db2" "mkdir -p ${SOFT_DIR}" || die "无法 ssh 到 ${NODE_NAME}db2,请检查 root 互信"
> local yum_cmd=$YUM_CMD
> if [[ $YUM_SRC == *.iso ]]; then
> scp "$YUM_SRC" "${NODE_NAME}db2:${SOFT_DIR}/" || die "复制 yum 镜像失败"
> yum_cmd="mount -o loop ${SOFT_DIR}/$(basename "$YUM_SRC") /mnt"
> fi
> scp "${SOFT_DIR}/setos.env" "${SOFT_DIR}/setos.sh" "${NODE_NAME}db2:${SOFT_DIR}/" \
> || die "复制 setos 脚本失败"
> ssh "${NODE_NAME}db2" "source ${SOFT_DIR}/setos.env; export ROLE=secondary NODE_SUFFIX=2 YUM_CMD='${yum_cmd}'; bash ${SOFT_DIR}/setos.sh" \
> || die "node2 OS 初始化失败"
> }
> # -----------------------------------------------------------------------------
> # RAC 互信 / ASM 存储
> # -----------------------------------------------------------------------------
> find_ssh_setup_script(){
> local p
> for p in "${GRID_HOME}/oui/prov/resources/scripts/sshUserSetup.sh" \
> "${SOFT_DIR}/grid/oui/prov/resources/scripts/sshUserSetup.sh" \
> "${SOFT_DIR}/grid/sshsetup/sshUserSetup.sh"; do
> [[ -f $p ]] && { echo "$p"; return 0; }
> done
> return 1
> }
> config_ssh_trust(){
> local user=$1 pwd script expfile
> script=$(find_ssh_setup_script) || die "未找到 sshUserSetup.sh,请确认 Grid 介质已解压"
> case $user in root) pwd=$ROOT_PWD ;; *) pwd=$DB_PWD ;; esac
> expfile="${SOFT_DIR}/sshsetup_${user}.exp"
> cat > "$expfile" <<EOF
> set timeout 180
> set pwd "${pwd}"
> spawn ${script} -hosts "${NODE_NAME}db1 ${NODE_NAME}db2" -user ${user} -advanced
> expect {
> -re "(?i)(yes/no)" { send "yes\r"; exp_continue }
> -re "(?i)password" { send "\$pwd\r"; exp_continue }
> eof
> }
> EOF
> chmod 600 "$expfile"
> if [[ $user == root ]]; then
> expect "$expfile" || die "root 互信配置失败"
> else
> chown "${user}:oinstall" "$expfile"
> run_as "$user" "expect $expfile" || die "${user} 互信配置失败"
> fi
> log "${user} 互信配置完成"
> }
> setup_multipath(){
> local disk wwid i
> {
> echo 'defaults {'
> echo ' user_friendly_names yes'
> echo ' find_multipaths yes'
> echo '}'
> echo 'blacklist {'
> echo ' devnode "^sda"'
> echo '}'
> echo 'multipaths {'
> i=0
> for disk in ${OCR_DISKS//,/ }; do
> i=$((i+1))
> wwid=$(/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device="$disk" 2>/dev/null) \
> || die "无法获取 $disk 的 wwid"
> cat <<EOF
> multipath {
> wwid ${wwid}
> alias ocr${i}
> path_grouping_policy failover
> }
> EOF
> done
> i=0
> for disk in ${DATA_DISKS//,/ }; do
> i=$((i+1))
> wwid=$(/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device="$disk" 2>/dev/null) \
> || die "无法获取 $disk 的 wwid"
> cat <<EOF
> multipath {
> wwid ${wwid}
> alias data${i}
> path_grouping_policy failover
> }
> EOF
> done
> echo '}'
> } > /etc/multipath.conf
> systemctl restart multipathd >/dev/null 2>&1 || true
> systemctl enable multipathd >/dev/null 2>&1 || true
> multipath -ll
> }
> setup_udev(){
> local d uuid
> : > /etc/udev/rules.d/99-oracle-asmdevices.rules
> for d in $(ls /dev/mapper/ 2>/dev/null | grep -E '^(ocr|data)'); do
> uuid=$(udevadm info --query=property --name="/dev/mapper/$d" 2>/dev/null \
> | awk -F= '/^DM_UUID=/{print $2}')
> [[ -n $uuid ]] || { log "WARN: 无法获取 $d 的 DM_UUID,跳过"; continue; }
> echo "KERNEL==\"dm-*\",ENV{DM_UUID}==\"${uuid}\",SYMLINK+=\"oracleasm/disks/${d}\",OWNER=\"grid\",GROUP=\"asmadmin\",MODE=\"0660\"" \
> >> /etc/udev/rules.d/99-oracle-asmdevices.rules
> done
> udevadm control --reload-rules
> udevadm trigger
> sleep 5
> ls -ltr "${ASM_DISK_DIR}/"
> }
> push_asm_config_remote(){
> scp /etc/multipath.conf "${NODE_NAME}db2:/etc/" || die "复制 multipath.conf 失败"
> scp /etc/udev/rules.d/99-oracle-asmdevices.rules "${NODE_NAME}db2:/etc/udev/rules.d/" \
> || die "复制 udev 规则失败"
> ssh "${NODE_NAME}db2" "systemctl restart multipathd; systemctl enable multipathd; udevadm control --reload-rules; udevadm trigger; sleep 5; ls -ltr ${ASM_DISK_DIR}/"
> }
> install_cvuqdisk(){
> local rpm_path
> rpm_path=$(ls "${GRID_HOME}"/cv/rpm/cvuqdisk-*.rpm "${SOFT_DIR}"/grid/rpm/cvuqdisk-*.rpm 2>/dev/null | head -1)
> [[ -n $rpm_path ]] || { log "WARN: 未找到 cvuqdisk rpm,跳过"; return 0; }
> rpm -q cvuqdisk >/dev/null 2>&1 || rpm -ivh "$rpm_path" || log "WARN: 本机 cvuqdisk 安装失败"
> scp "$rpm_path" "${NODE_NAME}db2:${SOFT_DIR}/" >/dev/null 2>&1 || true
> ssh "${NODE_NAME}db2" "rpm -q cvuqdisk >/dev/null 2>&1 || rpm -ivh ${SOFT_DIR}/$(basename "$rpm_path")" \
> || log "WARN: node2 cvuqdisk 安装失败"
> }
> init_asm_disks(){
> local d
> for d in $(ls "${ASM_DISK_DIR}/" 2>/dev/null | grep -E '^(ocr|data|redo|arch)'); do
> dd if=/dev/zero of="${ASM_DISK_DIR}/${d}" bs=1M count=10 status=none || \
> log "WARN: 擦除 ${d} 失败"
> done
> }
> # -----------------------------------------------------------------------------
> # 响应文件
> # -----------------------------------------------------------------------------
> write_netca_rsp(){
> local ver
> [[ $ORA_NUMBER == 11.2.0 ]] && ver="11.2" || ver=$ORA_NUMBER
> rm -f "${SOFT_DIR}/netca.rsp"
> cat > "${SOFT_DIR}/netca.rsp" <<EOF
> [GENERAL]
> RESPONSEFILE_VERSION="${ver}"
> CREATE_TYPE="CUSTOM"
> [oracle.net.ca]
> INSTALLED_COMPONENTS={"server","net8","javavm"}
> INSTALL_TYPE="typical"
> LISTENER_NUMBER=1
> LISTENER_NAMES={"LISTENER"}
> LISTENER_PROTOCOLS={"TCP;1521"}
> LISTENER_START="LISTENER"
> NAMING_METHODS={"TNSNAMES","ONAMES","HOSTNAME"}
> NSN_NUMBER=1
> NSN_NAMES={"EXTPROC_CONNECTION_DATA"}
> NSN_SERVICE={"PLSExtProc"}
> NSN_PROTOCOLS={"TCP;HOSTNAME;1521"}
> EOF
> }
> write_db_rsp(){
> local cluster_nodes="" host_name
> [[ $HA == rac ]] && cluster_nodes="${NODE_NAME}db1,${NODE_NAME}db2"
> if [[ $HA == rac ]]; then host_name="${NODE_NAME}db1"; else host_name=$(hostname -s); fi
> rm -f "${SOFT_DIR}/db_install.rsp"
> if [[ $ORA_NUMBER == 11.2.0 ]]; then
> cat > "${SOFT_DIR}/db_install.rsp" <<EOF
> oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v11_2_0
> oracle.install.option=INSTALL_DB_SWONLY
> ORACLE_HOSTNAME=${host_name}
> UNIX_GROUP_NAME=oinstall
> INVENTORY_LOCATION=${INVENTORY}
> SELECTED_LANGUAGES=en,zh_CN
> ORACLE_HOME=${ORACLE_HOME}
> ORACLE_BASE=${ORA_BASE}
> oracle.install.db.InstallEdition=EE
> oracle.install.db.EEOptionsSelection=false
> oracle.install.db.DBA_GROUP=dba
> oracle.install.db.OPER_GROUP=oper
> oracle.install.db.CLUSTER_NODES=${cluster_nodes}
> oracle.install.db.isRACOneInstall=false
> SECURITY_UPDATES_VIA_MYORACLESUPPORT=false
> DECLINE_SECURITY_UPDATES=true
> oracle.installer.autoupdates.option=SKIP_UPDATES
> EOF
> else
> cat > "${SOFT_DIR}/db_install.rsp" <<EOF
> oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_${RSP_DB_SCHEMA}
> oracle.install.option=INSTALL_DB_SWONLY
> UNIX_GROUP_NAME=oinstall
> INVENTORY_LOCATION=${INVENTORY}
> ORACLE_BASE=${ORA_BASE}
> oracle.install.db.InstallEdition=EE
> oracle.install.db.OSDBA_GROUP=dba
> oracle.install.db.OSOPER_GROUP=oper
> oracle.install.db.OSBACKUPDBA_GROUP=backupdba
> oracle.install.db.OSDGDBA_GROUP=dgdba
> oracle.install.db.OSKMDBA_GROUP=kmdba
> oracle.install.db.OSRACDBA_GROUP=racdba
> oracle.install.db.rootconfig.executeRootScript=false
> oracle.install.db.rootconfig.configMethod=
> oracle.install.db.rootconfig.sudoPath=
> oracle.install.db.rootconfig.sudoUserName=
> oracle.install.db.CLUSTER_NODES=${cluster_nodes}
> EOF
> fi
> chown oracle:oinstall "${SOFT_DIR}/db_install.rsp"
> chmod 660 "${SOFT_DIR}/db_install.rsp"
> }
> write_grid_rsp(){
> rm -f "${SOFT_DIR}/grid.rsp"
> if [[ $HA == rac ]]; then write_grid_rsp_rac; else write_grid_rsp_ha; fi
> chown grid:oinstall "${SOFT_DIR}/grid.rsp"
> chmod 660 "${SOFT_DIR}/grid.rsp"
> }
> write_grid_rsp_rac(){
> local ocr_list
> ocr_list=$(ls "${ASM_DISK_DIR}"/ocr* 2>/dev/null | xargs | sed 's/ /,/g')
> if [[ $ORA_NUMBER == 11.2.0 ]]; then
> cat > "${SOFT_DIR}/grid.rsp" <<EOF
> oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_${RSP_GRID_SCHEMA}
> ORACLE_HOSTNAME=${NODE_NAME}db1
> INVENTORY_LOCATION=${INVENTORY}
> SELECTED_LANGUAGES=en,zh_CN
> oracle.install.option=CRS_CONFIG
> ORACLE_BASE=${GRID_BASE}
> ORACLE_HOME=${GRID_HOME}
> oracle.install.asm.OSDBA=asmdba
> oracle.install.asm.OSOPER=asmoper
> oracle.install.asm.OSASM=asmadmin
> oracle.install.crs.config.gpnp.scanName=${NODE_NAME}db-scan
> oracle.install.crs.config.gpnp.scanPort=1521
> oracle.install.crs.config.clusterName=${NODE_NAME}db-cluster
> oracle.install.crs.config.gpnp.configureGNS=false
> oracle.install.crs.config.gpnp.gnsSubDomain=
> oracle.install.crs.config.gpnp.gnsVIPAddress=
> oracle.install.crs.config.autoConfigureClusterNodeVIP=false
> oracle.install.crs.config.clusterNodes=${NODE_NAME}db1:${NODE_NAME}db1-vip,${NODE_NAME}db2:${NODE_NAME}db2-vip
> oracle.install.crs.config.networkInterfaceList=${PUB_IF}:$(cidr24 "$PUB1"):1,${PRIV_IF}:$(cidr24 "$PRIV1"):2
> oracle.install.crs.config.storageOption=ASM_STORAGE
> oracle.install.crs.config.sharedFileSystemStorage.diskDriveMapping=
> oracle.install.crs.config.sharedFileSystemStorage.votingDiskLocations=
> oracle.install.crs.config.sharedFileSystemStorage.votingDiskRedundancy=${OCR_REDU}
> oracle.install.crs.config.sharedFileSystemStorage.ocrLocations=
> oracle.install.crs.config.sharedFileSystemStorage.ocrRedundancy=${OCR_REDU}
> oracle.install.crs.config.useIPMI=false
> oracle.install.crs.config.ipmi.bmcUsername=
> oracle.install.crs.config.ipmi.bmcPassword=
> oracle.install.asm.SYSASMPassword=${DB_PWD}
> oracle.install.asm.diskGroup.name=OCR_VOT
> oracle.install.asm.diskGroup.redundancy=${OCR_REDU}
> oracle.install.asm.diskGroup.AUSize=${AU_SIZE}
> oracle.install.asm.diskGroup.disks=${ocr_list}
> oracle.install.asm.diskGroup.diskDiscoveryString=${ASM_DISK_DIR}/*
> oracle.install.asm.monitorPassword=${DB_PWD}
> oracle.install.crs.upgrade.clusterNodes=
> oracle.install.asm.upgradeASM=false
> oracle.installer.autoupdates.option=SKIP_UPDATES
> oracle.installer.autoupdates.downloadUpdatesLoc=
> AUTOUPDATES_MYORACLESUPPORT_USERNAME=
> AUTOUPDATES_MYORACLESUPPORT_PASSWORD=
> PROXY_HOST=
> PROXY_PORT=0
> PROXY_USER=
> PROXY_PWD=
> PROXY_REALM=
> EOF
> else
> cat > "${SOFT_DIR}/grid.rsp" <<EOF
> oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_${RSP_GRID_SCHEMA}
> INVENTORY_LOCATION=${INVENTORY}
> oracle.install.option=CRS_CONFIG
> ORACLE_BASE=${GRID_BASE}
> oracle.install.asm.OSDBA=asmdba
> oracle.install.asm.OSOPER=asmoper
> oracle.install.asm.OSASM=asmadmin
> oracle.install.crs.config.scanType=LOCAL_SCAN
> oracle.install.crs.config.SCANClientDataFile=
> oracle.install.crs.config.gpnp.scanName=${NODE_NAME}db-scan
> oracle.install.crs.config.gpnp.scanPort=1521
> oracle.install.crs.config.ClusterConfiguration=STANDALONE
> oracle.install.crs.config.configureAsExtendedCluster=false
> oracle.install.crs.config.memberClusterManifestFile=
> oracle.install.crs.config.clusterName=${NODE_NAME}db-cluster
> oracle.install.crs.config.gpnp.configureGNS=false
> oracle.install.crs.config.autoConfigureClusterNodeVIP=false
> oracle.install.crs.config.gpnp.gnsOption=
> oracle.install.crs.config.gpnp.gnsClientDataFile=
> oracle.install.crs.config.gpnp.gnsSubDomain=
> oracle.install.crs.config.gpnp.gnsVIPAddress=
> oracle.install.crs.config.sites=
> oracle.install.crs.config.clusterNodes=${NODE_NAME}db1:${NODE_NAME}db1-vip,${NODE_NAME}db2:${NODE_NAME}db2-vip
> oracle.install.crs.config.networkInterfaceList=${PUB_IF}:$(cidr24 "$PUB1"):1,${PRIV_IF}:$(cidr24 "$PRIV1"):5
> oracle.install.crs.configureGIMR=false
> oracle.install.asm.configureGIMRDataDG=false
> oracle.install.crs.config.storageOption=FLEX_ASM_STORAGE
> oracle.install.crs.config.sharedFileSystemStorage.votingDiskLocations=
> oracle.install.crs.config.sharedFileSystemStorage.ocrLocations=
> oracle.install.crs.config.useIPMI=false
> oracle.install.crs.config.ipmi.bmcUsername=
> oracle.install.crs.config.ipmi.bmcPassword=
> oracle.install.asm.SYSASMPassword=${DB_PWD}
> oracle.install.asm.diskGroup.name=OCR_VOT
> oracle.install.asm.diskGroup.redundancy=${OCR_REDU}
> oracle.install.asm.diskGroup.AUSize=${AU_SIZE}
> oracle.install.asm.diskGroup.FailureGroups=
> oracle.install.asm.diskGroup.disksWithFailureGroupNames=
> oracle.install.asm.diskGroup.disks=${ocr_list}
> oracle.install.asm.diskGroup.quorumFailureGroupNames=
> oracle.install.asm.diskGroup.diskDiscoveryString=${ASM_DISK_DIR}/
> oracle.install.asm.monitorPassword=${DB_PWD}
> oracle.install.asm.gimrDG.name=
> oracle.install.asm.gimrDG.redundancy=
> oracle.install.asm.gimrDG.AUSize=1
> oracle.install.asm.gimrDG.FailureGroups=
> oracle.install.asm.gimrDG.disksWithFailureGroupNames=
> oracle.install.asm.gimrDG.disks=
> oracle.install.asm.gimrDG.quorumFailureGroupNames=
> oracle.install.asm.configureAFD=false
> oracle.install.crs.configureRHPS=false
> EOF
> fi
> }
> # standalone(Oracle Restart)的 GI 响应文件
> write_grid_rsp_ha(){
> local ocr_list host="${NODE_NAME}db"
> ocr_list=$(ls "${ASM_DISK_DIR}"/ocr* 2>/dev/null | xargs | sed 's/ /,/g')
> if [[ $ORA_NUMBER == 11.2.0 ]]; then
> cat > "${SOFT_DIR}/grid.rsp" <<EOF
> oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_${RSP_GRID_SCHEMA}
> ORACLE_HOSTNAME=${host}
> INVENTORY_LOCATION=${INVENTORY}
> SELECTED_LANGUAGES=en,zh_CN
> oracle.install.option=CRS_CONFIG
> ORACLE_BASE=${GRID_BASE}
> ORACLE_HOME=${GRID_HOME}
> oracle.install.asm.OSDBA=asmdba
> oracle.install.asm.OSOPER=asmoper
> oracle.install.asm.OSASM=asmadmin
> oracle.install.crs.config.gpnp.scanName=${host}
> oracle.install.crs.config.gpnp.scanPort=1521
> oracle.install.crs.config.clusterName=${host}-cluster
> oracle.install.crs.config.gpnp.configureGNS=false
> oracle.install.crs.config.gpnp.gnsSubDomain=
> oracle.install.crs.config.gpnp.gnsVIPAddress=
> oracle.install.crs.config.autoConfigureClusterNodeVIP=false
> oracle.install.crs.config.clusterNodes=${host}
> oracle.install.crs.config.networkInterfaceList=${PUB_IF}:$(cidr24 "$PUBLIC_IP"):1
> oracle.install.crs.config.storageOption=ASM_STORAGE
> oracle.install.crs.config.sharedFileSystemStorage.diskDriveMapping=
> oracle.install.crs.config.sharedFileSystemStorage.votingDiskLocations=
> oracle.install.crs.config.sharedFileSystemStorage.votingDiskRedundancy=${OCR_REDU}
> oracle.install.crs.config.sharedFileSystemStorage.ocrLocations=
> oracle.install.crs.config.sharedFileSystemStorage.ocrRedundancy=${OCR_REDU}
> oracle.install.crs.config.useIPMI=false
> oracle.install.crs.config.ipmi.bmcUsername=
> oracle.install.crs.config.ipmi.bmcPassword=
> oracle.install.asm.SYSASMPassword=${DB_PWD}
> oracle.install.asm.diskGroup.name=OCR_VOT
> oracle.install.asm.diskGroup.redundancy=${OCR_REDU}
> oracle.install.asm.diskGroup.AUSize=${AU_SIZE}
> oracle.install.asm.diskGroup.disks=${ocr_list}
> oracle.install.asm.diskGroup.diskDiscoveryString=${ASM_DISK_DIR}/*
> oracle.install.asm.monitorPassword=${DB_PWD}
> oracle.installer.autoupdates.option=SKIP_UPDATES
> oracle.installer.autoupdates.downloadUpdatesLoc=
> AUTOUPDATES_MYORACLESUPPORT_USERNAME=
> AUTOUPDATES_MYORACLESUPPORT_PASSWORD=
> PROXY_HOST=
> PROXY_PORT=0
> PROXY_USER=
> PROXY_PWD=
> PROXY_REALM=
> EOF
> else
> cat > "${SOFT_DIR}/grid.rsp" <<EOF
> oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_${RSP_GRID_SCHEMA}
> INVENTORY_LOCATION=${INVENTORY}
> oracle.install.option=CRS_CONFIG
> ORACLE_BASE=${GRID_BASE}
> oracle.install.asm.OSDBA=asmdba
> oracle.install.asm.OSOPER=asmoper
> oracle.install.asm.OSASM=asmadmin
> oracle.install.crs.config.scanType=LOCAL_SCAN
> oracle.install.crs.config.SCANClientDataFile=
> oracle.install.crs.config.gpnp.scanName=${host}
> oracle.install.crs.config.gpnp.scanPort=1521
> oracle.install.crs.config.ClusterConfiguration=STANDALONE
> oracle.install.crs.config.configureAsExtendedCluster=false
> oracle.install.crs.config.memberClusterManifestFile=
> oracle.install.crs.config.clusterName=${host}-cluster
> oracle.install.crs.config.gpnp.configureGNS=false
> oracle.install.crs.config.autoConfigureClusterNodeVIP=false
> oracle.install.crs.config.gpnp.gnsOption=
> oracle.install.crs.config.gpnp.gnsClientDataFile=
> oracle.install.crs.config.gpnp.gnsSubDomain=
> oracle.install.crs.config.gpnp.gnsVIPAddress=
> oracle.install.crs.config.sites=
> oracle.install.crs.config.clusterNodes=${host}
> oracle.install.crs.config.networkInterfaceList=${PUB_IF}:$(cidr24 "$PUBLIC_IP"):1
> oracle.install.crs.configureGIMR=false
> oracle.install.asm.configureGIMRDataDG=false
> oracle.install.crs.config.storageOption=FLEX_ASM_STORAGE
> oracle.install.crs.config.sharedFileSystemStorage.votingDiskLocations=
> oracle.install.crs.config.sharedFileSystemStorage.ocrLocations=
> oracle.install.crs.config.useIPMI=false
> oracle.install.crs.config.ipmi.bmcUsername=
> oracle.install.crs.config.ipmi.bmcPassword=
> oracle.install.asm.SYSASMPassword=${DB_PWD}
> oracle.install.asm.diskGroup.name=OCR_VOT
> oracle.install.asm.diskGroup.redundancy=${OCR_REDU}
> oracle.install.asm.diskGroup.AUSize=${AU_SIZE}
> oracle.install.asm.diskGroup.FailureGroups=
> oracle.install.asm.diskGroup.disksWithFailureGroupNames=
> oracle.install.asm.diskGroup.disks=${ocr_list}
> oracle.install.asm.diskGroup.quorumFailureGroupNames=
> oracle.install.asm.diskGroup.diskDiscoveryString=${ASM_DISK_DIR}/
> oracle.install.asm.monitorPassword=${DB_PWD}
> oracle.install.asm.gimrDG.name=
> oracle.install.asm.gimrDG.redundancy=
> oracle.install.asm.gimrDG.AUSize=1
> oracle.install.asm.gimrDG.FailureGroups=
> oracle.install.asm.gimrDG.disksWithFailureGroupNames=
> oracle.install.asm.gimrDG.disks=
> oracle.install.asm.gimrDG.quorumFailureGroupNames=
> oracle.install.asm.configureAFD=false
> oracle.install.crs.configureRHPS=false
> EOF
> fi
> }
> # -----------------------------------------------------------------------------
> # 安装执行
> # -----------------------------------------------------------------------------
> install_grid(){
> local runInstaller
> if [[ $GRID_MEDIA_MODE == image ]]; then
> runInstaller=${GRID_HOME}/runInstaller
> else
> runInstaller=${SOFT_DIR}/grid/runInstaller
> fi
> [[ -x $runInstaller ]] || die "未找到 Grid runInstaller: $runInstaller"
> log "开始安装 Grid Infrastructure($HA)..."
> run_as grid "cd ${GRID_HOME} && ${runInstaller} -silent -waitforcompletion -responseFile ${SOFT_DIR}/grid.rsp ${IGNORE_FLAG}" \
> || die "Grid Infrastructure 安装失败"
> log "Grid Infrastructure 安装完成"
> }
> run_root_scripts_grid(){
> log "执行 Grid root 脚本 ..."
> [[ -f ${INVENTORY}/orainstRoot.sh ]] && bash "${INVENTORY}/orainstRoot.sh"
> bash "${GRID_HOME}/root.sh" || die "node1 ${GRID_HOME}/root.sh 失败"
> if [[ $HA == rac ]]; then
> scp "${GRID_HOME}/root.sh" "${NODE_NAME}db2:${GRID_HOME}/root.sh" >/dev/null 2>&1 \
> || die "复制 root.sh 到 node2 失败"
> ssh "${NODE_NAME}db2" "bash ${GRID_HOME}/root.sh" || die "node2 ${GRID_HOME}/root.sh 失败"
> fi
> log "Grid root 脚本执行完成"
> }
> create_data_dg(){
> local data_list
> data_list=$(ls "${ASM_DISK_DIR}"/data* 2>/dev/null | xargs | sed 's/ /,/g')
> [[ -n $data_list ]] || { log "WARN: 未发现 data 盘,跳过 DATA 磁盘组创建"; return 0; }
> log "创建 DATA 磁盘组 ..."
> run_as grid "${GRID_HOME}/bin/asmca -silent -createDiskGroup \
> -diskGroupName DATA -diskList '${data_list}' -redundancy ${DATA_REDU} \
> -au_size ${AU_SIZE} -sysAsmPassword '${DB_PWD}'" \
> || die "创建 DATA 磁盘组失败"
> log "DATA 磁盘组创建完成"
> }
> install_db(){
> local runInstaller
> if [[ $DB_MEDIA_MODE == image ]]; then
> runInstaller=${ORACLE_HOME}/runInstaller
> else
> runInstaller=${SOFT_DIR}/database/runInstaller
> fi
> [[ -x $runInstaller ]] || die "未找到 DB runInstaller: $runInstaller"
> log "开始安装数据库软件 ..."
> run_as oracle "cd ${ORACLE_HOME} && ${runInstaller} -silent -waitforcompletion -responseFile ${SOFT_DIR}/db_install.rsp ${IGNORE_FLAG}" \
> || die "数据库软件安装失败"
> log "数据库软件安装完成"
> }
> run_root_scripts_db(){
> log "执行 DB root.sh ..."
> [[ -f ${INVENTORY}/orainstRoot.sh ]] && bash "${INVENTORY}/orainstRoot.sh"
> bash "${ORACLE_HOME}/root.sh" || die "${ORACLE_HOME}/root.sh 失败"
> log "DB root.sh 执行完成"
> }
> config_netca(){
> case $HA in
> single)
> log "配置监听(oracle home)..."
> run_as oracle "${ORACLE_HOME}/bin/netca -silent -responsefile ${SOFT_DIR}/netca.rsp" \
> || die "netca 配置失败" ;;
> standalone)
> log "配置监听(grid home)..."
> run_as grid "${GRID_HOME}/bin/netca -silent -responsefile ${SOFT_DIR}/netca.rsp" \
> || die "netca 配置失败" ;;
> rac)
> log "RAC 监听由 Grid 管理,跳过 netca" ;;
> esac
> }
> create_db(){
> local dbca common cdb_opt storage_opt user run_home
> if [[ $HA == single ]]; then
> user=oracle; run_home=$ORACLE_HOME
> storage_opt="-datafileDestination /oradata -storageType FS"
> else
> user=oracle; run_home=$ORACLE_HOME
> storage_opt="-storageType ASM -diskGroupName DATA -recoveryGroupName DATA"
> fi
> if (( SUPPORTS_CDB == 1 )); then
> if [[ $USE_CDB == TRUE ]]; then
> cdb_opt="-createAsContainerDatabase true -numberOfPDBs 1 -pdbName ${PDB_NAME} -pdbAdminPassword '${DB_PWD}'"
> else
> cdb_opt="-createAsContainerDatabase false"
> fi
> else
> cdb_opt=""
> fi
> common="-silent -createDatabase -templateName General_Purpose.dbc \
> -gdbname ${DB_SID} -sid ${DB_SID} \
> -characterSet ${DB_CHARSET} -nationalCharacterSet ${DB_NCHARSET} \
> -sysPassword '${DB_PWD}' -systemPassword '${DB_PWD}' \
> -emConfiguration NONE -sampleSchema false ${storage_opt} ${cdb_opt}"
> if [[ $HA == rac && $ORA_NUMBER == 11.2.0 ]]; then
> common="${common} -nodeinfo ${NODE_NAME}db1,${NODE_NAME}db2"
> fi
> log "开始创建数据库 ${DB_SID} ..."
> run_as "$user" "${run_home}/bin/dbca ${common}" || die "dbca 建库失败"
> log "数据库 ${DB_SID} 创建完成"
> }
> # -----------------------------------------------------------------------------
> # 主流程
> # -----------------------------------------------------------------------------
> main(){
> parse_args "$@"
> normalize_inputs
> load_profile
> validate_params
> resolve_yum_cmd
> precheck
> log "===== 部署模式: $HA | 版本: $VER | SID: $DB_SID ====="
> run_setos_local
> if [[ $HA != single ]]; then
> if [[ $HA == rac ]]; then
> run_setos_remote
> config_ssh_trust root
> config_ssh_trust oracle
> config_ssh_trust grid
> fi
> setup_multipath
> setup_udev
> [[ $HA == rac ]] && push_asm_config_remote
> install_cvuqdisk
> init_asm_disks
> write_grid_rsp
> install_grid
> run_root_scripts_grid
> create_data_dg
> fi
> write_netca_rsp
> write_db_rsp
> install_db
> run_root_scripts_db
> config_netca
> create_db
> log "===== 全部部署完成 ====="
> }
> main "$@"