aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/services/backup/bacula.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services/backup/bacula.nix')
-rw-r--r--nixpkgs/nixos/modules/services/backup/bacula.nix556
1 files changed, 556 insertions, 0 deletions
diff --git a/nixpkgs/nixos/modules/services/backup/bacula.nix b/nixpkgs/nixos/modules/services/backup/bacula.nix
new file mode 100644
index 00000000000..cef304734ae
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/backup/bacula.nix
@@ -0,0 +1,556 @@
+{ config, lib, pkgs, ... }:
+
+# TODO: test configuration when building nixexpr (use -t parameter)
+# TODO: support sqlite3 (it's deprecate?) and mysql
+
+with lib;
+
+let
+ libDir = "/var/lib/bacula";
+
+ fd_cfg = config.services.bacula-fd;
+ fd_conf = pkgs.writeText "bacula-fd.conf"
+ ''
+ Client {
+ Name = "${fd_cfg.name}";
+ FDPort = ${toString fd_cfg.port};
+ WorkingDirectory = "${libDir}";
+ Pid Directory = "/run";
+ ${fd_cfg.extraClientConfig}
+ }
+
+ ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
+ Director {
+ Name = "${name}";
+ Password = "${value.password}";
+ Monitor = "${value.monitor}";
+ }
+ '') fd_cfg.director)}
+
+ Messages {
+ Name = Standard;
+ syslog = all, !skipped, !restored
+ ${fd_cfg.extraMessagesConfig}
+ }
+ '';
+
+ sd_cfg = config.services.bacula-sd;
+ sd_conf = pkgs.writeText "bacula-sd.conf"
+ ''
+ Storage {
+ Name = "${sd_cfg.name}";
+ SDPort = ${toString sd_cfg.port};
+ WorkingDirectory = "${libDir}";
+ Pid Directory = "/run";
+ ${sd_cfg.extraStorageConfig}
+ }
+
+ ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
+ Autochanger {
+ Name = "${name}";
+ Device = ${concatStringsSep ", " (map (a: "\"${a}\"") value.devices)};
+ Changer Device = "${value.changerDevice}";
+ Changer Command = "${value.changerCommand}";
+ ${value.extraAutochangerConfig}
+ }
+ '') sd_cfg.autochanger)}
+
+ ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
+ Device {
+ Name = "${name}";
+ Archive Device = "${value.archiveDevice}";
+ Media Type = "${value.mediaType}";
+ ${value.extraDeviceConfig}
+ }
+ '') sd_cfg.device)}
+
+ ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
+ Director {
+ Name = "${name}";
+ Password = "${value.password}";
+ Monitor = "${value.monitor}";
+ }
+ '') sd_cfg.director)}
+
+ Messages {
+ Name = Standard;
+ syslog = all, !skipped, !restored
+ ${sd_cfg.extraMessagesConfig}
+ }
+ '';
+
+ dir_cfg = config.services.bacula-dir;
+ dir_conf = pkgs.writeText "bacula-dir.conf"
+ ''
+ Director {
+ Name = "${dir_cfg.name}";
+ Password = "${dir_cfg.password}";
+ DirPort = ${toString dir_cfg.port};
+ Working Directory = "${libDir}";
+ Pid Directory = "/run/";
+ QueryFile = "${pkgs.bacula}/etc/query.sql";
+ ${dir_cfg.extraDirectorConfig}
+ }
+
+ Catalog {
+ Name = "PostgreSQL";
+ dbname = "bacula";
+ user = "bacula";
+ }
+
+ Messages {
+ Name = Standard;
+ syslog = all, !skipped, !restored
+ ${dir_cfg.extraMessagesConfig}
+ }
+
+ ${dir_cfg.extraConfig}
+ '';
+
+ directorOptions = {...}:
+ {
+ options = {
+ password = mkOption {
+ # TODO: required?
+ description = ''
+ Specifies the password that must be supplied for the default Bacula
+ Console to be authorized. The same password must appear in the
+ Director resource of the Console configuration file. For added
+ security, the password is never passed across the network but instead
+ a challenge response hash code created with the password. This
+ directive is required. If you have either /dev/random or bc on your
+ machine, Bacula will generate a random password during the
+ configuration process, otherwise it will be left blank and you must
+ manually supply it.
+
+ The password is plain text. It is not generated through any special
+ process but as noted above, it is better to use random text for
+ security reasons.
+ '';
+ };
+
+ monitor = mkOption {
+ default = "no";
+ example = "yes";
+ description = ''
+ If Monitor is set to <literal>no</literal>, this director will have
+ full access to this Storage daemon. If Monitor is set to
+ <literal>yes</literal>, this director will only be able to fetch the
+ current status of this Storage daemon.
+
+ Please note that if this director is being used by a Monitor, we
+ highly recommend to set this directive to yes to avoid serious
+ security problems.
+ '';
+ };
+ };
+ };
+
+ autochangerOptions = {...}:
+ {
+ options = {
+ changerDevice = mkOption {
+ description = ''
+ The specified name-string must be the generic SCSI device name of the
+ autochanger that corresponds to the normal read/write Archive Device
+ specified in the Device resource. This generic SCSI device name
+ should be specified if you have an autochanger or if you have a
+ standard tape drive and want to use the Alert Command (see below).
+ For example, on Linux systems, for an Archive Device name of
+ <literal>/dev/nst0</literal>, you would specify
+ <literal>/dev/sg0</literal> for the Changer Device name. Depending
+ on your exact configuration, and the number of autochangers or the
+ type of autochanger, what you specify here can vary. This directive
+ is optional. See the Using AutochangersAutochangersChapter chapter of
+ this manual for more details of using this and the following
+ autochanger directives.
+ '';
+ };
+
+ changerCommand = mkOption {
+ description = ''
+ The name-string specifies an external program to be called that will
+ automatically change volumes as required by Bacula. Normally, this
+ directive will be specified only in the AutoChanger resource, which
+ is then used for all devices. However, you may also specify the
+ different Changer Command in each Device resource. Most frequently,
+ you will specify the Bacula supplied mtx-changer script as follows:
+
+ <literal>"/path/mtx-changer %c %o %S %a %d"</literal>
+
+ and you will install the mtx on your system (found in the depkgs
+ release). An example of this command is in the default bacula-sd.conf
+ file. For more details on the substitution characters that may be
+ specified to configure your autochanger please see the
+ AutochangersAutochangersChapter chapter of this manual. For FreeBSD
+ users, you might want to see one of the several chio scripts in
+ examples/autochangers.
+ '';
+ default = "/etc/bacula/mtx-changer %c %o %S %a %d";
+ };
+
+ devices = mkOption {
+ description = ''
+ '';
+ };
+
+ extraAutochangerConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Autochanger directive.
+ '';
+ example = ''
+
+ '';
+ };
+ };
+ };
+
+
+ deviceOptions = {...}:
+ {
+ options = {
+ archiveDevice = mkOption {
+ # TODO: required?
+ description = ''
+ The specified name-string gives the system file name of the storage
+ device managed by this storage daemon. This will usually be the
+ device file name of a removable storage device (tape drive), for
+ example <literal>/dev/nst0</literal> or
+ <literal>/dev/rmt/0mbn</literal>. For a DVD-writer, it will be for
+ example <literal>/dev/hdc</literal>. It may also be a directory name
+ if you are archiving to disk storage. In this case, you must supply
+ the full absolute path to the directory. When specifying a tape
+ device, it is preferable that the "non-rewind" variant of the device
+ file name be given.
+ '';
+ };
+
+ mediaType = mkOption {
+ # TODO: required?
+ description = ''
+ The specified name-string names the type of media supported by this
+ device, for example, <literal>DLT7000</literal>. Media type names are
+ arbitrary in that you set them to anything you want, but they must be
+ known to the volume database to keep track of which storage daemons
+ can read which volumes. In general, each different storage type
+ should have a unique Media Type associated with it. The same
+ name-string must appear in the appropriate Storage resource
+ definition in the Director's configuration file.
+
+ Even though the names you assign are arbitrary (i.e. you choose the
+ name you want), you should take care in specifying them because the
+ Media Type is used to determine which storage device Bacula will
+ select during restore. Thus you should probably use the same Media
+ Type specification for all drives where the Media can be freely
+ interchanged. This is not generally an issue if you have a single
+ Storage daemon, but it is with multiple Storage daemons, especially
+ if they have incompatible media.
+
+ For example, if you specify a Media Type of <literal>DDS-4</literal>
+ then during the restore, Bacula will be able to choose any Storage
+ Daemon that handles <literal>DDS-4</literal>. If you have an
+ autochanger, you might want to name the Media Type in a way that is
+ unique to the autochanger, unless you wish to possibly use the
+ Volumes in other drives. You should also ensure to have unique Media
+ Type names if the Media is not compatible between drives. This
+ specification is required for all devices.
+
+ In addition, if you are using disk storage, each Device resource will
+ generally have a different mount point or directory. In order for
+ Bacula to select the correct Device resource, each one must have a
+ unique Media Type.
+ '';
+ };
+
+ extraDeviceConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Device directive.
+ '';
+ example = ''
+ LabelMedia = yes
+ Random Access = no
+ AutomaticMount = no
+ RemovableMedia = no
+ MaximumOpenWait = 60
+ AlwaysOpen = no
+ '';
+ };
+ };
+ };
+
+in {
+ options = {
+ services.bacula-fd = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable the Bacula File Daemon.
+ '';
+ };
+
+ name = mkOption {
+ default = "${config.networking.hostName}-fd";
+ description = ''
+ The client name that must be used by the Director when connecting.
+ Generally, it is a good idea to use a name related to the machine so
+ that error messages can be easily identified if you have multiple
+ Clients. This directive is required.
+ '';
+ };
+
+ port = mkOption {
+ default = 9102;
+ type = types.int;
+ description = ''
+ This specifies the port number on which the Client listens for
+ Director connections. It must agree with the FDPort specified in
+ the Client resource of the Director's configuration file.
+ '';
+ };
+
+ director = mkOption {
+ default = {};
+ description = ''
+ This option defines director resources in Bacula File Daemon.
+ '';
+ type = with types; attrsOf (submodule directorOptions);
+ };
+
+ extraClientConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Client directive.
+ '';
+ example = ''
+ Maximum Concurrent Jobs = 20;
+ Heartbeat Interval = 30;
+ '';
+ };
+
+ extraMessagesConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Messages directive.
+ '';
+ example = ''
+ console = all
+ '';
+ };
+ };
+
+ services.bacula-sd = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable Bacula Storage Daemon.
+ '';
+ };
+
+ name = mkOption {
+ default = "${config.networking.hostName}-sd";
+ description = ''
+ Specifies the Name of the Storage daemon.
+ '';
+ };
+
+ port = mkOption {
+ default = 9103;
+ type = types.int;
+ description = ''
+ Specifies port number on which the Storage daemon listens for
+ Director connections.
+ '';
+ };
+
+ director = mkOption {
+ default = {};
+ description = ''
+ This option defines Director resources in Bacula Storage Daemon.
+ '';
+ type = with types; attrsOf (submodule directorOptions);
+ };
+
+ device = mkOption {
+ default = {};
+ description = ''
+ This option defines Device resources in Bacula Storage Daemon.
+ '';
+ type = with types; attrsOf (submodule deviceOptions);
+ };
+
+ autochanger = mkOption {
+ default = {};
+ description = ''
+ This option defines Autochanger resources in Bacula Storage Daemon.
+ '';
+ type = with types; attrsOf (submodule autochangerOptions);
+ };
+
+ extraStorageConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Storage directive.
+ '';
+ example = ''
+ Maximum Concurrent Jobs = 20;
+ Heartbeat Interval = 30;
+ '';
+ };
+
+ extraMessagesConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Messages directive.
+ '';
+ example = ''
+ console = all
+ '';
+ };
+
+ };
+
+ services.bacula-dir = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable Bacula Director Daemon.
+ '';
+ };
+
+ name = mkOption {
+ default = "${config.networking.hostName}-dir";
+ description = ''
+ The director name used by the system administrator. This directive is
+ required.
+ '';
+ };
+
+ port = mkOption {
+ default = 9101;
+ type = types.int;
+ description = ''
+ Specify the port (a positive integer) on which the Director daemon
+ will listen for Bacula Console connections. This same port number
+ must be specified in the Director resource of the Console
+ configuration file. The default is 9101, so normally this directive
+ need not be specified. This directive should not be used if you
+ specify DirAddresses (N.B plural) directive.
+ '';
+ };
+
+ password = mkOption {
+ # TODO: required?
+ description = ''
+ Specifies the password that must be supplied for a Director.
+ '';
+ };
+
+ extraMessagesConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Messages directive.
+ '';
+ example = ''
+ console = all
+ '';
+ };
+
+ extraDirectorConfig = mkOption {
+ default = "";
+ description = ''
+ Extra configuration to be passed in Director directive.
+ '';
+ example = ''
+ Maximum Concurrent Jobs = 20;
+ Heartbeat Interval = 30;
+ '';
+ };
+
+ extraConfig = mkOption {
+ default = "";
+ type = types.lines;
+ description = ''
+ Extra configuration for Bacula Director Daemon.
+ '';
+ example = ''
+ TODO
+ '';
+ };
+ };
+ };
+
+ config = mkIf (fd_cfg.enable || sd_cfg.enable || dir_cfg.enable) {
+ systemd.services.bacula-fd = mkIf fd_cfg.enable {
+ after = [ "network.target" ];
+ description = "Bacula File Daemon";
+ wantedBy = [ "multi-user.target" ];
+ path = [ pkgs.bacula ];
+ serviceConfig = {
+ ExecStart = "${pkgs.bacula}/sbin/bacula-fd -f -u root -g bacula -c ${fd_conf}";
+ ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ LogsDirectory = "bacula";
+ StateDirectory = "bacula";
+ };
+ };
+
+ systemd.services.bacula-sd = mkIf sd_cfg.enable {
+ after = [ "network.target" ];
+ description = "Bacula Storage Daemon";
+ wantedBy = [ "multi-user.target" ];
+ path = [ pkgs.bacula ];
+ serviceConfig = {
+ ExecStart = "${pkgs.bacula}/sbin/bacula-sd -f -u bacula -g bacula -c ${sd_conf}";
+ ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ LogsDirectory = "bacula";
+ StateDirectory = "bacula";
+ };
+ };
+
+ services.postgresql.enable = dir_cfg.enable == true;
+
+ systemd.services.bacula-dir = mkIf dir_cfg.enable {
+ after = [ "network.target" "postgresql.service" ];
+ description = "Bacula Director Daemon";
+ wantedBy = [ "multi-user.target" ];
+ path = [ pkgs.bacula ];
+ serviceConfig = {
+ ExecStart = "${pkgs.bacula}/sbin/bacula-dir -f -u bacula -g bacula -c ${dir_conf}";
+ ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ LogsDirectory = "bacula";
+ StateDirectory = "bacula";
+ };
+ preStart = ''
+ if ! test -e "${libDir}/db-created"; then
+ ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole bacula
+ #${pkgs.postgresql}/bin/createdb --owner bacula bacula
+
+ # populate DB
+ ${pkgs.bacula}/etc/create_bacula_database postgresql
+ ${pkgs.bacula}/etc/make_bacula_tables postgresql
+ ${pkgs.bacula}/etc/grant_bacula_privileges postgresql
+ touch "${libDir}/db-created"
+ else
+ ${pkgs.bacula}/etc/update_bacula_tables postgresql || true
+ fi
+ '';
+ };
+
+ environment.systemPackages = [ pkgs.bacula ];
+
+ users.users.bacula = {
+ group = "bacula";
+ uid = config.ids.uids.bacula;
+ home = "${libDir}";
+ createHome = true;
+ description = "Bacula Daemons user";
+ shell = "${pkgs.bash}/bin/bash";
+ };
+
+ users.groups.bacula.gid = config.ids.gids.bacula;
+ };
+}