]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Add alternate cloud storage for daily backups
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Wed, 15 Jul 2020 23:10:17 +0000 (01:10 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Wed, 15 Jul 2020 23:10:17 +0000 (01:10 +0200)
14 files changed:
modules/duply_backup/default.nix
modules/private/environment.nix
modules/private/monitoring/default.nix
modules/private/monitoring/objects_common.nix
modules/private/monitoring/objects_monitoring-1.nix
modules/private/monitoring/plugins/check_backup_age [moved from modules/private/monitoring/plugins/check_eriomem_age with 100% similarity]
modules/private/websites/chloe/production.nix
modules/private/websites/connexionswing/production.nix
modules/private/websites/isabelle/aten_production.nix
modules/private/websites/isabelle/iridologie.nix
modules/private/websites/ludivine/production.nix
modules/private/websites/piedsjaloux/production.nix
modules/private/websites/richie/production.nix
modules/private/websites/syden/peertube.nix

index bce4d658332c99bbb0915859ecdca9ae8051fcae..73ac8f03140094455feb7c413f60bfa7d0c258d4 100644 (file)
@@ -1,13 +1,13 @@
-{ lib, pkgs, config, ... }:
+{ lib, pkgs, config, name, ... }:
 
 let
   cfg = config.myEnv.backup;
   varDir = "/var/lib/duply";
-  duplyProfile = profile: prefix: ''
+  duplyProfile = profile: remote: prefix: ''
     GPG_PW="${cfg.password}"
-    TARGET="${cfg.remote}${prefix}"
-    export AWS_ACCESS_KEY_ID="${cfg.accessKeyId}"
-    export AWS_SECRET_ACCESS_KEY="${cfg.secretAccessKey}"
+    TARGET="${cfg.remotes.${remote}.remote profile.bucket}${prefix}"
+    export AWS_ACCESS_KEY_ID="${cfg.remotes.${remote}.accessKeyId}"
+    export AWS_SECRET_ACCESS_KEY="${cfg.remotes.${remote}.secretAccessKey}"
     SOURCE="${profile.rootDir}"
     FILENAME=".duplicity-ignore"
     DUPL_PARAMS="$DUPL_PARAMS --exclude-if-present '$FILENAME'"
@@ -24,6 +24,8 @@ let
     MAX_FULLS_WITH_INCRS=2
   '';
   action = "bkp_purge_purgeFull_purgeIncr";
+  varName = k: remoteName:
+    if remoteName == "eriomem" then k else remoteName + "_" + k;
 in
 {
   options = {
@@ -43,6 +45,20 @@ in
               Path to backup
               '';
           };
+          bucket = lib.mkOption {
+            type = lib.types.str;
+            default = "immae-${name}";
+            description = ''
+              Bucket to use
+              '';
+          };
+          remotes = lib.mkOption {
+            type = lib.types.listOf lib.types.str;
+            default = ["eriomem"];
+            description = ''
+              Remotes to use for backup
+              '';
+          };
           excludeFile = lib.mkOption {
             type = lib.types.lines;
             default = "";
@@ -59,18 +75,19 @@ in
     system.activationScripts.backup = ''
       install -m 0700 -o root -g root -d ${varDir} ${varDir}/caches
       '';
-    secrets.keys = lib.flatten (lib.mapAttrsToList (k: v: [
-      {
-        permissions = "0400";
-        dest = "backup/${k}/conf";
-        text = duplyProfile v "${k}/";
-      }
-      {
-        permissions = "0400";
-        dest = "backup/${k}/exclude";
-        text = v.excludeFile;
-      }
-    ]) config.services.duplyBackup.profiles);
+    secrets.keys = lib.flatten (lib.mapAttrsToList (k: v:
+      map (remote: [
+        {
+          permissions = "0400";
+          dest = "backup/${varName k remote}/conf";
+          text = duplyProfile v remote "${k}/";
+        }
+        {
+          permissions = "0400";
+          dest = "backup/${varName k remote}/exclude";
+          text = v.excludeFile;
+        }
+    ]) v.remotes) config.services.duplyBackup.profiles);
 
     services.cron = {
       enable = true;
@@ -78,13 +95,15 @@ in
         backups = pkgs.writeScript "backups" ''
           #!${pkgs.stdenv.shell}
 
-          ${builtins.concatStringsSep "\n" (lib.mapAttrsToList (k: v:
+          ${builtins.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList (k: v:
+            map (remote: [
             ''
-              touch ${varDir}/${k}.log
-              ${pkgs.duply}/bin/duply ${config.secrets.location}/backup/${k}/ ${action} --force >> ${varDir}/${k}.log
-              [[ $? = 0 ]] || echo -e "Error when doing backup for ${k}, see above\n---------------------------------------" >&2
+              touch ${varDir}/${varName k remote}.log
+              ${pkgs.duply}/bin/duply ${config.secrets.location}/backup/${varName k remote}/ ${action} --force >> ${varDir}/${varName k remote}.log
+              [[ $? = 0 ]] || echo -e "Error when doing backup for ${varName k remote}, see above\n---------------------------------------" >&2
             ''
-          ) config.services.duplyBackup.profiles)}
+            ]) v.remotes
+          ) config.services.duplyBackup.profiles))}
         '';
       in
         [
index b8c4dd2325a89497decbdc876f0b73f1dc05601e..069a344bc04096de285d2ba6f016b51f0e4e2f39 100644 (file)
@@ -441,9 +441,24 @@ in
       type = submodule {
         options = {
           password = mkOption { type = str; description = "Password for encrypting files"; };
-          remote = mkOption { type = str; description = "Remote url access"; };
-          accessKeyId = mkOption { type = str; description = "Remote access-key"; };
-          secretAccessKey = mkOption { type = str; description = "Remote access secret"; };
+          remotes = mkOption {
+            type = attrsOf (submodule {
+              options = {
+                remote = mkOption {
+                  type = unspecified;
+                  example = literalExample ''
+                    bucket: "s3://some_host/${bucket}";
+                    '';
+                  description = ''
+                    Function.
+                    Takes a bucket name as argument and returns a url
+                    '';
+                };
+                accessKeyId = mkOption { type = str; description = "Remote access-key"; };
+                secretAccessKey = mkOption { type = str; description = "Remote access secret"; };
+              };
+            });
+          };
         };
       };
     };
index d5bf7fb275fe1c026f5b7b1f146b985dad096d14..c573af212b924031534a7fb92babaf63295382ce 100644 (file)
@@ -58,9 +58,12 @@ let
     wrapProgram $out/check_eriomem --prefix PATH : ${lib.makeBinPath [
       pkgs.s3cmd pkgs.python3
     ]}
-    wrapProgram $out/check_eriomem_age --prefix PATH : ${lib.makeBinPath [
+    makeWrapper $out/check_backup_age $out/check_backup_eriomem_age --prefix PATH : ${lib.makeBinPath [
       pkgs.duplicity
     ]} --set SECRETS_PATH ${lib.optionalString cfg.master config.secrets.fullPaths."eriomem_access_key"}
+    makeWrapper $out/check_backup_age $out/check_backup_ovh_age --prefix PATH : ${lib.makeBinPath [
+      pkgs.duplicity
+    ]} --set SECRETS_PATH ${lib.optionalString cfg.master config.secrets.fullPaths."ovh_access_key"}
     wrapProgram $out/notify_by_email --prefix PATH : ${lib.makeBinPath [
       pkgs.mailutils
     ]}
@@ -256,18 +259,19 @@ in
         permissions = "0400";
         text = config.myEnv.monitoring.ssh_secret_key;
       }
-    ] ++ lib.optional cfg.master (
+    ] ++ lib.optionals cfg.master (
+      lib.mapAttrsToList (k: v:
       {
-        dest = "eriomem_access_key";
+        dest = "${k}_access_key";
         user = "naemon";
         group = "naemon";
         permissions = "0400";
         text = ''
-          export AWS_ACCESS_KEY_ID="${config.myEnv.backup.accessKeyId}"
-          export AWS_SECRET_ACCESS_KEY="${config.myEnv.backup.secretAccessKey}"
-          export BASE_URL="${config.myEnv.backup.remote}"
+          export AWS_ACCESS_KEY_ID="${v.accessKeyId}"
+          export AWS_SECRET_ACCESS_KEY="${v.secretAccessKey}"
+          export BASE_URL="${v.remote "immae-eldiron"}"
         '';
-      }
+      }) config.myEnv.backup.remotes
     );
     # needed since extraResource is not in the closure
     systemd.services.naemon.path = [ myplugins ];
index d3a46ce06a9ac1a6233affcac3b4d995e1a1893d..25f812432a8756082e4e969db6cbf47ed4f25801 100644 (file)
@@ -108,8 +108,9 @@ in
     check_dns = "$USER1$/check_dns -H $ARG1$ -s $HOSTADDRESS$ $ARG2$";
     check_emails = "$USER2$/check_emails -H $HOSTADDRESS$ -i $USER203$ -l $ARG1$ -p $ARG2$ -s $ARG3$ -f $ARG4$";
     check_emails_local = "$USER2$/check_emails -H $HOSTADDRESS$ -n $ARG1$ -r $ADMINEMAIL$ -s $ARG2$ -f $ARG3$";
-    check_eriomem = "$USER2$/check_eriomem $USER208$";
-    check_eriomem_age = "$USER2$/check_eriomem_age $ARG1$";
+    check_backup_eriomem = "$USER2$/check_eriomem $USER208$";
+    check_backup_eriomem_age = "$USER2$/check_backup_eriomem_age $ARG1$";
+    check_backup_ovh_age = "$USER2$/check_backup_ovh_age $ARG1$";
     check_external_dns = "$USER1$/check_dns -H $ARG2$ -s $ARG1$ $ARG3$";
     check_ftp_database = "$USER2$/check_ftp_database";
     check_git = "$USER2$/check_git $USER203$";
index 2cba58e03179748048be801cc49865c3873f1943..1aebd262e37e8b7a68b70dbf0243d43dbc527be8 100644 (file)
@@ -1,22 +1,24 @@
-{ config, pkgs, nodes, hostFQDN, emailCheck, ... }:
+{ config, pkgs, nodes, hostFQDN, emailCheck, lib, ... }:
 let
-  to_eriomem_age_dependency = name: {
-    dependent_host_name = "eldiron.immae.eu";
-    host_name           = "eldiron.immae.eu";
-    dependent_service_description = "Eriomem backup for ${name} is not too old";
-    service_description = "Eriomem backup is up and not full";
-    execution_failure_criteria = "u";
-    notification_failure_criteria = "u";
-  };
-  to_eriomem_age = name: {
-    service_description = "Eriomem backup for ${name} is not too old";
-    host_name = "eldiron.immae.eu";
-    use = "external-service";
-    check_command = ["check_eriomem_age" name];
-
-    check_interval = "120";
-    notification_interval = "1440";
-  };
+  to_backup_age_dependency = name: profile: map (remote:
+    {
+      dependent_host_name = "eldiron.immae.eu";
+      host_name           = "eldiron.immae.eu";
+      dependent_service_description = "${remote} backup for ${name} is not too old";
+      service_description = "${remote} backup is up and not full";
+      execution_failure_criteria = "u";
+      notification_failure_criteria = "u";
+    }) profile.remotes;
+  to_backup_age = name: profile: map (remote:
+    {
+      service_description = "${remote} backup for ${name} is not too old";
+      host_name = "eldiron.immae.eu";
+      use = "external-service";
+      check_command = ["check_backup_${remote}_age" name];
+
+      check_interval = "120";
+      notification_interval = "1440";
+    }) profile.remotes;
 in
 {
   host = {
@@ -111,10 +113,21 @@ in
 
     # Backup services
     {
-      service_description = "Eriomem backup is up and not full";
+      service_description = "eriomem backup is up and not full";
+      host_name = "eldiron.immae.eu";
+      use = "external-service";
+      check_command = "check_backup_eriomem";
+
+      check_interval = "120";
+      notification_interval = "1440";
+
+      servicegroups = "webstatus-backup";
+    }
+    {
+      service_description = "ovh backup is up and not full";
       host_name = "eldiron.immae.eu";
       use = "external-service";
-      check_command = "check_eriomem";
+      check_command = "check_ok";
 
       check_interval = "120";
       notification_interval = "1440";
@@ -673,7 +686,7 @@ in
       _webstatus_name = "LDAP";
       _webstatus_url = "ldap.immae.eu";
     }
-  ] ++ map to_eriomem_age (builtins.attrNames nodes.eldiron.config.services.duplyBackup.profiles);
+  ] ++ lib.flatten (lib.mapAttrsToList to_backup_age nodes.eldiron.config.services.duplyBackup.profiles);
   contact = {
     telio-tortay = config.myEnv.monitoring.contacts.telio-tortay // {
       use = "generic-contact";
@@ -688,5 +701,5 @@ in
     telio-tortay = { alias = "Telio Tortay"; members = "immae"; };
     tiboqorl = { alias = "Tiboqorl"; members = "immae"; };
   };
-  servicedependency = map to_eriomem_age_dependency (builtins.attrNames nodes.eldiron.config.services.duplyBackup.profiles);
+  servicedependency = lib.flatten (lib.mapAttrsToList to_backup_age_dependency nodes.eldiron.config.services.duplyBackup.profiles);
 }
index b5233c68a74731485c08d4cd6c1ca19be1ff7357..7f8f1ded4cba0324ecb0c92615071dfe0004af37 100644 (file)
@@ -15,6 +15,7 @@ in {
 
   config = lib.mkIf cfg.enable {
     services.duplyBackup.profiles.chloe_production.rootDir = app.varDir;
+    services.duplyBackup.profiles.chloe_production.remotes = ["eriomem" "ovh"];
     secrets.keys = [
       {
         dest = "websites/chloe/production";
index e172f84a4511ce57f8a3d183026b8990a0d25825..f6a059db215c46045ee48b732fe737e46d46eb45 100644 (file)
@@ -14,6 +14,7 @@ in {
 
   config = lib.mkIf cfg.enable {
     services.duplyBackup.profiles.connexionswing_production.rootDir = app.varDir;
+    services.duplyBackup.profiles.connexionswing_production.remotes = ["eriomem" "ovh"];
     services.webstats.sites = [ { name = "connexionswing.com"; } ];
     services.phpApplication.apps.connexionswing_production = {
       websiteEnv = "production";
index 4fa3622663bff945ecda55b93c0f6e80cab6ae45..367171227e052ae1193974fcf0d73a63fcc7eea1 100644 (file)
@@ -13,6 +13,7 @@ in {
 
   config = lib.mkIf cfg.enable {
     services.duplyBackup.profiles.isabelle_aten_production.rootDir = app.varDir;
+    services.duplyBackup.profiles.isabelle_aten_production.remotes = ["eriomem" "ovh"];
     services.webstats.sites = [ { name = "aten.pro"; } ];
     services.phpApplication.apps.isabelle_aten_production = {
       websiteEnv = "production";
index 5fa87cee075a81508d8dcf5390918086d3e5d9cb..14296bf3957aa7ce1d6165c6c82cb27096caef69 100644 (file)
@@ -17,6 +17,7 @@ in {
 
   config = lib.mkIf cfg.enable {
     services.duplyBackup.profiles.isabelle_iridologie.rootDir = app.varDir;
+    services.duplyBackup.profiles.isabelle_iridologie.remotes = ["eriomem" "ovh"];
     secrets.keys = [
       {
         dest = "websites/isabelle/iridologie";
index b30f488937fb39c03d57dc2adf093f38665a4ea0..3a9895d3a2a166e5d59b37ee83deffeabb04a233 100644 (file)
@@ -14,6 +14,7 @@ in {
 
   config = lib.mkIf cfg.enable {
     services.duplyBackup.profiles.ludivine_production.rootDir = app.varDir;
+    services.duplyBackup.profiles.ludivine_production.remotes = ["eriomem" "ovh"];
     services.webstats.sites = [ { name = "ludivinecassal.com"; } ];
     services.phpApplication.apps.ludivine_production = {
       websiteEnv = "production";
index 03b9ec5e3d34784bcd7cdc77bb0a2a9934503f78..e12b046fa688331da510a3bd9873b60847047d6d 100644 (file)
@@ -15,6 +15,7 @@ in {
 
   config = lib.mkIf cfg.enable {
     services.duplyBackup.profiles.piedsjaloux_production.rootDir = app.varDir;
+    services.duplyBackup.profiles.piedsjaloux_production.remotes = ["eriomem" "ovh"];
     services.webstats.sites = [ { name = "piedsjaloux.fr"; } ];
     services.phpApplication.apps.piedsjaloux_production = {
       websiteEnv = "production";
index a6957af13937cf9b6620a64bef4e49f603a7da73..2d85175441abbfebff231b0fa6c225d9cc8877db 100644 (file)
@@ -26,6 +26,7 @@ in
   options.myServices.websites.richie.production.enable = lib.mkEnableOption "enable Richie's website";
   config = lib.mkIf cfg.enable {
     services.duplyBackup.profiles.richie_production.rootDir = vardir;
+    services.duplyBackup.profiles.richie_production.remotes = ["eriomem" "ovh"];
     services.webstats.sites = [ { name = "europe-richie.org"; } ];
 
     secrets.keys = [{
index b17e775b3617873808dda56bda06805ec1b11522..5970cca5891e80a0021eaf079e1c994a98825673 100644 (file)
@@ -12,6 +12,7 @@ in
   config = lib.mkIf scfg.enable {
     services.duplyBackup.profiles.syden_peertube = {
       rootDir = dataDir;
+      remotes = ["eriomem" "ovh"];
     };
     users.users.peertube = {
       uid = config.ids.uids.peertube;