From 6b217399ee5a50a961b2959bade91546b48e28d2 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Wed, 11 Oct 2023 10:31:00 +0200 Subject: [PATCH] nixos/ca-gateway: init module --- nixos/module-list.nix | 1 + nixos/modules/ca-gateway.nix | 196 +++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 nixos/modules/ca-gateway.nix diff --git a/nixos/module-list.nix b/nixos/module-list.nix index aca74aa8..fadbdec0 100644 --- a/nixos/module-list.nix +++ b/nixos/module-list.nix @@ -1,5 +1,6 @@ [ ./modules/archiver-appliance.nix + ./modules/ca-gateway.nix ./modules/phoebus/alarm-logger.nix ./modules/phoebus/alarm-server.nix ./modules/phoebus/local-kafka.nix diff --git a/nixos/modules/ca-gateway.nix b/nixos/modules/ca-gateway.nix new file mode 100644 index 00000000..14e42261 --- /dev/null +++ b/nixos/modules/ca-gateway.nix @@ -0,0 +1,196 @@ +{ + config, + lib, + pkgs, + ... +}: let + cfg = config.services.ca-gateway; + pkg = pkgs.epnix.ca-gateway; + + # the CA gateway doesn't use the long/short options conventions + mkOptionName = k: "-${k}"; + # List are for IP address lists + mkList = k: v: [(mkOptionName k) (lib.concatStringsSep " " v)]; + toCommandLine = lib.cli.toGNUCommandLine {inherit mkOptionName mkList;}; + + commandLine = lib.escapeShellArgs (toCommandLine cfg.settings); +in { + options.services.ca-gateway = { + enable = lib.mkEnableOption "the Channel Access PV gateway"; + + openFirewall = lib.mkOption { + description = '' + Open the firewall for allowing Channel Access communications. + + Warning: this opens the firewall on all network interfaces. + ''; + type = lib.types.bool; + default = false; + }; + + settings = lib.mkOption { + description = '' + Configuration for the Channel Access PV gateway. + + These options are passed onto the gateway command-line. + + Available options can be seen here: + + ''; + default = {}; + type = lib.types.submodule { + freeformType = with lib.types; + nullOr (oneOf [ + bool + int + float + str + path + (listOf str) + ]); + options = { + pvlist = lib.mkOption { + description = '' + Name of file with all the allowed PVs in it. + + See the sample file gateway.pvlist in the source distribution + for a description of how to create this file: + + + ''; + type = with lib.types; nullOr (either path str); + default = null; + example = lib.literalExpression '' + pkgs.writeText "gateway.pvlist" ''' + EVALUATION ORDER DENY, ALLOW + + * DENY + + MY_PV ALLOW + + # ... + ''' + ''; + }; + + access = lib.mkOption { + description = '' + Name of file with all the EPICS access security rules in it. + + PVs in the pvlist file use groups and rules defined in this file. + + See the sample file gateway.pvlist in the source distribution: + + + ''; + type = with lib.types; nullOr (either path str); + default = null; + example = lib.literalExpression '' + pkgs.writeText "gateway.access" ''' + UAG(GatewayAdmin) {gateway,smith} + + # ... + ''' + ''; + }; + + sip = lib.mkOption { + description = '' + IP address list that gateway's CA server listens for PV requests. + + Sets env variable `EPICS_CAS_INTF_ADDR_LIST`. + + By default, the CA server is accessible from all network interfaces configured into its host. + ''; + type = with lib.types; nullOr (listOf str); + default = null; + example = ["192.168.1.1"]; + }; + + signore = lib.mkOption { + description = '' + IP address list that gateway's CA server ignores. + + Sets env variable `EPICS_CAS_IGNORE_ADDR_LIST`. + ''; + type = with lib.types; nullOr (listOf str); + default = null; + example = ["192.168.1.5" "192.168.1.42"]; + }; + + sport = lib.mkOption { + description = '' + The port which the gateway's CA server uses to listen for PV requests. + + Sets environment variable `EPICS_CAS_SERVER_PORT`. + ''; + type = lib.types.port; + default = 5064; + }; + + cip = lib.mkOption { + description = '' + IP address list that the gateway's CA client uses to find the real PVs. + + See CA reference manual. + + This sets environment variables `EPICS_CA_AUTO_LIST=NO` and `EPICS_CA_ADDR_LIST`. + ''; + type = with lib.types; nullOr (listOf str); + default = null; + example = ["192.168.1.4" "192.168.1.3"]; + }; + + cport = lib.mkOption { + description = '' + The port which the gateway's CA client uses to find the real PVs. + + Sets environment variable `EPICS_CA_SERVER_PORT`. + ''; + type = lib.types.port; + default = 5064; + }; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.settings ? server -> !cfg.settings.server; + message = "the ca-gateway 'server' option is incompatible with systemd"; + } + ]; + + systemd.services.ca-gateway = { + description = "Channel Access PV gateway"; + + wantedBy = ["multi-user.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"]; + + serviceConfig = { + ExecStart = "${pkg}/bin/gateway ${commandLine}"; + DynamicUser = true; + }; + }; + + networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ + cfg.settings.sport + cfg.settings.cport + ]; + + networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ + cfg.settings.sport + cfg.settings.cport + + # Repeater port + 5065 + ]; + }; +}