diff --git a/.copier-answers.yml b/.copier-answers.yml index ceef758..7e05f23 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: 3.4.3-1-g8195b55 +_commit: 3.6.1-7-gb5b6581 _src_path: gh:epics-containers/ioc-template description: The Generic ioc for GigE cameras using the Aravis Library git_platform: github.com diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f7f096c..90e5081 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,10 +13,10 @@ } }, "remoteEnv": { - // allows X11 apps to run inside the container - "DISPLAY": "${localEnv:DISPLAY}", // provides a name for epics-containers to use in bash prompt etc. - "EC_PROJECT": "${localWorkspaceFolderBasename}" + "EC_PROJECT": "${localWorkspaceFolderBasename}", + "EPICS_CA_AUTO_ADDR_LIST": "NO", + "EPICS_CA_ADDR_LIST": "127.0.0.1" }, "features": { // add quality of life features for developers including git config integration @@ -26,9 +26,9 @@ } }, // IMPORTANT for this devcontainer to work with docker EC_REMOTE_USER must be - // set to vscode. You will run as vscode with full sudo rights. + // set to your user name. You will run 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. + // will be owned by your user id. "remoteUser": "${localEnv:EC_REMOTE_USER}", "customizations": { "vscode": { @@ -48,8 +48,9 @@ // One time global setup commands inside the container "postCreateCommand": "bash .devcontainer/postCreateCommand ${devcontainerId}", "runArgs": [ - // Allow the container to access the host X11 display and EPICS CA - "--net=host", + // IMPORTANT: this network must exist before the container is created + // source compose/environment.sh to create it before first use + "--network=channel_access_devcontainer", // Make sure SELinux does not disable write access to host filesystems like tmp "--security-opt=label=disable" ], @@ -60,6 +61,8 @@ // 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" + "source=${localWorkspaceFolder},target=/epics/generic-source,type=bind", + // Mount the opi folder so we can use phoebus from outside the container + "source=${localWorkspaceFolder}/opi/auto-generated,target=/epics/opi,type=bind" ] } diff --git a/.devcontainer/initializeCommand b/.devcontainer/initializeCommand index 732ec1f..5cd42cd 100644 --- a/.devcontainer/initializeCommand +++ b/.devcontainer/initializeCommand @@ -3,4 +3,11 @@ # custom initialization goes here - runs outside of the dev container # just before the container is launched but after the container is created +FOLDER=$(dirname $(readlink -f $0)) + echo "devcontainerID ${1}" + +# make sure the shared network is created +# TODO this would be better done with compose but compose and podman +# in devcontainers is not currently stable. +source $FOLDER/../compose/environment.sh diff --git a/.gitignore b/.gitignore index a8a054d..5c5a948 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,11 @@ ibek # 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. +# config folder is a container mount at /epics/ioc/config ioc/config +# the opi folder is also mounted into the container at /epics/ioc/opi +opi/auto-generated/* +!opi/auto-generated/.placeholder # podman may leave this around in aborted builds .build.swp diff --git a/Dockerfile b/Dockerfile index 879531b..8afd4e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,9 @@ WORKDIR ${SOURCE_FOLDER}/ibek-support # copy the global ibek files COPY ibek-support/_global/ _global +COPY ibek-support/pvxs/ pvxs/ +RUN pvxs/install.sh 1.3.1 + COPY ibek-support/iocStats/ iocStats RUN iocStats/install.sh 3.2.0 @@ -59,6 +62,8 @@ RUN cd ${IOC} && ./install.sh && make # install runtime proxy for non-native builds RUN bash ${IOC}/install_proxy.sh +# make sure that start.sh can write its generated files +RUN chmod a+rw /epics/* ##### runtime preparation stage ################################################ FROM developer AS runtime_prep diff --git a/README.md b/README.md index d96bede..e2ad1ab 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,20 @@ To update to the latest version of the template: pip install copier cd ioc-adaravis copier update -a --trust . -``` \ No newline at end of file +``` + +## Developer Container + +This repository includes a developer container configuration for Visual Studio Code. This allows you to run the Generic IOC locally and debug it. See https://epics-containers.github.io/main/tutorials/dev_container.html. + +### IMPORTANT: First Time Preparation + +The devcontainer uses a docker network that it can share with a ca-gateway in order that your PVs are accessible from your host machine. We arrange to create this network once and as long as you don't delete it or reset docker it will be available for all your devcontainers going forward. + +To create the network run the following commands: + +```bash +cd ioc-adsimdetector +source ./compose/environment.sh +``` + diff --git a/build b/build index 0b94f16..95ab316 100755 --- a/build +++ b/build @@ -22,13 +22,14 @@ cd $(dirname ${0}) # use docker if available else use podman if ! docker version &>/dev/null; then docker=podman; else docker=docker; fi -if $docker buildx version &>/dev/null; then builx=buildx; load=--load; fi +if $docker buildx version &>/dev/null; then buildx=buildx; load=--load ; fi +if [[ $DOCKER_BUILDKIT == "0" ]]; then buildx=; load=; fi # make sure new repos get their submodule ibek-support if [ ! -d ibek-support/_global ] ; then git submodule update --init ; fi # build and developer images set -x -$docker build $buildx -t ${TAG} "${@}" $load \ +$docker $buildx build -t ${TAG} "${@}" $load \ --build-arg IMAGE_EXT=$IMAGE_EXT \ $runtime --target $TARGET . diff --git a/compose/compose.yaml b/compose/compose.yaml new file mode 100644 index 0000000..2aacfd1 --- /dev/null +++ b/compose/compose.yaml @@ -0,0 +1,11 @@ +# This docker compose definition stands up a ca-gateway and phoebus instance. +# This enables interactive testing to the IOC developer container +# +# To lauch these services:- +# source ./environment.sh +# docker compose up -d +# + +include: + - services/gateway/compose.yml + - services/phoebus/compose.yml diff --git a/compose/environment.sh b/compose/environment.sh new file mode 100644 index 0000000..d437e6d --- /dev/null +++ b/compose/environment.sh @@ -0,0 +1,54 @@ +#! /bin/bash + +# Setup environment variables required to launch the services described in this +# repo. A standard install of docker compose and permission to run docker +# are the only other requirements (membership of the docker group). +# +# docker compose may be backed by podman or docker container engines, see +# https://epics-containers.github.io/main/tutorials/setup_workstation.html. + + +# This script must be sourced +if [ "$0" = "$BASH_SOURCE" ]; then + echo "ERROR: Please source this script (source ./environment.sh)" + exit 1 +fi + +# if there is a docker-compose module then load it +if [[ $(module avail docker-compose 2>/dev/null) != "" ]] ; then + module load docker-compose +fi + +function check_docker { + # return 0 if docker is detected, or 1 otherwise, + # cope with the possibility that podman is aliased to docker + if [[ $(docker version) =~ "Podman" ]]&> /dev/null; then + return 1 + fi +} + +if check_docker; then + USER_ID=$(id -u); USER_GID=$(id -g) +else + USER_ID=0; USER_GID=0 + alias docker=podman +fi + +# make sure we have a network to share beteen the devcontainer and gateway container +if ! docker network inspect channel_access_devcontainer &>/dev/null ; then + docker network create --subnet="170.21.0.0/16" channel_access_devcontainer +fi + +# ensure local container users can access X11 server +xhost +SI:localuser:$(id -un) + +# Set up the environment for compose ########################################### + +# set user id for the phoebus container for easy X11 forwarding. +export UIDGID=$USER_ID:$USER_GID +# choose test profile for docker compose +export COMPOSE_PROFILES=test +# for test profile our ca-gateway publishes PVS on the loopback interface +export EPICS_CA_ADDR_LIST=127.0.0.1 +# make a short alias for docker-compose for convenience +alias ec='docker compose' diff --git a/compose/services/gateway/compose.yml b/compose/services/gateway/compose.yml new file mode 100644 index 0000000..dcd2f3e --- /dev/null +++ b/compose/services/gateway/compose.yml @@ -0,0 +1,54 @@ +# ca gateway for exposing container network PVs to the host's loopback interface + +services: + + # ca-gateway for test / dev ################################################## + + ca-gateway: &ca-gateway + + container_name: ca-gateway + + image: ghcr.io/epics-containers/docker-ca-gateway:2.1.3ec1 + + expose: + - 5064-5065/udp + - 5064-5065 + + ports: + # bind to localhost to isolate channel access to this host only + - 127.0.0.1:5064:5064/udp + - 127.0.0.1:5064-5065:5064-5065 + + restart: unless-stopped + + networks: + channel_access_devcontainer: + + configs: + - source: ca-gateway_config + target: /config + + command: -cip 170.21.255.255 -pvlist /config/pvlist -access /config/access -log /dev/stdout -debug 1 + + profiles: + - test + - dev + + # debugging version of gateway container ##################################### + ca-gateway-debug: + + <<: *ca-gateway + + # this image is not distroless and has network tools installed + image: ghcr.io/epics-containers/docker-ca-gateway-debug:2.1.3ec1 + + profiles: + - debug + +configs: + ca-gateway_config: + file: ./config + +networks: + channel_access_devcontainer: + external: true \ No newline at end of file diff --git a/compose/services/gateway/config/access b/compose/services/gateway/config/access new file mode 100644 index 0000000..f69d0e8 --- /dev/null +++ b/compose/services/gateway/config/access @@ -0,0 +1,6 @@ +# See /EPICS/extensions/src/gateway/GATEWAY.access for more detailed example + +ASG(DEFAULT) { + RULE(1,READ) + RULE(1,WRITE) +} diff --git a/compose/services/gateway/config/pvlist b/compose/services/gateway/config/pvlist new file mode 100644 index 0000000..209c98b --- /dev/null +++ b/compose/services/gateway/config/pvlist @@ -0,0 +1,7 @@ +# See /EPICS/extensions/src/gateway/GATEWAY.pvlist for more detailed example + +EVALUATION ORDER ALLOW, DENY + +[0-9].* ALLOW +[a-z].* ALLOW +[A-Z].* ALLOW diff --git a/compose/services/phoebus/compose.yml b/compose/services/phoebus/compose.yml new file mode 100644 index 0000000..0f759d7 --- /dev/null +++ b/compose/services/phoebus/compose.yml @@ -0,0 +1,34 @@ +# for development and testing it is useful to bring up phoebus instanced to +# interact with the local IOCs PVs. + +services: + phoebus: + container_name: phoebus + image: ghcr.io/epics-containers/ec-phoebus:4.7.3ec2 + environment: + DISPLAY: $DISPLAY + tty: true + # pick a server port for phoebus so it does not reconnect to existing phoebus + command: phoebus-product/phoebus.sh -settings /config/settings.ini -resource /opi/auto-generated/index.bob -server 7010 + volumes: + - /tmp/.X11-unix:/tmp/.X11-unix + - ~/.Xauthority:/root/.Xauthority + - ../../../opi:/opi + - ../../../..:/workspaces + + # for X11 to work we need to run as the same UID as the host + # IMPORTANT: set UIDGID to your host user:group e.g. 1000:1000 + # BUT: always to 0:0 if you are using podman + user: ${UIDGID} + + # network host with a gateway for CA is the most reliable way to + # get X11 forwarding to work - even with ssh->container. + network_mode: host + + configs: + - source: phoebus_config + target: /config + +configs: + phoebus_config: + file: ./config diff --git a/compose/services/phoebus/config/settings.ini b/compose/services/phoebus/config/settings.ini new file mode 100644 index 0000000..c4d462b --- /dev/null +++ b/compose/services/phoebus/config/settings.ini @@ -0,0 +1,4 @@ +# using localhost for channel access to isolate it to the host for development + +# TODO restore this once we have PVA gateway and IOCS running in the CNI +org.phoebus.pv.ca/addr_list=127.0.0.1 diff --git a/ibek-support b/ibek-support index 6766d7a..2c1ca79 160000 --- a/ibek-support +++ b/ibek-support @@ -1 +1 @@ -Subproject commit 6766d7a14cc58c49a2c7422d4b95dc5a895ccf6a +Subproject commit 2c1ca79c335c6d24b63490ae34f7dcbce818edb3 diff --git a/ioc/start.sh b/ioc/start.sh index 9547123..5ab8dc2 100755 --- a/ioc/start.sh +++ b/ioc/start.sh @@ -33,7 +33,7 @@ description=' startup script. The file name should always be 'ioc.yaml'. The ioc instance can determine its own name with the following as the first line in 'ioc.yaml' - ioc_name: ""{{ __utils__.get_env('IOC_NAME') }}"" + ioc_name: ""{{ _global.get_env('IOC_NAME') }}"" at the top of the file and in turn "{{ ioc_name }}"" can be used in any of the fields within the file. For example: by default Kubernetes will be