Skip to content

Instantly share code, notes, and snippets.

@griff
Created November 10, 2019 16:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save griff/09e7de290a83528341fddc04ed9d902b to your computer and use it in GitHub Desktop.
Save griff/09e7de290a83528341fddc04ed9d902b to your computer and use it in GitHub Desktop.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.mail-awstats;
package = pkgs.awstats;
domainsOpts = {name, config, ...}: {
options = {
domain = mkOption {
type = types.string;
default = name;
description = "The domain name to collect stats for";
example = "example.com";
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = "Extra configuration to be appendend to awstats.conf.";
};
updateAt = mkOption {
type = types.string;
default = "hourly";
example = "hourly";
description = ''
Specification of the time at which awstats will get updated.
(in the format described by <citerefentry>
<refentrytitle>systemd.time</refentrytitle>
<manvolnum>7</manvolnum></citerefentry>)
'';
};
site = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable the awstats web site.";
};
hostname = mkOption {
type = types.string;
default = config.domain;
description = "The hostname under which the awstats pages appear.";
};
urlPrefix = mkOption {
type = types.string;
default = "/awstats";
description = "The URL prefix under which the awstats pages appear.";
};
};
};
};
sites = filterAttrs (name: value: value.site.enable) cfg.domains;
in
{
options.services.mail-awstats = {
enable = mkOption {
type = types.bool;
default = cfg.service.enable;
description = ''
Enable the awstats program (but not service).
Currently only simple httpd (Apache) configs are supported,
and awstats plugins may not work correctly.
'';
};
vardir = mkOption {
type = types.path;
default = "/var/lib/mail-awstats";
description = "The directory where variable awstats data will be stored.";
};
rundir = mkOption {
type = types.path;
default = "/run/mail-awstats";
description = "The directory where runtime awstats data will be stored.";
};
domains = mkOption {
type = with types; attrsOf (submodule domainsOpts);
description = ''
Attribute set of domains to collect stats for.
'';
example = literalExample ''
{
"example.com" = {};
"test" = { domain = "example.com"; };
}
'';
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ package.bin ];
environment.etc = mapAttrs' (name: cfg': {
name = "awstats/awstats.mail-${name}.conf";
value = {
source = pkgs.runCommand "awstats.mail-${name}.conf"
{ preferLocalBuild = true; }
( ''
sed \
-e 's|^\(DirData\)=.*$|\1="${cfg.vardir}/stats"|' \
-e 's|^\(DirIcons\)=.*$|\1="icons"|' \
-e 's|^\(CreateDirDataIfNotExists\)=.*$|\1=1|' \
-e 's|^\(SiteDomain\)=.*$|\1="${cfg'.domain}"|' \
-e 's#^\(LogFile\)=.*$#\1="journalctl $OLD_CURSOR -u postfix.service | ${pkgs.perl}/bin/perl ${package.out}/share/awstats/tools/maillogconvert.pl standard |"#' \
-e 's|^\(LogType\)=.*$|\1=M|' \
-e 's|^\(LogFormat\)=.*$|\1="%time2 %email %email_r %host %host_r %method %url %code %bytesd"|' \
-e 's|^\(LevelForBrowsersDetection\)=.*$|\1=0|' \
-e 's|^\(LevelForOSDetection\)=.*$|\1=0|' \
-e 's|^\(LevelForRefererAnalyze\)=.*$|\1=0|' \
-e 's|^\(LevelForRobotsDetection\)=.*$|\1=0|' \
-e 's|^\(LevelForSearchEnginesDetection\)=.*$|\1=0|' \
-e 's|^\(LevelForFileTypesDetection\)=.*$|\1=0|' \
-e 's|^\(LevelForWormsDetection\)=.*$|\1=0|' \
-e 's|^\(ShowMenu\)=.*$|\1=1|' \
-e 's|^\(ShowSummary\)=.*$|\1=HB|' \
-e 's|^\(ShowMonthStats\)=.*$|\1=HB|' \
-e 's|^\(ShowDaysOfMonthStats\)=.*$|\1=HB|' \
-e 's|^\(ShowDaysOfWeekStats\)=.*$|\1=HB|' \
-e 's|^\(ShowHoursStats\)=.*$|\1=HB|' \
-e 's|^\(ShowDomainsStats\)=.*$|\1=0|' \
-e 's|^\(ShowHostsStats\)=.*$|\1=HB|' \
-e 's|^\(ShowAuthenticatedUsers\)=.*$|\1=0|' \
-e 's|^\(ShowRobotsStats\)=.*$|\1=0|' \
-e 's|^\(ShowEMailSenders\)=.*$|\1=HBML|' \
-e 's|^\(ShowEMailReceivers\)=.*$|\1=HBML|' \
-e 's|^\(ShowSessionsStats\)=.*$|\1=0|' \
-e 's|^\(ShowPagesStats\)=.*$|\1=0|' \
-e 's|^\(ShowFileTypesStats\)=.*$|\1=0|' \
-e 's|^\(ShowFileSizesStats\)=.*$|\1=0|' \
-e 's|^\(ShowBrowsersStats\)=.*$|\1=0|' \
-e 's|^\(ShowOSStats\)=.*$|\1=0|' \
-e 's|^\(ShowOriginStats\)=.*$|\1=0|' \
-e 's|^\(ShowKeyphrasesStats\)=.*$|\1=0|' \
-e 's|^\(ShowKeywordsStats\)=.*$|\1=0|' \
-e 's|^\(ShowMiscStats\)=.*$|\1=0|' \
-e 's|^\(ShowHTTPErrorsStats\)=.*$|\1=0|' \
-e 's|^\(ShowSMTPErrorsStats\)=.*$|\1=1|' \
< '${package.out}/wwwroot/cgi-bin/awstats.model.conf' > "$out"
echo '${cfg'.extraConfig}' >> "$out"
'');
};
}) cfg.domains;
services.nginx.virtualHosts = mapAttrs' (name: cfg': {
name = cfg'.site.hostname;
value = {
locations = {
"${cfg'.site.urlPrefix}/css" = {
alias = "${package.out}/wwwroot/css";
};
"${cfg'.site.urlPrefix}/icons" = {
alias = "${package.out}/wwwroot/icon";
};
"${cfg'.site.urlPrefix}" = {
alias = "${cfg.vardir}/wwwroot/${name}";
extraConfig = ''
autoindex on;
'';
};
};
};
}) sites;
systemd.services = mapAttrs' (name: cfg': {
name = "awstats-mail-${name}-update";
value = {
description = "awstats mail log collector for ${cfg'.domain}";
script = ''
mkdir -p "${cfg.rundir}"
mkdir -p "${cfg.vardir}/wwwroot/${name}"
if [[ -f "${cfg.rundir}/mail-${name}-cursor" ]]; then
CURSOR="$(cat "${cfg.rundir}/mail-${name}-cursor" | tr -d '\n')"
if [[ -n "$CURSOR" ]]; then
echo "Using cursor: $CURSOR"
export OLD_CURSOR="--cursor $CURSOR"
fi
fi
NEW_CURSOR="$(journalctl $OLD_CURSOR -u postfix.service --show-cursor | tail -n 1 | tr -d '\n' | sed -e 's#^-- cursor: \(.*\)#\1#')"
echo "New cursor: $NEW_CURSOR"
${package.bin}/bin/awstats -update -config=mail-${name}
if [ -n "$NEW_CURSOR" ]; then
echo -n "$NEW_CURSOR" > ${cfg.rundir}/mail-${name}-cursor
fi
'${package.out}/share/awstats/tools/awstats_buildstaticpages.pl' \
-config=mail-${name} -dir="${cfg.vardir}/wwwroot/${name}" -builddate=%YY%MM \
-awstatsprog='${package.bin}/bin/awstats'
'';
startAt = cfg'.updateAt;
};
}) sites;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment