#!/bin/sh

set -e
set -x

if ! [ -r /usr/share/openstack-pkg-tools/pkgos_func ] ; then
	echo "Could not read /usr/share/openstack-pkg-tools/pkgos_func."
	exit 1
fi
. /usr/share/openstack-pkg-tools/pkgos_func

# Configure the puppet agent to talk to the puppet master
hook_puppet_agent_config () {
	local PUPPET_MASTER_HOST RET
	if [ -r /puppet-master-host ] ; then
		PUPPET_MASTER_HOST=$(cat /puppet-master-host)
	else
		PUPPET_MASTER_HOST=$(hostname --fqdn)
	fi
	if [ -e ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf ] ; then
		if ! cat ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf | grep '\[main\]' ; then
			echo '[main]' >>${BODI_CHROOT_PATH}/etc/puppet/puppet.conf
		fi
		. /usr/share/openstack-pkg-tools/pkgos_func
		pkgos_add_directive ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main server=example.com "#puppet master address"
		pkgos_inifile set ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main server ${PUPPET_MASTER_HOST}

		# Default is 512, which is not enough, we had a warning about 665 top level facts.
		pkgos_add_directive ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main top_level_facts_soft_limit=81920 "#Default is 512, which is not enough, we had a warning about 2382 top level facts."
		pkgos_inifile set ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main top_level_facts_soft_limit 81920

		pkgos_add_directive ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main fact_value_length_soft_limit=40960 "#With a lot of VMs in a compute, there is a fact with all interfaces in one line, so it is huge."
		pkgos_inifile set ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main fact_value_length_soft_limit 40960

		pkgos_add_directive ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main number_of_facts_soft_limit=40960 "#With a lot of VMs in a compute (hundreds), there is also too many facts."
		pkgos_inifile set ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main number_of_facts_soft_limit 40960

		# On controllers, the default 1h is not enough on first run.
		pkgos_add_directive ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main runtimeout=7200 "#On controllers, the default 1h is not enough on first run."
		pkgos_inifile set ${BODI_CHROOT_PATH}/etc/puppet/puppet.conf main runtimeout 7200
	fi
}

# Copy files under /oci-in-target to the root of the target
hook_copy_oci_in_target () {
	local CWD
	if [ -d /oci-in-target ] ; then
		CWD=$(pwd)
		cd /oci-in-target
		if [ -d usr/bin ] ; then
			chmod +x usr/bin/*
			chown root:root usr/bin/*
		fi
		if [ -d etc/oci ] ; then
			chown -R root:root etc/oci
		fi
		cp -axf * ${BODI_CHROOT_PATH}
		cd ${CWD}
		# Make sure we have correct rights for /root/.ssh
		mkdir -p ${BODI_CHROOT_PATH}/root
		if [ -e ${BODI_CHROOT_PATH}/root/.ssh ] ; then
			chmod 0700 ${BODI_CHROOT_PATH}/root/.ssh
		fi
		chmod 0700 ${BODI_CHROOT_PATH}/root
		chown -R root:root ${BODI_CHROOT_PATH}/root
		if [ -e ${BODI_CHROOT_PATH}/root/.ssh/id_rsa.pub ] ; then
			cat ${BODI_CHROOT_PATH}/root/.ssh/id_rsa.pub >> ${BODI_CHROOT_PATH}/root/.ssh/authorized_keys
		fi
		if [ -e ${BODI_CHROOT_PATH}/etc ] ; then
			chown root:root ${BODI_CHROOT_PATH}/etc || true
			chown root:root ${BODI_CHROOT_PATH}/etc/motd || true
			if [ -e ${BODI_CHROOT_PATH}/etc/facter ] ; then
				chown root:root ${BODI_CHROOT_PATH}/etc/facter
				if [ -e ${BODI_CHROOT_PATH}/etc/facter/facts.d ] ; then
					chown root:root ${BODI_CHROOT_PATH}/etc/facter/facts.d
					if [ -e ${BODI_CHROOT_PATH}/etc/facter/facts.d/swift_blockdevs_names_to_uuid.sh ] ; then
						chown root:root ${BODI_CHROOT_PATH}/etc/facter/facts.d/swift_blockdevs_names_to_uuid.sh
						chmod +x ${BODI_CHROOT_PATH}/etc/facter/facts.d/swift_blockdevs_names_to_uuid.sh
					fi
					if [ -e ${BODI_CHROOT_PATH}/etc/facter/facts.d/swift_fstab_dev_list.sh ] ; then
						chown root:root ${BODI_CHROOT_PATH}/etc/facter/facts.d/swift_fstab_dev_list.sh
						chmod +x ${BODI_CHROOT_PATH}/etc/facter/facts.d/swift_fstab_dev_list.sh
					fi
				fi
			fi
		fi
		# Make sure we have correct rights for /etc/cron.weekly scripts
		chown -R root:root ${BODI_CHROOT_PATH}/etc/cron.weekly || true
		if [ -e ${BODI_CHROOT_PATH}/etc/cron.weekly/oci-fernet-keys-rotate ] ; then
			chmod +x ${BODI_CHROOT_PATH}/etc/cron.weekly/oci-fernet-keys-rotate
		fi
		chown -R root:root ${BODI_CHROOT_PATH}/etc/cron.hourly || true
		if [ -e ${BODI_CHROOT_PATH}/etc/cron.hourly/oci-glance-image-rsync ] ; then
			chmod +x ${BODI_CHROOT_PATH}/etc/cron.hourly/oci-glance-image-rsync
		fi
	fi
}

# Install the firmware from backports, dist-upgrade from osbpo,
# and install the packages the fixup scripts need.
hook_install_packages () {
	local production_system_install_nonfree_firmware_from_backports production_system_install_firmware_from_backports_list
	if [ -r /etc/oci/production_system_install_nonfree_firmware_from_backports ] ; then
		production_system_install_nonfree_firmware_from_backports=$(cat /etc/oci/production_system_install_nonfree_firmware_from_backports)
	else
		production_system_install_nonfree_firmware_from_backports=no
	fi
	if [ -r /etc/oci/production_system_install_firmware_from_backports_list ] ; then
		production_system_install_firmware_from_backports_list=$(cat /etc/oci/production_system_install_firmware_from_backports_list)
	else
		production_system_install_firmware_from_backports_list=""
	fi

	# Install firmware from the official backports repository, if wanted.
	# The backports .sources file itself is now managed by the repository
	# templates, and by puppet.
	if [ "${production_system_install_nonfree_firmware_from_backports}" = "yes" ] ; then
		chroot ${BODI_CHROOT_PATH} apt-get update
		chroot ${BODI_CHROOT_PATH} apt-get install -t ${debian_release}-backports -y ${production_system_install_firmware_from_backports_list} || true
	fi

	# After installing the osbpo repository, make sure the system is
	# upgraded from it, like the old hard-coded block used to do.
	if [ "${OCI_OSBPO_INSTALLED}" = "yes" ] ; then
		chroot ${BODI_CHROOT_PATH} apt-get update
		chroot ${BODI_CHROOT_PATH} apt-get -y -o Dpkg::Options::="--force-confnew" dist-upgrade
	fi

	# This has to be installed *after* the debootstrap, otherwise debootstrap will fail
	# and libxml-xpath-perl is a dependency of oci-fixup-compute-node
	if [ -x ${BODI_CHROOT_PATH}/usr/bin/oci-fixup-compute-node ] ; then
		chroot ${BODI_CHROOT_PATH} apt-get install libxml-xpath-perl -y -o Dpkg::Options::="--force-confnew"
	fi
}

# Customize /root/.screenrc, /root/.bashrc, and joe's joerc,
# plus always load the nf_conntrack kernel module.
hook_misc_system_pref () {
	# Add the nf_conntrack module by default.
	if ! grep -q nf_conntrack ${BODI_CHROOT_PATH}/etc/modules ; then echo nf_conntrack >>${BODI_CHROOT_PATH}/etc/modules ; fi

	echo "startup_message off
defscrollback 5000
caption always \"%{= kw}%-w%{= BW}%n %t%{-}%+w %-= @%H  -  %d.%m.%Y  - %c\"
termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
defbce on
term screen-256color
termcapinfo konsole-256color ti@:te@" >${BODI_CHROOT_PATH}/root/.screenrc

	echo "# ~/.bashrc: executed by bash(1) for non-login shells.

export LS_OPTIONS='--color=auto'
eval \"\$(dircolors)\"
alias ls='ls \${LS_OPTIONS}'

SYSTEM_SERIAL_NUM=\$(oci-system-serial)

   RED=\"\\[\\033[1;31m\\]\"
 LGRAY=\"\\[\\033[0;37m\\]\"
  TEAL=\"\\[\\033[38;5;6m\\]\"
  BLUE=\"\\[\\033[1;34m\\]\"
NO_COL=\"\\[\\033[0m\\]\"
 LBLUE=\"\\[\\033[1;36m\\]\"

export PS1=\${RED}'\\u'\${LGRAY}@\${TEAL}\${SYSTEM_SERIAL_NUM}\${LGRAY}-\${BLUE}'\\h'\${LGRAY}'>_'\${NO_COL}' \\w # '

alias ssh='ssh -A -X'

if [ -f /etc/bash_completion ]; then
        . /etc/bash_completion
fi

export PAGER=most
" > ${BODI_CHROOT_PATH}/root/.bashrc

	# No backup for joe
	if [ -e ${BODI_CHROOT_PATH}/etc/joe/joerc ] ; then
		sed -i "s/^ -nobackups/-nobackups/" ${BODI_CHROOT_PATH}/etc/joe/joerc
	fi
}

# Install puppet client certificate
hook_install_puppet_client_certificate () {
	local MACHINE_HOSTNAME
	MACHINE_HOSTNAME=$(cat ${BODI_CHROOT_PATH}/etc/hostname)
	if [ -r /puppet-private-key.pem ] && [ -r /puppet-public-key.pem ] && [ -r /puppet-ca.pem ] && [ -r /puppet-signed-cert.pem ] ; then
	        # Install puppet so we have the puppet:puppet user
	        chroot ${BODI_CHROOT_PATH} apt-get install -y -o Dpkg::Options::="--force-confnew" puppet

	        # Private key
	        mkdir -p ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/private_keys
	        chroot ${BODI_CHROOT_PATH} chown puppet:puppet /var/lib/puppet/ssl/private_keys
	        cp /puppet-private-key.pem ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/private_keys/${MACHINE_HOSTNAME}.pem
	        chmod 640 ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/private_keys/${MACHINE_HOSTNAME}.pem
	        chroot ${BODI_CHROOT_PATH} chown puppet:puppet /var/lib/puppet/ssl/private_keys/${MACHINE_HOSTNAME}.pem

	        # Public key
	        mkdir -p ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/public_keys
	        chroot ${BODI_CHROOT_PATH} chown puppet:puppet /var/lib/puppet/ssl/public_keys
	        cp /puppet-public-key.pem ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/public_keys/${MACHINE_HOSTNAME}.pem
	        chmod 644 ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/public_keys/${MACHINE_HOSTNAME}.pem
	        chroot ${BODI_CHROOT_PATH} chown puppet:puppet /var/lib/puppet/ssl/public_keys/${MACHINE_HOSTNAME}.pem

	        # ca.pem + cert
	        mkdir -p ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/certs
	        chroot ${BODI_CHROOT_PATH} chown puppet:puppet /var/lib/puppet/ssl/certs

	        cp /puppet-ca.pem ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/certs/ca.pem
	        chmod 644 ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/certs/ca.pem
	        chroot ${BODI_CHROOT_PATH} chown puppet:puppet /var/lib/puppet/ssl/certs/ca.pem

	        cp /puppet-signed-cert.pem ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/certs/${MACHINE_HOSTNAME}.pem
	        chmod 644 ${BODI_CHROOT_PATH}/var/lib/puppet/ssl/certs/${MACHINE_HOSTNAME}.pem
	        chroot ${BODI_CHROOT_PATH} chown puppet:puppet /var/lib/puppet/ssl/certs/${MACHINE_HOSTNAME}.pem
	        touch ${BODI_CHROOT_PATH}/var/lib/oci-first-boot

	        # This is needed by puppet-openstack
	        mkdir -p ${BODI_CHROOT_PATH}/etc/facter/facts.d
	        echo "os_service_default=<SERVICE DEFAULT>" >${BODI_CHROOT_PATH}/etc/facter/facts.d/os_service_default.txt
	        echo "os_immutable=<SERVICE DEFAULT>" >${BODI_CHROOT_PATH}/etc/facter/facts.d/os_immutable.txt

	        # We need puppet to start with OCI's generated root CA cert knowledge. That's the
	        # Environment=OS_CACERT=/etc/ssl/certs/oci-pki-oci-ca-chain.pem
	        # that will do this.
	        # We can't do that if the cert isn't just self-signed: this breaks the setup of
	        # keystone's admin role in puppet.
	        if [ -e /self-signed-api-cert ] ; then
		        mkdir -p ${BODI_CHROOT_PATH}/etc/systemd/system/puppet.service.d/
		        echo "[Service]
Environment=OS_CACERT=/etc/ssl/certs/oci-pki-oci-ca-chain.pem
" >${BODI_CHROOT_PATH}/etc/systemd/system/puppet.service.d/oci-ca-cert.conf
		fi
	fi
}

# Overrides epmd.socket file to have it bind on all IPs
hook_override_epmd_socket () {
	mkdir -p ${BODI_CHROOT_PATH}/etc/systemd/system
	echo "[Unit]
Description=Erlang Port Mapper Daemon Activation Socket

[Socket]
ListenStream=4369
BindIPv6Only=both
Accept=false

[Install]
WantedBy=sockets.target
" >${BODI_CHROOT_PATH}/etc/systemd/system/epmd.socket
}

# Fix the unix rights of the SSH (signed) host keys
hook_fix_ssh_host_keys_rights () {
	local SSH_KEYS SSH_KEYS_CERTS CERT i
	SSH_KEYS=$(ls ${BODI_CHROOT_PATH}/etc/ssh/ssh_host_*_key 2>/dev/null)
	if [ -n "${SSH_KEYS}" ] ; then
		for i in ${SSH_KEYS} ; do
			chown root:root $i $i.pub
			chmod 0600 $i
			chmod 0644 $i.pub
		done
	fi
	SSH_KEYS_CERTS=$(ls ${BODI_CHROOT_PATH}/etc/ssh/ssh_host_*_key.pub 2>/dev/null)
	if [ -n "${SSH_KEYS_CERTS}" ] ; then
		for i in ${SSH_KEYS_CERTS} ; do
			chown root:root $i
			chmod 0600 $i
			CERT=$(basename $i)
			echo "HostCertificate /etc/ssh/${CERT}" >>${BODI_CHROOT_PATH}/etc/ssh/sshd_config
		done
	fi
	if [ -e ${BODI_CHROOT_PATH}/etc/ssh/ssh_known_hosts ] ; then
		chown root:root ${BODI_CHROOT_PATH}/etc/ssh/ssh_known_hosts
	fi
	if [ -e ${BODI_CHROOT_PATH}/etc/ssh ] ; then
		chown root:root ${BODI_CHROOT_PATH}/etc/ssh
	fi
}

# Install an eventual x509 PKI, used so OpenStack nodes trust each other
hook_install_x509_pki () {
	local MACHINE_HOSTNAME
	MACHINE_HOSTNAME=$(cat ${BODI_CHROOT_PATH}/etc/hostname)
	# These are the CA certificates
	if ls /oci-pki* >/dev/null 2>&1 ; then
	        mkdir -p ${BODI_CHROOT_PATH}/etc/ssl/certs
	        cp /oci-pki* ${BODI_CHROOT_PATH}/etc/ssl/certs
	        chroot ${BODI_CHROOT_PATH} /usr/sbin/update-ca-certificates -f
	fi
	# These are the node's SSL keys
	if [ -r "/${MACHINE_HOSTNAME}.key" ] && [ -r "/${MACHINE_HOSTNAME}.crt" ] ; then
	        mkdir -p ${BODI_CHROOT_PATH}/etc/ssl/private/
	        cp /${MACHINE_HOSTNAME}.key ${BODI_CHROOT_PATH}/etc/ssl/private/ssl-cert-snakeoil.key
	        mkdir -p ${BODI_CHROOT_PATH}/etc/ssl/certs
	        cp /${MACHINE_HOSTNAME}.crt ${BODI_CHROOT_PATH}/etc/ssl/certs/ssl-cert-snakeoil.pem
	        chroot ${BODI_CHROOT_PATH} /usr/sbin/update-ca-certificates -f
	fi

	# These are the swiftproxy SSL keys
	if [ -r "/oci-pki-swiftproxy.key" ] && [ -r "/oci-pki-swiftproxy.crt" ] ; then
		mkdir -p ${BODI_CHROOT_PATH}/etc/ssl/private/
		cp /oci-pki-swiftproxy.key ${BODI_CHROOT_PATH}/etc/ssl/private/oci-pki-swiftproxy.key
		mkdir -p ${BODI_CHROOT_PATH}/etc/ssl/certs
		cp /oci-pki-swiftproxy.crt ${BODI_CHROOT_PATH}/etc/ssl/certs/oci-pki-swiftproxy.crt
		cp /oci-pki-swiftproxy.pem ${BODI_CHROOT_PATH}/etc/ssl/private/oci-pki-swiftproxy.pem
		chroot ${BODI_CHROOT_PATH} /usr/sbin/update-ca-certificates -f
	fi

	# These are the OpenStack public API SSL keys
	if [ -r /oci-pki-api.crt ] ; then
	        cp /oci-pki-api.crt ${BODI_CHROOT_PATH}/etc/ssl/certs/oci-pki-api.crt
	        chroot ${BODI_CHROOT_PATH} /usr/sbin/update-ca-certificates -f
	fi
	if [ -r /oci-pki-api.pem ] ; then
	        cp /oci-pki-api.pem ${BODI_CHROOT_PATH}/etc/ssl/private/oci-pki-api.pem
	        chroot ${BODI_CHROOT_PATH} /usr/sbin/update-ca-certificates -f
	fi
	if [ -r /oci-pki-api.key ] ; then
	        cp /oci-pki-api.key ${BODI_CHROOT_PATH}/etc/ssl/private/oci-pki-api.key
	fi
}

#########################
### Install OCI utils ###
#########################
hook_install_oci_utils () {
	chroot ${BODI_CHROOT_PATH} apt-get install -y -o Dpkg::Options::="--force-confnew" openstack-cluster-installer-utils
	chroot ${BODI_CHROOT_PATH} systemctl enable oci-report-status.service
	chroot ${BODI_CHROOT_PATH} systemctl enable oci-first-boot.service
}

##########################################
### Install the repositories templates ###
##########################################
# Everything under /etc/oci/repos/<family> is now data-driven: the
# .sources template, the GPG key and the pinning file of a repository
# folder are all optional, and the code adapts to what is present.
# Only the folders activated with the install_repo_in_target
# directive of their repo.conf are installed in the target.
# The deb822 file a repository folder writes in the target: the
# filename directive of repo.conf wins, otherwise the name is
# derived from the family and the folder name.
hook_repo_sources_target () {
	local R FAMILY REPO_DIR RET
	R=$1
	FAMILY=$2
	REPO_DIR=$3
	pkgos_inifile get ${R}/repo.conf DEFAULT filename
	if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
		echo ${RET}
		return 0
	fi
	case "${FAMILY}" in
	debian)
		case "${REPO_DIR}" in
		base)
			echo debian.sources
		;;
		security)
			echo debian-security.sources
		;;
		backports)
			echo debian-backports.sources
		;;
		incoming)
			echo debian-incoming.sources
		;;
		*)
			echo oci-debian-${REPO_DIR}.sources
		;;
		esac
	;;
	vendors)
		echo oci-vendor-${REPO_DIR}.sources
	;;
	*)
		echo oci-${FAMILY}-${REPO_DIR}.sources
	;;
	esac
}

# The precedence of a repository folder when two folders write the
# same deb822 file: a folder restricted to the distribution being
# installed wins over an unrestricted one, mirroring the gates of
# the oci::repos::<family> puppet classes.
hook_repo_precedence () {
	local R c RET
	R=$1
	pkgos_inifile get ${R}/repo.conf DEFAULT supported_codename
	if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
		for c in $(echo ${RET} | sed 's/,/ /g') ; do
			if [ "$c" = "${debian_release}" ] ; then
				echo 2
				return 0
			fi
		done
		echo 0
	else
		echo 1
	fi
}

process_repo_folders () {
	local FAMILY REPOS_DIR machine_role SELECT_FILE REPO_DIR R found_codename \
		found_arch found_role VENDOR_CHECK_CMD VENDOR_CHECK_VALS found_system \
		RESULT WINNERS KEY SOURCES_TARGET SOURCES_FILE TOKEN PKG c a r v RET UNAME_MINUS_M
	FAMILY=$1
	OCI_FAMILY_INSTALLED=no
	OCI_FAMILY_PACKAGES=""

	UNAME_MINUS_M=$(uname -m)


	REPOS_DIR=/etc/oci/repos/${FAMILY}
	if ! [ -d ${REPOS_DIR} ] ; then
		return 0
	fi

	# The role of the machine being installed, used by the
	# supported_role check of repo.conf.
	if [ -r /etc/oci/my-role ] ; then
		machine_role=$(cat /etc/oci/my-role)
	else
		machine_role=""
	fi

	# First pass: apply the activation gates, then keep, for each
	# deb822 file, the most specific matching folder, so that two
	# repository folders never fight over the same file.
	SELECT_FILE=$(mktemp)
	for REPO_DIR in $(ls -1 ${REPOS_DIR}) ; do
		R=${REPOS_DIR}/${REPO_DIR}
		if ! [ -d ${R} ] ; then
			continue
		fi
		if ! [ -e ${R}/repo.conf ] ; then
			continue
		fi
		# Activation check: install_repo_in_target defaults to no.
		pkgos_inifile get ${R}/repo.conf DEFAULT install_repo_in_target
		case "${RET}" in
		yes|1|true|on)
			:
		;;
		*)
			continue
		;;
		esac
		# Codename gate: the repository may be restricted to some
		# distributions.
		pkgos_inifile get ${R}/repo.conf DEFAULT supported_codename
		if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
			found_codename=no
			for c in $(echo ${RET} | sed 's/,/ /g') ; do
				if [ "$c" = "${debian_release}" ] ; then
					found_codename=yes
				fi
			done
			if [ "${found_codename}" = "no" ] ; then
				continue
			fi
		fi
		# Deny-list gate: the repository may also be disabled on
		# some distributions.
		pkgos_inifile get ${R}/repo.conf DEFAULT unsupported_codename
		if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
			for c in $(echo ${RET} | sed 's/,/ /g') ; do
				if [ "$c" = "${debian_release}" ] ; then
					continue 2
				fi
			done
		fi
		# Architecture gate.
		pkgos_inifile get ${R}/repo.conf DEFAULT supported_arch
		if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
			found_arch=no
			for a in $(echo ${RET} | sed 's/,/ /g') ; do
				if [ "$a" = "${UNAME_MINUS_M}" ] ; then
					found_arch=yes
				fi
			done
			if [ "${found_arch}" = "no" ] ; then
				continue
			fi
		fi
		# Machine role gate.
		pkgos_inifile get ${R}/repo.conf DEFAULT supported_role
		if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
			found_role=no
			for r in $(echo ${RET} | sed 's/,/ /g') ; do
				if [ "$r" = "${machine_role}" ] ; then
					found_role=yes
				fi
			done
			if [ "${found_role}" = "no" ] ; then
				continue
			fi
		fi
		# Hardware vendor gate: the check command is run, and its
		# output matched against the accepted values.
		pkgos_inifile get ${R}/repo.conf DEFAULT target_hardware_vendor_cmd_check
		if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
			VENDOR_CHECK_CMD=$(echo "${RET}" | sed 's/^"//; s/"$//')
			pkgos_inifile get ${R}/repo.conf DEFAULT target_hardware_vendor_value
			VENDOR_CHECK_VALS=$(echo "${RET}" | sed 's/^"//; s/"$//')
			found_system=yes
			if [ "${VENDOR_CHECK_CMD}" != "/usr/bin/true" ] && [ "${VENDOR_CHECK_CMD}" != "/bin/true" ] ; then
				found_system=no
				RESULT=$(${VENDOR_CHECK_CMD} 2>/dev/null | sed 's/ /_/g' || echo "")
				for v in $(echo "${VENDOR_CHECK_VALS}" | sed 's/ /_/g' | tr ',' ' ') ; do
					if [ "$RESULT" = "$v" ] ; then
						found_system=yes
						break
					fi
				done
			fi
			if [ "${found_system}" = "no" ] ; then
				continue
			fi
		fi
		echo "$(hook_repo_precedence ${R}) ${REPO_DIR} $(hook_repo_sources_target ${R} ${FAMILY} ${REPO_DIR})" >>${SELECT_FILE}
	done
	WINNERS=$(sort -k3,3 -k1,1nr ${SELECT_FILE} | awk '!seen[$3]++ { print $2 }')
	rm -f ${SELECT_FILE}
	# Second pass: the winners only.
	for REPO_DIR in ${WINNERS} ; do
		R=${REPOS_DIR}/${REPO_DIR}
		OCI_FAMILY_INSTALLED=yes
		# GPG key.
		mkdir -p ${BODI_CHROOT_PATH}/etc/apt/keyrings
		for KEY in ${R}/*.asc ; do
			if [ -e "$KEY" ] ; then
				cp $KEY ${BODI_CHROOT_PATH}/etc/apt/keyrings/oci-${FAMILY}-${REPO_DIR}.asc
			fi
		done
		# Pinning file.
		if [ -e ${R}/repo.pref ] ; then
			mkdir -p ${BODI_CHROOT_PATH}/etc/apt/preferences.d
			case "${FAMILY}" in
			vendors)
				cp ${R}/repo.pref ${BODI_CHROOT_PATH}/etc/apt/preferences.d/oci-vendor-${REPO_DIR}.pref
			;;
			*)
				cp ${R}/repo.pref ${BODI_CHROOT_PATH}/etc/apt/preferences.d/oci-${FAMILY}-${REPO_DIR}.pref
			;;
			esac
		fi
		# Sources template, with its tokens.
		if [ -e ${R}/repo.sources ] ; then
			mkdir -p ${BODI_CHROOT_PATH}/etc/apt/sources.list.d
			SOURCES_TARGET=$(hook_repo_sources_target ${R} ${FAMILY} ${REPO_DIR})
			SOURCES_FILE=${BODI_CHROOT_PATH}/etc/apt/sources.list.d/${SOURCES_TARGET}
			cp ${R}/repo.sources ${SOURCES_FILE}
			sed -i "s#%%OS_VERSION%%#${debian_release}#g; s#%%OPENSTACK_RELEASE%%#${openstack_release}#g" ${SOURCES_FILE}
			# Resolve the remaining tokens: first from the [<codename>]
			# section of repo.conf, then from the [repo_tokens] section
			# of openstack-cluster-installer.conf, then from the
			# [DEFAULT] section of repo.conf, and finally from the
			# server side values. A token which cannot be resolved at
			# all makes the .sources file invalid: skip the folder.
			for TOKEN in $(grep -o '%%[A-Za-z0-9_]*%%' ${SOURCES_FILE} | sort -u | sed 's/%%//g') ; do
				pkgos_inifile get ${R}/repo.conf ${debian_release} ${TOKEN}
				if [ "${RET}" = "NOT_FOUND" ] || [ -z "${RET}" ] ; then
					RET=$(grep -m1 "^${TOKEN}=" /etc/oci/repo-tokens 2>/dev/null | cut -d= -f2-)
				fi
				if [ "${RET}" = "NOT_FOUND" ] || [ -z "${RET}" ] ; then
					pkgos_inifile get ${R}/repo.conf DEFAULT ${TOKEN}
				fi
				if [ "${RET}" = "NOT_FOUND" ] || [ -z "${RET}" ] ; then
					echo "? Could not resolve %%${TOKEN}%% of ${FAMILY}/${REPO_DIR}: skipping the folder."
					rm -f ${SOURCES_FILE} ${BODI_CHROOT_PATH}/etc/apt/keyrings/oci-${FAMILY}-${REPO_DIR}.asc
					case "${FAMILY}" in
					vendors)
						rm -f ${BODI_CHROOT_PATH}/etc/apt/preferences.d/oci-vendor-${REPO_DIR}.pref
					;;
					*)
						rm -f ${BODI_CHROOT_PATH}/etc/apt/preferences.d/oci-${FAMILY}-${REPO_DIR}.pref
					;;
					esac
					continue 2
				fi
				sed -i "s#%%${TOKEN}%%#${RET}#g" ${SOURCES_FILE}
			done
		fi
		# Packages to install from this repository.
		pkgos_inifile get ${R}/repo.conf DEFAULT target_package_list
		if [ "${RET}" != "NOT_FOUND" ] && [ -n "${RET}" ] ; then
			OCI_FAMILY_PACKAGES="${OCI_FAMILY_PACKAGES} $(echo ${RET} | sed 's/,/ /g')"
		fi
	done
	if [ "${OCI_FAMILY_INSTALLED}" = "yes" ] ; then
		chroot ${BODI_CHROOT_PATH} apt-get update
		for PKG in ${OCI_FAMILY_PACKAGES} ; do
			chroot ${BODI_CHROOT_PATH} env DEBIAN_FRONTEND=noninteractive apt-get install -y -o Dpkg::Options::="--force-confnew" ${PKG}
		done
	fi
}

# The official Debian repositories: build-openstack-debian-image
# writes base and security with the mirrors of the installation
# time, and they only serve the debootstrap and the early apt
# phases: they are rewritten here from the templates, honoring the
# site wide token overrides, and puppet converges them to the
# template content afterwards. The classic /etc/apt/sources.list
# written by bodi only served the debootstrap and the early apt
# phases as well: its content is now owned by the deb822 files
# generated from the repository templates, so it is removed
# entirely before any apt-get update can run, and only kept as a
# fallback if no template repository could be installed.
hook_manage_repositories () {
	process_repo_folders debian
	if [ "${OCI_FAMILY_INSTALLED}" = "yes" ] ; then
		rm -f ${BODI_CHROOT_PATH}/etc/apt/sources.list
	fi

	# The osbpo.debian.net repository, and its optional add-ons.
	process_repo_folders osbpo
	if [ "${OCI_FAMILY_INSTALLED}" = "yes" ] ; then
		OCI_OSBPO_INSTALLED=yes
	fi

	# The hardware vendor repositories.
	process_repo_folders vendors

	# The repository templates have been consumed: the target's apt
	# setup now lives in /etc/apt/sources.list.d and in the keyrings,
	# and puppet converges the repository definitions from the ENC
	# data. The next install re-stages the folder, so remove it.
	rm -rf /etc/oci/repos
}

openstack_release=$(cat /etc/oci_openstack_release)
debian_release=$(cat /etc/oci_debian_release)

hook_puppet_agent_config
hook_copy_oci_in_target
hook_manage_repositories
hook_install_packages
hook_misc_system_pref
hook_install_puppet_client_certificate
hook_override_epmd_socket
hook_fix_ssh_host_keys_rights
hook_install_x509_pki
hook_install_oci_utils
