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