diff --git a/.vscode/settings.json b/.vscode/settings.json index a7d0fc7..4875fc5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,8 @@ { - "esbonio.sphinx.confDir": "" + "esbonio.sphinx.confDir": "", + "workbench.colorCustomizations": { + "activityBar.background": "#4D1B3C", + "titleBar.activeBackground": "#6B2654", + "titleBar.activeForeground": "#FDF8FB" + } } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 3ee31d3..3f554a5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -78,10 +78,6 @@ FROM developer-${TARGET_ARCHITECTURE} AS developer # copy initial epics folder structure COPY epics /epics -# prepare tools settings -RUN git config --global advice.detachedHead false - - # get and build EPICS base RUN git clone https://github.com/epics-base/epics-base.git -q --branch ${EPICS_VERSION} --recursive ${EPICS_BASE} RUN bash /epics/scripts/patch-epics-base.sh @@ -97,7 +93,7 @@ RUN make -C ${SUPPORT}/sncseq -j $(nproc) # setup a global python venv and install ibek -RUN python3 -m venv ${VIRTUALENV} && pip install ibek +RUN python3 -m venv ${VIRTUALENV} && pip install ibek==1.0.0 ##### runtime preparation stage ################################################ diff --git a/epics/ioc/config/st.cmd b/epics/ioc/config/st.cmd new file mode 100755 index 0000000..2459c09 --- /dev/null +++ b/epics/ioc/config/st.cmd @@ -0,0 +1,10 @@ +# EXAMPLE IOC Instance to demonstrate the ADSimDetector Generic IOC + +cd "$(TOP)" + +dbLoadDatabase "dbd/ioc.dbd" +ioc_registerRecordDeviceDriver(pdbbase) + +# start IOC shell +iocInit + diff --git a/epics/ioc/iocApp/src/Makefile.jinja b/epics/ioc/iocApp/src/Makefile.jinja index 162cd4a..ab981af 100644 --- a/epics/ioc/iocApp/src/Makefile.jinja +++ b/epics/ioc/iocApp/src/Makefile.jinja @@ -10,14 +10,12 @@ PROD_IOC = ioc DBD += ioc.dbd ioc_DBD += base.dbd -{% for dbd in dbds %} -ioc_DBD += {{dbd}} +{% for dbd in dbds %}ioc_DBD += {{dbd}} {% endfor %} ioc_SRCS += ioc_registerRecordDeviceDriver.cpp -{% for lib in libs %} -ioc_LIBS += {{lib}} +{% for lib in libs %}ioc_LIBS += {{lib}} {% endfor %} ioc_LIBS += $(EPICS_BASE_IOC_LIBS) diff --git a/epics/ioc/liveness.sh b/epics/ioc/liveness.sh new file mode 100755 index 0000000..861e5c4 --- /dev/null +++ b/epics/ioc/liveness.sh @@ -0,0 +1,40 @@ +#!/bin/bash +TOP=/repos/epics/ioc +cd ${TOP} +CONFIG_DIR=${TOP}/config + +set -ex + +CONFIG_DIR=/repos/epics/ioc/config +THIS_SCRIPT=$(realpath ${0}) +override=${CONFIG_DIR}/liveness.sh + +if [[ -f ${override} && ${override} != ${THIS_SCRIPT} ]]; then + exec bash ${override} +fi + +if [[ ${K8S_IOC_LIVENESS_ENABLED} != 'true' ]]; then + exit 0 +fi + +# use devIOCStats UPTIME as the default liveness PV +# but allow override from the environment +K8S_IOC_PV=${K8S_IOC_PV:-"${IOC_PREFIX}:UPTIME"} + +# use default CA PORT or override from the environment +K8S_IOC_PORT=${K8S_IOC_PORT:-5064} + +export EPICS_CA_ADDR_LIST=${K8S_IOC_ADDRESS} +export EPICS_CA_SERVER_PORT=${K8S_IOC_PORT} + +# verify that the IOC is running +if caget ${K8S_IOC_PV} ; then + exit 0 +else + # send the error message to the container's main process stdout + echo "Liveness check failed for ${IOC_NAME}" > /proc/1/fd/1 + echo "Failing PV: ${K8S_IOC_PV}" > /proc/1/fd/2 + echo "Address list: ${EPICS_CA_ADDR_LIST}" > /proc/1/fd/2 + echo "CA Port: ${EPICS_CA_SERVER_PORT}" > /proc/1/fd/2 + exit 1 +fi diff --git a/epics/ioc/start.sh b/epics/ioc/start.sh new file mode 100755 index 0000000..6216579 --- /dev/null +++ b/epics/ioc/start.sh @@ -0,0 +1,112 @@ +#!/bin/bash + +# +# The epics-containers IOC startup script. +# +# This script is used to start an EPICS IOC in a Kubernetes pod. Implementers +# of generic IOCs are free to replace this script with their own. But +# this script as is should work for most IOCs. +# +# When a generic IOC runs in a kubernetes pod it is expected to have +# a config folder that defines the IOC instance. +# The helm chart for the generic IOC will mount the config folder +# as a configMap and this turns a generic IOC into aspecific IOC instance. +# +# Here we support the following set of options for the contents of +# the config folder: +# +# 1. start.sh ****************************************************************** +# If the config folder contains a start.sh script it will be executed. +# This allows the instance implementer to provide a conmpletely custom +# startup script. +# +# 2. ioc.yaml ************************************************************* +# If the config folder contains an ioc.yaml file we invoke the ibek tool to +# generate the startup script and database. Then launch with the generated +# startup script. +# +# 3. st.cmd + ioc.subst ********************************************************* +# If the config folder contains a st.cmd script and a ioc.subst file then +# optionally generate ioc.db from the ioc.subst file and use the st.cmd script +# as the IOC startup script. Note that the expanded database file will +# be generated in /tmp/ioc.db +# +# 4. empty config folder ******************************************************* +# If the config folder is empty then this IOC will launch the example in +# ./example folder +# +# RTEMS IOCS - RTEMS IOC startup files can be generated using 2,3,4 above. For +# RTEMS we do not execute the ioc inside of the pod. Instead we: +# - copy the IOC directory to the RTEMS mount point +# - send a reboot command to the RTEMS crate +# - start a telnet session to the RTEMS IOC console +# + +set -x -e + +# environment setup ************************************************************ + +export TOP=$(realpath $(dirname $0)) +cd ${TOP} +CONFIG_DIR=${TOP}/config + +# add module paths to environment for use in ioc startup script +source ${SUPPORT}/configure/RELEASE.shell + +# override startup script +override=${CONFIG_DIR}/start.sh +# source YAML for IOC Builder for EPICS on Kubernetes (ibek) +ibek_src=${CONFIG_DIR}/ioc.yaml +# Startup script for EPICS IOC generated by ibek +ioc_startup=${CONFIG_DIR}/st.cmd +# expanded database file +epics_db=/tmp/ioc.db + + +# 1. start.sh ****************************************************************** + +if [ -f ${override} ]; then + exec ${override} + +# 2. ioc.yaml ****************************************************************** + +elif [ -f ${ibek_src} ]; then + # Database generation script generated by ibek + db_src=/tmp/make_db.sh + final_ioc_startup=/tmp/st.cmd + + # get ibek the support yaml files this ioc's support modules + defs=/ctools/*/*.ibek.support.yaml + ibek build-startup ${ibek_src} ${defs} --out ${final_ioc_startup} --db-out ${db_src} + + # build expanded database using the db_src shell script + if [ -f ${db_src} ]; then + bash ${db_src} > ${epics_db} + fi + +# 3. st.cmd + ioc.substitutions ************************************************ + +elif [ -f ${ioc_startup} ] ; then + if [ -f ${CONFIG_DIR}/ioc.substitutions ]; then + # generate ioc.db from ioc.substitutions, including all templates from SUPPORT + includes=$(for i in ${SUPPORT}/*/db; do echo -n "-I $i "; done) + msi ${includes} -S ${CONFIG_DIR}/ioc.substitutions -o ${epics_db} + fi + final_ioc_startup=${ioc_startup} + +# 4. empty config folder ******************************************************* + +else + final_ioc_startup=${TOP}/example/st.cmd +fi + +# Launch the IOC *************************************************************** + +if [[ ${TARGET_ARCHITECTURE} == "rtems" ]] ; then + echo "RTEMS IOC startup - copying IOC to RTEMS mount point ..." + cp -r ${IOC} ${K8S_IOC_ROOT} + sleep 100 +else + # Execute the IOC binary and pass the startup script as an argument + exec ${IOC}/bin/linux-x86_64/ioc ${final_ioc_startup} +fi diff --git a/epics/ioc/stop.sh b/epics/ioc/stop.sh new file mode 100644 index 0000000..9d92a1e --- /dev/null +++ b/epics/ioc/stop.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +TOP=/repos/epics/ioc +cd ${TOP} +CONFIG_DIR=${TOP}/config + +override=${CONFIG_DIR}/stop.sh + +if [[ -f ${override} ]]; then + exec bash ${override} +elif [[ ${RTEMS_VME_AUTO_REBOOT} == 'true' ]] ; then + # This is a placeholder for a script that is called when the pod is stopped. + # Placing your own stop.sh in the config directory will override this script. +fi + +