| #!/bin/bash | |
| # shellcheck disable=SC1091 | |
| # shellcheck disable=SC2034 | |
| # shellcheck disable=SC2059 | |
| # shellcheck disable=SC2086 # we want word splitting | |
| . "$SCRIPTS_DIR"/setup-test-env.sh | |
| # Boot script for devices attached to a PoE switch, using NFS for the root | |
| # filesystem. | |
| # We're run from the root of the repo, make a helper var for our paths | |
| BM=$CI_PROJECT_DIR/install/bare-metal | |
| CI_COMMON=$CI_PROJECT_DIR/install/common | |
| CI_INSTALL=$CI_PROJECT_DIR/install | |
| # Runner config checks | |
| if [ -z "$BM_SERIAL" ]; then | |
| echo "Must set BM_SERIAL in your gitlab-runner config.toml [[runners]] environment" | |
| echo "This is the serial port to listen the device." | |
| exit 1 | |
| fi | |
| if [ -z "$BM_POE_ADDRESS" ]; then | |
| echo "Must set BM_POE_ADDRESS in your gitlab-runner config.toml [[runners]] environment" | |
| echo "This is the PoE switch address to connect for powering up/down devices." | |
| exit 1 | |
| fi | |
| if [ -z "$BM_POE_INTERFACE" ]; then | |
| echo "Must set BM_POE_INTERFACE in your gitlab-runner config.toml [[runners]] environment" | |
| echo "This is the PoE switch interface where the device is connected." | |
| exit 1 | |
| fi | |
| if [ -z "$BM_POWERUP" ]; then | |
| echo "Must set BM_POWERUP in your gitlab-runner config.toml [[runners]] environment" | |
| echo "This is a shell script that should power up the device and begin its boot sequence." | |
| exit 1 | |
| fi | |
| if [ -z "$BM_POWERDOWN" ]; then | |
| echo "Must set BM_POWERDOWN in your gitlab-runner config.toml [[runners]] environment" | |
| echo "This is a shell script that should power off the device." | |
| exit 1 | |
| fi | |
| if [ ! -d /nfs ]; then | |
| echo "NFS rootfs directory needs to be mounted at /nfs by the gitlab runner" | |
| exit 1 | |
| fi | |
| if [ ! -d /tftp ]; then | |
| echo "TFTP directory for this board needs to be mounted at /tftp by the gitlab runner" | |
| exit 1 | |
| fi | |
| # job config checks | |
| if [ -z "$BM_ROOTFS" ]; then | |
| echo "Must set BM_ROOTFS to your board's rootfs directory in the job's variables" | |
| exit 1 | |
| fi | |
| if [ -z "$BM_BOOTFS" ] && { [ -z "$BM_KERNEL" ] || [ -z "$BM_DTB" ]; } ; then | |
| echo "Must set /boot files for the TFTP boot in the job's variables or set kernel and dtb" | |
| exit 1 | |
| fi | |
| if [ -z "$BM_CMDLINE" ]; then | |
| echo "Must set BM_CMDLINE to your board's kernel command line arguments" | |
| exit 1 | |
| fi | |
| section_start prepare_rootfs "Preparing rootfs components" | |
| set -ex | |
| date +'%F %T' | |
| # Clear out any previous run's artifacts. | |
| rm -rf results/ | |
| mkdir -p results | |
| # Create the rootfs in the NFS directory. rm to make sure it's in a pristine | |
| # state, since it's volume-mounted on the host. | |
| rsync -a --delete $BM_ROOTFS/ /nfs/ | |
| date +'%F %T' | |
| # If BM_BOOTFS is an URL, download it | |
| if echo $BM_BOOTFS | grep -q http; then | |
| curl -L --retry 4 -f --retry-all-errors --retry-delay 60 \ | |
| "${FDO_HTTP_CACHE_URI:-}$BM_BOOTFS" -o /tmp/bootfs.tar | |
| BM_BOOTFS=/tmp/bootfs.tar | |
| fi | |
| date +'%F %T' | |
| # If BM_BOOTFS is a file, assume it is a tarball and uncompress it | |
| if [ -f "${BM_BOOTFS}" ]; then | |
| mkdir -p /tmp/bootfs | |
| tar xf $BM_BOOTFS -C /tmp/bootfs | |
| BM_BOOTFS=/tmp/bootfs | |
| fi | |
| # If BM_KERNEL and BM_DTS is present | |
| if [ -n "${EXTERNAL_KERNEL_TAG}" ]; then | |
| if [ -z "${BM_KERNEL}" ] || [ -z "${BM_DTB}" ]; then | |
| echo "This machine cannot be tested with external kernel since BM_KERNEL or BM_DTB missing!" | |
| exit 1 | |
| fi | |
| curl -L --retry 4 -f --retry-all-errors --retry-delay 60 \ | |
| "${FDO_HTTP_CACHE_URI:-}${KERNEL_IMAGE_BASE}/${DEBIAN_ARCH}/${BM_KERNEL}" -o "${BM_KERNEL}" | |
| curl -L --retry 4 -f --retry-all-errors --retry-delay 60 \ | |
| "${FDO_HTTP_CACHE_URI:-}${KERNEL_IMAGE_BASE}/${DEBIAN_ARCH}/${BM_DTB}.dtb" -o "${BM_DTB}.dtb" | |
| curl -L --retry 4 -f --retry-all-errors --retry-delay 60 \ | |
| "${FDO_HTTP_CACHE_URI:-}${KERNEL_IMAGE_BASE}/${DEBIAN_ARCH}/modules.tar.zst" -o modules.tar.zst | |
| fi | |
| date +'%F %T' | |
| # Install kernel modules (it could be either in /lib/modules or | |
| # /usr/lib/modules, but we want to install in the latter) | |
| if [ -n "${EXTERNAL_KERNEL_TAG}" ]; then | |
| tar --keep-directory-symlink --zstd -xf modules.tar.zst -C /nfs/ | |
| rm modules.tar.zst & | |
| elif [ -n "${BM_BOOTFS}" ]; then | |
| [ -d $BM_BOOTFS/usr/lib/modules ] && rsync -a $BM_BOOTFS/usr/lib/modules/ /nfs/usr/lib/modules/ | |
| [ -d $BM_BOOTFS/lib/modules ] && rsync -a $BM_BOOTFS/lib/modules/ /nfs/lib/modules/ | |
| else | |
| echo "No modules!" | |
| fi | |
| date +'%F %T' | |
| # Install kernel image + bootloader files | |
| if [ -n "${EXTERNAL_KERNEL_TAG}" ] || [ -z "$BM_BOOTFS" ]; then | |
| mv "${BM_KERNEL}" "${BM_DTB}.dtb" /tftp/ | |
| else # BM_BOOTFS | |
| rsync -aL --delete $BM_BOOTFS/boot/ /tftp/ | |
| fi | |
| date +'%F %T' | |
| # Set up the pxelinux config for Jetson Nano | |
| mkdir -p /tftp/pxelinux.cfg | |
| cat <<EOF >/tftp/pxelinux.cfg/default-arm-tegra210-p3450-0000 | |
| PROMPT 0 | |
| TIMEOUT 30 | |
| DEFAULT primary | |
| MENU TITLE jetson nano boot options | |
| LABEL primary | |
| MENU LABEL CI kernel on TFTP | |
| LINUX Image | |
| FDT tegra210-p3450-0000.dtb | |
| APPEND \${cbootargs} $BM_CMDLINE | |
| EOF | |
| # Set up the pxelinux config for Jetson TK1 | |
| cat <<EOF >/tftp/pxelinux.cfg/default-arm-tegra124-jetson-tk1 | |
| PROMPT 0 | |
| TIMEOUT 30 | |
| DEFAULT primary | |
| MENU TITLE jetson TK1 boot options | |
| LABEL primary | |
| MENU LABEL CI kernel on TFTP | |
| LINUX zImage | |
| FDT tegra124-jetson-tk1.dtb | |
| APPEND \${cbootargs} $BM_CMDLINE | |
| EOF | |
| # Create the rootfs in the NFS directory | |
| . $BM/rootfs-setup.sh /nfs | |
| date +'%F %T' | |
| echo "$BM_CMDLINE" > /tftp/cmdline.txt | |
| # Add some options in config.txt, if defined | |
| if [ -n "$BM_BOOTCONFIG" ]; then | |
| printf "$BM_BOOTCONFIG" >> /tftp/config.txt | |
| fi | |
| section_end prepare_rootfs | |
| set +e | |
| STRUCTURED_LOG_FILE=results/job_detail.json | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --update dut_job_type "${DEVICE_TYPE}" | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --update farm "${FARM}" | |
| ATTEMPTS=3 | |
| first_attempt=True | |
| while [ $((ATTEMPTS--)) -gt 0 ]; do | |
| section_start dut_boot "Booting hardware device ..." | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --create-dut-job dut_name "${CI_RUNNER_DESCRIPTION}" | |
| # Update subtime time to CI_JOB_STARTED_AT only for the first run | |
| if [ "$first_attempt" = "True" ]; then | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --update-dut-time submit "${CI_JOB_STARTED_AT}" | |
| else | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --update-dut-time submit | |
| fi | |
| python3 $BM/poe_run.py \ | |
| --dev="$BM_SERIAL" \ | |
| --powerup="$BM_POWERUP" \ | |
| --powerdown="$BM_POWERDOWN" \ | |
| --boot-timeout-seconds ${BOOT_PHASE_TIMEOUT_SECONDS:-300} \ | |
| --test-timeout-minutes ${TEST_PHASE_TIMEOUT_MINUTES:-$((CI_JOB_TIMEOUT/60 - ${TEST_SETUP_AND_UPLOAD_MARGIN_MINUTES:-5}))} | |
| ret=$? | |
| if [ $ret -eq 2 ]; then | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --close-dut-job | |
| first_attempt=False | |
| error "Device failed to boot; will retry" | |
| else | |
| # We're no longer in dut_boot by this point | |
| unset CURRENT_SECTION | |
| ATTEMPTS=0 | |
| fi | |
| done | |
| section_start dut_cleanup "Cleaning up after job" | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --close-dut-job | |
| python3 $CI_INSTALL/custom_logger.py ${STRUCTURED_LOG_FILE} --close | |
| set -e | |
| date +'%F %T' | |
| # Bring artifacts back from the NFS dir to the build dir where gitlab-runner | |
| # will look for them. | |
| cp -Rp /nfs/results/. results/ | |
| date +'%F %T' | |
| section_end dut_cleanup | |
| exit $ret |