From 22466c305714ceddb2291c50a1e54974a5100001 Mon Sep 17 00:00:00 2001 From: Christos Arvanitis Date: Tue, 6 Oct 2020 12:44:36 +0200 Subject: [PATCH] Add rollback snapshot purging functionality --- cerndb-sw-zkpolicy.spec | 3 + zkPolicy/pom.xml | 2 +- .../src/main/java/ch/cern/ZKPolicyCli.java | 2 +- .../src/main/java/ch/cern/ZKPolicyDefs.java | 7 ++ .../main/java/ch/cern/ZKPurgeRollback.java | 71 +++++++++++++++++++ .../main/java/ch/cern/ZKPurgeRollbackCli.java | 41 +++++++++++ .../test/java/ch/cern/ZKPolicyCliTest.java | 1 - .../src/test/java/ch/cern/ZKQueryCliTest.java | 2 - 8 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 zkPolicy/src/main/java/ch/cern/ZKPurgeRollback.java create mode 100644 zkPolicy/src/main/java/ch/cern/ZKPurgeRollbackCli.java diff --git a/cerndb-sw-zkpolicy.spec b/cerndb-sw-zkpolicy.spec index e1a3ded..9c76435 100644 --- a/cerndb-sw-zkpolicy.spec +++ b/cerndb-sw-zkpolicy.spec @@ -101,6 +101,9 @@ rm -rf /var/log/zkpolicy %postun -p /bin/sh %changelog +* Tue Oct 6 2020 Christos Arvanitis 1.0.1-18 +- Add rollback snapshot purge feature + * Fri Jul 18 2020 Christos Arvanitis 1.0.1-8 - Add MIT License diff --git a/zkPolicy/pom.xml b/zkPolicy/pom.xml index f82f85a..7d701a9 100644 --- a/zkPolicy/pom.xml +++ b/zkPolicy/pom.xml @@ -13,7 +13,7 @@ or submit itself to any jurisdiction. 4.0.0 ch.cern cerndb-sw-zkpolicy - 1.0.1-17 + 1.0.1-18 ${project.groupId}:${project.artifactId} zkpolicy - ZooKeeper Policy Auditing Tool https://github.com/cerndb/zkpolicy diff --git a/zkPolicy/src/main/java/ch/cern/ZKPolicyCli.java b/zkPolicy/src/main/java/ch/cern/ZKPolicyCli.java index 6b8c349..4367724 100644 --- a/zkPolicy/src/main/java/ch/cern/ZKPolicyCli.java +++ b/zkPolicy/src/main/java/ch/cern/ZKPolicyCli.java @@ -25,7 +25,7 @@ @Command(name = "zkpolicy", description = ZkPolicy.DESCRIPTION, versionProvider = ZKPolicyCli.PropertiesVersionProvider.class, subcommands = { ZKQueryCli.class, ZKExportCli.class, ZKTreeCli.class, ZKEnforceCli.class, ZKAuditCli.class, ZKCheckCli.class, - ZKRollbackCli.class, HelpCommand.class }, mixinStandardHelpOptions = true) + ZKRollbackCli.class, ZKPurgeRollbackCli.class, HelpCommand.class }, mixinStandardHelpOptions = true) /** * Class that handles CLI arguments for the tool. */ diff --git a/zkPolicy/src/main/java/ch/cern/ZKPolicyDefs.java b/zkPolicy/src/main/java/ch/cern/ZKPolicyDefs.java index 524e60f..28e6301 100644 --- a/zkPolicy/src/main/java/ch/cern/ZKPolicyDefs.java +++ b/zkPolicy/src/main/java/ch/cern/ZKPolicyDefs.java @@ -137,6 +137,13 @@ static class Rollback { static final String DESCRIPTION = "Rollback ACLs to pre enforce state"; static final String INPUT_STATE_DESCRIPTION = "File with ZooKeeper tree state before enforcing"; } + + static class PurgeRollback { + static final String DESCRIPTION = "Purge rollback snapshots, retaining a user defined number"; + static final String RETAIN_CNT_DESCRIPTION = "Number of rollback snapshots to retain after purging"; + static final String ROLLBACK_DIR_DESCRIPTION = "Rollback snapshots directory"; + static final String ROLLBACK_DIR_DEFAULT = "/opt/zkpolicy/rollback"; + } } static class Queries { diff --git a/zkPolicy/src/main/java/ch/cern/ZKPurgeRollback.java b/zkPolicy/src/main/java/ch/cern/ZKPurgeRollback.java new file mode 100644 index 0000000..09d706a --- /dev/null +++ b/zkPolicy/src/main/java/ch/cern/ZKPurgeRollback.java @@ -0,0 +1,71 @@ +/* +* Copyright © 2020, CERN +* This software is distributed under the terms of the MIT Licence, +* copied verbatim in the file 'LICENSE'. In applying this licence, +* CERN does not waive the privileges and immunities +* granted to it by virtue of its status as an Intergovernmental Organization +* or submit itself to any jurisdiction. +*/ +package ch.cern; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.Arrays; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.AccessLevel; + + +/** + * Purge rollback snapshots. + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor(access = AccessLevel.PROTECTED) +public class ZKPurgeRollback { + private static Logger logger = LogManager.getLogger(ZKPurgeRollback.class); + + private File rollbackDir; + /** + * Purge rollback snapshots retaining retainCount number of snapshots. + * + * @param retainCount Number of snapshots to retain + * @throws IOException + */ + public void purgeRollback(Integer retainCount) throws IOException { + // Sort files lexicographically + final File[] files = rollbackDir.listFiles(new RollbackFilenameFilter()); + + if (files != null) { + Arrays.sort(files); + Integer totalSnapshotNum = files.length; + Integer cnt = 0; + for (File rollbackFile : files) { + if (totalSnapshotNum - cnt > retainCount) { + logger.info("Purging: " + rollbackFile.getPath()); + if (!rollbackFile.delete()) { + logger.error("Failed to delete " + rollbackFile.getPath()); + throw new IOException("Failed to delete " + rollbackFile.getPath()); + } + } else { + break; + } + cnt = cnt + 1; + } + } + } + + static class RollbackFilenameFilter implements FilenameFilter { + @Override + public boolean accept(final File dir, final String name) { + return name.matches("^ROLLBACK_STATE.*\\.yml"); + } + } + +} \ No newline at end of file diff --git a/zkPolicy/src/main/java/ch/cern/ZKPurgeRollbackCli.java b/zkPolicy/src/main/java/ch/cern/ZKPurgeRollbackCli.java new file mode 100644 index 0000000..7de49c8 --- /dev/null +++ b/zkPolicy/src/main/java/ch/cern/ZKPurgeRollbackCli.java @@ -0,0 +1,41 @@ +/* +* Copyright © 2020, CERN +* This software is distributed under the terms of the MIT Licence, +* copied verbatim in the file 'LICENSE'. In applying this licence, +* CERN does not waive the privileges and immunities +* granted to it by virtue of its status as an Intergovernmental Organization +* or submit itself to any jurisdiction. +*/ +package ch.cern; + +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import java.io.File; +import java.io.IOException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import ch.cern.ZKPolicyDefs.Cli.PurgeRollback; + +@Command(name = "purge-rollback", aliases = { + "p" }, description = PurgeRollback.DESCRIPTION, helpCommand = true, mixinStandardHelpOptions = true) +public class ZKPurgeRollbackCli implements Runnable { + private static Logger logger = LogManager.getLogger(ZKPurgeRollbackCli.class); + + @Option(names = { "-r", "--retain-count" }, required = true, description = PurgeRollback.RETAIN_CNT_DESCRIPTION) + Integer retainCount; + + @Option(names = { "-d", + "--rollback-dir" }, required = false, defaultValue = PurgeRollback.ROLLBACK_DIR_DEFAULT, description = PurgeRollback.ROLLBACK_DIR_DESCRIPTION) + File rollbackDir; + + @Override + public void run() { + ZKPurgeRollback zkPurge = new ZKPurgeRollback(rollbackDir); + try { + zkPurge.purgeRollback(this.retainCount); + } catch (IOException e) { + System.out.println(e.toString()); + logger.error("Exception occurred!", e); + } + } +} \ No newline at end of file diff --git a/zkPolicy/src/test/java/ch/cern/ZKPolicyCliTest.java b/zkPolicy/src/test/java/ch/cern/ZKPolicyCliTest.java index 6e92e74..529cfd4 100644 --- a/zkPolicy/src/test/java/ch/cern/ZKPolicyCliTest.java +++ b/zkPolicy/src/test/java/ch/cern/ZKPolicyCliTest.java @@ -10,7 +10,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNull; import java.io.ByteArrayOutputStream; import java.io.File; diff --git a/zkPolicy/src/test/java/ch/cern/ZKQueryCliTest.java b/zkPolicy/src/test/java/ch/cern/ZKQueryCliTest.java index b7affc3..7b81387 100644 --- a/zkPolicy/src/test/java/ch/cern/ZKQueryCliTest.java +++ b/zkPolicy/src/test/java/ch/cern/ZKQueryCliTest.java @@ -16,9 +16,7 @@ import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.apache.curator.test.InstanceSpec; import org.apache.curator.test.TestingServer;