From d106ad6921823fd3bc2e6dcf9ae9b853f6ab68c8 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 18 May 2024 23:28:35 +0200 Subject: [PATCH 1/8] restic: regenerate snapshot keep policy golden test files --- .../restic/testdata/policy_keep_snapshots_36 | 412 ++++++++++---- .../restic/testdata/policy_keep_snapshots_37 | 515 ++++++++++++++---- .../restic/testdata/policy_keep_snapshots_38 | 362 ++++++++---- .../restic/testdata/policy_keep_snapshots_39 | 67 ++- 4 files changed, 1045 insertions(+), 311 deletions(-) diff --git a/internal/restic/testdata/policy_keep_snapshots_36 b/internal/restic/testdata/policy_keep_snapshots_36 index 75a3a5b46..cce4cf537 100644 --- a/internal/restic/testdata/policy_keep_snapshots_36 +++ b/internal/restic/testdata/policy_keep_snapshots_36 @@ -590,7 +590,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -601,7 +603,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -612,7 +616,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -623,7 +629,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -634,7 +642,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -645,7 +655,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -656,7 +668,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -667,7 +681,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -678,7 +694,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -689,7 +707,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -700,7 +720,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -711,7 +733,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -722,7 +746,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -733,7 +759,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -744,7 +772,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -755,7 +785,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -766,7 +798,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -777,7 +811,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -788,7 +824,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -799,7 +837,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -810,7 +850,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -821,7 +863,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -832,7 +876,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -843,7 +889,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -854,7 +902,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -865,7 +915,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -876,7 +928,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -887,7 +941,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -898,7 +954,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -909,7 +967,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -920,7 +980,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -935,7 +997,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -950,7 +1014,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -968,7 +1034,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -979,7 +1047,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -990,7 +1060,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1001,7 +1073,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1012,7 +1086,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1023,7 +1099,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1034,7 +1112,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1045,7 +1125,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1056,7 +1138,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1067,7 +1151,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1078,7 +1164,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1089,7 +1177,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1100,7 +1190,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1111,7 +1203,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1122,7 +1216,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1133,7 +1229,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1144,7 +1242,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1155,7 +1255,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1166,7 +1268,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1177,7 +1281,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1188,7 +1294,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1199,7 +1307,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1210,7 +1320,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1221,7 +1333,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1232,7 +1346,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1243,7 +1359,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1254,7 +1372,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1265,7 +1385,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1276,7 +1398,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1287,7 +1411,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1298,7 +1424,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1309,7 +1437,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1320,7 +1450,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1331,7 +1463,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1346,7 +1480,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1360,7 +1496,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1374,7 +1512,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1388,7 +1528,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1402,7 +1544,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1416,7 +1560,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1430,7 +1576,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1444,7 +1592,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1458,7 +1608,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1472,7 +1624,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1486,7 +1640,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1500,7 +1656,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1514,7 +1672,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1528,7 +1688,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1542,7 +1704,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1556,7 +1720,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1567,7 +1733,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1578,7 +1746,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1589,7 +1759,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1600,7 +1772,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1611,7 +1785,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1622,7 +1798,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1633,7 +1811,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1644,7 +1824,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1655,7 +1837,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1666,7 +1850,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1677,7 +1863,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1688,7 +1876,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1699,7 +1889,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1710,7 +1902,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1721,7 +1915,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1732,7 +1928,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1743,7 +1941,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1754,7 +1954,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1765,7 +1967,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } }, { "snapshot": { @@ -1776,7 +1980,9 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1} + "counters": { + "last": -1 + } } ] } \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_37 b/internal/restic/testdata/policy_keep_snapshots_37 index f6ffa40ea..9856a83d6 100644 --- a/internal/restic/testdata/policy_keep_snapshots_37 +++ b/internal/restic/testdata/policy_keep_snapshots_37 @@ -591,7 +591,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -603,7 +606,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -614,7 +620,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -626,7 +635,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -638,7 +650,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -650,7 +665,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -662,7 +680,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -674,7 +695,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -686,7 +710,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -698,7 +725,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -709,7 +739,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -720,7 +753,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -731,7 +767,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -743,7 +782,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -755,7 +797,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -767,7 +812,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -779,7 +827,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -791,7 +842,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -802,7 +856,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -814,7 +871,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -826,7 +886,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -838,7 +901,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -850,7 +916,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -862,7 +931,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -874,7 +946,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -885,7 +960,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -897,7 +975,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -909,7 +990,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -921,7 +1005,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -933,7 +1020,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -944,7 +1034,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -959,7 +1052,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -974,7 +1070,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -992,7 +1091,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1004,7 +1106,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1016,7 +1121,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1028,7 +1136,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1040,7 +1151,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1052,7 +1166,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1064,7 +1181,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1076,7 +1196,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1088,7 +1211,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1100,7 +1226,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1112,7 +1241,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1124,7 +1256,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1136,7 +1271,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1148,7 +1286,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1160,7 +1301,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1172,7 +1316,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1184,7 +1331,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1196,7 +1346,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1208,7 +1361,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1220,7 +1376,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1232,7 +1391,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1244,7 +1406,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1256,7 +1421,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1268,7 +1436,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1280,7 +1451,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1292,7 +1466,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1303,7 +1480,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1315,7 +1495,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1327,7 +1510,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1339,7 +1525,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1351,7 +1540,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1363,7 +1555,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1375,7 +1570,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1387,7 +1585,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1403,7 +1604,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1418,7 +1622,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1432,7 +1639,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1447,7 +1657,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1462,7 +1675,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1477,7 +1693,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1492,7 +1711,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1507,7 +1729,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1522,7 +1747,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1537,7 +1765,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1552,7 +1783,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1567,7 +1801,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1582,7 +1819,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1597,7 +1837,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1612,7 +1855,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1627,7 +1873,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1639,7 +1888,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1651,7 +1903,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1663,7 +1918,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1675,7 +1933,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1687,7 +1948,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1699,7 +1963,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1711,7 +1978,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1723,7 +1993,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1735,7 +2008,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1747,7 +2023,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1759,7 +2038,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1771,7 +2053,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1783,7 +2068,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1795,7 +2083,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1807,7 +2098,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1819,7 +2113,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1830,7 +2127,10 @@ "matches": [ "last snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1842,7 +2142,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1854,7 +2157,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } }, { "snapshot": { @@ -1866,7 +2172,10 @@ "last snapshot", "hourly snapshot" ], - "counters": {"Last": -1, "Hourly": -1} + "counters": { + "last": -1, + "hourly": -1 + } } ] } \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_38 b/internal/restic/testdata/policy_keep_snapshots_38 index 6bfdd57f1..f5d7136d4 100644 --- a/internal/restic/testdata/policy_keep_snapshots_38 +++ b/internal/restic/testdata/policy_keep_snapshots_38 @@ -507,7 +507,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -518,7 +520,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -529,7 +533,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -540,7 +546,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -551,7 +559,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -562,7 +572,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -573,7 +585,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -584,7 +598,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -595,7 +611,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -606,7 +624,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -617,7 +637,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -628,7 +650,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -639,7 +663,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -650,7 +676,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -661,7 +689,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -672,7 +702,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -683,7 +715,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -694,7 +728,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -705,7 +741,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -716,7 +754,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -727,7 +767,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -738,7 +780,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -749,7 +793,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -760,7 +806,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -771,7 +819,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -782,7 +832,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -793,7 +845,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -804,7 +858,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -815,7 +871,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -826,7 +884,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -837,7 +897,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -848,7 +910,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -859,7 +923,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -870,7 +936,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -881,7 +949,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -892,7 +962,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -903,7 +975,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -914,7 +988,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -925,7 +1001,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -936,7 +1014,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -947,7 +1027,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -958,7 +1040,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -969,7 +1053,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -980,7 +1066,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -991,7 +1079,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1002,7 +1092,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1013,7 +1105,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1024,7 +1118,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1035,7 +1131,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1046,7 +1144,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1057,7 +1157,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1068,7 +1170,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1079,7 +1183,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1090,7 +1196,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1101,7 +1209,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1112,7 +1222,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1127,7 +1239,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1141,7 +1255,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1155,7 +1271,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1169,7 +1287,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1183,7 +1303,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1197,7 +1319,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1211,7 +1335,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1225,7 +1351,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1239,7 +1367,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1253,7 +1383,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1267,7 +1399,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1281,7 +1415,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1295,7 +1431,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1309,7 +1447,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1323,7 +1463,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1334,7 +1476,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1345,7 +1489,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1356,7 +1502,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1367,7 +1515,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1378,7 +1528,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1389,7 +1541,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1400,7 +1554,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1411,7 +1567,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1422,7 +1580,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1433,7 +1593,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1444,7 +1606,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1455,7 +1619,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1466,7 +1632,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1477,7 +1645,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1488,7 +1658,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1499,7 +1671,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1510,7 +1684,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1521,7 +1697,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } }, { "snapshot": { @@ -1532,7 +1710,9 @@ "matches": [ "hourly snapshot" ], - "counters": {"Hourly": -1} + "counters": { + "hourly": -1 + } } ] -} +} \ No newline at end of file diff --git a/internal/restic/testdata/policy_keep_snapshots_39 b/internal/restic/testdata/policy_keep_snapshots_39 index 4b111503b..f5fb4b1bf 100644 --- a/internal/restic/testdata/policy_keep_snapshots_39 +++ b/internal/restic/testdata/policy_keep_snapshots_39 @@ -74,10 +74,15 @@ "matches": [ "daily snapshot", "weekly snapshot", - "monthly snapshot", - "yearly snapshot" + "monthly snapshot", + "yearly snapshot" ], - "counters": {"Daily": 2, "Weekly": 1, "Monthly": -1, "Yearly": -1} + "counters": { + "daily": 2, + "weekly": 1, + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -89,7 +94,11 @@ "daily snapshot", "weekly snapshot" ], - "counters": {"Daily": 1, "Monthly": -1, "Yearly": -1} + "counters": { + "daily": 1, + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -100,7 +109,10 @@ "matches": [ "daily snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -112,7 +124,10 @@ "monthly snapshot", "yearly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -123,7 +138,10 @@ "matches": [ "monthly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -134,7 +152,10 @@ "matches": [ "monthly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -145,7 +166,10 @@ "matches": [ "monthly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -157,7 +181,10 @@ "monthly snapshot", "yearly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -171,7 +198,10 @@ "matches": [ "monthly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -182,7 +212,10 @@ "matches": [ "monthly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -193,7 +226,10 @@ "matches": [ "monthly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } }, { "snapshot": { @@ -205,7 +241,10 @@ "monthly snapshot", "yearly snapshot" ], - "counters": {"Monthly": -1, "Yearly": -1} + "counters": { + "monthly": -1, + "yearly": -1 + } } ] } \ No newline at end of file From c0e1f36830bf9eda7bd1e660270ebc388e590176 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 14 Apr 2024 22:44:32 +0200 Subject: [PATCH 2/8] forget: refuse deleting the last snapshot in a snapshot group `--keep-tag invalid-tag` was previously able to wipe all snapshots in a repository. As a user specified a `--keep-*` option this is likely unintentional. This forbid deleting all snapshot if a `--keep-*` option was specified to prevent data loss. (Not specifying such an option currently also causes the command to abort) --- cmd/restic/cmd_forget.go | 5 +++++ internal/restic/snapshot_find.go | 4 ++-- internal/restic/snapshot_group.go | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index 92eeed4a1..6d04d0f70 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + "fmt" "io" "strconv" @@ -248,6 +249,10 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy) + if !policy.Empty() && len(keep) == 0 { + return fmt.Errorf("refusing to delete last snapshot of snapshot group %v", key) + } + if len(keep) != 0 && !gopts.Quiet && !gopts.JSON { printer.P("keep %d snapshots:\n", len(keep)) PrintSnapshots(globalOptions.stdout, keep, reasons, opts.Compact) diff --git a/internal/restic/snapshot_find.go b/internal/restic/snapshot_find.go index cb761aee3..6d1ab9a7a 100644 --- a/internal/restic/snapshot_find.go +++ b/internal/restic/snapshot_find.go @@ -24,7 +24,7 @@ type SnapshotFilter struct { TimestampLimit time.Time } -func (f *SnapshotFilter) empty() bool { +func (f *SnapshotFilter) Empty() bool { return len(f.Hosts)+len(f.Tags)+len(f.Paths) == 0 } @@ -173,7 +173,7 @@ func (f *SnapshotFilter) FindAll(ctx context.Context, be Lister, loader LoaderUn } // Give the user some indication their filters are not used. - if !usedFilter && !f.empty() { + if !usedFilter && !f.Empty() { return fn("filters", nil, errors.Errorf("explicit snapshot ids are given")) } return nil diff --git a/internal/restic/snapshot_group.go b/internal/restic/snapshot_group.go index 964a230b3..f4e1ed384 100644 --- a/internal/restic/snapshot_group.go +++ b/internal/restic/snapshot_group.go @@ -66,6 +66,20 @@ type SnapshotGroupKey struct { Tags []string `json:"tags"` } +func (s *SnapshotGroupKey) String() string { + var parts []string + if s.Hostname != "" { + parts = append(parts, fmt.Sprintf("host %v", s.Hostname)) + } + if len(s.Paths) != 0 { + parts = append(parts, fmt.Sprintf("path %v", s.Paths)) + } + if len(s.Tags) != 0 { + parts = append(parts, fmt.Sprintf("tags %v", s.Tags)) + } + return strings.Join(parts, ", ") +} + // GroupSnapshots takes a list of snapshots and a grouping criteria and creates // a grouped list of snapshots. func GroupSnapshots(snapshots Snapshots, groupBy SnapshotGroupByOptions) (map[string]Snapshots, bool, error) { From 5b7952e426b21358557669fcdc7960e011fc5416 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 14 Apr 2024 22:46:49 +0200 Subject: [PATCH 3/8] forget: return error if no policy was specified --- cmd/restic/cmd_forget.go | 75 +++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index 6d04d0f70..e568bf11d 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -222,58 +222,55 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption Tags: opts.KeepTags, } - if policy.Empty() && len(args) == 0 { - printer.P("no policy was specified, no snapshots will be removed\n") + if policy.Empty() { + return errors.Fatal("no policy was specified, no snapshots will be removed") } - if !policy.Empty() { - printer.P("Applying Policy: %v\n", policy) + printer.P("Applying Policy: %v\n", policy) - for k, snapshotGroup := range snapshotGroups { - if gopts.Verbose >= 1 && !gopts.JSON { - err = PrintSnapshotGroupHeader(globalOptions.stdout, k) - if err != nil { - return err - } - } - - var key restic.SnapshotGroupKey - if json.Unmarshal([]byte(k), &key) != nil { + for k, snapshotGroup := range snapshotGroups { + if gopts.Verbose >= 1 && !gopts.JSON { + err = PrintSnapshotGroupHeader(globalOptions.stdout, k) + if err != nil { return err } + } - var fg ForgetGroup - fg.Tags = key.Tags - fg.Host = key.Hostname - fg.Paths = key.Paths + var key restic.SnapshotGroupKey + if json.Unmarshal([]byte(k), &key) != nil { + return err + } - keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy) + var fg ForgetGroup + fg.Tags = key.Tags + fg.Host = key.Hostname + fg.Paths = key.Paths - if !policy.Empty() && len(keep) == 0 { - return fmt.Errorf("refusing to delete last snapshot of snapshot group %v", key) - } + keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy) - if len(keep) != 0 && !gopts.Quiet && !gopts.JSON { - printer.P("keep %d snapshots:\n", len(keep)) - PrintSnapshots(globalOptions.stdout, keep, reasons, opts.Compact) - printer.P("\n") - } - fg.Keep = asJSONSnapshots(keep) + if !policy.Empty() && len(keep) == 0 { + return fmt.Errorf("refusing to delete last snapshot of snapshot group \"%v\"", key.String()) + } + if len(keep) != 0 && !gopts.Quiet && !gopts.JSON { + printer.P("keep %d snapshots:\n", len(keep)) + PrintSnapshots(globalOptions.stdout, keep, reasons, opts.Compact) + printer.P("\n") + } + fg.Keep = asJSONSnapshots(keep) - if len(remove) != 0 && !gopts.Quiet && !gopts.JSON { - printer.P("remove %d snapshots:\n", len(remove)) - PrintSnapshots(globalOptions.stdout, remove, nil, opts.Compact) - printer.P("\n") - } - fg.Remove = asJSONSnapshots(remove) + if len(remove) != 0 && !gopts.Quiet && !gopts.JSON { + printer.P("remove %d snapshots:\n", len(remove)) + PrintSnapshots(globalOptions.stdout, remove, nil, opts.Compact) + printer.P("\n") + } + fg.Remove = asJSONSnapshots(remove) - fg.Reasons = asJSONKeeps(reasons) + fg.Reasons = asJSONKeeps(reasons) - jsonGroups = append(jsonGroups, &fg) + jsonGroups = append(jsonGroups, &fg) - for _, sn := range remove { - removeSnIDs.Insert(*sn.ID()) - } + for _, sn := range remove { + removeSnIDs.Insert(*sn.ID()) } } } From 57f9739573435af041a2b85a2e05c5ebfc931784 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Mon, 15 Apr 2024 22:02:14 +0200 Subject: [PATCH 4/8] forget: Add --unsafe-allow-remove-all option To prevent accidentally wiping all snapshots from a repository, that option can only be used if either a snapshot filter or a keep policy is specified. Essentially, the option allows `forget --tag something --unsafe-allow-remove-all` calls to remove all snapshots with a specific tag. --- cmd/restic/cmd_forget.go | 12 +- internal/restic/snapshot_policy.go | 16 +- .../restic/testdata/policy_keep_snapshots_0 | 1781 +---------------- 3 files changed, 17 insertions(+), 1792 deletions(-) diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index e568bf11d..328b28271 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -92,6 +92,8 @@ type ForgetOptions struct { WithinYearly restic.Duration KeepTags restic.TagLists + UnsafeAllowRemoveAll bool + restic.SnapshotFilter Compact bool @@ -121,6 +123,7 @@ func init() { f.VarP(&forgetOptions.WithinMonthly, "keep-within-monthly", "", "keep monthly snapshots that are newer than `duration` (eg. 1y5m7d2h) relative to the latest snapshot") f.VarP(&forgetOptions.WithinYearly, "keep-within-yearly", "", "keep yearly snapshots that are newer than `duration` (eg. 1y5m7d2h) relative to the latest snapshot") f.Var(&forgetOptions.KeepTags, "keep-tag", "keep snapshots with this `taglist` (can be specified multiple times)") + f.BoolVar(&forgetOptions.UnsafeAllowRemoveAll, "unsafe-allow-remove-all", false, "allow deleting all snapshots of a snapshot group") initMultiSnapshotFilter(f, &forgetOptions.SnapshotFilter, false) f.StringArrayVar(&forgetOptions.Hosts, "hostname", nil, "only consider snapshots with the given `hostname` (can be specified multiple times)") @@ -223,7 +226,14 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption } if policy.Empty() { - return errors.Fatal("no policy was specified, no snapshots will be removed") + if opts.UnsafeAllowRemoveAll { + if opts.SnapshotFilter.Empty() { + return errors.Fatal("--unsafe-allow-remove-all is not allowed unless a snapshot filter option is specified") + } + // UnsafeAllowRemoveAll together with snapshot filter is fine + } else { + return errors.Fatal("no policy was specified, no snapshots will be removed") + } } printer.P("Applying Policy: %v\n", policy) diff --git a/internal/restic/snapshot_policy.go b/internal/restic/snapshot_policy.go index 0ff0c5ec8..950c26c91 100644 --- a/internal/restic/snapshot_policy.go +++ b/internal/restic/snapshot_policy.go @@ -94,7 +94,11 @@ func (e ExpirePolicy) String() (s string) { s += fmt.Sprintf("all snapshots within %s of the newest", e.Within) } - s = "keep " + s + if s == "" { + s = "remove" + } else { + s = "keep " + s + } return s } @@ -186,16 +190,6 @@ func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots, reason // sort newest snapshots first sort.Stable(list) - if p.Empty() { - for _, sn := range list { - reasons = append(reasons, KeepReason{ - Snapshot: sn, - Matches: []string{"policy is empty"}, - }) - } - return list, remove, reasons - } - if len(list) == 0 { return list, nil, nil } diff --git a/internal/restic/testdata/policy_keep_snapshots_0 b/internal/restic/testdata/policy_keep_snapshots_0 index 11ca587c8..96cc25cc7 100644 --- a/internal/restic/testdata/policy_keep_snapshots_0 +++ b/internal/restic/testdata/policy_keep_snapshots_0 @@ -1,1782 +1,3 @@ { - "keep": [ - { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:08:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-12T21:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-09T21:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-08T20:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-07T10:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-06T08:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-05T09:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-04T16:23:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-04T12:30:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-04T12:28:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-04T12:24:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-04T12:23:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-04T11:23:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-04T10:23:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-03T07:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-01T07:08:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-01T01:03:03Z", - "tree": null, - "paths": null - }, - { - "time": "2016-01-01T01:02:03Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-11-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2015-10-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-10-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2015-08-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30.1Z", - "tree": null, - "paths": null, - "tags": [ - "bar" - ] - }, - { - "time": "2014-11-13T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-12T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-11-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-20T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-11T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-09T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-06T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-05T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-02T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-10-01T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - { - "time": "2014-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - { - "time": "2014-08-08T10:20:30Z", - "tree": null, - "paths": null - } - ], - "reasons": [ - { - "snapshot": { - "time": "2016-01-18T12:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-12T21:08:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-12T21:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-09T21:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-08T20:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-07T10:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-06T08:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-05T09:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-04T16:23:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-04T12:30:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-04T12:28:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-04T12:24:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-04T12:23:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-04T11:23:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-04T10:23:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-03T07:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-01T07:08:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-01T01:03:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2016-01-01T01:02:03Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-15T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-13T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-12T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-10T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-11-08T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-22T10:20:30Z", - "tree": null, - "paths": [ - "path1", - "path2" - ], - "tags": [ - "foo", - "bar" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-20T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-11T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-10T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-09T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-08T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-06T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-05T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-02T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-10-01T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2015-08-08T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-21T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-20T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-18T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-15T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo", - "bar" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-13T10:20:30.1Z", - "tree": null, - "paths": null, - "tags": [ - "bar" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-13T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-12T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-11-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-22T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-20T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-11T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-10T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-09T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-08T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-06T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-05T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-02T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-10-01T10:20:30Z", - "tree": null, - "paths": null, - "tags": [ - "foo" - ] - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-20T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-11T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-10T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-09T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-08T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-06T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-05T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-02T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-09-01T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-22T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-21T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-20T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-18T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-15T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-13T10:20:30.1Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-13T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-12T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-10T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - }, - { - "snapshot": { - "time": "2014-08-08T10:20:30Z", - "tree": null, - "paths": null - }, - "matches": [ - "policy is empty" - ], - "counters": {} - } - ] + "keep": null } \ No newline at end of file From 82ca0030b7667e46c00cddaa55db0aa66e383d19 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 19 May 2024 00:09:12 +0200 Subject: [PATCH 5/8] forget: test --unsafe-allow-remove-all and --keep-tags safety check --- cmd/restic/cmd_forget_integration_test.go | 55 +++++++++++++++++-- cmd/restic/cmd_prune_integration_test.go | 4 +- .../cmd_repair_snapshots_integration_test.go | 4 +- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/cmd/restic/cmd_forget_integration_test.go b/cmd/restic/cmd_forget_integration_test.go index e4cdb744e..06487a841 100644 --- a/cmd/restic/cmd_forget_integration_test.go +++ b/cmd/restic/cmd_forget_integration_test.go @@ -2,18 +2,65 @@ package main import ( "context" + "path/filepath" + "strings" "testing" + "github.com/restic/restic/internal/restic" rtest "github.com/restic/restic/internal/test" "github.com/restic/restic/internal/ui/termstatus" ) -func testRunForget(t testing.TB, gopts GlobalOptions, args ...string) { - opts := ForgetOptions{} +func testRunForgetMayFail(gopts GlobalOptions, opts ForgetOptions, args ...string) error { pruneOpts := PruneOptions{ MaxUnused: "5%", } - rtest.OK(t, withTermStatus(gopts, func(ctx context.Context, term *termstatus.Terminal) error { + return withTermStatus(gopts, func(ctx context.Context, term *termstatus.Terminal) error { return runForget(context.TODO(), opts, pruneOpts, gopts, term, args) - })) + }) +} + +func testRunForget(t testing.TB, gopts GlobalOptions, opts ForgetOptions, args ...string) { + rtest.OK(t, testRunForgetMayFail(gopts, opts, args...)) +} + +func TestRunForgetSafetyNet(t *testing.T) { + env, cleanup := withTestEnvironment(t) + defer cleanup() + + testSetupBackupData(t, env) + + opts := BackupOptions{ + Host: "example", + } + testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, opts, env.gopts) + testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, opts, env.gopts) + testListSnapshots(t, env.gopts, 2) + + // --keep-tags invalid + err := testRunForgetMayFail(env.gopts, ForgetOptions{ + KeepTags: restic.TagLists{restic.TagList{"invalid"}}, + GroupBy: restic.SnapshotGroupByOptions{Host: true, Path: true}, + }) + rtest.Assert(t, strings.Contains(err.Error(), `refusing to delete last snapshot of snapshot group "host example, path`), "wrong error message got %v", err) + + // disallow `forget --unsafe-allow-remove-all` + err = testRunForgetMayFail(env.gopts, ForgetOptions{ + UnsafeAllowRemoveAll: true, + }) + rtest.Assert(t, strings.Contains(err.Error(), `--unsafe-allow-remove-all is not allowed unless a snapshot filter option is specified`), "wrong error message got %v", err) + + // disallow `forget` without options + err = testRunForgetMayFail(env.gopts, ForgetOptions{}) + rtest.Assert(t, strings.Contains(err.Error(), `no policy was specified, no snapshots will be removed`), "wrong error message got %v", err) + + // `forget --host example --unsafe-allow-remmove-all` should work + testRunForget(t, env.gopts, ForgetOptions{ + UnsafeAllowRemoveAll: true, + GroupBy: restic.SnapshotGroupByOptions{Host: true, Path: true}, + SnapshotFilter: restic.SnapshotFilter{ + Hosts: []string{opts.Host}, + }, + }) + testListSnapshots(t, env.gopts, 0) } diff --git a/cmd/restic/cmd_prune_integration_test.go b/cmd/restic/cmd_prune_integration_test.go index 715adea9a..5eb16a2ea 100644 --- a/cmd/restic/cmd_prune_integration_test.go +++ b/cmd/restic/cmd_prune_integration_test.go @@ -75,7 +75,7 @@ func createPrunableRepo(t *testing.T, env *testEnvironment) { testListSnapshots(t, env.gopts, 3) testRunForgetJSON(t, env.gopts) - testRunForget(t, env.gopts, firstSnapshot.String()) + testRunForget(t, env.gopts, ForgetOptions{}, firstSnapshot.String()) } func testRunForgetJSON(t testing.TB, gopts GlobalOptions, args ...string) { @@ -129,7 +129,7 @@ func TestPruneWithDamagedRepository(t *testing.T) { // create and delete snapshot to create unused blobs testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "2")}, opts, env.gopts) firstSnapshot := testListSnapshots(t, env.gopts, 1)[0] - testRunForget(t, env.gopts, firstSnapshot.String()) + testRunForget(t, env.gopts, ForgetOptions{}, firstSnapshot.String()) oldPacks := listPacks(env.gopts, t) diff --git a/cmd/restic/cmd_repair_snapshots_integration_test.go b/cmd/restic/cmd_repair_snapshots_integration_test.go index 34cd186d3..9f65c9328 100644 --- a/cmd/restic/cmd_repair_snapshots_integration_test.go +++ b/cmd/restic/cmd_repair_snapshots_integration_test.go @@ -62,7 +62,7 @@ func TestRepairSnapshotsWithLostData(t *testing.T) { testRunCheckMustFail(t, env.gopts) // repository must be ok after removing the broken snapshots - testRunForget(t, env.gopts, snapshotIDs[0].String(), snapshotIDs[1].String()) + testRunForget(t, env.gopts, ForgetOptions{}, snapshotIDs[0].String(), snapshotIDs[1].String()) testListSnapshots(t, env.gopts, 2) _, err := testRunCheckOutput(env.gopts, false) rtest.OK(t, err) @@ -86,7 +86,7 @@ func TestRepairSnapshotsWithLostTree(t *testing.T) { // remove tree for foo/bar and the now completely broken first snapshot removePacks(env.gopts, t, restic.NewIDSet(oldPacks...)) - testRunForget(t, env.gopts, oldSnapshot[0].String()) + testRunForget(t, env.gopts, ForgetOptions{}, oldSnapshot[0].String()) testRunCheckMustFail(t, env.gopts) // repair From 3f468088983177d3b87b009ddd8c489a91a3ffc6 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 19 May 2024 00:26:12 +0200 Subject: [PATCH 6/8] add forget safety net changelogs --- changelog/unreleased/issue-4568 | 13 +++++++++++++ changelog/unreleased/pull-4764 | 8 ++++++++ 2 files changed, 21 insertions(+) create mode 100644 changelog/unreleased/issue-4568 create mode 100644 changelog/unreleased/pull-4764 diff --git a/changelog/unreleased/issue-4568 b/changelog/unreleased/issue-4568 new file mode 100644 index 000000000..4d44809c5 --- /dev/null +++ b/changelog/unreleased/issue-4568 @@ -0,0 +1,13 @@ +Bugfix: Prevent `forget --keep-tags invalid` from deleting all snapshots + +Running `forget --keep-tags invalid`, where the tag `invalid` does not +exist in the repository, would remove all snapshots. This is especially +problematic if the tag name contains a typo. + +The `forget` command now fails with an error if all snapshots in a snapshot +group would be deleted. This prevents the above example from deleting all +snapshots. + +https://github.com/restic/restic/issues/4568 +https://github.com/restic/restic/pull/4764 +https://forum.restic.net/t/delete-all-snapshots-in-one-command-is-this-feature-intentional/6923/3 diff --git a/changelog/unreleased/pull-4764 b/changelog/unreleased/pull-4764 new file mode 100644 index 000000000..61b2edac9 --- /dev/null +++ b/changelog/unreleased/pull-4764 @@ -0,0 +1,8 @@ +Enhancement: Remove all snapshots using `forget --unsafe-allow-remove-all` + +The forget command now supports the `--unsafe-allow-remove-all` option. It must +always be combined with a snapshot filter (by host, path or tag). +For example the command `forget --tag example --unsafe-allow-remove-all`, +removes all snapshots with tag `example`. + +https://github.com/restic/restic/pull/4764 From 7948912b311cc3a304fa6c804cb2fa4f24c9e709 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 19 May 2024 00:34:18 +0200 Subject: [PATCH 7/8] document --unsafe-allow-remove-all option --- doc/060_forget.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/060_forget.rst b/doc/060_forget.rst index 113098d0c..b8d206c97 100644 --- a/doc/060_forget.rst +++ b/doc/060_forget.rst @@ -182,7 +182,9 @@ The ``forget`` command accepts the following policy options: - ``--keep-yearly n`` for the last ``n`` years which have one or more snapshots, keep only the most recent one for each year. - ``--keep-tag`` keep all snapshots which have all tags specified by - this option (can be specified multiple times). + this option (can be specified multiple times). The ``forget`` command will + exit with an error if all snapshots in a snapshot group would be removed + as none of them have the specified tags. - ``--keep-within duration`` keep all snapshots having a timestamp within the specified duration of the latest snapshot, where ``duration`` is a number of years, months, days, and hours. E.g. ``2y5m7d3h`` will keep all @@ -336,12 +338,23 @@ year and yearly for the last 75 years, you can instead specify ``forget --keep-within-yearly 75y`` (note that `1w` is not a recognized duration, so you will have to specify `7d` instead). + +Removing all snapshots +====================== + For safety reasons, restic refuses to act on an "empty" policy. For example, if one were to specify ``--keep-last 0`` to forget *all* snapshots in the repository, restic will respond that no snapshots will be removed. To delete all snapshots, use ``--keep-last 1`` and then finally remove the last snapshot manually (by passing the ID to ``forget``). +Since restic 0.17.0, it is possible to delete all snapshots for a specific +host, tag or path using the ``--unsafe-allow-remove-all`` option. The option +must always be combined with a snapshot filter (by host, path or tag). +For example the command ``forget --tag example --unsafe-allow-remove-all`` +removes all snapshots with tag ``example``. + + Security considerations in append-only mode =========================================== From 3cc6827f09f75f94904cbfeb3f1497af6510a56a Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 24 May 2024 20:41:19 +0200 Subject: [PATCH 8/8] forget: add feature flag for safe --keep-tags behavior --- changelog/unreleased/issue-4568 | 4 ++++ cmd/restic/cmd_forget.go | 3 ++- internal/feature/registry.go | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelog/unreleased/issue-4568 b/changelog/unreleased/issue-4568 index 4d44809c5..fedf373ea 100644 --- a/changelog/unreleased/issue-4568 +++ b/changelog/unreleased/issue-4568 @@ -8,6 +8,10 @@ The `forget` command now fails with an error if all snapshots in a snapshot group would be deleted. This prevents the above example from deleting all snapshots. +It is possible to temporarily disable the new check by setting the environment variable +`RESTIC_FEATURES=safe-forget-keep-tags=false`. Note that this feature flag +will be removed in the next minor restic version. + https://github.com/restic/restic/issues/4568 https://github.com/restic/restic/pull/4764 https://forum.restic.net/t/delete-all-snapshots-in-one-command-is-this-feature-intentional/6923/3 diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index 328b28271..9c40b1d09 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/restic/restic/internal/errors" + "github.com/restic/restic/internal/feature" "github.com/restic/restic/internal/restic" "github.com/restic/restic/internal/ui/termstatus" "github.com/spf13/cobra" @@ -258,7 +259,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy) - if !policy.Empty() && len(keep) == 0 { + if feature.Flag.Enabled(feature.SafeForgetKeepTags) && !policy.Empty() && len(keep) == 0 { return fmt.Errorf("refusing to delete last snapshot of snapshot group \"%v\"", key.String()) } if len(keep) != 0 && !gopts.Quiet && !gopts.JSON { diff --git a/internal/feature/registry.go b/internal/feature/registry.go index ac4105140..74d8a2f61 100644 --- a/internal/feature/registry.go +++ b/internal/feature/registry.go @@ -9,6 +9,7 @@ const ( DeprecateLegacyIndex FlagName = "deprecate-legacy-index" DeprecateS3LegacyLayout FlagName = "deprecate-s3-legacy-layout" DeviceIDForHardlinks FlagName = "device-id-for-hardlinks" + SafeForgetKeepTags FlagName = "safe-forget-keep-tags" ) func init() { @@ -17,5 +18,6 @@ func init() { DeprecateLegacyIndex: {Type: Beta, Description: "disable support for index format used by restic 0.1.0. Use `restic repair index` to update the index if necessary."}, DeprecateS3LegacyLayout: {Type: Beta, Description: "disable support for S3 legacy layout used up to restic 0.7.0. Use `RESTIC_FEATURES=deprecate-s3-legacy-layout=false restic migrate s3_layout` to migrate your S3 repository if necessary."}, DeviceIDForHardlinks: {Type: Alpha, Description: "store deviceID only for hardlinks to reduce metadata changes for example when using btrfs subvolumes. Will be removed in a future restic version after repository format 3 is available"}, + SafeForgetKeepTags: {Type: Beta, Description: "prevent deleting all snapshots if the tag passed to `forget --keep-tags tagname` does not exist"}, }) }