Skip to content

Commit b46323f

Browse files
authored
Merge pull request #75 from epics-containers/2024-rework
rewrite change a generic ioc tutorial
2 parents 239d94a + 58d643e commit b46323f

File tree

4 files changed

+249
-61
lines changed

4 files changed

+249
-61
lines changed

docs/user/explanations/ioc-source.rst

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,69 @@
33
Dev Container vs Runtime Container
44
==================================
55

6-
TODO: explain how and why ioc-xxxx is mounted in dev container and what happens
7-
to the ioc folder.
6+
Introduction
7+
------------
8+
9+
The dev container is where all development of IOCs and support modules will
10+
take place. The runtime container is where the IOC will run when deployed
11+
to a target system.
12+
13+
The dev container mounts several host folders into the container to achieve
14+
the following goals:
15+
16+
- make the developer container look as similar as possible to the runtime
17+
container
18+
- allow the developer to make changes and recompile things without having
19+
to rebuild the container
20+
- make sure that all useful changes occur in the host filesystem so that
21+
they are not lost when the container is rebuilt or deleted
22+
23+
The details of which folders are mounted where in the container are
24+
shown here: `container-layout`.
25+
26+
The ioc-XXX project folder is found in the container at ``/workspaces/ioc-XXX``,
27+
along with all of it's peers (because the parent folder is mounted
28+
at ``/workspaces``).
29+
30+
31+
The ioc Folder
32+
--------------
33+
34+
The ioc folder contains the Generic IOC source code. It is typically the same
35+
for all Generic IOCs but is included in the ioc-XXX repo in /ioc so that it can be
36+
modified if necessary.
37+
38+
At container build time this folder is copied into the container at
39+
``/epics/generic-source/ioc`` and it is compiled so that the binaries are
40+
available at runtime.
41+
42+
In the dev container the ``/epics/generic-source`` folder has the project
43+
folder ioc-XXX mounted over the top of it. This means:
44+
45+
- the project folder ioc-XXX is mounted in two locations in the container
46+
- ``/workspaces/ioc-XXX``
47+
- ``/epics/generic-source``
48+
- the ioc source folder ``/epics/generic-source/ioc`` is also mounted over
49+
and now contains the source only. The compiled binaries are no longer
50+
visible inside the dev container.
51+
52+
It is for this reason that a newly created dev container needs to have the IOC
53+
binaries re-compiled. But this is a good thing, because now any changes you
54+
make to the IOC source code can be compiled and tested, but also those
55+
changes are now visible on the host filesystem inside the project folder
56+
``ioc-XXX/ioc``. This avoids loss of work.
57+
58+
Finally the ``ioc`` folder is always soft linked from ``/epics/ioc`` so that
59+
the source and binaries are always in a known location.
60+
61+
Summing Up
62+
----------
63+
64+
The above description makes things sound rather complicated. However,
65+
you can for the most part ignore the details and just remember:
66+
67+
- use ``/epics/ioc`` to compile and run the IOC.
68+
- you are free to make changes to the above folder and recompile
69+
- the changes you make will be visible on the host filesystem in the
70+
original project folder.
871

docs/user/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ side-bar.
7575
:maxdepth: 1
7676

7777
reference/faq
78+
reference/troubleshooting
7879
reference/configuration
7980
reference/environment
8081
reference/cli
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Troubleshooting
2+
===============
3+
4+
Permissions issues with GitHub
5+
-------------------------------
6+
7+
Problem: in the devcontainer you see the following error:
8+
9+
.. code-block:: none
10+
11+
[email protected]: Permission denied (publickey).
12+
fatal: Could not read from remote repository.
13+
14+
Solution: you may need to add your github ssh key to the ssh-agent as
15+
follows:
16+
17+
.. code-block:: none
18+
19+
eval "$(ssh-agent -s)"
20+
ssh-add ~/.ssh/id_rsa
21+
22+
Where ``id_rsa`` is the name of your private key file you use for connecting
23+
to GitHub.

docs/user/tutorials/ioc_changes2.rst

Lines changed: 160 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
Changing a Generic IOC
22
======================
33

4-
.. warning ::
5-
6-
TODO: This tutorial is a work in progress. It is not yet complete.
7-
84
This is a type 2 change from `ioc_change_types`.
95

106
The changes that you can make in an IOC instance are limited to what
@@ -24,123 +20,228 @@ Some of the reasons for doing this are:
2420
want to add support for a second device, this is allowed but you should
2521
consider the alternative of creating a new Generic IOC.
2622
If you keep your Generic IOCs simple and focused on a single device, they
27-
will be smaller and there will be less of them. IOCs can still be
28-
linked via CA and this is preferable to recompiling a Generic IOC
23+
will be smaller and there will be less of them. IOCs' records can still be
24+
linked via CA links and this is preferable to recompiling a Generic IOC
2925
for every possible combination of devices. Using Kubernetes to
3026
manage multiple small services is cleaner than having a handful of
3127
monolithic services.
3228

33-
This tutorial will make some changes to the generic IOC ``ioc-adsample``.
34-
This Generic IOC is a simplified copy of ``ioc-adsimdetector`` tailored for
35-
use in these tutorials.
3629

37-
For this exercise we will initially work locally inside the ``ioc-adsample``
38-
developer container.
30+
This tutorial will make some changes to the generic IOC ``ioc-adsimdetector``
31+
that you already used in earlier tutorials.
3932

40-
At the end we will push the changes and see the CI build a new version of the
41-
generic IOC container image. This allows for the demonstration of:
42-
43-
- Deploying an IOC instance using a new image published by the CI
44-
- Showing how to do a Pull Request back to the original repository.
33+
For this exercise we will work locally inside the ``ioc-adsimdetector``
34+
developer container. Following tutorials will show how to fork repositories
35+
and push changes back to GitHub
4536

4637
For this exercise we will be using an example IOC Instance to test our changes.
4738
Instead of working with a beamline repository, we will use the example ioc instance
48-
that comes with ``ioc-adsample``. It is a good idea for Generic IOC authors to
39+
inside ``ioc-adsimdetector``. It is a good idea for Generic IOC authors to
4940
include an example IOC Instance in their repository for testing changes in
5041
isolation.
5142

52-
5343
Preparation
5444
-----------
5545

56-
Because we want to push our changes we will first make a fork of the
57-
``ioc-adsample`` repository. We will then clone our fork locally and
58-
make the changes there.
59-
60-
To make a fork go to
61-
`ioc-adsample <https://github.com/epics-containers/ioc-adsample>`_
62-
and click the ``Fork`` button in the top right corner. This will create a fork
63-
of the repository under your own GitHub account.
64-
65-
Now, clone the fork, build the container image locally and open the
66-
developer container:
46+
First, clone the ``ioc-adsimdetector`` repository and make sure the container
47+
build is working:
6748

6849
.. code-block:: console
6950
70-
git clone [email protected]:<YOUR GITHUB ACCOUNT NAME>/ioc-adsample.git
71-
cd ioc-adsample
51+
git clone [email protected]:epics-containers/ioc-adsimdetector.git
52+
cd ioc-adsimdetector
7253
./build
7354
code .
74-
# click the green button in the bottom left corner of vscode and select
75-
# "Reopen in Container"
55+
# Choose "Reopen in Container"
56+
57+
Note that if you do not see the prompt to reopen in container, you can open
58+
the ``Remote`` menu with ``Ctrl+Alt+O`` and select ``Reopen in Container``.
7659

7760
The ``build`` script does two things.
7861

7962
- it fetches the git submodule called ``ibek-support``. This submodule is shared
8063
between all the EPICS IOC container images and contains the support YAML files
8164
that tell ``ibek`` how to build support modules inside the container
82-
environment.
65+
environment and how to use them at runtime.
8366
- it builds the Generic IOC container image locally.
8467

8568
.. note::
8669

8770
The ``build`` script is a convenience script that is provided in the
8871
Generic IOC Template project. It is exactly equivalent to cloning
89-
with ``--recursive`` flag and then running ``ec dev build``.
72+
with ``--recursive`` flag and then running ``ec dev build``. Equally,
73+
opening a vscode dev container will also build the container for you, but it
74+
does require the ``ibek-support`` submodule to be present - using
75+
``--recursive`` flag to git clone ensures this.
9076

9177
Verify the Example IOC Instance is working
9278
------------------------------------------
9379

9480
When a new Generic IOC developer container is opened, there are two things
9581
that need to be done before you can run an IOC instance inside of it.
9682

97-
- Build the IOC source code
83+
- Build the IOC binary
9884
- Select an IOC instance definition to run
9985

100-
The folder ``ioc`` inside of the ``ioc-adsample`` is where the IOC source code
101-
is created and built. When you open the developer container, this folder does
102-
not yet exist. The following command will create it and build the IOC:
86+
The folder ``ioc`` inside of the ``ioc-adsimdetector`` is where the IOC source code
87+
resided. However our containers always make a symlink to this folder at
88+
``/epics/ioc``. This is so that it is always in the same place and can easily be
89+
found by ibek (and the developer!). Therefore you can build the binary with the
90+
following command:
10391

10492
.. code-block:: console
10593
106-
ec ioc build
94+
cd /epics/ioc
95+
make
96+
97+
.. note::
98+
99+
Note that we are required to build the IOC.
100+
This is even though the container you are using already had the IOC
101+
source code built by its Dockerfile (``ioc-adsimdetector/Dockerfile``
102+
contains the same command).
103+
104+
For a detailed explanation of why this is the case see `ioc-source`
107105

108106
The IOC instance definition is a YAML file that tells ``ibek`` what the runtime
109107
assets (ie. EPICS DB and startup script) should look like. Previous tutorials
110108
selected the IOC instance definition from a beamline repository. In this case
111-
we will use the example IOC instance that comes with ``ioc-adsample``. The
109+
we will use the example IOC instance that comes with ``ioc-adsimdetector``. The
112110
following command will select the example IOC instance:
113111

114112
.. code-block:: console
115113
116-
ibek dev instance /epics/ioc-adsample/ioc_examples/bl01t-ea-ioc-02
114+
ibek dev instance /workspaces/ioc-adsimdetector/ioc_examples/bl01t-ea-ioc-02
117115
118-
In an earlier tutorial when learning about the dev container, we manually
119-
performed this step, see `choose-ioc-instance`. The above command does
120-
exactly the same thing: removes the existing config folder in ``/epics/ioc``
116+
The above command removes the existing config folder ``/epics/ioc/config`` and
121117
and symlinks in the chosen IOC instance definition's ``config`` folder.
122118

123119
Now run the IOC:
124120

125121
.. code-block:: console
126122
127-
ibek dev run
123+
cd /epics/ioc
124+
./start.sh
128125
129-
You should see a iocShell prompt and no error messages above.
126+
You should see an iocShell prompt and no error messages above.
130127

131-
.. note::
128+
Let us also make sure we can see the simulation images that the IOC is
129+
producing. For this we need the ``cd2v`` tool that we used earlier. You
130+
can use the same virtual environment that you created earlier, or create
131+
a new one and install again. Note that these commands are to be run
132+
in a terminal outside of the developer container.
132133

133-
The ``ec ioc build`` command required to re-create the IOC source code.
134-
This is even though the container you are using already had the IOC
135-
source code built by its Dockerfile (``ioc-adsample/Dockerfile``
136-
contains the same command).
134+
.. code-block:: console
135+
136+
python3 -m venv cd2v
137+
source ~/cd2v/bin/activate
138+
pip install c2dataviewer
139+
140+
Run the ``cd2v`` tool and connect it to our IOCs PVA output:
141+
142+
.. code-block:: console
143+
144+
cd2v --pv BL01T-EA-TST-02:PVA:OUTPUT &
145+
146+
147+
Back inside the developer container, you can now start the detector and
148+
the PVA plugin, by opening a new terminal and running the following:
149+
150+
.. code-block:: console
151+
152+
caput BL01T-EA-TST-02:PVA:EnableCallbacks 1
153+
caput BL01T-EA-TST-02:CAM:Acquire 1
154+
155+
You should see the moving image in the ``cd2v`` window. We now have a working
156+
IOC instance that we can use to test our changes.
157+
158+
Making a change to the Generic IOC
159+
----------------------------------
160+
161+
One interesting way of changing a Generic IOC is to modify the support YAML
162+
for one of the support modules. The support YAML describes the ``entities`` that
163+
an IOC instance can make use of in its instance YAML file. This will be
164+
covered in much more detail in `generic_ioc`.
165+
166+
For this exercise we will make a change to the ``ioc-adsimdetector`` support
167+
YAML file. We will change the startup script that it generates so that the
168+
simulation detector is automatically started when the IOC starts.
169+
170+
To make this change we just need to have the startup script set the values
171+
of the records ``BL01T-EA-TST-02:CAM:Acquire`` and
172+
``BL01T-EA-TST-02:PVA:EnableCallbacks`` to 1.
173+
174+
To make this change, open the file
175+
``ibek-support/ADSimDetector/ADSimDetector.ibek.support.yaml``
176+
and add a ``post_init`` section just after the ``pre_init`` section:
177+
178+
.. code-block:: yaml
179+
180+
post_init:
181+
- type: text
182+
value: |
183+
dbpf {{P}}{{R}}Acquire 1
184+
185+
Next make a change to the file ``ibek-support/ADCore/ADCore.ibek.support.yaml``.
186+
Find the NDPvaPlugin section and also add a ``post_init`` section:
187+
188+
.. code-block:: yaml
189+
190+
post_init:
191+
- type: text
192+
value: |
193+
dbpf {{P}}{{R}}EnableCallbacks 1
194+
195+
196+
If you now go to the terminal where you ran your IOC, you can stop it with
197+
``Ctrl+C`` and then start it again with ``./start.sh``. You should see the
198+
following output at the end of the startup log:
199+
200+
.. code-block:: console
201+
202+
dbpf BL01T-EA-TST-02:CAM:Acquire 1
203+
DBF_STRING: "Acquire"
204+
dbpf BL01T-EA-TST-02:PVA:EnableCallbacks 1
205+
DBF_STRING: "Enable"
206+
epics>
207+
208+
You should also see the ``cd2v`` window update with the moving image again.
209+
210+
If you wanted to publish these changes you would have to commit both the
211+
``ibek-support`` submodule and the ``ioc-adsimdetector`` repository and push
212+
them in that order because of the sub-module dependency. But we won't be
213+
pushing these changes as they are just for demonstration purposes. In later
214+
tutorials we will cover making forks and doing pull requests for when you have
215+
changes to share back with the community.
216+
217+
Note: this is a slightly artificial example, as it would change the behaviour
218+
for all instances of a PVA plugin and a simDetector. In a real IOC you would
219+
do this on a per instance basis.
220+
221+
Let us quickly do the instance YAML change to demonstrate the correct approach
222+
to this auto-starting detector.
223+
224+
Undo the support yaml changes:
225+
226+
.. code-block:: console
227+
228+
cd /workspaces/ioc-adsimdetector/ibek-support
229+
git reset --hard
230+
231+
Add the following to
232+
``/workspaces/ioc-adsimdetector/ioc_examples/bl01t-ea-ioc-02/config/ioc.yaml``:
233+
234+
.. code-block:: yaml
235+
236+
- type: epics.dbpf
237+
pv: BL01T-EA-TST-02:CAM:Acquire
238+
value: "1"
137239
138-
For a detailed explanation of why this is the case see
139-
`ioc-source`
240+
- type: epics.dbpf
241+
pv: BL01T-EA-TST-02:PVA:EnableCallbacks
242+
value: "1"
140243
244+
Now restart the IOC and you should see the same behaviour as before. Here
245+
we have made the change on a per instance basis, and used the ``dbpf`` entity
246+
declared globally in ``ibek-support/_global/epics.ibek.support.yaml``.
141247

142-
TODO: complete by adding iocStats and using it in the ioc instance, then
143-
pushing and verifying CI runs and publishes a new image.
144-
TODO: now that cacheing is working, consider using ioc-adsimdetector instead
145-
of ioc-adsample. This is simpler - the change could be the addition of
146-
auto start of the sim detector IOC just like the presentation.

0 commit comments

Comments
 (0)