it-infra/nixbld-etc-nixos/rt.nix

312 lines
9.1 KiB
Nix

# based on https://gist.github.com/ajs124/ff04ab14435908d914cf5cedbc56a52e
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.rt;
configFile = pkgs.writeTextFile {
name = "RT_SiteConfig.pm";
text = ''
use utf8;
# System (Base configuration)
Set($rtname, '${cfg.rtName}'); # Changing this will break responses to existing tickets
Set($Organization, '${cfg.organization}'); # Changing this will break all existing tickets
Set($CorrespondAddress, '${cfg.correspondAddress}');
Set($CommentAddress, '${cfg.commentAddress}');
Set($WebDomain, '${cfg.domain}');
Set($Timezone, '${cfg.timeZone}');
Set($DatabaseType, 'Pg');
Set($DatabaseHost, 'localhost');
Set($DatabaseUser, 'rt_user');
Set($DatabaseName, 'rt5');
# Read database password from file
open my $fh, '<', '${cfg.dbPasswordFile}' or die 'Can\'t open file $!';
my $dbpw = do { local $/; <$fh> };
$dbpw =~ s/^\s+|\s+$//g;
Set($DatabasePassword, $dbpw);
# System (Logging)
Set($LogToSTDERR, undef); # Don't log twice
# System (Incoming mail gateway)
Set($OwnerEmail, '${cfg.ownerEmail}');
Set($MaxAttachmentSize, 15360000);
Set($CheckMoreMSMailHeaders, 1);
Set($RTAddressRegexp, '^(helpdesk|sales)\@(m-labs.hk)$');
Set($LoopsToRTOwner, 0);
# System (Outgoing mail)
Set($SetOutgoingMailFrom, 'helpdesk@m-labs.hk');
# System (Sendmail configuration)
Set($SendmailPath, '${cfg.sendmailPath}');
Set($SendmailArguments, '${concatStringsSep " " cfg.sendmailArguments}');
# System (Application logic)
Set($ParseNewMessageForTicketCcs, 1);
# System (Extra Security)
Set($RestrictLoginReferrer, 1);
# System (Date and time handling)
Set($DefaultTimeUnitsToHours, 1);
Set($TimeInICal, 1);
Set($DateTimeFormat, 'RFC2822');
# System (Authorization and user configuration)
Set($AutoLogoff, 262800); # 6 months
Set($WebSecureCookies, 1);
# Web Interface (Base configuration)
Set($DefaultQueue, 'Helpdesk'); # Defaults to the first from the alphabet
Set($RememberDefaultQueue, 1);
Set($CanonicalizeRedirectURLs, 1);
Set($CanonicalizeURLsInFeeds, 1);
Set($WebBaseURL, '${cfg.baseUrl}');
Set($LogoLinkURL, '${cfg.baseUrl}');
# Web Interface (Home page)
Set($DefaultSummaryRows, 50);
# Web Interface (Ticket search)
Set($DefaultSearchResultOrder, 'DESC'); # Display newer tickets first
Set($SearchResultsAutoRedirect, 1); # Don't show result list when there is only one match
Set(%FullTextSearch,
Enable => 1,
Indexed => 1,
Column => 'ContentIndex',
Table => 'AttachmentsIndex',
);
# Web Interface (Ticket options)
Set($ShowMoreAboutPrivilegedUsers, 1);
Set($MoreAboutRequestorGroupsLimit, undef);
Set($HideUnsetFieldsOnDisplay, 1);
# Web Interface (Articles)
Set($ArticleOnTicketCreate, 0);
# Web Interface (Message box properties)
Set($MessageBoxRichText, 0);
Set($MessageBoxIncludeSignatureOnComment, 0);
# Web Interface (Transaction display)
Set($MaxInlineBody, 0);
# Web Interface (Administrative interface)
Set($ShowRTPortal, 0);
Set($ShowEditSsytemConfig, 0);
# Features (External storage)
Set(%ExternalStorage,
Type => 'Disk',
Path => '/var/lib/rt/attachments',
);
Set($ExternalStorageCutoffSize, 0);
# Features (Cryptography)
Set(%Crypt, RejectOnMissingPrivateKey => 0, RejectOnBadData => 0, AllowEncryptDataInDB => 0);
Set(%SMIME, Enable => 1, Keyring => '${pkgs.cacert}/etc/ssl/certs/');
Set(%GnuPG, Enable => 1);
Set(%GnuPGOptions,
'keyserver' => 'hkp://keys.openpgp.org',
'always-trust' => undef,
'auto-key-locate' => 'keyserver',
'keyserver-options' => 'auto-key-retrieve'
);
${cfg.extraConfig}
1;
'';
checkPhase = ''
${pkgs.perl}/bin/perl -c $out
'';
};
in {
options.services.rt = with types; {
enable = mkEnableOption "rt system";
package = mkOption {
description = "Package to use";
default = pkgs.rt;
defaultText = "pkgs.rt";
type = package;
};
baseUrl = mkOption {
description = "Base URL for web interface";
default = "https://${cfg.domain}";
defaultText = "https://\${cfg.domain}";
type = str;
};
commentAddress = mkOption {
description = "Default address from/to which comments are sent";
type = str;
};
correspondAddress = mkOption {
description = "Default address from/to which correspondences are sent";
type = str;
};
dbPasswordFile = mkOption {
description = "File containing the database password";
type = str;
default = "/etc/nixos/secret/rtpasswd";
internal = true;
};
domain = mkOption {
description = "Which domain RT is running on";
type = str;
};
ownerEmail = mkOption {
description = "Address of a human who manages RT. RT will send errors generated by the mail gateway to this address; it will also be displayed as the contact person on the RT's login page.";
type = str;
};
port = mkOption {
description = "Which port rt-server should listen on";
type = port;
default = 4201;
};
sendmailPath = mkOption {
description = "Sendmail binary used to send... mail";
default = "${pkgs.msmtp}/bin/sendmail";
defaultText = "\${pkgs.msmtp}/bin/sendmail";
type = str;
};
sendmailArguments = mkOption {
description = "Arguments to call sendmailPath with";
default = [ ];
type = listOf (oneOf [ str path ]);
};
timeZone = mkOption {
description = "Used to convert times entered by users into GMT, as they are stored in the database, and back again; users can override this";
type = str;
default = config.time.timeZone;
defaultText = "[time.timeZone]";
};
rtName = mkOption {
description = "Name of this RT instance";
type = str;
};
organization = mkOption {
description = "Name of the organization of this instance";
type = str;
};
extraConfig = mkOption {
description = "Verbatim config to append to generated on";
type = lines;
default = "";
};
};
config = let
components = [
"rt-clean-sessions"
"rt-email-dashboards"
"rt-email-digest-daily"
"rt-email-digest-weekly"
"rt-externalize-attachments"
"rt-fulltext-indexer"
"rt-validator"
];
mkTimer = name: {
"${name}" = {
wantedBy = [ "timers.target" ];
timerConfig.Unit = [ "${name}.service" ];
};
};
mkService = name: extraArgs: {
"${name}" = {
stopIfChanged = false;
serviceConfig = {
ExecStart = if extraArgs == ""
then "${cfg.package}/bin/${name}"
else mkForce "${cfg.package}/bin/${name} ${extraArgs}";
User = "rt";
Group = "rt";
PrivateNetwork = false;
MemoryDenyWriteExecute = false;
ReadOnlyPaths = [ cfg.dbPasswordFile ];
};
environment = {
RT_SITE_CONFIG = configFile;
};
path = with pkgs; [
w3m
];
};
};
in (mkIf cfg.enable {
systemd.services = mkMerge ((map (c: mkService c "") components) ++ [
(mkService "rt-server" "--port ${toString cfg.port} --server Starman")
(mkService "rt-clean-sessions" "--skip-user")
(mkService "rt-fulltext-indexer" "--limit 500000")
(mkService "rt-validator" "--check")
{
rt-server = {
serviceConfig = {
StateDirectory = [ "rt/" "rt/attachments/" "rt/shredder/" "rt/smime/" ];
RuntimeDirectory = [ "rt/" "rt/mason_data/" ];
LogsDirectory = "rt/";
};
wantedBy = [ "multi-user.target" ];
};
}
{
rt-externalize-attachments = {
serviceConfig.StateDirectory = "rt/attachments/";
};
}
{ rt-email-digest-daily.serviceConfig.ExecStart = mkForce "${cfg.package}/bin/rt-email-digest -m daily"; }
{ rt-email-digest-weekly.serviceConfig.ExecStart = mkForce "${cfg.package}/bin/rt-email-digest -m weekly"; }
]);
systemd.timers = mkMerge ((map mkTimer components) ++ [
{
rt-clean-sessions.timerConfig.OnCalendar = "daily";
rt-email-dashboards.timerConfig.OnCalendar = "hourly";
rt-email-digest-daily.timerConfig.OnCalendar = "daily";
rt-email-digest-weekly.timerConfig.OnCalendar = "weekly";
rt-externalize-attachments.timerConfig.OnCalendar = "01:00";
rt-fulltext-indexer.timerConfig.OnCalendar = "02:00";
rt-validator.timerConfig.OnCalendar = "*-*-01 03:00:00";
}
]);
users.users.rt = {
isSystemUser = true;
};
users.groups.rt = {};
systemd.tmpfiles.rules = [
"d /var/lib/secrets/rt 0500 rt rt -"
"d /var/lib/rt/gpg 0700 rt rt -"
];
});
}