Refactor btrbk out of makeDockerConfig, simplify btrbk config, add makePostgresConfig
This commit is contained in:
parent
800dded910
commit
e06a38ee9c
313
flake.nix
313
flake.nix
|
@ -44,25 +44,6 @@
|
|||
subvolumes;
|
||||
};
|
||||
|
||||
nextcloudSubvolumes = [
|
||||
"@nc-config"
|
||||
"@nc-data"
|
||||
"@postgres"
|
||||
"@redis"
|
||||
"@gitea"
|
||||
"@gitea-conf"
|
||||
"@pihole"
|
||||
"@papermc"
|
||||
"@docker-cfg"
|
||||
"@garage"
|
||||
"@garage-config"
|
||||
];
|
||||
|
||||
postgresSubvolumes = [
|
||||
"postgres"
|
||||
"postgres-cfg"
|
||||
];
|
||||
|
||||
sharedModule = ({ config, ... }: {
|
||||
services.openssh.settings.PasswordAuthentication = false;
|
||||
|
||||
|
@ -90,9 +71,17 @@
|
|||
format = "yaml";
|
||||
sopsFile = ./secrets/btrbk.yaml;
|
||||
};
|
||||
secrets.btrfsKeyFile = {
|
||||
secrets.nextcloudKeyFile = {
|
||||
format = "binary";
|
||||
sopsFile = ./secrets/keyfile.bin;
|
||||
sopsFile = ./secrets/nextcloudKeyFile.bin;
|
||||
};
|
||||
secrets.redtailKeyFile = {
|
||||
format = "binary";
|
||||
sopsFile = ./secrets/redtailKeyFile.bin;
|
||||
};
|
||||
secrets.whitestormKeyFile = {
|
||||
format = "binary";
|
||||
sopsFile = ./secrets/whitestormKeyFile.bin;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -103,71 +92,159 @@
|
|||
roles = [ "source" "info" "send" ];
|
||||
}
|
||||
];
|
||||
extraPackages = with pkgs; [ xz ];
|
||||
instances.btrbk = {
|
||||
onCalendar = "hourly";
|
||||
settings = {
|
||||
transaction_log = "/var/log/btrbk.log";
|
||||
stream_buffer = "512m";
|
||||
snapshot_preserve_min = "2d";
|
||||
snapshot_preserve = "35d 20w 12m";
|
||||
target_preserve_min = "24h";
|
||||
target_preserve = "24h 7d";
|
||||
archive_preserve_min = "latest";
|
||||
archive_preserve = "12m 10y";
|
||||
ssh_user = "btrbk";
|
||||
ssh_identity = config.sops.secrets.private_key.path;
|
||||
backend_remote = "btrfs-progs-sudo";
|
||||
};
|
||||
extraPackages = with pkgs; [ gzip ];
|
||||
instances.primary.settings = {
|
||||
snapshot_preserve_min = "2d";
|
||||
snapshot_preserve = "35d 20w 12m";
|
||||
transaction_log = "/var/log/btrbk.log";
|
||||
};
|
||||
instances.secondary.settings = {
|
||||
backend_remote = "btrfs-progs-sudo";
|
||||
ssh_identity = config.sops.secrets.private_key.path;
|
||||
ssh_user = "btrbk";
|
||||
stream_buffer = "512m";
|
||||
stream_compress = "gzip";
|
||||
stream_compress_level = "default";
|
||||
stream_compress_threads = "default";
|
||||
target_preserve = "24h 7d";
|
||||
target_preserve_min = "24h";
|
||||
transaction_log = "/var/log/btrbk.log";
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
makeDockerConfig = { hostname, volume, baseModule, extraModules ? [ ] }: with image-builder.packages.aarch64-linux.modules; nixpkgs.lib.nixosSystem {
|
||||
system = "aarch64-linux";
|
||||
modules = [
|
||||
sops-nix.nixosModules.sops
|
||||
baseModule
|
||||
sharedModule
|
||||
userModule
|
||||
({ config, ... }: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
docker
|
||||
docker-compose
|
||||
];
|
||||
|
||||
networking.hostName = hostname;
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
services.btrbk.instances.btrbk.settings.volume = volume;
|
||||
})
|
||||
] ++ extraModules;
|
||||
};
|
||||
|
||||
makeNextcloudConfig = { hostname, volume }: with image-builder.packages.aarch64-linux.modules; makeDockerConfig {
|
||||
inherit hostname;
|
||||
inherit volume;
|
||||
baseModule = rockPro64v2;
|
||||
extraModules = [
|
||||
({ config, ... }: {
|
||||
environment.etc.crypttab = {
|
||||
enable = true;
|
||||
text = ''
|
||||
cryptdrive1 /dev/sda1 ${config.sops.secrets.btrfsKeyFile.path} luks
|
||||
cryptdrive2 /dev/sdb1 ${config.sops.secrets.btrfsKeyFile.path} luks
|
||||
cryptdrive3 /dev/sdc1 ${config.sops.secrets.btrfsKeyFile.path} luks
|
||||
'';
|
||||
btrbkModule = ({ primaryIp ? null, mountDir, subvolumes }:
|
||||
let
|
||||
primary = {
|
||||
services.btrbk.instances.primary = {
|
||||
onCalendar = if primary then "hourly" else null;
|
||||
settings.volume = {
|
||||
"${mountDir}" = btrbkPrimary {
|
||||
inherit subvolumes;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fileSystems."/btrfs/hdd" = {
|
||||
device = "/dev/mapper/cryptdrive1";
|
||||
fsType = "btrfs";
|
||||
options = [ "defaults" "compress=zstd" "rw" ];
|
||||
};
|
||||
secondary = {
|
||||
services.btrbk.instances.secondary = {
|
||||
onCalendar = if primary then null else "hourly";
|
||||
settings.volume = {
|
||||
"ssh://${primaryIp}${mountDir}" = btrbkSecondary {
|
||||
target-dir = "${mountDir}/@snapshots";
|
||||
inherit subvolumes;
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
in
|
||||
if primaryIp == null then primary else secondary
|
||||
);
|
||||
|
||||
makeDockerConfig = { hostname, extraModules ? [ ] }:
|
||||
with image-builder.packages.aarch64-linux.modules;
|
||||
nixpkgs.lib.nixosSystem {
|
||||
system = "aarch64-linux";
|
||||
modules = [
|
||||
sops-nix.nixosModules.sops
|
||||
sharedModule
|
||||
userModule
|
||||
({ config, ... }: {
|
||||
environment.systemPackages = with pkgs; [
|
||||
docker
|
||||
docker-compose
|
||||
];
|
||||
|
||||
networking.hostName = hostname;
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
})
|
||||
] ++ extraModules;
|
||||
};
|
||||
|
||||
makeNextcloudConfig = { hostname, primaryIp ? null }:
|
||||
with image-builder.packages.aarch64-linux.modules;
|
||||
let
|
||||
mountDir = "/btrfs/hdd";
|
||||
in
|
||||
makeDockerConfig {
|
||||
inherit hostname;
|
||||
|
||||
extraModules = [
|
||||
rockPro64v2
|
||||
(btrbkModule {
|
||||
inherit mountDir primaryIp;
|
||||
|
||||
subvolumes = [
|
||||
"@nc-config"
|
||||
"@nc-data"
|
||||
"@postgres"
|
||||
"@redis"
|
||||
"@gitea"
|
||||
"@gitea-conf"
|
||||
"@pihole"
|
||||
"@papermc"
|
||||
"@docker-cfg"
|
||||
"@garage"
|
||||
"@garage-config"
|
||||
];
|
||||
})
|
||||
({ config, ... }: {
|
||||
environment.etc.crypttab = {
|
||||
enable = true;
|
||||
text = ''
|
||||
cryptdrive1 /dev/sda1 ${config.sops.secrets.nextcloudKeyFile.path} luks
|
||||
cryptdrive2 /dev/sdb1 ${config.sops.secrets.nextcloudKeyFile.path} luks
|
||||
cryptdrive3 /dev/sdc1 ${config.sops.secrets.nextcloudKeyFile.path} luks
|
||||
'';
|
||||
};
|
||||
|
||||
fileSystems."${mountDir}" = {
|
||||
device = "/dev/mapper/cryptdrive1";
|
||||
fsType = "btrfs";
|
||||
options = [ "defaults" "compress=zstd" "rw" ];
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
makePostgresConfig = { hostname, keyFile, primaryIp ? null }:
|
||||
with image-builder.packages.aarch64-linux.modules;
|
||||
let
|
||||
mountDir = "/btrfs/ssd";
|
||||
in
|
||||
makeDockerConfig {
|
||||
inherit hostname;
|
||||
|
||||
extraModules = [
|
||||
rock64
|
||||
(btrbkModule {
|
||||
inherit mountDir primaryIp;
|
||||
|
||||
subvolumes = [
|
||||
"postgres"
|
||||
"postgres-cfg"
|
||||
];
|
||||
})
|
||||
({ config, ... }:
|
||||
let
|
||||
keyFilePath = config.sops.secrets."${keyFile}".path;
|
||||
in
|
||||
{
|
||||
environment.etc.crypttab = {
|
||||
enable = true;
|
||||
text = ''
|
||||
cryptdrive1 /dev/sda1 ${keyFilePath} luks
|
||||
'';
|
||||
};
|
||||
|
||||
fileSystems."${mountDir}" = {
|
||||
device = "/dev/mapper/cryptdrive1";
|
||||
fsType = "btrfs";
|
||||
options = [ "defaults" "compress=zstd" "rw" ];
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
deployer = { hostname, configuration }: {
|
||||
hostname = hostname;
|
||||
|
@ -185,87 +262,39 @@
|
|||
};
|
||||
in
|
||||
{
|
||||
nixosConfigurations = with image-builder.packages.aarch64-linux.modules; {
|
||||
nixosConfigurations = {
|
||||
nextcloud1 = makeNextcloudConfig {
|
||||
hostname = "nextcloud1";
|
||||
volume = {
|
||||
# "ssh://192.168.20.28/btrfs/hdd" = btrbkSecondary {
|
||||
# target-dir = "/btrfs/hdd/@snapshots";
|
||||
# subvolumes = nextcloudSubvolumes;
|
||||
# };
|
||||
"/btrfs/hdd" = btrbkPrimary {
|
||||
subvolumes = nextcloudSubvolumes;
|
||||
};
|
||||
};
|
||||
# primaryIp = "192.168.20.28";
|
||||
};
|
||||
|
||||
nextcloud2 = makeNextcloudConfig {
|
||||
hostname = "nextcloud2";
|
||||
volume = {
|
||||
"ssh://192.168.20.21/btrfs/hdd" = btrbkSecondary {
|
||||
target-dir = "/btrfs/hdd/@snapshots";
|
||||
subvolumes = nextcloudSubvolumes;
|
||||
};
|
||||
# "/btrfs/hdd" = btrbkPrimary {
|
||||
# subvolumes = nextcloudSubvolumes;
|
||||
# };
|
||||
};
|
||||
primaryIp = "192.168.20.21";
|
||||
};
|
||||
|
||||
redtail1 = makeDockerConfig {
|
||||
redtail1 = makePostgresConfig {
|
||||
hostname = "redtail1";
|
||||
volume = {
|
||||
"ssh://192.168.20.24/btrfs/ssd" = btrbkSecondary {
|
||||
target-dir = "/btrfs/ssd/@snapshots";
|
||||
subvolumes = postgresSubvolumes;
|
||||
};
|
||||
# "/btrfs/ssd" = btrbkPrimary {
|
||||
# subvolumes = postgresSubvolumes;
|
||||
# };
|
||||
};
|
||||
baseModule = rock64;
|
||||
keyFile = "redtailKeyFile";
|
||||
primaryIp = "192.168.20.24";
|
||||
};
|
||||
|
||||
redtail2 = makeDockerConfig {
|
||||
redtail2 = makePostgresConfig {
|
||||
hostname = "redtail2";
|
||||
volume = {
|
||||
# "ssh://192.168.20.23/btrfs/ssd" = btrbkSecondary {
|
||||
# target-dir = "/btrfs/ssd/@snapshots";
|
||||
# subvolumes = postgresSubvolumes;
|
||||
# };
|
||||
"/btrfs/ssd" = btrbkPrimary {
|
||||
subvolumes = postgresSubvolumes;
|
||||
};
|
||||
};
|
||||
baseModule = rock64;
|
||||
keyFile = "redtailKeyFile";
|
||||
# primaryIp = "192.168.20.23";
|
||||
};
|
||||
|
||||
whitestorm1 = makeDockerConfig {
|
||||
whitestorm1 = makePostgresConfig {
|
||||
hostname = "whitestorm1";
|
||||
volume = {
|
||||
# "ssh://192.168.20.11/btrfs/ssd" = btrbkSecondary {
|
||||
# target-dir = "/btrfs/ssd/@snapshots";
|
||||
# subvolumes = postgresSubvolumes;
|
||||
# };
|
||||
"/btrfs/ssd" = btrbkPrimary {
|
||||
subvolumes = postgresSubvolumes;
|
||||
};
|
||||
};
|
||||
baseModule = rock64;
|
||||
keyFile = "whitestormKeyFile";
|
||||
# primaryIp = "192.168.20.11";
|
||||
};
|
||||
|
||||
whitestorm2 = makeDockerConfig {
|
||||
hostname = "whitestorm2";
|
||||
volume = {
|
||||
"ssh://192.168.20.26/btrfs/ssd" = btrbkSecondary {
|
||||
target-dir = "/btrfs/ssd/@snapshots";
|
||||
subvolumes = postgresSubvolumes;
|
||||
};
|
||||
# "/btrfs/ssd" = btrbkPrimary {
|
||||
# subvolumes = postgresSubvolumes;
|
||||
# };
|
||||
};
|
||||
baseModule = rock64;
|
||||
keyFile = "whitestormKeyFile";
|
||||
primaryIp = "192.168.20.26";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
24
secrets/redtailKeyFile.bin
Normal file
24
secrets/redtailKeyFile.bin
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"data": "ENC[AES256_GCM,data:y17JJ6rTCmRj4BhaLr0SYNcs4WqinhOAgyFl+wwKwM/WzIDFtDQ4pM7k4qn6hjPNOjfZajrxiRuaTBwvpu5tI8ooRgn3eCxPmAQP4VfHJz9RJX4DiJrJajfLl9k7LUI3BuBfLI4fKTt2ikkq5yTrjyPtJvVW80v+QOsC05jAZ8Tg82KaHRXBrAUNY2+OT8UXC8BB1BGGUnlf3KGXTPhqIgf+eENE1gT0280emBc0w+cfai4AOg8WFv7jkGMdtpHbcab5fySXsu+ScbaXBHXY+hgo7tR1zr4fq+kB7CWzr/y0r7UsMufxuKVrepEfUd/Fhlhvggs9VzNCu8fhJ+Qm5wa8PWqYqjoSdMFu/ypmt4knKHAdLWrWzLT7Qsj0/yTFF85MyP7RpOZd5FPOaN7QKmlMc/ULaPp5b7Exbf0Oot2iWKgMJwMJW5F9ADRWd99AY3LE8PXiR/KGjXjuPwUdsgzr03EUfB19MKaS5T1dDLGw68m3lKRTfnViL+Nux24cw44d3URX/rixy35CFT9fx3SfaOchIl7mye5MCM74JbBjGBJUlstegDvQG4LtfhxLrIoPs/qd0sbW7xHcBsnIrO+zl5tIWB7+c3nxivS31Rr1Hhlza/4cjwjxNYvO2RAYb5QreeXSV896PtlYFxUdohp/w7N5IE4ldgBGsf6MTlg=,iv:13rpHiHL1WEGKL1pP/mdOHInSK8GObLxsURtFWf5yGo=,tag:Dw4MzkVGeF1dR58MaQjRoQ==,type:str]",
|
||||
"sops": {
|
||||
"kms": null,
|
||||
"gcp_kms": null,
|
||||
"azure_kv": null,
|
||||
"hc_vault": null,
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age17yhtwnhqjssghc5qqamt0fqdu27zpqms8d8ghrc0txeevywfp3ssklfy57",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQckRnTW91SUVOZDY5K0VM\nazl5SFpjb1czRkFvRGhvT2kxZDBUbjJkK2xBCmVSYnRlUHNXaWVZTFFqZGNMN2Z5\ndXhNKzI4akVzeVh1MDF5WEpPRlZZajgKLS0tIEEwYXZIS1h5UllkOW9DQUwrcjNm\nb1daTzBPSTM3OEpuQUYvMS9nYUJjYWMKSFGGUDVIz5wYQZkT19dGiNsle/qXvqOc\nPwWxZWk1PxKTN9feNPTjKBEqRXUxUAyC7vINOVhwKZMCiBh1WRNDTg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age145uwrexj6ffaaxy7jg3j29gtchhwy0y0nttw06zeuxkqsy8rnpds7fh7xq",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoUnlxL3BpekY3MFIwTHlz\nS1VwNFp0K2hEaFQ1dXdnbVpwM0VJZ2Z0R2c4CkhlZjA2OGQwOFgyZ2JzNVJRMHRL\ndE4wNURWUTl4KzB1b3UvQzdockRBalUKLS0tIEE3OHQ0bk5xVEkyc1YzQlVZeS8z\ndnpoSnVlMFNoSlREZTRwSmFacldmRlkKheDzAG9ZhzOTQZLKZZp3dder13fxonP+\nu1S2FyuRcvjlabSYTWAtxlx0e4HQrKY0kM05uOBq7J6uvwwjAqLMjA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2023-01-26T17:42:33Z",
|
||||
"mac": "ENC[AES256_GCM,data:XcvDgiKDAESd2c3vVBvwJ133VwOPUq9qEfNudLECiYaI/hbTyRKsXQ9Zos+JWbz3JhgbtonFXOV8L3dcml3JA2YPC9qf8MLcFq3xhbf/EPPO71ZHX7GhHa0N/2tZWjFMIr4J3u7T5XfpvKoU676GzlBMZFjXq4NpWxAHluubbVA=,iv:K4xA63pMmKMFad+fpXWmz5V3T1Ss8ycMuqNjz8Ma+Yg=,tag:3hqKJq0mV9LIk0iMTNu+Pw==,type:str]",
|
||||
"pgp": null,
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.7.3"
|
||||
}
|
||||
}
|
24
secrets/whitestormKeyFile.bin
Normal file
24
secrets/whitestormKeyFile.bin
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"data": "ENC[AES256_GCM,data:hZ5SwLt2YvRuJcs7Fy4Fy4YTHiqwEouYPckJru5hPzAm5HUutKaSthvVvK85jf1jKM6qFaaf1gXBmzdW/SmPPwmPzOEKgkYcap7lTQG74WAdgEGpG44nbyz5hZlOw1qSxJ/JD8kpvEgzRYPO4JCyY0BEohwt38Oy/J7LT+n7giHzE/4WA3QaTRl6Pflo5RtyH41SMD7G2tfTvFeUv9QDUyuwqfvPC2FtEnoeayslmC3gB6LTQYO2CkxhE2ik4LqAZg/0NUX53q9M0asM1OligPQ9bCIbcDsyuU642H64AAesZ+rXw8oc9JKOpdhtvrWynW1kVhztiN6uT0hhv+rWiIm2FAGszK6cjriosgZi3G+soBCTvnV/LeM26EkGPWcTFXAa0WggCmJANLyNhITx79guAi110kAljAueHauk4vQ3N3vR0u3rDZMxlnr+mVxTRTtX4ZjJfQebbvrtOZ18D1xZ2gSN/d75/SCcpciFGRtPDOYha7Kdoef/Ok4t7G1qav9t0bDsuoH3XbAKK0UzvqK6iAV1Li1+rqUOd6I1R4H4AO22iSjw/dCPxe14U4zyNx1tUukD/HbUISYwJiKL3Ey1pnubVQy2IalCuXcjNQFJ4oPBPQpStpv7gwrZ3h6gmK7wVW0tqPEbG/pwByijlz5cefbU3TeOZ4Iw3rQur6g=,iv:qXcnFuRByJCyJTRb+QSvT2zVMykLJIGSBdPCrQGOGM4=,tag:7OP1ZwpZjRMuSdwZfhgnnQ==,type:str]",
|
||||
"sops": {
|
||||
"kms": null,
|
||||
"gcp_kms": null,
|
||||
"azure_kv": null,
|
||||
"hc_vault": null,
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age17yhtwnhqjssghc5qqamt0fqdu27zpqms8d8ghrc0txeevywfp3ssklfy57",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIbURWZlNneXFOUVVTUjB6\nU0s4cDBvSmZUUXpkbzJjUnVPQnNPNUwzNG04CmhIbkZrc096SEt5dFVSWThBTUJU\naktyckZnTmVjN1NMei9wdFRldllFak0KLS0tIHZtT1NQb3drWUNRcGFVc0JzTFhV\nUTB4OElUeTdZcm5TdG5PUTVaM1Fkd00KGdanZsiozmSZtI3+grHjU881jOOLVwfM\nkIYbcojpLQXMBsY4vaPIQbxOOR56oRJg5I5a278q0nwd79CDBTW2ew==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age145uwrexj6ffaaxy7jg3j29gtchhwy0y0nttw06zeuxkqsy8rnpds7fh7xq",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtSE9SM3lMZjlFQ2czWWVF\nNWNLbm93dTBRRmFCK0RjZVQvNkVkRlV1QXlvCjBxaExxSzNHWk5DRjRiMHRRSEVS\naVdHa0NyamM2NFpPMXF4b00vei9MZWsKLS0tIGRnSUp0RFYwZlZYZXlQNEZ6ZkJv\nZzBFWUxkeFJzTGFZeXo0TjUzcmJwVmcKGy5Y07RIpnPErqtmmDkiUhgQx9Dxz1Rl\nbRyxa9sH9jQhQSmoQXtuBLgVoCTbDxIJD032jAI75yVmfXcfFEX5MQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2023-01-26T17:40:40Z",
|
||||
"mac": "ENC[AES256_GCM,data:saR8UxS+g9DexsEI6v/jsDZyio/87swq1OL2C0HMoGtIHbsmpTOkI8QcxxXicOGzSnjDc/0GiYHMY7JdWWAaSSK4Hh6FaE8mBTbbJ2ShxdYSR3vF5gV9oVu5NdJCebgmB9Tqsi7lG3I0SHbsSmDXNWrma3U9J251myXZldpNlRE=,iv:MasbfHEPOZxX2+WRdpGkaAipSamTAdcJK9L8cGFUEq0=,tag:Zu9uCtJEbTD8IjYgLiD2Wg==,type:str]",
|
||||
"pgp": null,
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.7.3"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue