IOC services¶
This guide covers how to install EPICS IOCs as a systemd service on a NixOS machine.
Pre-requisites¶
Having a NixOS machine with a flake configuration.
If you’re not sure how to do this, you can follow the Creating an Archiver Appliance instance tutorial, which is a good introduction on how to make a NixOS VM.
If you have such a configuration, make sure that:
You have the
epnix
flake inputYou have added
epnix
as an argument to your flake outputsYou have imported EPNix’ NixOS module
For example:
flake.nix
¶ {
# ...
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
+ inputs.epnix.url = "github:epics-extensions/EPNix/nixos-24.11";
# ...
outputs = {
self,
nixpkgs,
+ epnix,
}: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
modules = [
+ epnix.nixosModules.nixos
# ...
];
};
};
}
Exposing a service from your IOC¶
If your EPICS top and your NixOS configuration are in two different repositories, the recommended way to integrate your IOC is to add the configuration inside your EPICS top repository. This configuration will be exposed, so that you can use it inside your NixOS configuration repository.
From your EPICS top repository,
make sure your flake.nix
has these lines:
flake.nix
— Exposed NixOS settings from your EPICS top¶ overlays.default = final: _prev: {
myIoc = final.callPackage ./ioc.nix {};
};
nixosModules.iocService = {config, ...}: {
services.iocs.myIoc = {
description = "An optional description of your IOC";
package = self.packages.x86_64-linux.default;
# Directory where to find the 'st.cmd' file
workingDirectory = "iocBoot/iocMyIoc";
};
};
Make sure description
and workingDirectory
are correct.
The workingDirectory
must point
to the directory containing the st.cmd
file to run.
If you need a file other than st.cmd
,
see Custom cmd file.
See also
For a complete list of all IOC service-related options,
see services.iocs
.
Importing the exposed service¶
From your NixOS configuration repository,
in your flake.nix
,
add your EPICS top as a flake input,
and import the exposed service:
flake.nix
— Importing the IOC service from your NixOS configuration¶{
# ...
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
inputs.epnix.url = "github:epics-extensions/EPNix/nixos-24.11";
inputs.myTop.url = "git+ssh://git@my-gitlab-server.com/EPICS/myTop.git";
# ...
outputs = {
self,
nixpkgs,
epnix,
myTop,
}: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
modules = [
epnix.nixosModules.nixos
myTop.nixosModules.iocService
# ...
];
};
};
}
Then apply your NixOS configuration.
Adding an external IOC¶
As an alternative, if the IOC you want to run doesn’t expose a pre-configured service, or if you don’t want to use that configuration, you can define it directly in your NixOS configuration.
From your NixOS configuration repository, add your EPICS top to your flake inputs and overlays. For example:
flake.nix
— Adding your top to your flake inputs and overlays¶{
# ...
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
inputs.epnix.url = "github:epics-extensions/EPNix/nixos-24.11";
inputs.myTop.url = "git+ssh://git@my-gitlab-server.com/EPICS/myTop.git";
# ...
outputs = {
self,
nixpkgs,
epnix,
myTop,
}: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
modules = [
epnix.nixosModules.nixos
# ...
{
nixpkgs.overlays = [
(final: prev: {
# Add 'myTop' to the set of 'pkgs'
myTop = myTop.packages.x86_64-linux.default;
# Add your other tops here, for example:
#myOtherTop = myOtherTop.packages.x86_64-linux.default;
})
];
}
];
};
};
}
Then create an myIoc.nix
file:
myIoc.nix
— IOC configuration example¶{ pkgs, ... }:
{
# Replace 'myIoc' below with the name of your IOC
services.iocs.myIoc = {
description = "An optional description of your IOC";
package = pkgs.myTop;
# Directory where to find the 'st.cmd' file
workingDirectory = "iocBoot/iocMyIoc";
};
}
Make sure to import it in your flake.nix
.
See also
For a list of all IOC-related options,
see services.iocs
.
Custom cmd file¶
If your IOC is started through a script other than a file st.cmd
,
set the option services.iocs.<name>.startupScript
to you cmd script.
Custom procServ options¶
To change the procServ port,
use services.iocs.<name>.procServ.port
.
To change or add procServ options,
use services.iocs.<name>.procServ.options
.
For example:
procServ
options¶ services.iocs.myIoc = {
package = pkgs.myTop;
# Directory where to find the 'st.cmd' file
workingDirectory = "iocBoot/iocMyIoc";
procServ = {
# Set the port procServ listens to
port = 2001;
# Add an option `--killcmd "^b"`
options.killcmd = "^b";
};
};
Passing environment variables¶
You can set environment variables for your IOC
by using the option services.iocs.<name>.environment
.
For example:
services.iocs.myIoc = {
package = pkgs.myTop;
workingDirectory = "iocBoot/iocMyIoc";
environment.EPICS_CA_MAX_ARRAY_BYTES = 10000;
};
Adding programs to the PATH¶
If your IOC calls external programs, you need to add those programs to your IOC’s PATH.
To do this,
use the option services.iocs.<name>.path
.
For example:
{pkgs, ...}:
{
services.iocs.myIoc = {
package = pkgs.myTop;
workingDirectory = "iocBoot/iocMyIoc";
path = [pkgs.pciutils];
};
}
Tip
Programs installed via the environment.systemPackages
option are not available
to systemd services.
Further customization¶
For other customization of IOC services,
you can edit the generated systemd service
by setting the options under systemd.services.myIoc
.
For example, to make your machine reboot if your IOC fails to start:
services.iocs.myIoc = {
package = pkgs.myTop;
workingDirectory = "iocBoot/iocMyIoc";
};
# These options will modify the generated systemd service
systemd.services.myIoc = {
# These options will modify the [Unit] section
# See `man systemd.unit` for available options in this section
unitConfig = {
# If the IOC reboot 5 times
StartLimitBurst = 5;
# in 30 seconds
StartLimitIntervalSec = 30;
# reboot
StartLimitAction = "reboot";
};
};
For more information, examine the systemd.services options, and the man pages systemd.unit(5), systemd.service(5), and other related systemd documentation.
Systemd hardening¶
By default,
the services.iocs
module configures some systemd security hardening options.
For example,
the IOC can’t change the system clock,
or change the machine’s hostname.
To examine the list of the enabled systemd hardening options,
examine the nixos/modules/iocs.nix
file in the EPNix source code.
You can turn off systemd hardening options by overriding the setting:
services.iocs.myIoc = {
package = pkgs.myTop;
workingDirectory = "iocBoot/iocMyIoc";
};
# These options will modify the generated systemd service
systemd.services.myIoc = {
# In the [Service] section,
# ProtectClock was enabled by default,
# but we override it here
# to allow the IOC to change the system clock:
serviceConfig.ProtectClock = false;
};
For more information about hardening options, examine the man pages systemd.exec(5) and systemd.resource-control(5).