D Script File To Validate Network Setup

You must create a script file to validate if the existing WebLogic Server subnet and the database subnets meet the prerequisites to provision the WebLogic instance in Oracle WebLogic Server for Oracle Cloud Infrastructure. You can copy the following scripts in Cloud Shell to perform the validation. For example, copy the scripts and save the file as validate.sh.

# ##################################################
# Script to validate existing WebLogic and DB subnets meet the pre-requisite for
# provisioning and proper functioning of WebLogic Server for Oracle Cloud Infrastructure.
#
version="1.0.0"
 
# Set Flags
# -----------------------------------
# Flags which can be overridden by user input.
# Default values are below
# -----------------------------------
DB_PORT=1521
SSH_PORT=22
T3S_PORT=9072
NETWORK_COMPARTMENT_OCID=""
WLS_SUBNET_OCID=""
DB_SUBNET_OCID=""
APP_DB_SUBNET_OCID=""
BASTION_SUBNET_OCID=""
BASTION_HOST_IP_CIDR=""
 
debug=false
args=()
 
function ip_to_int() {
  local ip_addr="${1}"
  local ip_1 ip_2 ip_3 ip_4
 
  ip_1=$(echo "${ip_addr}" | cut -d'.' -f1)
  ip_2=$(echo "${ip_addr}" | cut -d'.' -f2)
  ip_3=$(echo "${ip_addr}" | cut -d'.' -f3)
  ip_4=$(echo "${ip_addr}" | cut -d'.' -f4)
 
  echo $(( ip_1 * 256**3 + ip_2 * 256**2 + ip_3 * 256 + ip_4 ))
}
 
####################################################
# Determine whether IP address is in the specified subnet.
#
# Args:
#   cidr_subnet: Subnet, in CIDR notation.
#   ip_addr: IP address to check.
#
# Returns:
#   0|1
####################################################
function in_cidr_range() {
  local cidr_subnet="${1}"
  local ip_addr="${2}"
  local subnet_ip cidr_mask netmask ip_addr_subnet subnet rval
 
  subnet_ip=$(echo "${cidr_subnet}" | cut -d'/' -f1)
  cidr_mask=$(echo "${cidr_subnet}" | cut -d'/' -f2)
 
  netmask=$(( 0xFFFFFFFF << $(( 32 - ${cidr_mask} )) ))
 
  # Apply netmask to both the subnet IP and the given IP address
  ip_addr_subnet=$(( netmask & $(ip_to_int ${ip_addr}) ))
  subnet=$(( netmask & $(ip_to_int ${subnet_ip}) ))
 
  # Subnet IPs will match if given IP address is in CIDR subnet
  [ "${ip_addr_subnet}" == "${subnet}" ] && rval=0 || rval=1
 
  return $rval
}
 
####################################################
# Validates if one of service or nat gateways exist in the specified private subnet.
#
# Returns:
#   0|1
####################################################
function validate_service_or_nat_gw_exist() {
  local vcn_ocid=""
  local vcn_compartment_ocid=""
 
  is_private_subnet=$(oci network subnet get --subnet-id ${WLS_SUBNET_OCID} | jq -r '.data["prohibit-public-ip-on-vnic"]')
 
  if [[ $is_private_subnet = true ]]
  then
    vcn_ocid=$(oci network subnet get --subnet-id ${WLS_SUBNET_OCID} | jq -r '.data["vcn-id"]')
    vcn_compartment_ocid=$(oci network vcn get --vcn-id ${vcn_ocid} | jq -r '.data["compartment-id"]')
    # Check if NAT gateway exists in the VCN
    res=$(oci network nat-gateway list --compartment-id ${vcn_compartment_ocid} --vcn-id ${vcn_ocid})
    nat_gw_found=$(if [[ -n $res ]]; then echo 0; else echo 1; fi)
 
    # Check if Service gateway exists in the VCN
    res=$(oci network service-gateway list --compartment-id ${vcn_compartment_ocid} --vcn-id ${vcn_ocid})
    svc_gw_found=$(if [[ -n $res ]]; then echo 0; else echo 1; fi)
 
    # One of NAT or Service Gateway must exist
    if [[ $nat_gw_found -ne 0 ]] && [[ $svc_gw_found -ne 0 ]]
    then
      echo 1
      return
    fi
 
    # WLS subnet should be using either NAT or service gateway or both in its routetable
    rt_ocid=$(oci network subnet get --subnet-id ${WLS_SUBNET_OCID} | jq -r '.data["route-table-id"]')
    rt_rules=$(oci network route-table get --rt-id ${rt_ocid} | jq -r '.data["route-rules"]')
    rt_rules_count=$(echo $rt_rules | jq '.|length')
 
    nat=""
    svc=""
    nat_gw_id=""
    svc_gw_id=""
 
    for ((i = 0 ; i < $rt_rules_count ; i++))
    do
      network_entity_ocid=$(echo $rt_rules | jq -r --arg i "$i" '.[$i|tonumber]["network-entity-id"]')
      nat_id=$(echo $network_entity_ocid | grep natgateway)
      if [[ -n $nat_id ]]; then nat_gw_id=$nat_id; fi
      svc_id=$(echo $network_entity_ocid | grep servicegateway)
      if [[ -n $svc_id ]]; then svc_gw_id=$svc_id; fi
    done
 
    if [[ (-z $nat_gw_id  && -z $svc_gw_id) ]]; then
      echo 2
      return
    fi
 
    # If WLS subnet route table has a rule to use service gateway then it should be using
    # all-<region-code>-services-in-oracle-services-network destination
    if [[ -n $svc_gw_id ]]
    then
      is_all_services_name=$(oci network service-gateway get --service-gateway-id $svc_gw_id | jq -r '.data.services[0]["service-name"]' | grep -i "all.*services in oracle services network")
      if [[ -z $is_all_services_name ]]
      then
        echo 3
        return
      fi
      for ((i = 0 ; i < $rt_rules_count ; i++))
      do
        network_entity_ocid=$(echo $rt_rules | jq -r --arg i "$i" '.[$i|tonumber]["network-entity-id"]')
        res=$(echo $network_entity_ocid | grep servicegateway)
        if [[ -n $res ]]
        then
          all_services_destination=$(echo $rt_rules | jq -r --arg i "$i" '.[$i|tonumber].destination'  | grep -i "all-.*-services-in-oracle-services-network")
          if [[ -z $all_services_destination ]]
          then
            echo 4
            return
          fi
        fi
      done
    fi
  fi
  echo 0
}
 
####################################################
# Validates if the inetrnet gateway exists in the VCN of WLS subnet.
# Without Internet gateway in WLS VCN, SSH access from ORM will not work.
# When using terraform CLI from within private network, internet gateway is not required.
# Hence this check will give a warning and not an error.
#
# Returns:
#   0|1
####################################################
function validate_internet_gw_exist() {
  local vcn_ocid=""
  local vcn_compartment_ocid=""
 
  vcn_ocid=$(oci network subnet get --subnet-id ${WLS_SUBNET_OCID} | jq -r '.data["vcn-id"]')
  vcn_compartment_ocid=$(oci network vcn get --vcn-id ${vcn_ocid} | jq -r '.data["compartment-id"]')
 
  # Check if Service gateway exists in the VCN
  res=$(oci network internet-gateway list --compartment-id ${vcn_compartment_ocid} --vcn-id ${vcn_ocid})
 
  if [[ -n $res ]]; then
    echo 0
  else
    echo 1
  fi
}
 
####################################################
# Checks if specified port is open to specified source CIDR in the specified seclist's ingress rules.
#
# Args:
#     seclist_ocid: Security list OCID for the security list to check ingress rules for.
#     port: destination port to check
#     source: Source CIDR (either block/range of IPs or single IP (with /32 suffix)
#
# Returns:
#   0|1
####################################################
function check_tcp_port_open_in_seclist() {
  local seclist_ocid=$1
  local port=$2
  local source=$3
  local port_is_open=false
  local tcp_protocol="6"
 
  ingress_rules=$(oci network security-list get --security-list-id $seclist_ocid | jq -r '.data["ingress-security-rules"]')
  ingress_rules_count=$(echo $ingress_rules | jq '.|length')
 
  for ((i = 0 ; i < $ingress_rules_count ; i++))
  do
    ingress_protocol=$(echo $ingress_rules | jq -r --arg i "$i" '.[$i|tonumber].protocol')
    ingress_source=$(echo $ingress_rules | jq -r --arg i "$i" '.[$i|tonumber].source')
    tcp_options=$(echo $ingress_rules | jq -r --arg i "$i" '.[$i|tonumber]["tcp-options"]')
    port_min=$(echo $ingress_rules | jq -r --arg i "$i" '.[$i|tonumber]["tcp-options"]["destination-port-range"].min')
    port_max=$(echo $ingress_rules | jq -r --arg i "$i" '.[$i|tonumber]["tcp-options"]["destination-port-range"].max')
 
    source_in_cidr_range=1
    if [[ $source = "0.0.0.0/0" ]]
    then
      if [[ $ingress_source = $source ]]
      then
        source_in_cidr_range=0
      else
        source_in_cidr_range=1
      fi
    else
      source_in_cidr_range=$(in_cidr_range $ingress_source $source ; echo $?)
    fi
 
    if [[ ($ingress_protocol = "all" || $ingress_protocol = $tcp_protocol ) && ( $tcp_options = "null" || ( $port -ge $port_min && $port -le $port_max ) ) && $source_in_cidr_range -eq 0 ]]
    then
       port_is_open=true
       echo 0
       return
    fi
  done
  echo 1
}
 
####################################################
# Validates if the specified TCP port is open for the WLS subnet CIDR.
#
# Args:
#     port:         Destination port
#     source_cidr:  Source CIDR
#
# Returns:
#   0|1
####################################################
function validate_subnet_port_access() {
  local port_found_open=1
  local subnet=$1
  local port=$2
  local source_cidr=$3
 
  sec_lists=$(oci network subnet get --subnet-id ${subnet} | jq -c '.data["security-list-ids"]')
 
  # Convert to bash array
  declare -A seclists_array
 
  while IFS="=" read -r key value
  do
      seclists_array[$key]="$value"
  done < <(jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' <<< "$sec_lists")
 
  # Check the ingress rules for specified destination port is open for access by source CIDR
  for seclist_ocid in "${seclists_array[@]}"
  do
    if [[ $port_found_open -ne 0 ]]; then
      port_found_open=$(check_tcp_port_open_in_seclist $seclist_ocid "${port}" "$source_cidr")
    fi
  done
  echo $port_found_open
}
 
 
####################################################
# Validates if CIDR is a valid single host IP (must end with /32 suffix).
#
# Args:
#     ip_cidr: Single host IPv4 Address in CIDR format
#
# Returns:
#   0|1
####################################################
function is_valid_ip_cidr() {
  local ip_cidr=$1
 
  is_valid=$(echo ${ip_cidr} | grep -E '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(32))$')
  if [[ -n $is_valid ]]; then
    echo 0
  else
    echo 1
  fi
}
 
############## Begin Options and Usage ###################
 
# Print usage
usage() {
  echo -n "$0 [OPTIONS]...
 
This script is used to validate existing WebLogic subnet (and optionally DB Subnet) are setup correctly.
 ${bold}Options:${reset}
  -w, --wlssubnet     WebLogic Subnet OCID (Required)
  -d, --dbsubnet      DB Subnet OCID
  -a, --appdbsubnet   Application Database Subnet OCID
  -b, --bastionsubnet Bastion Subnet OCID
  -i, --bastionipcidr Bastion Host IP CIDR
      --debug         Runs script in BASH debug mode (set -x)
  -h, --help          Display this help and exit
      --version       Output version information and exit
  "
}
 
# Iterate over options breaking -ab into -a -b when needed and --foo=bar into
# --foo bar
optstring=h
unset options
while (($#)); do
  case $1 in
    # If option is of type -ab
    -[!-]?*)
      # Loop over each character starting with the second
      for ((i=1; i < ${#1}; i++)); do
        c=${1:i:1}
 
        # Add current char to options
        options+=("-$c")
 
        # If option takes a required argument, and it's not the last char make
        # the rest of the string its argument
        if [[ $optstring = *"$c:"* && ${1:i+1} ]]; then
          options+=("${1:i+1}")
          break
        fi
      done
      ;;
 
    # If option is of type --foo=bar
    --?*=*) options+=("${1%%=*}" "${1#*=}") ;;
    # add --endopts for --
    --) options+=(--endopts) ;;
    # Otherwise, nothing special
    *) options+=("$1") ;;
  esac
  shift
done
set -- "${options[@]}"
unset options
 
# Print help if no arguments were passed.
[[ $# -eq 0 ]] && set -- "--help"
 
# Read the options and set stuff
while [[ $1 = -?* ]]; do
  case $1 in
    -h|--help) usage >&2; exit 0 ;;
    --version) echo "$(basename $0) ${version}"; exit 0 ;;
    -w|--wlssubnet) shift; WLS_SUBNET_OCID=${1} ;;
    -d|--dbsubnet) shift; DB_SUBNET_OCID=${1} ;;
    -a|--appdbsubnet) shift; APP_DB_SUBNET_OCID=${1} ;;
    -b|--bastionsubnet) shift; BASTION_SUBNET_OCID=${1} ;;
    -i|--bastionipcidr) shift; BASTION_HOST_IP_CIDR=${1} ;;
    --debug) debug=true;;
    --endopts) shift; break ;;
    *) "invalid option: '$1'." ; usage >&2; exit 1 ;;
  esac
  shift
done
 
# Store the remaining part as arguments.
args+=("$@")
 
############## End Options and Usage ###################
 
# ############# ############# #############
# ##       MAIN SCRIPT BODY              ##
# ##                                     ##
# ##                                     ##
# ############# ############# #############
 
# Set IFS to preferred implementation
IFS=$'\n\t'
 
# Exit on error. Append '||true' when you run the script if you expect an error.
set -o errexit
 
# Run in debug mode, if set
if ${debug}; then set -x ; fi
 
# Bash will remember & return the highest exitcode in a chain of pipes.
# This way you can catch the error in case mysqldump fails in `mysqldump |gzip`, for example.
set -o pipefail
 
# Validate all required params are present
if [[ -z ${WLS_SUBNET_OCID} ]]
then
  echo "One or more required params are not specified."
  usage >&2
  exit
fi
 
# Check if service or NAT gateway exists in WLS subnet's VCN.
res=$(validate_service_or_nat_gw_exist)
 
if [[ $res -eq 1 ]]
then
  echo "ERROR: Missing Service or NAT gateway in the VCN of the private WLS subnet [$WLS_SUBNET_OCID]"
elif [[ $res -eq 2 ]]
then
  echo "ERROR: Private WLS subnet [$WLS_SUBNET_OCID] does not use NAT or Service gateway"
elif [[ $res -eq 3 ]]
then
  echo "ERROR: Service Gateway in VCN of private WLS subnet [$WLS_SUBNET_OCID] does not allow access to all services in Oracle services network"
elif [[ $res -eq 4 ]]
then
  echo "ERROR: Route Rule of private WLS subnet [$WLS_SUBNET_OCID] does not use 'ALL Services in Oracle services network' destination"
fi
 
# Check if internet gateway exists in WLS subnet's VCN.
res=$(validate_internet_gw_exist)
 
if [[ $res -ne 0 ]]
then
  echo "WARNING: Missing internet gateway in the VCN of the WLS subnet [$WLS_SUBNET_OCID]"
fi
 
wls_subnet_cidr_block=$(oci network subnet get --subnet-id ${WLS_SUBNET_OCID} | jq -r '.data["cidr-block"]')
 
# Check if SSH port is open for access by WLS subnet CIDR
res=$(validate_subnet_port_access ${WLS_SUBNET_OCID} ${SSH_PORT} ${wls_subnet_cidr_block})
 
if [[ $res -ne 0 ]]
then
  echo "ERROR: Port ${SSH_PORT} is not open for access by WLS Subnet CIDR [$wls_subnet_cidr_block] in WLS Subnet [$WLS_SUBNET_OCID]"
fi
 
# Check if t3s port is open for access by WLS subnet CIDR
res=$(validate_subnet_port_access ${WLS_SUBNET_OCID} ${T3S_PORT} ${wls_subnet_cidr_block})
if [[ $res -ne 0 ]]
then
  echo "ERROR: Port ${T3S_PORT} is not open for access by WLS Subnet CIDR [$wls_subnet_cidr_block] in WLS Subnet [$WLS_SUBNET_OCID]"
fi
 
# Check if DB port is open for access by WLS subnet CIDR in DB subnet (only if DB subnet is provided)
if [[ -n ${DB_SUBNET_OCID} ]]
then
  res=$(validate_subnet_port_access ${DB_SUBNET_OCID} ${DB_PORT} ${wls_subnet_cidr_block})
  if [[ $res -ne 0 ]]
  then
    echo "ERROR: DB port ${DB_PORT} is not open for access by WLS Subnet CIDR [$wls_subnet_cidr_block] in DB Subnet [$DB_SUBNET_OCID]"
  fi
fi
 
# Check if DB port is open for access by WLS subnet CIDR in Application DB subnet (only if Application DB subnet is provided)
if [[ -n ${APP_DB_SUBNET_OCID} ]]
then
  res=$(validate_subnet_port_access ${APP_DB_SUBNET_OCID} ${DB_PORT} ${wls_subnet_cidr_block})
  if [[ $res -ne 0 ]]
  then
    echo "ERROR: DB port ${DB_PORT} is not open for access by WLS Subnet CIDR [$wls_subnet_cidr_block] in Application DB Subnet [$APP_DB_SUBNET_OCID]"
  fi
fi
 
# Check if SSH port is open for access by Bastion Subnet or Host CIDR in WLS Private Subnet
if [[ -n ${BASTION_SUBNET_OCID} || -n ${BASTION_HOST_IP_CIDR} ]]
then
  is_private_subnet=$(oci network subnet get --subnet-id ${WLS_SUBNET_OCID} | jq -r '.data["prohibit-public-ip-on-vnic"]')
 
  if [[ $is_private_subnet = true ]]
  then
    # Check if Bastion subnet has SSH port open for 0.0.0.0/0
    if [[ -n ${BASTION_SUBNET_OCID} ]]
    then
      all_ips="0.0.0.0/0"
      res=$(validate_subnet_port_access ${BASTION_SUBNET_OCID} ${SSH_PORT} ${all_ips})
      if [[ $res -ne 0 ]]
      then
        echo "ERROR: SSH port ${SSH_PORT} is not open for access by [$all_ips] in Bastion Subnet [$BASTION_SUBNET_OCID]"
      fi
    fi
 
    # Check if bastion host IP is valid CIDR
    bastion_cidr_block=""
    if [[ -n ${BASTION_HOST_IP_CIDR} ]]
    then
      is_valid_cidr=$(is_valid_ip_cidr ${BASTION_HOST_IP_CIDR})
      if [[ $is_valid_cidr -ne 0 ]]
      then
        echo "Bastion host IP CIDR is not valid: [${BASTION_HOST_IP_CIDR}]"
        usage >&2
        exit
      fi
      bastion_cidr_block=${BASTION_HOST_IP_CIDR}
    else
      bastion_cidr_block=$(oci network subnet get --subnet-id ${BASTION_SUBNET_OCID} | jq -r '.data["cidr-block"]')
    fi
 
    # Check if bastion CIDR has access to SSH port on WLS subnet
    res=$(validate_subnet_port_access ${WLS_SUBNET_OCID} ${SSH_PORT} ${bastion_cidr_block})
    if [[ $res -ne 0 ]]
    then
      echo "WARNING: SSH port ${SSH_PORT} is not open for access by Bastion Subnet CIDR [$bastion_cidr_block] in private WLS Subnet [$WLS_SUBNET_OCID]"
    fi
  fi
fi