#!/bin/bash

# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at 
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.


# Make sure you are root before doing anything
uid="$(id -u)"
if [ "$uid" -ne 0 ]; then
	echo "This script must be run using sudo!"
	fail_setup
fi

# Save the original argument array since we modify it
original_args=("$@")

cd "$(dirname "$0")" || fail_setup

echo "Getting started..."

# Source the generic function libraries that are also used by the product after
# setup. These functions are intended to be reusable outside of the setup process.
source ../salt/common/tools/sbin/so-common
source ../salt/common/tools/sbin/so-image-common

# Setup bash functionality is divided into functions and user-facing prompts. 
# Do not attempt to re-use any of this functionality outside of setup. Instead, 
# if needed, migrated generic functions into so-common.
source ./so-functions
source ./so-whiptail

# Finally, source the default variable definitions, which require availability of
# functions sourced above.
source ./so-variables

# Parse command line arguments
setup_type=$1
test_profile=$2

WHATWOULDYOUSAYYAHDOHERE=setup

while [[ $# -gt 0 ]]; do
	arg="$1"
	shift
	case "$arg" in
		"--turbo="* ) 
			export TURBO="http://${arg#*=}";;
		"--proxy="* ) 
			export {http,https,ftp,rsync,all}_proxy="${arg#*=}";;
		"--allow-cidr="* )
			export ALLOW_CIDR="${arg#*=}";;
		* )
			if [[ "$arg" == "--"* ]]; then
				echo "Invalid option"
			fi
	esac
done

set_timezone
# Preserve old setup/error logs
[ -f "$error_log" ] && mv "$error_log" "$error_log.$(date +%Y-%m-%dT%H:%M:%S)"
[ -f "$setup_log" ] && mv "$setup_log" "$setup_log.$(date +%Y-%m-%dT%H:%M:%S)"

# Let's see what OS we are dealing with here
detect_os

# Ubuntu/Debian whiptail pallete to make it look the same as CentOS and Rocky.
set_palette >> $setup_log 2>&1

if [[ $not_supported ]] && [ -z "$test_profile" ]; then
	if [[ "$OSVER" == "focal" ]]; then
		if (whiptail_focal_warning); then
			true
		else
			info "User cancelled setup."
			whiptail_cancel
		fi
	else
		if (whiptail_unsupported_os_warning); then
			true
		else
			info "User cancelled setup."
			whiptail_cancel
		fi
	fi
fi

# we need to upgrade packages on debian prior to install and reboot if there are due to iptables-restore not running properly
# if packages are updated and the box isn't rebooted
if [[ $is_debian ]]; then
	update_packages
	if [[ -f "/var/run/reboot-required" ]] && [ -z "$test_profile" ]; then
		whiptail_debian_reboot_required
		reboot
	fi
fi

# Check to see if this is the setup type of "desktop".
is_desktop=
if [ "$setup_type" = 'desktop' ]; then
	is_desktop=true
	# Check to see if this is an ISO. Usually this dir on exists on ISO installs.
	if [ -d /root/SecurityOnion ]; then
		is_desktop_iso=true
		install_type='DESKTOP'
	fi
fi

# Make sure if ISO is specified that we are dealing with CentOS or Rocky
title "Detecting if this is an ISO install"
if [[ "$setup_type" == 'iso' ]]; then
	if [[ $is_rpm ]]; then
		is_iso=true
	else
		echo "Only use 'so-setup iso' for an ISO install on Security Onion ISO images. Please run 'so-setup network' instead."
		fail_setup
	fi
fi

if ! [ -f $install_opt_file ] && [ -d /root/manager_setup/securityonion ] && [[ $(pwd) != /root/manager_setup/securityonion/setup ]]; then
	exec bash /root/manager_setup/securityonion/setup/so-setup "${original_args[@]}"
fi

title "Checking to see if install has run before"
if [[ -f /root/accept_changes ]]; then
	is_reinstall=true
	whiptail_reinstall
	info "Old setup detected. Preparing for reinstallation."
	reinstall_init
	reset_proxy
fi

# Previous setup attempts, even if setup doesn't actually start the installation,
# can leave behind results that may interfere with the current setup attempt.
clear_previous_setup_results

title "Parsing Username for Install"
parse_install_username

if ! [ -f $install_opt_file ]; then
	# Begin Installation pre-processing
	title "Initializing Setup"
	info "Installing as the $INSTALLUSERNAME user"

	analyze_system
fi

# Set up handler for setup to exit early (use `kill -SIGUSR1 "$setup_proc"; exit 1` in child scripts)
trap 'catch $LINENO' SIGUSR1
setup_proc="$$"
catch() {
	info "Fatal error occurred at $1 in so-setup, failing setup."
	grep --color=never "ERROR" "$setup_log" > "$error_log"
	whiptail_setup_failed
	fail_setup
}

# Add the progress function for manager node type installs
progress() {
	local msg=${1:-'Please wait while installing...'}

	if [ -z "$TESTING" ]; then
		whiptail --title "$whiptail_title" --gauge "$msg" 6 70 0 # append to text
	else
		cat >> $setup_log 2>&1
	fi		
}

if [ -n "$test_profile" ]; then
	install_type="$(echo $test_profile |awk -F- '{print $1}')"
	if [[ "$install_type" == "distributed" ]]; then
		install_type=MANAGER
	else
		install_type=${install_type^^}
	fi

	# The below settings are hardcoded purely for automated testing purposes.
	TESTING=true
	
	if [[ "$test_profile" =~ "-sensor" ]]; then
		install_type=SENSOR
		HOSTNAME=sensor
		MSRVIP_OFFSET=-2
	elif [[ "$test_profile" =~ "-search" ]]; then
		install_type=SEARCHNODE
		HOSTNAME=search
		MSRVIP_OFFSET=-1
	elif [[ "$test_profile" =~ "-managersearch" ]]; then
		install_type=MANAGERSEARCH
		HOSTNAME=manager
	elif [[ "$test_profile" =~ "-heavynode" ]]; then
		install_type=HEAVYNODE
		HOSTNAME=sensor
		MSRVIP_OFFSET=-1
	elif [[ "$test_profile" =~ "-desktop" ]]; then
		install_type=DESKTOP
		MSRVIP_OFFSET=-3
		is_desktop_grid=true
	elif [[ "$test_profile" =~ "-idh" ]]; then
		install_type=IDH
		HOSTNAME=idh
		MSRVIP_OFFSET=-4
	elif [[ "$test_profile" =~ "-receiver" ]]; then
		install_type=RECEIVER
		HOSTNAME=receiver
		MSRVIP_OFFSET=-5
	elif [[ "$test_profile" =~ "-fleet" ]]; then
		install_type=FLEET
		HOSTNAME=fleet
		MSRVIP_OFFSET=-6
	else
		HOSTNAME=manager
	fi

	if [[ "$install_type" =~ "DESKTOP" ]]; then
		is_desktop=true
		HOSTNAME=desktop
		if [[ -z "$is_desktop_grid" ]]; then
			is_desktop_grid=false
		fi
	fi
	
	info "Activating test profile; profile=$test_profile; install_type=$install_type"

	MINION_CIDR=10.0.0.0/8
	MSRV=manager
	if [[ "$test_profile" =~ "-net" ]] || [[ "$test_profile" =~ "-iso" ]]; then
		address_type=DHCP
	elif [[ "$test_profile" =~ "-cloud" ]]; then
		MSRVIP=10.99.1.20
	elif [[ "$test_profile" =~ "-airgap" ]]; then
		is_airgap=true
		address_type=DHCP
	fi

	if [ -f "/root/public_ip" ]; then
		REDIRECTHOST=$(cat /root/public_ip)
		REDIRECTINFO=OTHER
	else
		REDIRECTINFO=IP
	fi

	ALLOW_CIDR=0.0.0.0/0
	nic_list=$(ls -1 /sys/class/net | grep -v docker | grep -v lo)
	MNIC=$(echo "$nic_list" | head -1)
	BNICS=$(echo "$nic_list" | head -2 | tail -1)
	WEBUSER=onionuser@somewhere.invalid
	WEBPASSWD1=0n10nus3r
	WEBPASSWD2=0n10nus3r

	update_sudoers_for_testing
fi

# Make sure the setup type is suppoted.
case "$setup_type" in
	iso | network | desktop) # Accepted values
		info "Beginning Security Onion $setup_type install"
		;;
	*)
		error "Invalid install type, must be 'iso', 'network' or 'desktop'."
		fail_setup
		;;
esac

# Allow execution of SO tools during setup
local_sbin="$(pwd)/../salt/common/tools/sbin"
manager_sbin="$(pwd)/../salt/manager/tools/sbin"
export PATH=$PATH:$local_sbin:$manager_sbin

# Kernel messages can overwrite whiptail screen #812
# https://github.com/Security-Onion-Solutions/securityonion/issues/812
dmesg -D

# Kernel consoleblank is causing whiptail progress screen to appear to hang #1084
# https://github.com/Security-Onion-Solutions/securityonion/issues/1084
if [ -z "$TESTING" ]; then
	TTY=$(tty)
	info "Setup is running on TTY $TTY"
	if echo $TTY | grep -q "/dev/tty"; then 
		CONSOLEBLANK=$(cat /sys/module/kernel/parameters/consoleblank)
		info "Kernel consoleblank value before: $CONSOLEBLANK"
		if [ $CONSOLEBLANK -gt 0 ]; then 
			info "Running 'setterm -blank 0' for TTY $TTY" 
			TERM=linux setterm -blank 0 >$TTY <$TTY
			CONSOLEBLANK=$(cat /sys/module/kernel/parameters/consoleblank)
			info "Kernel consoleblank value after: $CONSOLEBLANK"
		fi
	fi
fi

# Begin prompting the user with whiptail.
if ! [[ -f $install_opt_file ]]; then
	if (whiptail_you_sure); then
		true
	else
		info "User cancelled setup."
		whiptail_cancel
	fi
	# If this is an desktop install lets streamline the process. 
	if [[ $is_desktop ]]; then
		# Prompt for hostname
		collect_hostname
		if [[ $is_desktop_iso ]]; then
			# Prompt Network Setup
			whiptail_management_nic
			whiptail_dhcp_or_static
			
			if [ "$address_type" != 'DHCP' ]; then
				collect_int_ip_mask
				collect_gateway
				collect_dns
				collect_dns_domain
			fi
		
		fi
		if [[ ! $is_desktop_iso ]]; then
			# This should be a network install
			whiptail_network_notice
			# Warn about the dangers of DHCP
			whiptail_dhcp_warn
			whiptail_management_nic
		fi
		# Initializing the network based on the previous information
		network_init
		printf '%s\n' \
			"MNIC=$MNIC" \
			"HOSTNAME=$HOSTNAME" > "$net_init_file"
		set_main_ip
		compare_main_nic_ip

	fi
	if [[ $setup_type == 'iso' ]] && [ -z "$TESTING" ]; then
		whiptail_first_menu_iso
		if [[ $option == "CONFIGURENETWORK" ]]; then
			collect_hostname
			network_init_whiptail
			network_init
			printf '%s\n' \
				"MNIC=$MNIC" \
				"HOSTNAME=$HOSTNAME" > "$net_init_file"
			set_main_ip
			compare_main_nic_ip
			whiptail_net_setup_complete
		else
			true
		fi
	fi
	if [[ ! $is_desktop ]]; then
		whiptail_install_type
	fi
else
	source $install_opt_file
fi

# Process the install type
process_installtype

# Check to see if this is an desktop install. If it is let's run things differently
if [[ $is_desktop ]]; then
	title "This is a desktop install"

	# Make sure it's oracle
	if [[ $is_oracle ]]; then
		info "Security Onion Desktop is supported on this OS."
	else
		info "Security Onion Desktop is not supported on this OS."
		exit 1
	fi

	whiptail_desktop_install
	if ! $is_desktop_grid; then
		if [[ $is_desktop_iso ]]; then
			if whiptail_desktop_nongrid_iso; then
				# Remove setup from auto launching
				parse_install_username
				sed -i '$ d' /home/$INSTALLUSERNAME/.bash_profile >> "$setup_log" 2>&1
				securityonion_repo
				info "Enabling graphical interface and setting it to load at boot"
				systemctl set-default graphical.target
				info "Setting desktop background"
				set_desktop_background
				echo "Desktop Install Complete!"
				echo ""
				echo "Please reboot to start graphical interface."
				exit 0
			else
				# Abort!
				exit 0
			fi
		else
			if whiptail_desktop_nongrid_network; then
				networking_needful
				info ""
				info ""
				info "Kicking off the automated setup of the Security Onion Desktop. This can take a while depending on your network connection."
				info ""
				info ""
				desktop_salt_local
			else
				# Abort!
				exit 0
			fi
		fi
	fi

	# If you got this far then you want to join the grid
	is_minion=true

fi



# If this is not an automated install prompt
if ! [[ -f $install_opt_file ]]; then
	# If you are a manager ask ALL the manager things here. I know there is code re-use but this makes it easier to add new roles
	if [[ $is_eval ]]; then
		info "Setting up as node type eval"
		# waitforstate means we will run the full salt state at the end. This is for only nodes running the salt-master service
		waitforstate=true
		# Does this role have monitoring interfaces?
		monints=true
		# Prompt the user to accept the elastic license
		check_elastic_license
		# If it is an install from ISO is this airgap?
		[[ $is_iso ]] && whiptail_airgap
		# Make sure minimum requirements are met
		check_requirements
		# Do networking things
		networking_needful
		# Do we need a proxy?
		[[ ! $is_airgap ]] && collect_net_method
		# Do we need to change the dockernet subnet?
		collect_dockernet
		# Are we in the clouds?
		[[ ! $is_airgap ]] && detect_cloud
		# Sets some minion info
		set_minion_info
		set_default_log_size >> $setup_log 2>&1
		info "Verifying all network devices are managed by Network Manager that should be"
		check_network_manager_conf
		set_network_dev_status_list
		# What NIC for watching network traffic?
		whiptail_sensor_nics
		# How many cores do we have?
		calculate_useable_cores
		# What is the web user?
		collect_webuser_inputs
		# How are we accessing the UI?
		get_redirect
		# Does the user want to allow access to the UI?
		collect_so_allow
		[[ ! $is_airgap ]] && whiptail_accept_telemetry
		whiptail_end_settings
	elif [[ $is_standalone ]]; then
		waitforstate=true
		monints=true
		check_elastic_license
		[[ $is_iso ]] && whiptail_airgap
		check_requirements
		networking_needful
		[[ ! $is_airgap ]] && collect_net_method
		collect_dockernet
		[[ ! $is_airgap ]] && detect_cloud
		set_minion_info
		set_default_log_size >> $setup_log 2>&1
		info "Verifying all network devices are managed by Network Manager that should be"
		check_network_manager_conf
		set_network_dev_status_list
		whiptail_sensor_nics
		calculate_useable_cores
		collect_webuser_inputs
		get_redirect
		collect_so_allow
		[[ ! $is_airgap ]] && whiptail_accept_telemetry
		whiptail_end_settings
	elif [[ $is_manager ]]; then
		info "Setting up as node type manager"
		check_elastic_license
		waitforstate=true
		[[ $is_iso ]] && whiptail_airgap
		check_requirements
		networking_needful
		[[ ! $is_airgap ]] && collect_net_method
		collect_dockernet
		[[ ! $is_airgap ]] && detect_cloud
		set_minion_info
		set_default_log_size >> $setup_log 2>&1
		info "Verifying all network devices are managed by Network Manager that should be"
		check_network_manager_conf
		set_network_dev_status_list
		calculate_useable_cores
		collect_webuser_inputs
		get_redirect
		collect_so_allow
		[[ ! $is_airgap ]] && whiptail_accept_telemetry
		whiptail_end_settings
	elif [[ $is_managersearch ]]; then
		info "Setting up as node type managersearch"
		check_elastic_license
		waitforstate=true
		[[ $is_iso ]] && whiptail_airgap
		check_requirements
		networking_needful
		[[ ! $is_airgap ]] && collect_net_method
		collect_dockernet
		[[ ! $is_airgap ]] && detect_cloud
		set_minion_info
		set_default_log_size >> $setup_log 2>&1
		info "Verifying all network devices are managed by Network Manager that should be"
		check_network_manager_conf
		set_network_dev_status_list
		calculate_useable_cores
		collect_webuser_inputs
		get_redirect
		collect_so_allow
		[[ ! $is_airgap ]] && whiptail_accept_telemetry
		whiptail_end_settings
	elif [[ $is_sensor ]]; then
		info "Setting up as node type sensor"
		monints=true
		check_requirements
		calculate_useable_cores
		networking_needful
		check_network_manager_conf
		set_network_dev_status_list
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		detect_cloud
		whiptail_sensor_nics
		set_minion_info
		whiptail_end_settings

	elif [[ $is_fleet ]]; then
		info "Setting up as node type fleet"
		check_requirements
		networking_needful
		check_network_manager_conf
		set_network_dev_status_list
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		detect_cloud
		set_minion_info
		whiptail_end_settings

	elif [[ $is_searchnode ]]; then
		info "Setting up as node type searchnode"
		check_requirements
		networking_needful
		check_network_manager_conf
		set_network_dev_status_list
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		detect_cloud
		set_minion_info
		whiptail_end_settings

	elif [[ $is_heavynode ]]; then
		info "Setting up as node type heavynode"
		monints=true
		check_requirements
		calculate_useable_cores
		networking_needful
		check_network_manager_conf
		set_network_dev_status_list
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		detect_cloud
		whiptail_sensor_nics
		set_minion_info
		whiptail_end_settings

	elif [[ $is_idh ]]; then
		info "Setting up as node type idh"
		check_requirements
		networking_needful
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		collect_idh_preferences
		set_minion_info
		whiptail_end_settings

	elif [[ $is_import ]]; then
		info "Setting up as node type import"
		waitforstate=true
		[[ $is_iso ]] && whiptail_airgap
		check_elastic_license
		check_requirements
		networking_needful
		[[ ! $is_airgap ]] && detect_cloud
		collect_dockernet
		[[ ! $is_airgap ]] && collect_net_method
		set_minion_info
		set_default_log_size >> $setup_log 2>&1
		info "Verifying all network devices are managed by Network Manager that should be"
		check_network_manager_conf
		set_network_dev_status_list
		calculate_useable_cores
		collect_webuser_inputs
		get_redirect
		collect_so_allow
		[[ ! $is_airgap ]] && whiptail_accept_telemetry
		whiptail_end_settings

	elif [[ $is_receiver ]]; then
		info "Setting up as node type receiver"
		check_requirements
		networking_needful
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		set_minion_info
		whiptail_end_settings

	# desktop install will only get this far if joining the grid
	elif [[ $is_desktop ]]; then
		info "Setting up as node type desktop"
		networking_needful
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		set_minion_info
		whiptail_end_settings

	elif [[ $is_hypervisor ]]; then
		info "Setting up as node type hypervisor"
		check_requirements
		networking_needful
		configure_hyper_bridge
		collect_mngr_hostname
		add_mngr_ip_to_hosts
		check_manager_connection
		set_minion_info
		whiptail_end_settings

	elif [[ $is_managerhype ]]; then
		info "Setting up as node type managerhype"
		check_elastic_license
		waitforstate=true
		[[ $is_iso ]] && whiptail_airgap
		check_requirements
		networking_needful
		configure_hyper_bridge
		[[ ! $is_airgap ]] && collect_net_method
		collect_dockernet
		[[ ! $is_airgap ]] && detect_cloud
		set_minion_info
		set_default_log_size >> $setup_log 2>&1
		info "Verifying all network devices are managed by Network Manager that should be"
		check_network_manager_conf
		set_network_dev_status_list
		calculate_useable_cores
		collect_webuser_inputs
		get_redirect
		collect_so_allow
		[[ ! $is_airgap ]] && whiptail_accept_telemetry
		whiptail_end_settings

	fi

	if [[ $waitforstate ]]; then
		touch /root/accept_changes
		touch /etc/sohotfix
		make_some_dirs
		percentage=0
		es_heapsize
		ls_heapsize
		if [[ $needs_proxy ]]; then
			set_proxy
		fi
		set_redirect
		if [[ $monints ]]; then
			# Generate Interface Vars
			generate_interface_vars
			configure_network_sensor
		fi
		info "Reserving ports"
		reserve_ports
		info "Reserving group ids"
		reserve_group_ids
		info "Setting Paths"
		# Set the paths
		set_path
		echo "Disable auto start of setup"
		# Disable the setup from prompting at login
		disable_auto_start
		info "Setting the version"
		# Set the version
		mark_version
		info "Clearing the old manager"
		# Remove old manager if re-install
		clear_manager
		info "Generating Secrets"
		# Generate passwords
		generate_passwords
		info "Populating the secrets pillar"
		# Create the secrets pillar
		secrets_pillar
		info "Add socore user"
		# Add the socore user
		add_socore_user_manager
		
		create_local_directories ${SCRIPTDIR::-5}
		setup_salt_master_dirs
		create_manager_pillars

		info "Generating the minion pillar"
		# Create the minion defaults

		export NODETYPE=$install_type
		export MINION_ID=$MINION_ID
		export ES_HEAP_SIZE=$ES_HEAP_SIZE
		export MNIC=$MNIC
		export NODE_DESCRIPTION=$NODE_DESCRIPTION
		export MAINIP=$MAINIP
		export PATCHSCHEDULENAME=$PATCHSCHEDULENAME
		export INTERFACE=$INTERFACE
		if [[ $low_mem == "true" ]]; then
			export CORECOUNT=1
		else
			export CORECOUNT=$lb_procs
		fi
		export LSHOSTNAME=$HOSTNAME
		export LSHEAP=$LS_HEAP_SIZE
		export CPUCORES=$num_cpu_cores
		logCmd "so-minion -o=setup" 
		title "Creating Global SLS"

		if [[ $is_airgap ]]; then
			# Airgap Rules
			airgap_rules
		fi

		manager_pillar

		# Set up the repo to point to local file https://access.redhat.com/solutions/1355683
		# reposync down the files is network and createrepo if CentOS
		# Import the GPG keys
		gpg_rpm_import
		# Create the local repo and point the box to use the local repo
		securityonion_repo
		# Update existing packages
		update_packages
		# Put salt-master config in place
		copy_salt_master_config
		configure_minion "$minion_type"
		# Install salt
		saltify
		check_sos_appliance
		logCmd "salt-key -yd $MINION_ID"
		sleep 2 # Debug RSA Key format errors
		logCmd "salt-call state.show_top"
		sleep 2 # Debug RSA Key format errors
		logCmd "salt-key -ya $MINION_ID"
		logCmd "salt-call saltutil.sync_all"
		# we need to sync the runner and generate the soqemussh user keys so that first highstate after license created
		# doesnt have a state failure for soqemussh_pub_key source for id_ecdsa.pub missing
		if [[ $is_manager || $is_managerhype ]]; then
			logCmd "salt-run saltutil.sync_all"
			logCmd "salt-run setup_hypervisor.regenerate_ssh_keys"
		fi
		logCmd "salt-call state.apply common.packages"
		logCmd "salt-call state.apply common"
		hypervisor_local_states
		# this will apply the salt.minion state first since salt.master includes salt.minion
		logCmd "salt-call state.apply salt.master"
		# wait here until we get a response from the salt-master since it may have just restarted
		# exit setup after 5-6 minutes of trying
		check_salt_master_status || fail  "Can't access salt master or it is not ready"
		# apply the ca state to create the ca and symlink to local/salt/ca/files/ca.crt
		# the minion ip will already be in the mine from configure_minion function in so-functions
		generate_ca
		logCmd "salt-call state.apply docker"
		firewall_generate_templates
		set_initial_firewall_policy
		# Download Elastic Agent Artifacts
		title "Downloading Elastic Agent Artifacts"
		download_elastic_agent_artifacts

		logCmd "salt-call state.apply -l info firewall"

		# create these so the registry state can add so-registry to /opt/so/conf/so-status/so-status.conf
		logCmd "mkdir -p /opt/so/conf/so-status/ "
		logCmd "touch /opt/so/conf/so-status/so-status.conf"
		title "Importing Registry Docker" 
		import_registry_docker
		title "Applying the registry state"
		logCmd "salt-call state.apply -l info registry"
		title "Seeding the docker registry"
		docker_seed_registry
		title "Applying the manager state"
		logCmd "salt-call state.apply -l info manager"
		logCmd "salt-call state.apply influxdb -l info"
		logCmd "salt-call state.highstate -l info"
		logCmd "salt-call schedule.disable -linfo --local"
		if [[ ! $is_airgap ]]; then
			title "Downloading IDS Rules"
			logCmd "so-rule-update"
			if [[ $monints || $is_import ]]; then
				title "Applying the Suricata state to load the new rules"
				logCmd "salt-call state.apply suricata -l info"
			fi
		fi
		if [[ $is_airgap ]]; then
			title "Syncing AI-Generated Detection Summaries"
			airgap_detection_summaries
		fi
		if [[ $is_airgap ]]; then
			title "Syncing Playbooks"
			logCmd "airgap_playbooks /root/SecurityOnion"
		fi
		title "Setting up Kibana Default Space"
		logCmd "so-kibana-space-defaults"
		add_web_user
		info "Restarting SOC to pick up initial user"
		logCmd "so-soc-restart"
		title "Setting up Elastic Fleet"
		logCmd "salt-call state.apply elasticfleet.config"	
		if ! logCmd so-elastic-fleet-setup; then
			error "Failed to run so-elastic-fleet-setup"
			fail_setup
		fi
		checkin_at_boot
		set_initial_firewall_access
		# run a final highstate before enabling scheduled highstates. 
		# this will ensure so-elasticsearch-ilm-policy-load and so-elasticsearch-templates-load have a chance to run after elasticfleet is setup
		info "Running final highstate for setup"
		logCmd "salt-call state.highstate -l info"
		logCmd "salt-call schedule.enable -linfo --local"
		verify_setup
	else
		touch /root/accept_changes
		mkdir -p /opt/so
		es_heapsize
		ls_heapsize
		generate_interface_vars
		if [[ $monints ]]; then
			configure_network_sensor
		fi
		info "Reserving ports"
		reserve_ports
		info "Reserving group ids"
		reserve_group_ids
		# Set the version
		mark_version
		# Disable the setup from prompting at login
		disable_auto_start
		info "Clearing the old manager"
		# Remove old manager if re-install
		clear_manager		
		gpg_rpm_import
		securityonion_repo
		update_packages
		configure_minion "$minion_type"
		saltify
		check_sos_appliance
		drop_install_options
		hypervisor_local_states
		verify_setup
	fi

	# Need to make sure the latest install is located on the web server of the manager to check the versions and download the code if required
fi
