summary refs log blame commit diff
path: root/nixos/modules/services/networking/asterisk.nix
blob: 03a2544b9a7eaebf689ba339735e4055ea8f5612 (plain) (tree)
1
2
3
4
5
6
7
8
9







                                 
                             




                                   




                                                                                          
                                                                                                      

                                                




                                               
                        

                                            
                            

      
                          




                                                                        
                                
                                                      





                                            
                                
                                    
                                       

































































































































                                                                                 









                                                                                                                                                                                                                                                                                                                                                                                                                             








                                                                





                                                     



                            
                                                 


                                                  
                          






                                             
                           


                                       







                                         


                                                                                       




                                                                                    
                         
                                                      
                                                                   










                                                                   

                                                                                                          
             
                         
                                               



        
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.asterisk;

  asteriskUser = "asterisk";
  asteriskGroup = "asterisk";

  varlibdir = "/var/lib/asterisk";
  spooldir = "/var/spool/asterisk";
  logdir = "/var/log/asterisk";

  # Add filecontents from files of useTheseDefaultConfFiles to confFiles, do not override
  defaultConfFiles = subtractLists (attrNames cfg.confFiles) cfg.useTheseDefaultConfFiles;
  allConfFiles =
    cfg.confFiles //
    builtins.listToAttrs (map (x: { name = x;
                                    value = builtins.readFile (cfg.package + "/etc/asterisk/" + x); })
                              defaultConfFiles);

  asteriskEtc = pkgs.stdenv.mkDerivation
  ((mapAttrs' (name: value: nameValuePair
        # Fudge the names to make bash happy
        ((replaceChars ["."] ["_"] name) + "_")
        (value)
      ) allConfFiles) //
  {
    confFilesString = concatStringsSep " " (
      attrNames allConfFiles
    );

    name = "asterisk-etc";

    # Default asterisk.conf file
    # (Notice that astetcdir will be set to the path of this derivation)
    asteriskConf = ''
      [directories]
      astetcdir => /etc/asterisk
      astmoddir => ${cfg.package}/lib/asterisk/modules
      astvarlibdir => /var/lib/asterisk
      astdbdir => /var/lib/asterisk
      astkeydir => /var/lib/asterisk
      astdatadir => /var/lib/asterisk
      astagidir => /var/lib/asterisk/agi-bin
      astspooldir => /var/spool/asterisk
      astrundir => /run/asterisk
      astlogdir => /var/log/asterisk
      astsbindir => ${cfg.package}/sbin
    '';
    extraConf = cfg.extraConfig;

    # Loading all modules by default is considered sensible by the authors of
    # "Asterisk: The Definitive Guide". Secure sites will likely want to
    # specify their own "modules.conf" in the confFiles option.
    modulesConf = ''
      [modules]
      autoload=yes
    '';

    # Use syslog for logging so logs can be viewed with journalctl
    loggerConf = ''
      [general]

      [logfiles]
      syslog.local0 => notice,warning,error
    '';

    buildCommand = ''
      mkdir -p "$out"

      # Create asterisk.conf, pointing astetcdir to the path of this derivation
      echo "$asteriskConf" | sed "s|@out@|$out|g" > "$out"/asterisk.conf
      echo "$extraConf" >> "$out"/asterisk.conf

      echo "$modulesConf" > "$out"/modules.conf

      echo "$loggerConf" > "$out"/logger.conf

      # Config files specified in confFiles option override all other files
      for i in $confFilesString; do
        conf=$(echo "$i"_ | sed 's/\./_/g')
        echo "''${!conf}" > "$out"/"$i"
      done
    '';
  });
in

{
  options = {
    services.asterisk = {
      enable = mkOption {
        type = types.bool;
        default = false;
        description = ''
          Whether to enable the Asterisk PBX server.
        '';
      };

      extraConfig = mkOption {
        default = "";
        type = types.lines;
        example = ''
          [options]
          verbose=3
          debug=3
        '';
        description = ''
          Extra configuration options appended to the default
          <literal>asterisk.conf</literal> file.
        '';
      };

      confFiles = mkOption {
        default = {};
        type = types.attrsOf types.str;
        example = literalExample
          ''
            {
              "extensions.conf" = '''
                [tests]
                ; Dial 100 for "hello, world"
                exten => 100,1,Answer()
                same  =>     n,Wait(1)
                same  =>     n,Playback(hello-world)
                same  =>     n,Hangup()

                [softphones]
                include => tests

                [unauthorized]
              ''';
              "sip.conf" = '''
                [general]
                allowguest=no              ; Require authentication
                context=unauthorized       ; Send unauthorized users to /dev/null
                srvlookup=no               ; Don't do DNS lookup
                udpbindaddr=0.0.0.0        ; Listen on all interfaces
                nat=force_rport,comedia    ; Assume device is behind NAT

                [softphone](!)
                type=friend                ; Match on username first, IP second
                context=softphones         ; Send to softphones context in
                                           ; extensions.conf file
                host=dynamic               ; Device will register with asterisk
                disallow=all               ; Manually specify codecs to allow
                allow=g722
                allow=ulaw
                allow=alaw

                [myphone](softphone)
                secret=GhoshevFew          ; Change this password!
              ''';
              "logger.conf" = '''
                [general]

                [logfiles]
                ; Add debug output to log
                syslog.local0 => notice,warning,error,debug
              ''';
            }
        '';
        description = ''
          Sets the content of config files (typically ending with
          <literal>.conf</literal>) in the Asterisk configuration directory.

          Note that if you want to change <literal>asterisk.conf</literal>, it
          is preferable to use the <option>services.asterisk.extraConfig</option>
          option over this option. If <literal>"asterisk.conf"</literal> is
          specified with the <option>confFiles</option> option (not recommended),
          you must be prepared to set your own <literal>astetcdir</literal>
          path.

          See
          <link xlink:href="http://www.asterisk.org/community/documentation"/>
          for more examples of what is possible here.
        '';
      };

      useTheseDefaultConfFiles = mkOption {
        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" ];
        type = types.listOf types.str;
        example = [ "sip.conf" "dundi.conf" ];
        description = ''Sets these config files to the default content. The default value for
          this option contains all necesscary files to avoid errors at startup.
          This does not override settings via <option>services.asterisk.confFiles</option>.
        '';
      };

      extraArguments = mkOption {
        default = [];
        type = types.listOf types.str;
        example =
          [ "-vvvddd" "-e" "1024" ];
        description = ''
          Additional command line arguments to pass to Asterisk.
        '';
      };
      package = mkOption {
        type = types.package;
        default = pkgs.asterisk;
        defaultText = "pkgs.asterisk";
        description = "The Asterisk package to use.";
      };
    };
  };

  config = mkIf cfg.enable {
    environment.systemPackages = [ cfg.package ];

    environment.etc.asterisk.source = asteriskEtc;

    users.users.asterisk =
      { name = asteriskUser;
        group = asteriskGroup;
        uid = config.ids.uids.asterisk;
        description = "Asterisk daemon user";
        home = varlibdir;
      };

    users.groups.asterisk =
      { name = asteriskGroup;
        gid = config.ids.gids.asterisk;
      };

    systemd.services.asterisk = {
      description = ''
        Asterisk PBX server
      '';

      wantedBy = [ "multi-user.target" ];

      # Do not restart, to avoid disruption of running calls. Restart unit by yourself!
      restartIfChanged = false;

      preStart = ''
        # Copy skeleton directory tree to /var
        for d in '${varlibdir}' '${spooldir}' '${logdir}'; do
          # TODO: Make exceptions for /var directories that likely should be updated
          if [ ! -e "$d" ]; then
            mkdir -p "$d"
            cp --recursive ${cfg.package}/"$d"/* "$d"/
            chown --recursive ${asteriskUser}:${asteriskGroup} "$d"
            find "$d" -type d | xargs chmod 0755
          fi
        done
      '';

      serviceConfig = {
        ExecStart =
          let
            # FIXME: This doesn't account for arguments with spaces
            argString = concatStringsSep " " cfg.extraArguments;
          in
          "${cfg.package}/bin/asterisk -U ${asteriskUser} -C /etc/asterisk/asterisk.conf ${argString} -F";
        ExecReload = ''${cfg.package}/bin/asterisk -x "core reload"
          '';
        Type = "forking";
        PIDFile = "/run/asterisk/asterisk.pid";
      };
    };
  };
}