1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.asterisk;
7
8 asteriskUser = "asterisk";
9 asteriskGroup = "asterisk";
10
11 varlibdir = "/var/lib/asterisk";
12 spooldir = "/var/spool/asterisk";
13 logdir = "/var/log/asterisk";
14
15 # Add filecontents from files of useTheseDefaultConfFiles to confFiles, do not override
16 defaultConfFiles = subtractLists (attrNames cfg.confFiles) cfg.useTheseDefaultConfFiles;
17 allConfFiles = {
18 # Default asterisk.conf file
19 "asterisk.conf".text = ''
20 [directories]
21 astetcdir => /etc/asterisk
22 astmoddir => ${cfg.package}/lib/asterisk/modules
23 astvarlibdir => /var/lib/asterisk
24 astdbdir => /var/lib/asterisk
25 astkeydir => /var/lib/asterisk
26 astdatadir => /var/lib/asterisk
27 astagidir => /var/lib/asterisk/agi-bin
28 astspooldir => /var/spool/asterisk
29 astrundir => /run/asterisk
30 astlogdir => /var/log/asterisk
31 astsbindir => ${cfg.package}/sbin
32 ${cfg.extraConfig}
33 '';
34
35 # Loading all modules by default is considered sensible by the authors of
36 # "Asterisk: The Definitive Guide". Secure sites will likely want to
37 # specify their own "modules.conf" in the confFiles option.
38 "modules.conf".text = ''
39 [modules]
40 autoload=yes
41 '';
42
43 # Use syslog for logging so logs can be viewed with journalctl
44 "logger.conf".text = ''
45 [general]
46
47 [logfiles]
48 syslog.local0 => notice,warning,error
49 '';
50 } //
51 mapAttrs (name: text: { inherit text; }) cfg.confFiles //
52 listToAttrs (map (x: nameValuePair x { source = cfg.package + "/etc/asterisk/" + x; }) defaultConfFiles);
53
54in
55
56{
57 options = {
58 services.asterisk = {
59 enable = mkOption {
60 type = types.bool;
61 default = false;
62 description = lib.mdDoc ''
63 Whether to enable the Asterisk PBX server.
64 '';
65 };
66
67 extraConfig = mkOption {
68 default = "";
69 type = types.lines;
70 example = ''
71 [options]
72 verbose=3
73 debug=3
74 '';
75 description = lib.mdDoc ''
76 Extra configuration options appended to the default
77 `asterisk.conf` file.
78 '';
79 };
80
81 confFiles = mkOption {
82 default = {};
83 type = types.attrsOf types.str;
84 example = literalExpression
85 ''
86 {
87 "extensions.conf" = '''
88 [tests]
89 ; Dial 100 for "hello, world"
90 exten => 100,1,Answer()
91 same => n,Wait(1)
92 same => n,Playback(hello-world)
93 same => n,Hangup()
94
95 [softphones]
96 include => tests
97
98 [unauthorized]
99 ''';
100 "sip.conf" = '''
101 [general]
102 allowguest=no ; Require authentication
103 context=unauthorized ; Send unauthorized users to /dev/null
104 srvlookup=no ; Don't do DNS lookup
105 udpbindaddr=0.0.0.0 ; Listen on all interfaces
106 nat=force_rport,comedia ; Assume device is behind NAT
107
108 [softphone](!)
109 type=friend ; Match on username first, IP second
110 context=softphones ; Send to softphones context in
111 ; extensions.conf file
112 host=dynamic ; Device will register with asterisk
113 disallow=all ; Manually specify codecs to allow
114 allow=g722
115 allow=ulaw
116 allow=alaw
117
118 [myphone](softphone)
119 secret=GhoshevFew ; Change this password!
120 ''';
121 "logger.conf" = '''
122 [general]
123
124 [logfiles]
125 ; Add debug output to log
126 syslog.local0 => notice,warning,error,debug
127 ''';
128 }
129 '';
130 description = lib.mdDoc ''
131 Sets the content of config files (typically ending with
132 `.conf`) in the Asterisk configuration directory.
133
134 Note that if you want to change `asterisk.conf`, it
135 is preferable to use the {option}`services.asterisk.extraConfig`
136 option over this option. If `"asterisk.conf"` is
137 specified with the {option}`confFiles` option (not recommended),
138 you must be prepared to set your own `astetcdir`
139 path.
140
141 See
142 <http://www.asterisk.org/community/documentation>
143 for more examples of what is possible here.
144 '';
145 };
146
147 useTheseDefaultConfFiles = mkOption {
148 default = [ "ari.conf" "acl.conf" "agents.conf" "amd.conf" "calendar.conf" "cdr.conf" "cdr_syslog.conf" "cdr_custom.conf" "cel.conf" "cel_custom.conf" "cli_aliases.conf" "confbridge.conf" "dundi.conf" "features.conf" "hep.conf" "iax.conf" "pjsip.conf" "pjsip_wizard.conf" "phone.conf" "phoneprov.conf" "queues.conf" "res_config_sqlite3.conf" "res_parking.conf" "statsd.conf" "udptl.conf" "unistim.conf" ];
149 type = types.listOf types.str;
150 example = [ "sip.conf" "dundi.conf" ];
151 description = lib.mdDoc ''Sets these config files to the default content. The default value for
152 this option contains all necesscary files to avoid errors at startup.
153 This does not override settings via {option}`services.asterisk.confFiles`.
154 '';
155 };
156
157 extraArguments = mkOption {
158 default = [];
159 type = types.listOf types.str;
160 example =
161 [ "-vvvddd" "-e" "1024" ];
162 description = lib.mdDoc ''
163 Additional command line arguments to pass to Asterisk.
164 '';
165 };
166 package = mkOption {
167 type = types.package;
168 default = pkgs.asterisk;
169 defaultText = literalExpression "pkgs.asterisk";
170 description = lib.mdDoc "The Asterisk package to use.";
171 };
172 };
173 };
174
175 config = mkIf cfg.enable {
176 environment.systemPackages = [ cfg.package ];
177
178 environment.etc = mapAttrs' (name: value:
179 nameValuePair "asterisk/${name}" value
180 ) allConfFiles;
181
182 users.users.asterisk =
183 { name = asteriskUser;
184 group = asteriskGroup;
185 uid = config.ids.uids.asterisk;
186 description = "Asterisk daemon user";
187 home = varlibdir;
188 };
189
190 users.groups.asterisk =
191 { name = asteriskGroup;
192 gid = config.ids.gids.asterisk;
193 };
194
195 systemd.services.asterisk = {
196 description = ''
197 Asterisk PBX server
198 '';
199
200 wantedBy = [ "multi-user.target" ];
201
202 # Do not restart, to avoid disruption of running calls. Restart unit by yourself!
203 restartIfChanged = false;
204
205 preStart = ''
206 # Copy skeleton directory tree to /var
207 for d in '${varlibdir}' '${spooldir}' '${logdir}'; do
208 # TODO: Make exceptions for /var directories that likely should be updated
209 if [ ! -e "$d" ]; then
210 mkdir -p "$d"
211 cp --recursive ${cfg.package}/"$d"/* "$d"/
212 chown --recursive ${asteriskUser}:${asteriskGroup} "$d"
213 find "$d" -type d | xargs chmod 0755
214 fi
215 done
216 '';
217
218 serviceConfig = {
219 ExecStart =
220 let
221 # FIXME: This doesn't account for arguments with spaces
222 argString = concatStringsSep " " cfg.extraArguments;
223 in
224 "${cfg.package}/bin/asterisk -U ${asteriskUser} -C /etc/asterisk/asterisk.conf ${argString} -F";
225 ExecReload = ''${cfg.package}/bin/asterisk -x "core reload"
226 '';
227 Type = "forking";
228 PIDFile = "/run/asterisk/asterisk.pid";
229 };
230 };
231 };
232}