Skip to content

Commit

Permalink
Merge pull request #10 from epics-extensions/nixos-integration-in-checks
Browse files Browse the repository at this point in the history
Nixos integration in checks
  • Loading branch information
minijackson committed Jun 8, 2023
2 parents ed7e9bd + 164f7ca commit 8ec9f81
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 94 deletions.
15 changes: 13 additions & 2 deletions ioc/modules/checks.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
config,
epnix,
epnixConfig,
lib,
pkgs,
...
Expand Down Expand Up @@ -41,8 +43,17 @@ in {

importCheck = path:
import path {
inherit pkgs;
inherit (config.epnix.outputs) build;
inherit pkgs epnix epnixConfig;

build =
lib.warn
''
using 'build' in a check is deprecated.
Please see the current EPNix IOC template for the new way of implementing checks:
- ${epnix}/templates/top/checks/simple.nix
''
config.epnix.outputs.build;
};
in
listToAttrs
Expand Down
165 changes: 92 additions & 73 deletions ioc/modules/nixos-integration.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,96 +5,115 @@
pkgs,
...
}: let
cfg = config.epnix.nixos;
globalConfig = config;

iocTop = "${config.epnix.outputs.build}";
in {
options.epnix.nixos = {
service = {
app = lib.mkOption {
type = lib.types.str;
example = "my_exec";
description = ''
Name of the app to start the IOC with.
'';
services = lib.mkOption {
description = ''
Services for which to create a systemd service config.
'';
example = {
ioc = {
app = "examples";
ioc = "iocExamples";
};
};
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
options = {
app = lib.mkOption {
type = lib.types.str;
example = "my_exec";
description = ''
Name of the app to start the IOC with.
'';
};

ioc = lib.mkOption {
type = lib.types.str;
example = "iocMyDevice";
description = ''
Name of the directory under `iocBoot` containing the start commands.
'';
};
ioc = lib.mkOption {
type = lib.types.str;
example = "iocMyDevice";
description = ''
Name of the directory under `iocBoot` containing the start commands.
'';
};

startCommandsFile = lib.mkOption {
default = "st.cmd";
example = "other_st.cmd";
type = lib.types.str;
description = ''
Name of the file containing the EPICS start commands.
'';
};
startCommandsFile = lib.mkOption {
default = "st.cmd";
example = "other_st.cmd";
type = lib.types.str;
description = ''
Name of the file containing the EPICS start commands.
'';
};

config = lib.mkOption {
type = lib.types.attrs;
readOnly = true;
description = ''
Resulting configuration for the systemd service.
'';
};
config = lib.mkOption {
type = lib.types.attrs;
readOnly = true;
description = ''
Resulting configuration for the systemd service.
'';
};

procServ = {
port = lib.mkOption {
default = 2000;
type = lib.types.port;
description = ''
Port where the procServ utility will listen.
'';
};
procServ = {
port = lib.mkOption {
default = 2000;
type = lib.types.port;
description = ''
Port where the procServ utility will listen.
'';
};

options = lib.mkOption {
default = {};
example = {
allow = true;
info-file = "/var/run/ioc/procServ_info";
options = lib.mkOption {
default = {};
example = {
allow = true;
info-file = "/var/run/ioc/procServ_info";
};
type = with lib.types; attrsOf (oneOf [str int bool (listOf str)]);
description = ''
Extra command-line options to pass to procServ.
Note: using `lib.mkForce` will override the default options needed
for the systemd service to work. If you wish to do this, you will
need to specify needed arguments like `foreground` and `chdir`.
'';
};
};
type = with lib.types; attrsOf (oneOf [str int bool (listOf str)]);
description = ''
Extra command-line options to pass to procServ.
};

Note: using `lib.mkForce` will override the default options needed
for the systemd service to work. If you wish to do this, you will
need to specify needed arguments like `foreground` and `chdir`.
'';
config.procServ.options = {
foreground = true;
oneshot = true;
logfile = "-";
holdoff = 0;
chdir = "${iocTop}/iocBoot/${config.ioc}";
};
};
};
};

config.epnix.nixos.service.procServ.options = {
foreground = true;
oneshot = true;
logfile = "-";
chdir = "${iocTop}/iocBoot/${cfg.service.ioc}";
};
config.config = {
wantedBy = ["multi-user.target"];

config.epnix.nixos.service.config = {
wantedBy = ["multi-user.target"];
after = ["network.target"];
# When initializing the IOC, PV Access looks for network interfaces that
# have IP addresses. "network.target" may be too early, especially for
# systems with DHCP.
wants = ["network-online.target"];
after = ["network-online.target"];

description = "EPICS IOC ${config.epnix.meta.name}";
description = "EPICS IOC ${globalConfig.epnix.meta.name}";

serviceConfig = {
ExecStart = let
procServ = "${pkgs.epnix.procServ}/bin/procServ";
arch = epnix.lib.toEpicsArch config.epnix.outputs.build.stdenv.hostPlatform;
in ''
${procServ} ${lib.cli.toGNUCommandLineShell {} cfg.service.procServ.options} \
${toString cfg.service.procServ.port} \
${iocTop}/bin/${arch}/${cfg.service.app} ${cfg.service.startCommandsFile}
'';
Restart = "on-failure";
serviceConfig = {
ExecStart = let
procServ = "${pkgs.epnix.procServ}/bin/procServ";
arch = epnix.lib.toEpicsArch globalConfig.epnix.outputs.build.stdenv.hostPlatform;
in ''
${procServ} ${lib.cli.toGNUCommandLineShell {} config.procServ.options} \
${toString config.procServ.port} \
${iocTop}/bin/${arch}/${config.app} ${config.startCommandsFile}
'';
Restart = "on-failure";
};
};
}));
};
};
}
2 changes: 1 addition & 1 deletion ioc/tests/support/StreamDevice/simple/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
epnixConfig.imports = [./top/epnix.nix];
};

service = result.config.epnix.nixos.service.config;
service = result.config.epnix.nixos.services.ioc.config;

ioc = result.outputs.build;
in
Expand Down
6 changes: 4 additions & 2 deletions ioc/tests/support/StreamDevice/simple/top/epnix.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

support.modules = with pkgs.epnix.support; [StreamDevice epics-systemd];

nixos.service.app = "simple";
nixos.service.ioc = "iocsimple";
nixos.services.ioc = {
app = "simple";
ioc = "iocsimple";
};
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

support.modules = with pkgs.epnix.support; [autosave];

nixos.service.app = "simple";
nixos.service.ioc = "iocSimple";
nixos.services.ioc = {
app = "simple";
ioc = "iocSimple";
};
};
}
2 changes: 1 addition & 1 deletion ioc/tests/support/autosave/simple/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
epnixConfig.imports = [./autosaveSimpleTestTop/epnix.nix];
};

service = result.config.epnix.nixos.service.config;
service = result.config.epnix.nixos.services.ioc.config;

ioc = result.outputs.build;
in
Expand Down
2 changes: 1 addition & 1 deletion ioc/tests/support/seq/simple/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
epnixConfig.imports = [./top/epnix.nix];
};

service = result.config.epnix.nixos.service.config;
service = result.config.epnix.nixos.services.ioc.config;

ioc = result.outputs.build;
in
Expand Down
6 changes: 4 additions & 2 deletions ioc/tests/support/seq/simple/top/epnix.nix
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

support.modules = with pkgs.epnix.support; [seq];

nixos.service.app = "simple";
nixos.service.ioc = "iocsimple";
nixos.services.ioc = {
app = "simple";
ioc = "iocsimple";
};
};
}
3 changes: 3 additions & 0 deletions lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ with lib; let
in {
# See: https://github.com/NixOS/nixpkgs/pull/190358
pkgs = finalPkgs.__splicedPackages;

# Used when we want to apply the same config in checks
inherit epnixConfig;
};
})

Expand Down
19 changes: 9 additions & 10 deletions templates/top/checks/simple.nix
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
{
build,
epnix,
# Your EPNix configuration, as defined in flake.nix
epnixConfig,
pkgs,
...
}:
pkgs.nixosTest {
name = "simple";

nodes.machine = {
nodes.machine = {config, ...}: {
imports = [
epnix.nixosModules.ioc
epnixConfig
];
environment.systemPackages = [pkgs.epnix.epics-base];

systemd.services.ioc = {
wantedBy = ["multi-user.target"];
serviceConfig = {
ExecStart = "${build}/iocBoot/iocexample/st.cmd";
WorkingDirectory = "${build}/iocBoot/iocexample";
StandardInputText = "epicsThreadSleep(100)";
};
};
systemd.services.ioc = config.epnix.nixos.services.ioc.config;
};

testScript = ''
Expand Down
8 changes: 8 additions & 0 deletions templates/top/flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@
# ---
checks.files = [./checks/simple.nix];

# Used when generating NixOS systemd services, for example for
# deployment to production, or for the NixOS tests in checks/
# ---
nixos.services.ioc = {
app = "example";
ioc = "iocExample";
};

# You can specify environment variables in your development shell like this:
# ---
#devShell.environment.variables = {
Expand Down

0 comments on commit 8ec9f81

Please sign in to comment.