diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d4ccac8..9d2fd2d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -15,15 +15,16 @@ "EC_PROJECT": "${localWorkspaceFolderBasename}" }, "features": { + // add quality of life features for developers including git config integration "ghcr.io/devcontainers/features/common-utils:2": { - "installZsh": false, - "installOhMyZsh": false, - "installOhMyZshConfig": false, + // don't upgrade to make this similar to the runtime container "upgradePackages": false } }, // IMPORTANT for this devcontainer to work with docker EC_REMOTE_USER must be - // set to vscode. For podman it should be left blank. + // set to vscode. You will run as vscode with full sudo rights. + // For podman it should be left blank. You will run as root but host mounts + // will be owned by your user. "remoteUser": "${localEnv:EC_REMOTE_USER}", "customizations": { "vscode": { @@ -34,7 +35,7 @@ "redhat.vscode-yaml", "ryanluker.vscode-coverage-gutters", "epicsdeb.vscode-epics", - "ms-python.black-formatter" + "charliermarsh.ruff" ] } }, @@ -47,15 +48,17 @@ "runArgs": [ // Allow the container to access the host X11 display and EPICS CA "--net=host", - // Make sure SELinux does not disable with access to host filesystems like tmp + // Make sure SELinux does not disable write access to host filesystems like tmp "--security-opt=label=disable" ], - "workspaceMount": "source=${localWorkspaceFolder},target=/epics/${localWorkspaceFolderBasename},type=bind", - "workspaceFolder": "/epics/${localWorkspaceFolderBasename}", + // Mount the parent of the project folder so we can access peer projects + "workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspaces,type=bind", + // mount in other useful files from the host "mounts": [ - // Mount some useful local files from the user's home directory - // By mounting the parent of the workspace we can work on multiple peer projects - "source=${localWorkspaceFolder}/../,target=/repos,type=bind", + // we also mount the project folder into a know location in the container + // this is where the ibek-support and ioc folders reside in the container build + // in this way the devcontainer and runtime look very similar + "source=${localWorkspaceFolder},target=/epics/generic-source,type=bind", // this provides eternal bash history in and out of the container "source=${localEnv:HOME}/.bash_eternal_history,target=/root/.bash_eternal_history,type=bind", // this bashrc hooks up the .bashrc_dev_container in the following mount diff --git a/.devcontainer/postCreateCommand b/.devcontainer/postCreateCommand index df4587c..f8160b3 100644 --- a/.devcontainer/postCreateCommand +++ b/.devcontainer/postCreateCommand @@ -7,8 +7,8 @@ if [[ $USER != "root" ]] ; then # make sure the non-root user can build iocs and (mounted in) support modules - sudo chown -R ${USER}:${USER} /epics/links /venv - sudo chown -h ${USER}:${USER} /epics /epics/ioc + sudo chown -R ${USER}:${USER} /epics/ibek-defs /epics/pvi-defs /epics/support/configure /venv + sudo chown -h ${USER}:${USER} /epics /epics/ioc /epics/support # also give non-root user access to the same bash config we use in podman sudo chmod a+rx /root @@ -23,7 +23,6 @@ fi # all epics-containers devcontainers ################################################################################ - # add user's custom profile container creation script if [ -f ~/.bashprofile_dev_container ]; then . ~/.bashprofile_dev_container diff --git a/.github/workflows/build.sh b/.github/workflows/build.sh deleted file mode 100755 index 412a0e9..0000000 --- a/.github/workflows/build.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# A generic build script for epics-containers ioc repositories -# -# Note that this is implemented in bash to make it portable between -# CI frameworks. This approach uses the minimum of GitHub Actions. -# Also works locally for testing outside of CI -# -# INPUTS: -# PUSH: if true, push the container image to the registry -# TAG: the tag to use for the container image -# PLATFORM: the platform to build for (linux/amd64 or linux/arm64) -# CACHE: the directory to use for caching - -export EC_TAG="--tag ${TAG:-latest}" -export EC_PLATFORM="--platform ${PLATFORM:-linux/amd64}" -export EC_CACHE="${CACHE:-/tmp/ec-cache}" -if [[ "${PUSH}" == 'true' ]] ; then EC_PUSH='--push' ; fi - -THIS=$(dirname ${0}) -set -xe -mkdir -p ${EC_CACHE} - -# get the current version of ec CLI -pip install -r ${THIS}/../../requirements_ec.txt - -# add cache arguments - local file cache passed by github seems to be most reliable -export EC_CARGS=" - --cache-from type=local,src=${EC_CACHE} - --cache-to type=local,dest=${EC_CACHE} -" - -# add extra cross compilation platforms below if needed e.g. -# ec dev build --arch rtems ... for RTEMS cross compile - -# build runtime and developer images -ec -v dev build ${EC_TAG} ${EC_PLATFORM} ${EC_PUSH} ${EC_CARGS} - -# extract the ioc schema from the runtime image -ec dev launch-local ${EC_TAG} --execute 'ibek ioc generate-schema' > ibek.ioc.schema.json - -# run acceptance tests -shopt -s nullglob # expand to nothing if no tests are found -for t in "${THIS}/../../tests/*.sh"; do ${t}; done - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4d85407..fe03d58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,57 +11,60 @@ jobs: permissions: contents: read packages: write - env: - CACHE: /tmp/.buildx-cache strategy: fail-fast: false + max-parallel: 1 # take advantage of caching matrix: + target: [developer, runtime] + architecture: [linux] include: - - architecture: linux - os: ubuntu-latest - platform: linux/amd64 + - os: ubuntu-latest + platforms: linux/amd64 runs-on: ${{ matrix.os }} + env: + TAG: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}-${{ matrix.architecture }}-${{ matrix.target }}:${{ github.ref_name }} steps: - name: Checkout uses: actions/checkout@v3 with: submodules: recursive - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: ${{ env.CACHE }} - key: ${{ runner.os }}-${{ matrix.architecture }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-${{ matrix.architecture }}-buildx- - - name: Log in to GitHub Docker Registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io/${{ github.repository_owner }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Setup python - uses: actions/setup-python@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image + uses: docker/build-push-action@v5 with: - python-version: "3.10" + context: . + platforms: ${{ matrix.platforms }} + target: ${{ matrix.target }} + build-args: TARGET_ARCHITECTURE=${{ matrix.architecture }} + tags: ${{ env.TAG }} + cache-from: type=gha + cache-to: type=gha,mode=max + load: true - - name: Docker Build Script - env: - ARCH: ${{ matrix.architecture }} - PLATFORM: ${{ matrix.platform }} - TAG: ${{ github.ref_name }} - PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }} - CACHE: ${{ env.CACHE }} - run: .github/workflows/build.sh + - name: Test image + run: tests/run-tests.sh - - name: Upload schema as artifact - uses: actions/upload-artifact@v3 + - name: Push image + if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} + uses: docker/build-push-action@v5 with: - name: ioc-schema - path: ibek.ioc.schema.json + context: . + platforms: ${{ matrix.platforms }} + target: ${{ matrix.target }} + build-args: TARGET_ARCHITECTURE=${{ matrix.architecture }} + tags: ${{ env.TAG }} + push: true release: # Release on tag push - publish ioc schema @@ -69,11 +72,14 @@ jobs: if: ${{ github.event_name == 'push' && github.ref_type == 'tag' }} runs-on: ubuntu-latest + # this job runs in the (linux) developer container we just made + container: + image: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}-linux-developer:${{ github.ref_name }} + steps: - - uses: actions/download-artifact@v3 - with: - name: ioc-schema - path: ./ + - name: generate-schema + run: | + ibek ioc generate-schema --output ibek.ioc.schema.json - name: Github Release uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 diff --git a/.gitignore b/.gitignore index fb96ef2..a13736e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,14 +8,11 @@ repos* # while working on ibek with this project somethimes include it as subfolder ibek -# The ioc source tree is created here from a template inside the generic ioc -# repo. -# Remove from .gitignore if you want to customize the template. -/ioc/ - # dont save workspaces as other users will have differing folders *workspace +# config folder is there to be replaced there is just a dummy with Readme. +ioc/config -# opi folder is created to hold generated operator interface files -/opi/ +# podman may leave this around in aborted builds +.build.swp diff --git a/Dockerfile b/Dockerfile index 5a68865..ef1af6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,18 +1,22 @@ ##### build stage ############################################################## ARG TARGET_ARCHITECTURE -ARG BASE=7.0.7ec2 +ARG BASE=7.0.7ec3 ARG REGISTRY=ghcr.io/epics-containers FROM ${REGISTRY}/epics-base-${TARGET_ARCHITECTURE}-developer:${BASE} AS developer +# The devcontainer mounts the project root to /epics/generic-source +# Using the same location here makes devcontainer/runtime differences transparent. +ENV SOURCE_FOLDER=/epics/generic-source +# connect ioc source folder to its know location +RUN ln -s ${SOURCE_FOLDER}/ioc ${IOC} + # Get latest ibek while in development. Will come from epics-base when stable COPY requirements.txt requirements.txt RUN pip install --upgrade -r requirements.txt -# The devcontainer mounts the project root to /epics/ioc-adsimdetector. Using -# the same location here makes devcontainer/runtime differences transparent. -WORKDIR /epics/ioc-adaravis/ibek-support +WORKDIR ${SOURCE_FOLDER}/ibek-support # copy the global ibek files COPY ibek-support/_global/ _global @@ -44,15 +48,16 @@ RUN ADGenICam/install.sh R1-9 COPY ibek-support/ADAravis/ ADAravis/ RUN ADAravis/install.sh R2-3 -# create IOC source tree, generate Makefile and compile IOC Instance -RUN ibek ioc build +# get the ioc source and build it +COPY ioc ${SOURCE_FOLDER}/ioc +RUN cd ${IOC} && make ##### runtime preparation stage ################################################ FROM developer AS runtime_prep # get the products from the build stage and reduce to runtime assets only -RUN ibek ioc extract-runtime-assets /assets --extras /usr/local/lib/x86_64-linux-gnu +RUN ibek ioc extract-runtime-assets /assets ${SOURCE_FOLDER}/ibek* /usr/local/lib/x86_64-linux-gnu ##### runtime stage ############################################################ diff --git a/build b/build index ca9d319..7c5d905 100755 --- a/build +++ b/build @@ -4,18 +4,24 @@ # generic local build script for epics-containers ioc repositories # ################################################################################ -# pass rtems as first argument to build RTEMS on cross-compiler -TARGET_ARCHITECTURE=${1:-linux} +# set TARGET_ARCHITECTURE to rtems for RTEMS based targets +T_A=${TARGET_ARCHITECTURE:-linux} +# set TARGET to runtime for runtime images +TARGET=${TARGET:-developer} +# set TAG to override the default tag +TAG=${TAG:-ec_test} +# log commands and stop on erros set -xe cd $(dirname ${0}) +# use docker if available else use podman +if ! docker version &>/dev/null; then alias docker=podman; fi + # make sure new repos get their submodule ibek-support git submodule update --init -# build runtime and developer images -ec dev build --arch ${TARGET_ARCHITECTURE} +# build and developer images +docker build -t ${TAG} --build-arg TARGET_ARCHITECTURE=$T_A --target $TARGET . -# get the schema file from the developer container and save it locally -ec dev launch-local --execute 'ibek ioc generate-schema' > ibek.ioc.schema.json diff --git a/ibek-support b/ibek-support index 64813f4..3f69380 160000 --- a/ibek-support +++ b/ibek-support @@ -1 +1 @@ -Subproject commit 64813f496038b16d14e0b632f61feaa81d159371 +Subproject commit 3f69380c62bfade750e67184c71d0c2f9b14f034 diff --git a/ioc/.gitignore b/ioc/.gitignore new file mode 100644 index 0000000..f815a88 --- /dev/null +++ b/ioc/.gitignore @@ -0,0 +1,10 @@ +*~ +O.* +bin +dbd +db +data +lib +.svn* +iocs/*IOC* +.idea \ No newline at end of file diff --git a/ioc/Makefile b/ioc/Makefile new file mode 100644 index 0000000..2c82d61 --- /dev/null +++ b/ioc/Makefile @@ -0,0 +1,7 @@ +TOP = . +include $(TOP)/configure/CONFIG + +DIRS += configure +DIRS += iocApp/src + +include $(TOP)/configure/RULES_TOP diff --git a/ioc/configure/CONFIG b/ioc/configure/CONFIG new file mode 100644 index 0000000..722d9ca --- /dev/null +++ b/ioc/configure/CONFIG @@ -0,0 +1,30 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common +ifdef T_A +-include $(TOP)/configure/RELEASE.Common.$(T_A) +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG +-include $(CONFIG)/CONFIG.Dls + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain other build configuration settings +include $(TOP)/configure/CONFIG_SITE +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +ifdef T_A + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/ioc/configure/CONFIG_SITE b/ioc/configure/CONFIG_SITE new file mode 100644 index 0000000..7eaf11b --- /dev/null +++ b/ioc/configure/CONFIG_SITE @@ -0,0 +1,5 @@ +# CONFIG_SITE + +CROSS_COMPILER_TARGET_ARCHS = +CHECK_RELEASE = NO + diff --git a/ioc/configure/Makefile b/ioc/configure/Makefile new file mode 100644 index 0000000..9254309 --- /dev/null +++ b/ioc/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/ioc/configure/RELEASE b/ioc/configure/RELEASE new file mode 100644 index 0000000..57c536e --- /dev/null +++ b/ioc/configure/RELEASE @@ -0,0 +1,5 @@ +# The following definitions must be changed for each site +# +# Common prefixes +SUPPORT=/epics/support +include $(SUPPORT)/configure/RELEASE diff --git a/ioc/configure/RULES b/ioc/configure/RULES new file mode 100644 index 0000000..3425740 --- /dev/null +++ b/ioc/configure/RULES @@ -0,0 +1,7 @@ +# RULES + +-include $(CONFIG)/RULES.Dls +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/ioc/configure/RULES.ioc b/ioc/configure/RULES.ioc new file mode 100644 index 0000000..901987c --- /dev/null +++ b/ioc/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/ioc/configure/RULES_DIRS b/ioc/configure/RULES_DIRS new file mode 100644 index 0000000..3ba269d --- /dev/null +++ b/ioc/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/ioc/configure/RULES_TOP b/ioc/configure/RULES_TOP new file mode 100644 index 0000000..d09d668 --- /dev/null +++ b/ioc/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/ioc/iocApp/src/Makefile b/ioc/iocApp/src/Makefile new file mode 100644 index 0000000..f7d5648 --- /dev/null +++ b/ioc/iocApp/src/Makefile @@ -0,0 +1,21 @@ +# Generic IOC Makefile + +TOP = ../.. +include $(TOP)/configure/CONFIG + +PROD_IOC = ioc +DBD += ioc.dbd +ioc_DBD += base.dbd + +# add in the dbds collected by ibek during container build +ioc_DBD += $(shell cat /epics/support/configure/dbd_list) + +ioc_SRCS += ioc_registerRecordDeviceDriver.cpp + +# add in the libs collected by ibek during container build +ioc_LIBS += $(shell cat /epics/support/configure/lib_list) + +ioc_LIBS += $(EPICS_BASE_IOC_LIBS) +ioc_SRCS += iocMain.cpp + +include $(TOP)/configure/RULES diff --git a/ioc/iocApp/src/iocMain.cpp b/ioc/iocApp/src/iocMain.cpp new file mode 100644 index 0000000..e45dda1 --- /dev/null +++ b/ioc/iocApp/src/iocMain.cpp @@ -0,0 +1,20 @@ +/* This file was automatically generated on Fri 25 May 2018 08:06:10 BST from + * source: /home/hgv27681/R3.14.12.3/support/pmac/etc/makeIocs/lab.xml + * + * *** Please do not edit this file: edit the source file instead. *** + * */ +#include "epicsExit.h" +#include "epicsThread.h" +#include "iocsh.h" + +int main(int argc, char *argv[]) +{ + if(argc>=2) { + iocsh(argv[1]); + epicsThreadSleep(.2); + } + iocsh(NULL); + epicsExit(0); + return 0; +} + diff --git a/ioc/liveness.sh b/ioc/liveness.sh new file mode 100755 index 0000000..b0f5c0c --- /dev/null +++ b/ioc/liveness.sh @@ -0,0 +1,40 @@ +#!/bin/bash +TOP=/epics/ioc +cd ${TOP} +CONFIG_DIR=${TOP}/config + +set -ex + +CONFIG_DIR=/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/ioc/start.sh b/ioc/start.sh new file mode 100755 index 0000000..344edef --- /dev/null +++ b/ioc/start.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +description=' + + 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 a specific 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 completely custom + startup script. Any other files that the script needs can also be placed + in the config folder. + + The presence of this file overrides all other options. + + WARNING: config maps are restricted to 1MB total. + + 2. ioc.yaml ************************************************************* + If the config folder contains a yaml file we invoke the ibek tool to + generate the startup script and database. Then launch with the generated + startup script. The file name should be the name of the ioc with a 'yaml' + extension e.g. bl38p-ea-panda-02.yaml. Using a unique name allows for: + + ioc_name: "{{ ioc_yaml_file_name }}" + + at the top of the file and in turn "{{ ioc_name }}"" can be used in any + of the fields within the file. + + 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 ${RUNTIME_DIR}/ioc.db + + 4. empty config folder ******************************************************* + If the config folder is empty this message will be displayed. + + + RTEMS IOCS - RTEMS IOC startup files can be generated using any of the 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 and connect that to + stdio of the pod. + +' + +# error reporting ************************************************************* + +function ibek_error { + echo "${1}" + + # Wait for a bit so the container does not exit and restart continually + sleep 10 +} + +# environment setup ************************************************************ + +# log commands and stop on errors +set -xe + +cd ${IOC} +CONFIG_DIR=${IOC}/config + +# add module paths to environment for use in ioc startup script +if [[ -f ${SUPPORT}/configure/RELEASE.shell ]]; then + source ${SUPPORT}/configure/RELEASE.shell +fi + +# override startup script +override=${CONFIG_DIR}/start.sh +# source YAML for IOC Builder for EPICS on Kubernetes (ibek) +ibek_yamls=(${CONFIG_DIR}/*.yaml) +# Startup script for EPICS IOC generated by ibek +ioc_startup=${CONFIG_DIR}/st.cmd + +# folder for runtime assets +export RUNTIME_DIR=${EPICS_ROOT}/runtime +mkdir -p ${RUNTIME_DIR} + +# expanded database file +epics_db=${RUNTIME_DIR}/ioc.db + +# in case there are multiple YAML, pick the first one in the glob +ibek_src=${ibek_yamls[0]} + +if [ -d ${CONFIG_DIR} ]; then + echo "checking config folder ${CONFIG_DIR}" + ls -al ${CONFIG_DIR} +else + echo "ERROR: No config folder found." + ibek_error "${description}" +fi + +# 1. start.sh override script ************************************************** +if [ -f ${override} ]; then + exec bash ${override} +# 2. ioc.yaml ****************************************************************** +elif [ -f ${ibek_src} ]; then + + if [[ ${#ibek_yams[@]} > 1 ]]; then + ibek_error "ERROR: Multiple YAML files found in ${CONFIG_DIR}." + fi + + # Database generation script generated by ibek + db_src=${RUNTIME_DIR}/ioc.subst + final_ioc_startup=${RUNTIME_DIR}/st.cmd + + # get the ibek support yaml files this ioc's support modules + defs=/epics/ibek-defs/*.ibek.support.yaml + ibek runtime generate ${ibek_src} ${defs} --out ${final_ioc_startup} --db-out ${db_src} + + # build expanded database using msi + if [ -f ${db_src} ]; then + includes=$(for i in ${SUPPORT}/*/db; do echo -n "-I $i "; done) + bash -c "msi -o${epics_db} ${includes} -I${RUNTIME_DIR} -S${db_src}" + fi + +# 2. st.cmd + ioc.subst ************************************************ +elif [ -f ${ioc_startup} ] ; then + + if [ -f ${CONFIG_DIR}/ioc.subst ]; then + # generate ioc.db from ioc.subst, including all templates from SUPPORT + includes=$(for i in ${SUPPORT}/*/db; do echo -n "-I $i "; done) + msi ${includes} -I${RUNTIME_DIR} -S ${CONFIG_DIR}/ioc.subst -o ${epics_db} + fi + final_ioc_startup=${ioc_startup} +# 4. incorrect config folder *************************************************** +else + echo "ERROR: No startup assets found in ${CONFIG_DIR}" + ibek_error "${description}" +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/ioc/stop.sh b/ioc/stop.sh new file mode 100644 index 0000000..f734409 --- /dev/null +++ b/ioc/stop.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +TOP=/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. + + # No action is required here for RTEMS because the start.sh script will + # monitor for SIG_TERM and reboot the IOC when it is received. +fi + + diff --git a/requirements.txt b/requirements.txt index 7ccac7b..452119c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -ibek==1.5.4 -# to install direct from github during development in the dev branch: -#git+https://github.com/epics-containers/ibek.git@dev +ibek==1.6.2 +# to install direct from github during development in a branch +# git+https://github.com/epics-containers/ibek.git@fix-extract-assets \ No newline at end of file diff --git a/requirements_ec.txt b/requirements_ec.txt deleted file mode 100644 index 67af14e..0000000 --- a/requirements_ec.txt +++ /dev/null @@ -1,3 +0,0 @@ -epics-containers-cli==2.6.9 -# to install direct from github during development in the dev branch: -#git+https://github.com/epics-containers/epics-containers-cli.git@dev diff --git a/tests/config/bl00i-ea-test-ioc.yaml b/tests/config/bl00i-ea-test-ioc.yaml new file mode 100644 index 0000000..50c768d --- /dev/null +++ b/tests/config/bl00i-ea-test-ioc.yaml @@ -0,0 +1,29 @@ +# yaml-language-server: $schema=https://github.com/epics-containers/ioc-template/releases/download/2024.1.1/ibek.ioc.schema.json + +ioc_name: "{{ ioc_yaml_file_name }}" + +description: Very generic instance for testing generic IOCs + +entities: + - type: epics.EpicsEnvSet + name: EPICS_TZ + value: "GMT0BST" + + - type: devIocStats.iocAdminSoft + IOC: "{{ ioc_name | upper }}" + + - type: epics.StartupCommand + command: dbLoadRecords("/epics/ioc/config/ioc.db") + + - type: epics.dbpf + pv: EXAMPLE:IBEK:A + value: "2.54" + + - type: epics.dbpf + pv: EXAMPLE:IBEK:B + value: "2.61" + + - type: epics.PostStartupCommand + command: | + dbgf EXAMPLE:IBEK:SUM + dbgf BL00I-EA-TEST-IOC:ST_SCRIPT1 diff --git a/tests/example-ibek-config/ioc.db b/tests/config/ioc.db similarity index 100% rename from tests/example-ibek-config/ioc.db rename to tests/config/ioc.db diff --git a/tests/example-config/calc.db b/tests/example-config/calc.db deleted file mode 100644 index ae23846..0000000 --- a/tests/example-config/calc.db +++ /dev/null @@ -1,26 +0,0 @@ -record(calc, "EXAMPLE2:SUM") { - field(DESC, "Sum A and B") - field(CALC, "A+B") - field(INPA, "EXAMPLE2:A") - field(INPB, "EXAMPLE2:B") -} - -record(ao, "EXAMPLE2:A") { - field(DESC, "A voltage") - field(PREC, "3") - field(EGU, "Volts") - field(DRVL, "-10") - field(DRVH, "+10") - field(VAL, "0.000") - field(FLNK, "EXAMPLE2:SUM") -} - -record(ao, "EXAMPLE2:B") { - field(DESC, "B voltage") - field(PREC, "3") - field(EGU, "Volts") - field(DRVL, "-10") - field(DRVH, "+10") - field(VAL, "0.000") - field(FLNK, "EXAMPLE2:SUM") -} \ No newline at end of file diff --git a/tests/example-config/ioc.substitutions b/tests/example-config/ioc.substitutions deleted file mode 100644 index 4fa1884..0000000 --- a/tests/example-config/ioc.substitutions +++ /dev/null @@ -1,16 +0,0 @@ - -# Macros: -# IOC Device prefix -file $(IOCSTATS)/db/iocAdminSoft.db -{ -pattern { IOC } - { "test-ioc" } -} - -# Macros: -# IOC Device prefix -file $(IOCSTATS)/db/iocAdminScanMon.db -{ -pattern { IOC } - { "test-ioc" } -} \ No newline at end of file diff --git a/tests/example-config/st.cmd b/tests/example-config/st.cmd deleted file mode 100644 index 61720df..0000000 --- a/tests/example-config/st.cmd +++ /dev/null @@ -1,12 +0,0 @@ -# Example hand coded IOC startup script for example-config -cd "/epics/ioc" - -epicsEnvSet "EPICS_CA_MAX_ARRAY_BYTES", '6000000' - -dbLoadDatabase "dbd/ioc.dbd" -ioc_registerRecordDeviceDriver(pdbbase) - -dbLoadRecords("config/calc.db") -dbLoadRecords("/tmp/ioc.db") - -iocInit() diff --git a/tests/example-ibek-config/ioc.yaml b/tests/example-ibek-config/ioc.yaml deleted file mode 100644 index 5740795..0000000 --- a/tests/example-ibek-config/ioc.yaml +++ /dev/null @@ -1,9 +0,0 @@ -ioc_name: test-ibek-ioc -description: a basic example for testing ioc-template - -entities: - - type: devIocStats.iocAdminSoft - IOC: test-ibek-ioc - - - type: epics.StartupCommand - command: dbLoadRecords("/epics/ioc/config/ioc.db") diff --git a/tests/run-tests.sh b/tests/run-tests.sh index f56fde5..76ca99c 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -5,36 +5,35 @@ # all present and correct and that mounting IOC config or ibek config # works as expected. -THIS_DIR=$(realpath $(dirname $0)) -ROOT=$(realpath ${THIS_DIR}/..) +THIS=$(realpath $(dirname $0)) +ROOT=$(realpath ${THIS}/..) +CONF=/epics/ioc/config +# log commands and stop on errorsr set -ex +# use docker if available else use podman +if ! docker version &>/dev/null; then alias docker=podman; fi + cd ${ROOT} -# Build the container (inherit arguments from CI workflow if set) ############## -ec dev build ${EC_TAG} - -# try out an ibek config IOC instance with the generic IOC ##################### -ec dev launch-local tests/example-config --args '-dit' ${EC_TAG} -ec dev wait-pv EXAMPLE2:A --attempts 20 -ec dev exec 'caput EXAMPLE2:A 1.3' -ec dev exec 'caput EXAMPLE2:B 1.2' -ec dev exec 'caget EXAMPLE2:SUM' | grep '2.5' - -# Test an ibek IOC ############################################################# -ec dev launch-local tests/example-ibek-config --args '-dit' ${EC_TAG} -ec dev wait-pv EXAMPLE:IBEK:A --attempts 20 -ec dev exec 'caput EXAMPLE:IBEK:A 1.3' -ec dev exec 'caput EXAMPLE:IBEK:B 1.2' -ec dev exec 'caget EXAMPLE:IBEK:SUM' | grep '2.5' -ec dev exec 'caget test-ibek-ioc:EPICS_VERS' | grep 'R7.0.7' - -# Stop the test IOC ############################################################ -ec dev stop - -# Done ######################################################################### -echo -echo "All tests passed!" + +# if a tag was passed in this implies it was already built +export TAG=${TAG:-ec_test} +if [[ ${TAG} == "ec_test" ]] ; then TARGET=runtime ./build; fi + +# try out a test ibek config IOC instance with the generic IOC +result=$(docker run --rm -v ${THIS}/config:${CONF} ${TAG} /epics/ioc/start.sh 2>&1) + +# check that the IOC output expected results +if echo "${result}" | grep -i error; then + echo "ERROR: errors in IOC startup" + exit 1 +elif [[ ! ${result} =~ "5.15" || ! ${result} =~ "/epics/runtime/st.cmd" ]]; then + echo "ERROR: dbgf output not as expected" + exit 1 +fi + +echo "Tests passed!" diff --git a/user_examples/.bashprofile_dev_container b/user_examples/.bashprofile_dev_container new file mode 100644 index 0000000..e5af527 --- /dev/null +++ b/user_examples/.bashprofile_dev_container @@ -0,0 +1,15 @@ +#!/bin/bash + +################################################################################ +# Custom profile for epics-containers devcontainer # +# # +# This will run inside the devcontainer after creation # +################################################################################ + +# apt-get update +# apt-get -y --no-install-recommends install vimdiff +# apt-get install what you like + +# add command line completion to the ibek tool +ibek --install-completion bash + diff --git a/user_examples/.bashrc_dev_container b/user_examples/.bashrc_dev_container new file mode 100644 index 0000000..0ca306a --- /dev/null +++ b/user_examples/.bashrc_dev_container @@ -0,0 +1,28 @@ +#!/bin/bash + +################################################################################ +###### This is sourced by all terminals epics-containers IOC devcontainer ###### +###### personal .bashrc_dev for setting up environment in devcontainers ###### +################################################################################ + +export LS_OPTIONS='--color=auto' +eval "$(dircolors)" 2> /dev/null +alias ls='ls $LS_OPTIONS' +alias ll='ls $LS_OPTIONS -l' +alias l='ls $LS_OPTIONS -lA' + +# Save all history forever +# Add these to your user's .bashrc to keep a single history inside and out of containers +export HISTCONTROL=ignoreboth:erasedups # Remove adjacent duplicate entries +export HISTSIZE= # Unlimited history +export HISTFILESIZE= # Unlimited history +# Use a unique bash history file so it doesn't get manually trucated by applications +export HISTFILE=${HOME}/.bash_eternal_history +shopt -s histappend # Append to history, don't overwrite it +export PROMPT_COMMAND='history -a' + +# add git completion +if [[ ! -f /tmp/git-completion.bash ]]; then + wget -q -P /tmp https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash +fi +source /tmp/git-completion.bash diff --git a/user_examples/README.md b/user_examples/README.md new file mode 100644 index 0000000..94bc520 --- /dev/null +++ b/user_examples/README.md @@ -0,0 +1,13 @@ +User Customization Examples +=========================== + +Users can customize their epics-containers developer containers by copying +the files in this folder into their home directory and customizing them as +required. + +epics-containers .devcontainer configuration will automatically pick up +these files from the home directory. + +- .bashrc_dev_container: runs on start of every new shell in the container. +- /bashprofile_dev_container: runs once immediately after the creation + of a devcontainer. \ No newline at end of file