Introduce CMS-specific SLC module
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 28 May 2022 06:19:20 +0000 (08:19 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 28 May 2022 06:19:20 +0000 (08:19 +0200)
48 files changed:
Makefile
cms/org.argeo.slc.cms/.classpath [new file with mode: 0644]
cms/org.argeo.slc.cms/.project [new file with mode: 0644]
cms/org.argeo.slc.cms/bnd.bnd [new file with mode: 0644]
cms/org.argeo.slc.cms/build.properties [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/AbstractAtomicBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/AtomicBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupContext.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupFileSystemManager.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupPurge.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupUtils.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/MaintenanceException.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/MySqlBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/OpenLdapBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/OsCallBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/PostgreSqlBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SimpleBackupContext.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SimpleBackupPurge.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SvnBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SystemBackup.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/package-info.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/cli/ArgeoCli.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/Echo.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/PosixCommands.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/package-info.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/cms/deploy/SimpleCmsTargetData.java [new file with mode: 0644]
cms/org.argeo.slc.cms/src/org/argeo/slc/cms/test/CmsSmokeTest.java [new file with mode: 0644]
org.argeo.slc.runtime/bnd.bnd
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/AbstractAtomicBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/AtomicBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupContext.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupFileSystemManager.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupPurge.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupUtils.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/MaintenanceException.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/MySqlBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/OpenLdapBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/OsCallBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/PostgreSqlBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SimpleBackupContext.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SimpleBackupPurge.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SvnBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SystemBackup.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/package-info.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/Echo.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/PosixCommands.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/package-info.java [deleted file]
org.argeo.slc.runtime/src/org/argeo/slc/runtime/ArgeoCli.java [deleted file]

index ff9eec9dc9ca38625125222c16b14bcbed9da91e..fd7e29145081abc0e8c4d2728141c2446d68e51f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,9 @@ BUNDLES = \
 org.argeo.slc.api \
 org.argeo.slc.factory \
 org.argeo.slc.runtime \
+cms/org.argeo.slc.cms \
 
+VPATH = .:cms
 
 clean:
        rm -rf $(BUILD_BASE)
diff --git a/cms/org.argeo.slc.cms/.classpath b/cms/org.argeo.slc.cms/.classpath
new file mode 100644 (file)
index 0000000..81fe078
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/cms/org.argeo.slc.cms/.project b/cms/org.argeo.slc.cms/.project
new file mode 100644 (file)
index 0000000..95c8de1
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.slc.cms</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/cms/org.argeo.slc.cms/bnd.bnd b/cms/org.argeo.slc.cms/bnd.bnd
new file mode 100644 (file)
index 0000000..927563f
--- /dev/null
@@ -0,0 +1,3 @@
+Import-Package: \
+org.apache.commons.logging,\
+*
\ No newline at end of file
diff --git a/cms/org.argeo.slc.cms/build.properties b/cms/org.argeo.slc.cms/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/AbstractAtomicBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/AbstractAtomicBackup.java
new file mode 100644 (file)
index 0000000..6d55374
--- /dev/null
@@ -0,0 +1,82 @@
+package org.argeo.slc.backup.vfs;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
+
+/**
+ * Simplify atomic backups implementation, especially by managing VFS.
+ */
+public abstract class AbstractAtomicBackup implements AtomicBackup {
+       private String name;
+       private String compression = "bz2";
+
+       protected abstract void writeBackup(FileObject targetFo);
+
+       public AbstractAtomicBackup() {
+       }
+
+       public AbstractAtomicBackup(String name) {
+               this.name = name;
+       }
+
+       public void init() {
+               if (name == null)
+                       throw new MaintenanceException("Atomic backup name must be set");
+       }
+
+       public void destroy() {
+
+       }
+
+       @Override
+       public String backup(FileSystemManager fileSystemManager,
+                       String backupsBase, BackupContext backupContext,
+                       FileSystemOptions opts) {
+               if (name == null)
+                       throw new MaintenanceException("Atomic backup name must be set");
+
+               FileObject targetFo = null;
+               try {
+                       if (backupsBase.startsWith("sftp:"))
+                               SftpFileSystemConfigBuilder.getInstance()
+                                               .setStrictHostKeyChecking(opts, "no");
+                       if (compression == null || compression.equals("none"))
+                               targetFo = fileSystemManager.resolveFile(backupsBase + '/'
+                                               + backupContext.getRelativeFolder() + '/' + name, opts);
+                       else if (compression.equals("bz2"))
+                               targetFo = fileSystemManager.resolveFile("bz2:" + backupsBase
+                                               + '/' + backupContext.getRelativeFolder() + '/' + name
+                                               + ".bz2" + "!" + name, opts);
+                       else if (compression.equals("gz"))
+                               targetFo = fileSystemManager.resolveFile("gz:" + backupsBase
+                                               + '/' + backupContext.getRelativeFolder() + '/' + name
+                                               + ".gz" + "!" + name, opts);
+                       else
+                               throw new MaintenanceException("Unsupported compression "
+                                               + compression);
+
+                       writeBackup(targetFo);
+
+                       return targetFo.toString();
+               } catch (Exception e) {
+                       throw new MaintenanceException("Cannot backup " + name + " to "
+                                       + targetFo, e);
+               } finally {
+                       BackupUtils.closeFOQuietly(targetFo);
+               }
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public void setCompression(String compression) {
+               this.compression = compression;
+       }
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/AtomicBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/AtomicBackup.java
new file mode 100644 (file)
index 0000000..0cfcfab
--- /dev/null
@@ -0,0 +1,22 @@
+package org.argeo.slc.backup.vfs;
+
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileSystemOptions;
+
+/** Performs the backup of a single component, typically a database dump */
+public interface AtomicBackup {
+       /** Name identifiying this backup */
+       public String getName();
+
+       /**
+        * Retrieves the data of the component in a format that allows to restore
+        * the component
+        * 
+        * @param backupContext
+        *            the context of this backup
+        * @return the VFS URI of the generated file or directory
+        */
+       public String backup(FileSystemManager fileSystemManager,
+                       String backupsBase, BackupContext backupContext,
+                       FileSystemOptions opts);
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupContext.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupContext.java
new file mode 100644 (file)
index 0000000..9c1140b
--- /dev/null
@@ -0,0 +1,25 @@
+package org.argeo.slc.backup.vfs;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+/**
+ * Transient information of a given backup, centralizing common information such
+ * as timestamp and location.
+ */
+public interface BackupContext {
+       /** Backup date */
+       public Date getTimestamp();
+
+       /** Formatted backup date */
+       public String getTimestampAsString();
+
+       /** System name */
+       public String getSystemName();
+
+       /** Local base */
+       public String getRelativeFolder();
+
+       /** Date format */
+       public DateFormat getDateFormat();
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupFileSystemManager.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupFileSystemManager.java
new file mode 100644 (file)
index 0000000..ad42dd3
--- /dev/null
@@ -0,0 +1,36 @@
+package org.argeo.slc.backup.vfs;
+
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
+import org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider;
+import org.apache.commons.vfs2.provider.ftp.FtpFileProvider;
+import org.apache.commons.vfs2.provider.gzip.GzipFileProvider;
+import org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider;
+import org.apache.commons.vfs2.provider.ram.RamFileProvider;
+import org.apache.commons.vfs2.provider.sftp.SftpFileProvider;
+import org.apache.commons.vfs2.provider.url.UrlFileProvider;
+
+/**
+ * Programatically configured VFS file system manager which can be declared as a
+ * bean and associated with a life cycle (methods
+ * {@link DefaultFileSystemManager#init()} and
+ * {@link DefaultFileSystemManager#close()}). Supports bz2, file, ram, gzip,
+ * ftp, sftp
+ */
+public class BackupFileSystemManager extends DefaultFileSystemManager {
+
+       public BackupFileSystemManager() {
+               super();
+               try {
+                       addProvider("file", new DefaultLocalFileProvider());
+                       addProvider("bz2", new Bzip2FileProvider());
+                       addProvider("ftp", new FtpFileProvider());
+                       addProvider("sftp", new SftpFileProvider());
+                       addProvider("gzip", new GzipFileProvider());
+                       addProvider("ram", new RamFileProvider());
+                       setDefaultProvider(new UrlFileProvider());
+               } catch (FileSystemException e) {
+                       throw new MaintenanceException("Cannot configure backup file provider", e);
+               }
+       }
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupPurge.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupPurge.java
new file mode 100644 (file)
index 0000000..1d07bbf
--- /dev/null
@@ -0,0 +1,18 @@
+package org.argeo.slc.backup.vfs;
+
+import java.text.DateFormat;
+
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileSystemOptions;
+
+/** Purges previous backups */
+public interface BackupPurge {
+       /**
+        * Purge the backups identified by these arguments. Although these are the
+        * same fields as a {@link BackupContext} we don't pass it as argument since
+        * we want to use this interface to purge remote backups as well (that is,
+        * with a different base), or outside the scope of a running backup.
+        */
+       public void purge(FileSystemManager fileSystemManager, String base,
+                       String name, DateFormat dateFormat, FileSystemOptions opts);
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupUtils.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/BackupUtils.java
new file mode 100644 (file)
index 0000000..bc4d0c8
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.slc.backup.vfs;
+
+import org.apache.commons.vfs2.FileObject;
+
+/** Backup utilities */
+public class BackupUtils {
+       /** Close a file object quietly even if it is null or throws an exception. */
+       public static void closeFOQuietly(FileObject fo) {
+               if (fo != null) {
+                       try {
+                               fo.close();
+                       } catch (Exception e) {
+                               // silent
+                       }
+               }
+       }
+       
+       /** Prevents instantiation */
+       private BackupUtils() {
+       }
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/MaintenanceException.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/MaintenanceException.java
new file mode 100644 (file)
index 0000000..1532503
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.slc.backup.vfs;
+
+@Deprecated
+class MaintenanceException extends RuntimeException {
+       private static final long serialVersionUID = -5770049663929537270L;
+
+       public MaintenanceException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+       public MaintenanceException(String message) {
+               super(message);
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/MySqlBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/MySqlBackup.java
new file mode 100644 (file)
index 0000000..3f0e670
--- /dev/null
@@ -0,0 +1,59 @@
+package org.argeo.slc.backup.vfs;
+
+import org.apache.commons.vfs2.FileObject;
+
+/** Backups a MySQL database using mysqldump. */
+public class MySqlBackup extends OsCallBackup {
+       private String mysqldumpLocation = "/usr/bin/mysqldump";
+
+       private String dbUser;
+       private String dbPassword;
+       private String dbName;
+
+       public MySqlBackup() {
+       }
+
+       public MySqlBackup(String dbUser, String dbPassword, String dbName) {
+               this.dbUser = dbUser;
+               this.dbPassword = dbPassword;
+               this.dbName = dbName;
+               init();
+       }
+
+       @Override
+       public void init() {
+               if (getName() == null)
+                       setName(dbName + ".mysql");
+               super.init();
+       }
+
+       @Override
+       public void writeBackup(FileObject targetFo) {
+               if (getCommand() == null)
+                       setCommand(mysqldumpLocation
+                                       + " --lock-tables --add-locks --add-drop-table"
+                                       + " -u ${dbUser} --password=${dbPassword} --databases ${dbName}");
+               getVariables().put("dbUser", dbUser);
+               getVariables().put("dbPassword", dbPassword);
+               getVariables().put("dbName", dbName);
+
+               super.writeBackup(targetFo);
+       }
+
+       public void setDbUser(String dbUser) {
+               this.dbUser = dbUser;
+       }
+
+       public void setDbPassword(String dbPassword) {
+               this.dbPassword = dbPassword;
+       }
+
+       public void setDbName(String dbName) {
+               this.dbName = dbName;
+       }
+
+       public void setMysqldumpLocation(String mysqldumpLocation) {
+               this.mysqldumpLocation = mysqldumpLocation;
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/OpenLdapBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/OpenLdapBackup.java
new file mode 100644 (file)
index 0000000..31914bd
--- /dev/null
@@ -0,0 +1,46 @@
+package org.argeo.slc.backup.vfs;
+
+import org.apache.commons.vfs2.FileObject;
+
+/** Backups an OpenLDAP server using slapcat */
+public class OpenLdapBackup extends OsCallBackup {
+       private String slapcatLocation = "/usr/sbin/slapcat";
+       private String slapdConfLocation = "/etc/openldap/slapd.conf";
+       private String baseDn;
+
+       public OpenLdapBackup() {
+               super();
+       }
+
+       public OpenLdapBackup(String baseDn) {
+               super();
+               this.baseDn = baseDn;
+       }
+
+       @Override
+       public void writeBackup(FileObject targetFo) {
+               if (baseDn == null)
+                       throw new MaintenanceException("Base DN must be set");
+
+               if (getCommand() == null)
+                       setCommand(slapcatLocation
+                                       + " -f ${slapdConfLocation} -b '${baseDn}'");
+               getVariables().put("slapdConfLocation", slapdConfLocation);
+               getVariables().put("baseDn", baseDn);
+
+               super.writeBackup(targetFo);
+       }
+
+       public void setSlapcatLocation(String slapcatLocation) {
+               this.slapcatLocation = slapcatLocation;
+       }
+
+       public void setSlapdConfLocation(String slapdConfLocation) {
+               this.slapdConfLocation = slapdConfLocation;
+       }
+
+       public void setBaseDn(String baseDn) {
+               this.baseDn = baseDn;
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/OsCallBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/OsCallBackup.java
new file mode 100644 (file)
index 0000000..380dffe
--- /dev/null
@@ -0,0 +1,115 @@
+package org.argeo.slc.backup.vfs;
+
+import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ExecuteException;
+import org.apache.commons.exec.ExecuteStreamHandler;
+import org.apache.commons.exec.Executor;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.vfs2.FileContent;
+import org.apache.commons.vfs2.FileObject;
+import org.argeo.api.cms.CmsLog;
+
+/**
+ * Runs an OS command and save its standard output as a file. Typically used for
+ * MySQL or OpenLDAP dumps.
+ */
+public class OsCallBackup extends AbstractAtomicBackup {
+       private final static CmsLog log = CmsLog.getLog(OsCallBackup.class);
+
+       private String command;
+       private Map<String, String> variables = new HashMap<String, String>();
+       private Executor executor = new DefaultExecutor();
+
+       private Map<String, String> environment = new HashMap<String, String>();
+
+       /** Name of the sudo user, root if "", not sudo if null */
+       private String sudo = null;
+
+       public OsCallBackup() {
+       }
+
+       public OsCallBackup(String name) {
+               super(name);
+       }
+
+       public OsCallBackup(String name, String command) {
+               super(name);
+               this.command = command;
+       }
+
+       @Override
+       public void writeBackup(FileObject targetFo) {
+               String commandToUse = command;
+
+               // sudo
+               if (sudo != null) {
+                       if (sudo.equals(""))
+                               commandToUse = "sudo " + commandToUse;
+                       else
+                               commandToUse = "sudo -u " + sudo + " " + commandToUse;
+               }
+
+               CommandLine commandLine = CommandLine.parse(commandToUse, variables);
+               ByteArrayOutputStream errBos = new ByteArrayOutputStream();
+               if (log.isTraceEnabled())
+                       log.trace(commandLine.toString());
+
+               try {
+                       // stdout
+                       FileContent targetContent = targetFo.getContent();
+                       // stderr
+                       ExecuteStreamHandler streamHandler = new PumpStreamHandler(targetContent.getOutputStream(), errBos);
+                       executor.setStreamHandler(streamHandler);
+                       executor.execute(commandLine, environment);
+               } catch (ExecuteException e) {
+                       byte[] err = errBos.toByteArray();
+                       String errStr = new String(err);
+                       throw new MaintenanceException("Process " + commandLine + " failed (" + e.getExitValue() + "): " + errStr, e);
+               } catch (Exception e) {
+                       byte[] err = errBos.toByteArray();
+                       String errStr = new String(err);
+                       throw new MaintenanceException("Process " + commandLine + " failed: " + errStr, e);
+               } finally {
+                       IOUtils.closeQuietly(errBos);
+               }
+       }
+
+       public void setCommand(String command) {
+               this.command = command;
+       }
+
+       protected String getCommand() {
+               return command;
+       }
+
+       /**
+        * A reference to the environment variables that will be passed to the
+        * process. Empty by default.
+        */
+       protected Map<String, String> getEnvironment() {
+               return environment;
+       }
+
+       protected Map<String, String> getVariables() {
+               return variables;
+       }
+
+       public void setVariables(Map<String, String> variables) {
+               this.variables = variables;
+       }
+
+       public void setExecutor(Executor executor) {
+               this.executor = executor;
+       }
+
+       public void setSudo(String sudo) {
+               this.sudo = sudo;
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/PostgreSqlBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/PostgreSqlBackup.java
new file mode 100644 (file)
index 0000000..613fd5a
--- /dev/null
@@ -0,0 +1,70 @@
+package org.argeo.slc.backup.vfs;
+
+import org.apache.commons.vfs2.FileObject;
+
+/** Backups a PostgreSQL database using pg_dump. */
+public class PostgreSqlBackup extends OsCallBackup {
+       /**
+        * PostgreSQL password environment variable (see
+        * http://stackoverflow.com/questions
+        * /2893954/how-to-pass-in-password-to-pg-dump)
+        */
+       protected final static String PGPASSWORD = "PGPASSWORD";
+
+       private String pgDumpLocation = "/usr/bin/pg_dump";
+
+       private String dbUser;
+       private String dbPassword;
+       private String dbName;
+
+       public PostgreSqlBackup() {
+               super();
+       }
+
+       public PostgreSqlBackup(String dbUser, String dbPassword, String dbName) {
+               this.dbUser = dbUser;
+               this.dbPassword = dbPassword;
+               this.dbName = dbName;
+               init();
+       }
+
+       @Override
+       public void init() {
+               // disable compression since pg_dump is used with -Fc option
+               setCompression(null);
+
+               if (getName() == null)
+                       setName(dbName + ".pgdump");
+               super.init();
+       }
+
+       @Override
+       public void writeBackup(FileObject targetFo) {
+               if (getCommand() == null) {
+                       getEnvironment().put(PGPASSWORD, dbPassword);
+                       setCommand(pgDumpLocation + " -Fc" + " -U ${dbUser} ${dbName}");
+               }
+               getVariables().put("dbUser", dbUser);
+               getVariables().put("dbPassword", dbPassword);
+               getVariables().put("dbName", dbName);
+
+               super.writeBackup(targetFo);
+       }
+
+       public void setDbUser(String dbUser) {
+               this.dbUser = dbUser;
+       }
+
+       public void setDbPassword(String dbPassword) {
+               this.dbPassword = dbPassword;
+       }
+
+       public void setDbName(String dbName) {
+               this.dbName = dbName;
+       }
+
+       public void setPgDumpLocation(String mysqldumpLocation) {
+               this.pgDumpLocation = mysqldumpLocation;
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SimpleBackupContext.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SimpleBackupContext.java
new file mode 100644 (file)
index 0000000..9ee6871
--- /dev/null
@@ -0,0 +1,48 @@
+package org.argeo.slc.backup.vfs;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.commons.vfs2.FileSystemManager;
+
+/** Simple implementation of a backup context */
+public class SimpleBackupContext implements BackupContext {
+       private DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmm");
+       private final Date timestamp;
+       private final String name;
+
+       private final FileSystemManager fileSystemManager;
+
+       public SimpleBackupContext(FileSystemManager fileSystemManager,
+                       String backupsBase, String name) {
+               this.name = name;
+               this.timestamp = new Date();
+               this.fileSystemManager = fileSystemManager;
+       }
+
+       public Date getTimestamp() {
+               return timestamp;
+       }
+
+       public String getTimestampAsString() {
+               return dateFormat.format(timestamp);
+       }
+
+       public String getSystemName() {
+               return name;
+       }
+
+       public String getRelativeFolder() {
+               return name + '/' + getTimestampAsString();
+       }
+
+       public DateFormat getDateFormat() {
+               return dateFormat;
+       }
+
+       public FileSystemManager getFileSystemManager() {
+               return fileSystemManager;
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SimpleBackupPurge.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SimpleBackupPurge.java
new file mode 100644 (file)
index 0000000..0871109
--- /dev/null
@@ -0,0 +1,71 @@
+package org.argeo.slc.backup.vfs;
+
+import java.text.DateFormat;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Date;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.Selectors;
+import org.argeo.api.cms.CmsLog;
+
+/** Simple backup purge which keeps backups only for a given number of days */
+public class SimpleBackupPurge implements BackupPurge {
+       private final static CmsLog log = CmsLog.getLog(SimpleBackupPurge.class);
+
+       private Integer daysKept = 30;
+
+       @Override
+       public void purge(FileSystemManager fileSystemManager, String base, String name, DateFormat dateFormat,
+                       FileSystemOptions opts) {
+               try {
+                       ZonedDateTime nowDt = ZonedDateTime.now();
+                       FileObject baseFo = fileSystemManager.resolveFile(base + '/' + name, opts);
+
+                       SortedMap<ZonedDateTime, FileObject> toDelete = new TreeMap<ZonedDateTime, FileObject>();
+                       int backupCount = 0;
+
+                       // make sure base dir exists
+                       baseFo.createFolder();
+
+                       // scan backups and list those which should be deleted
+                       for (FileObject backupFo : baseFo.getChildren()) {
+                               String backupName = backupFo.getName().getBaseName();
+                               Date backupDate = dateFormat.parse(backupName);
+                               backupCount++;
+                               ZonedDateTime backupDt = ZonedDateTime.ofInstant(backupDate.toInstant(), ZoneId.systemDefault());
+                               Period sinceThen = Period.between(backupDt.toLocalDate(), nowDt.toLocalDate());
+                               // new Period(backupDt, nowDt);
+                               int days = sinceThen.getDays();
+                               // int days = sinceThen.getMinutes();
+                               if (days > daysKept) {
+                                       toDelete.put(backupDt, backupFo);
+                               }
+                       }
+
+                       if (toDelete.size() != 0 && toDelete.size() == backupCount) {
+                               // all backups would be deleted
+                               // but we want to keep at least one
+                               ZonedDateTime lastBackupDt = toDelete.firstKey();
+                               FileObject keptFo = toDelete.remove(lastBackupDt);
+                               log.warn("Backup " + keptFo + " kept although it is older than " + daysKept + " days.");
+                       }
+
+                       // delete old backups
+                       for (FileObject backupFo : toDelete.values()) {
+                               backupFo.delete(Selectors.SELECT_ALL);
+                               if (log.isDebugEnabled())
+                                       log.debug("Deleted backup " + backupFo);
+                       }
+               } catch (Exception e) {
+                       throw new MaintenanceException("Could not purge previous backups", e);
+               }
+
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SvnBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SvnBackup.java
new file mode 100644 (file)
index 0000000..ea9f844
--- /dev/null
@@ -0,0 +1,55 @@
+package org.argeo.slc.backup.vfs;
+
+import java.io.File;
+
+import org.apache.commons.vfs2.FileObject;
+
+/** Backups a Subversion repository using svnadmin. */
+public class SvnBackup extends OsCallBackup {
+       private String svnadminLocation = "/usr/bin/svnadmin";
+
+       private String repoLocation;
+       private String repoName;
+
+       public SvnBackup() {
+       }
+
+       public SvnBackup(String repoLocation) {
+               this.repoLocation = repoLocation;
+               init();
+       }
+
+       @Override
+       public void init() {
+               // use directory as repo name
+               if (repoName == null)
+                       repoName = new File(repoLocation).getName();
+
+               if (getName() == null)
+                       setName(repoName + ".svndump");
+               super.init();
+       }
+
+       @Override
+       public void writeBackup(FileObject targetFo) {
+               if (getCommand() == null) {
+                       setCommand(svnadminLocation + " dump " + " ${repoLocation}");
+               }
+               getVariables().put("repoLocation", repoLocation);
+
+               super.writeBackup(targetFo);
+       }
+
+       public void setRepoLocation(String repoLocation) {
+               this.repoLocation = repoLocation;
+       }
+
+       public void setRepoName(String repoName) {
+               this.repoName = repoName;
+       }
+
+       public void setSvnadminLocation(String mysqldumpLocation) {
+               this.svnadminLocation = mysqldumpLocation;
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SystemBackup.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/SystemBackup.java
new file mode 100644 (file)
index 0000000..7f23d72
--- /dev/null
@@ -0,0 +1,199 @@
+package org.argeo.slc.backup.vfs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemException;
+import org.apache.commons.vfs2.FileSystemManager;
+import org.apache.commons.vfs2.FileSystemOptions;
+import org.apache.commons.vfs2.Selectors;
+import org.apache.commons.vfs2.UserAuthenticator;
+import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.util.LangUtils;
+
+/**
+ * Combines multiple backups and transfer them to a remote location. Purges
+ * remote and local data based on certain criteria.
+ */
+public class SystemBackup implements Runnable {
+       private final static CmsLog log = CmsLog.getLog(SystemBackup.class);
+
+       private FileSystemManager fileSystemManager;
+       private UserAuthenticator userAuthenticator = null;
+
+       private String backupsBase;
+       private String systemName;
+
+       private List<AtomicBackup> atomicBackups = new ArrayList<AtomicBackup>();
+       private BackupPurge backupPurge = new SimpleBackupPurge();
+
+       private Map<String, UserAuthenticator> remoteBases = new HashMap<String, UserAuthenticator>();
+
+       @Override
+       public void run() {
+               if (atomicBackups.size() == 0)
+                       throw new MaintenanceException("No atomic backup listed");
+               List<String> failures = new ArrayList<String>();
+
+               SimpleBackupContext backupContext = new SimpleBackupContext(fileSystemManager, backupsBase, systemName);
+
+               // purge older backups
+               FileSystemOptions opts = new FileSystemOptions();
+               try {
+                       DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, userAuthenticator);
+               } catch (Exception e) {
+                       throw new MaintenanceException("Cannot create authentication", e);
+               }
+
+               try {
+
+                       backupPurge.purge(fileSystemManager, backupsBase, systemName, backupContext.getDateFormat(), opts);
+               } catch (Exception e) {
+                       failures.add("Purge " + backupsBase + " failed: " + e.getMessage());
+                       log.error("Purge of " + backupsBase + " failed", e);
+               }
+
+               // perform backup
+               for (AtomicBackup atomickBackup : atomicBackups) {
+                       try {
+                               String target = atomickBackup.backup(fileSystemManager, backupsBase, backupContext, opts);
+                               if (log.isDebugEnabled())
+                                       log.debug("Performed backup " + target);
+                       } catch (Exception e) {
+                               String msg = "Atomic backup " + atomickBackup.getName() + " failed: "
+                                               + LangUtils.chainCausesMessages(e);
+                               failures.add(msg);
+                               log.error(msg);
+                               if (log.isTraceEnabled())
+                                       log.trace("Stacktrace of atomic backup " + atomickBackup.getName() + " failure.", e);
+                       }
+               }
+
+               // dispatch to remote
+               for (String remoteBase : remoteBases.keySet()) {
+                       FileObject localBaseFo = null;
+                       FileObject remoteBaseFo = null;
+                       UserAuthenticator auth = remoteBases.get(remoteBase);
+
+                       // authentication
+                       FileSystemOptions remoteOpts = new FileSystemOptions();
+                       try {
+                               DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(remoteOpts, auth);
+                               backupPurge.purge(fileSystemManager, remoteBase, systemName, backupContext.getDateFormat(), remoteOpts);
+                       } catch (Exception e) {
+                               failures.add("Purge " + remoteBase + " failed: " + e.getMessage());
+                               log.error("Cannot purge " + remoteBase, e);
+                       }
+
+                       try {
+                               localBaseFo = fileSystemManager.resolveFile(backupsBase + '/' + backupContext.getRelativeFolder(),
+                                               opts);
+                               remoteBaseFo = fileSystemManager.resolveFile(remoteBase + '/' + backupContext.getRelativeFolder(),
+                                               remoteOpts);
+                               remoteBaseFo.copyFrom(localBaseFo, Selectors.SELECT_ALL);
+                               if (log.isDebugEnabled())
+                                       log.debug("Copied backup to " + remoteBaseFo + " from " + localBaseFo);
+                               // }
+                       } catch (Exception e) {
+                               failures.add("Dispatch to " + remoteBase + " failed: " + e.getMessage());
+                               log.error("Cannot dispatch backups from " + backupContext.getRelativeFolder() + " to " + remoteBase, e);
+                       }
+                       BackupUtils.closeFOQuietly(localBaseFo);
+                       BackupUtils.closeFOQuietly(remoteBaseFo);
+               }
+
+               int failureCount = 0;
+               if (failures.size() > 0) {
+                       StringBuffer buf = new StringBuffer();
+                       for (String failure : failures) {
+                               buf.append('\n').append(failureCount).append(" - ").append(failure);
+                               failureCount++;
+                       }
+                       throw new MaintenanceException(failureCount + " error(s) when running the backup,"
+                                       + " check the logs and the backups as soon as possible." + buf);
+               }
+       }
+
+       public void setFileSystemManager(FileSystemManager fileSystemManager) {
+               this.fileSystemManager = fileSystemManager;
+       }
+
+       public void setBackupsBase(String backupsBase) {
+               this.backupsBase = backupsBase;
+       }
+
+       public void setSystemName(String name) {
+               this.systemName = name;
+       }
+
+       public void setAtomicBackups(List<AtomicBackup> atomicBackups) {
+               this.atomicBackups = atomicBackups;
+       }
+
+       public void setBackupPurge(BackupPurge backupPurge) {
+               this.backupPurge = backupPurge;
+       }
+
+       public void setUserAuthenticator(UserAuthenticator userAuthenticator) {
+               this.userAuthenticator = userAuthenticator;
+       }
+
+       public void setRemoteBases(Map<String, UserAuthenticator> remoteBases) {
+               this.remoteBases = remoteBases;
+       }
+
+       // public static void main(String args[]) {
+       // while (true) {
+       // try {
+       // StandardFileSystemManager fsm = new StandardFileSystemManager();
+       // fsm.init();
+       //
+       // SystemBackup systemBackup = new SystemBackup();
+       // systemBackup.setSystemName("mySystem");
+       // systemBackup
+       // .setBackupsBase("/home/mbaudier/dev/src/commons/server/runtime/org.argeo.server.core/target");
+       // systemBackup.setFileSystemManager(fsm);
+       //
+       // List<AtomicBackup> atomicBackups = new ArrayList<AtomicBackup>();
+       //
+       // MySqlBackup mySqlBackup = new MySqlBackup("root", "", "test");
+       // atomicBackups.add(mySqlBackup);
+       // PostgreSqlBackup postgreSqlBackup = new PostgreSqlBackup(
+       // "argeo", "argeo", "gis_template");
+       // atomicBackups.add(postgreSqlBackup);
+       // SvnBackup svnBackup = new SvnBackup(
+       // "/home/mbaudier/tmp/testsvnrepo");
+       // atomicBackups.add(svnBackup);
+       //
+       // systemBackup.setAtomicBackups(atomicBackups);
+       //
+       // Map<String, UserAuthenticator> remoteBases = new HashMap<String,
+       // UserAuthenticator>();
+       // StaticUserAuthenticator userAuthenticator = new StaticUserAuthenticator(
+       // null, "demo", "demo");
+       // remoteBases.put("sftp://localhost/home/mbaudier/test",
+       // userAuthenticator);
+       // systemBackup.setRemoteBases(remoteBases);
+       //
+       // systemBackup.run();
+       //
+       // fsm.close();
+       // } catch (FileSystemException e) {
+       // // TODO Auto-generated catch block
+       // e.printStackTrace();
+       // System.exit(1);
+       // }
+       //
+       // // wait
+       // try {
+       // Thread.sleep(120 * 1000);
+       // } catch (InterruptedException e) {
+       // e.printStackTrace();
+       // }
+       // }
+       // }
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/package-info.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/backup/vfs/package-info.java
new file mode 100644 (file)
index 0000000..f70499d
--- /dev/null
@@ -0,0 +1,2 @@
+/** Argeo Node backup utilities based on Apache Commons VFS. */
+package org.argeo.slc.backup.vfs;
\ No newline at end of file
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/ArgeoCli.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/ArgeoCli.java
new file mode 100644 (file)
index 0000000..4e23837
--- /dev/null
@@ -0,0 +1,31 @@
+package org.argeo.slc.cli;
+
+import org.apache.commons.cli.Option;
+import org.argeo.cms.cli.CommandsCli;
+import org.argeo.slc.cli.posix.PosixCommands;
+
+/** Argeo command line tools. */
+public class ArgeoCli extends CommandsCli {
+
+       public ArgeoCli(String commandName) {
+               super(commandName);
+               // Common options
+               options.addOption(Option.builder("v").hasArg().argName("verbose").desc("verbosity").build());
+               options.addOption(
+                               Option.builder("D").hasArgs().argName("property=value").desc("use value for given property").build());
+
+               addCommandsCli(new PosixCommands("posix"));
+//             addCommandsCli(new FsCommands("fs"));
+//             addCommandsCli(new JcrCommands("jcr"));
+       }
+
+       @Override
+       public String getDescription() {
+               return "Argeo command line utilities";
+       }
+
+       public static void main(String[] args) {
+               mainImpl(new ArgeoCli("argeo"), args);
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/Echo.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/Echo.java
new file mode 100644 (file)
index 0000000..d773760
--- /dev/null
@@ -0,0 +1,46 @@
+package org.argeo.slc.cli.posix;
+
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.argeo.cms.cli.DescribedCommand;
+
+public class Echo implements DescribedCommand<String> {
+
+       @Override
+       public Options getOptions() {
+               Options options = new Options();
+               options.addOption(Option.builder("n").desc("do not output the trailing newline").build());
+               return options;
+       }
+
+       @Override
+       public String getDescription() {
+               return "Display a line of text";
+       }
+
+       @Override
+       public String getUsage() {
+               return "[STRING]...";
+       }
+
+       @Override
+       public String apply(List<String> args) {
+               CommandLine cl = toCommandLine(args);
+
+               StringBuffer sb = new StringBuffer();
+               for (String s : cl.getArgList()) {
+                       sb.append(s).append(' ');
+               }
+
+               if (cl.hasOption('n')) {
+                       sb.deleteCharAt(sb.length() - 1);
+               } else {
+                       sb.setCharAt(sb.length() - 1, '\n');
+               }
+               return sb.toString();
+       }
+
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/PosixCommands.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/PosixCommands.java
new file mode 100644 (file)
index 0000000..bb5920e
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.slc.cli.posix;
+
+import org.argeo.cms.cli.CommandsCli;
+
+/** POSIX commands. */
+public class PosixCommands extends CommandsCli {
+
+       public PosixCommands(String commandName) {
+               super(commandName);
+               addCommand("echo", new Echo());
+       }
+
+       @Override
+       public String getDescription() {
+               return "Reimplementation of some POSIX commands in plain Java";
+       }
+
+       public static void main(String[] args) {
+               mainImpl(new PosixCommands("argeo-posix"), args);
+       }
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/package-info.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/cli/posix/package-info.java
new file mode 100644 (file)
index 0000000..f6da265
--- /dev/null
@@ -0,0 +1,2 @@
+/** Posix CLI commands. */
+package org.argeo.slc.cli.posix;
\ No newline at end of file
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/cms/deploy/SimpleCmsTargetData.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/cms/deploy/SimpleCmsTargetData.java
new file mode 100644 (file)
index 0000000..9ba955a
--- /dev/null
@@ -0,0 +1,10 @@
+package org.argeo.slc.cms.deploy;
+
+import java.nio.file.Path;
+
+import org.argeo.slc.deploy.TargetData;
+
+public class SimpleCmsTargetData implements TargetData {
+       private Integer httpPort;
+       private Path instanceData;
+}
diff --git a/cms/org.argeo.slc.cms/src/org/argeo/slc/cms/test/CmsSmokeTest.java b/cms/org.argeo.slc.cms/src/org/argeo/slc/cms/test/CmsSmokeTest.java
new file mode 100644 (file)
index 0000000..10b088c
--- /dev/null
@@ -0,0 +1,20 @@
+package org.argeo.slc.cms.test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class CmsSmokeTest {
+
+       public static void main(String[] args) throws IOException {
+               Path instanceData;
+               if (args.length > 0) {
+                       instanceData = Paths.get(args[0]);
+               } else {
+                       instanceData = Files.createTempDirectory("cms-test");
+               }
+
+       }
+
+}
index c035eedc1c343c77613713efe0e3c14d2ab7ea41..ea12318c6869078c695d9ded58316bcd28a93ddb 100644 (file)
@@ -1,3 +1,3 @@
-Import-Package: org.argeo.slc.deploy,\
-org.apache.commons.logging,\
+Import-Package: \
+org.argeo.slc.deploy,\
 *
\ No newline at end of file
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/AbstractAtomicBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/AbstractAtomicBackup.java
deleted file mode 100644 (file)
index 6d55374..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileSystemOptions;
-import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
-
-/**
- * Simplify atomic backups implementation, especially by managing VFS.
- */
-public abstract class AbstractAtomicBackup implements AtomicBackup {
-       private String name;
-       private String compression = "bz2";
-
-       protected abstract void writeBackup(FileObject targetFo);
-
-       public AbstractAtomicBackup() {
-       }
-
-       public AbstractAtomicBackup(String name) {
-               this.name = name;
-       }
-
-       public void init() {
-               if (name == null)
-                       throw new MaintenanceException("Atomic backup name must be set");
-       }
-
-       public void destroy() {
-
-       }
-
-       @Override
-       public String backup(FileSystemManager fileSystemManager,
-                       String backupsBase, BackupContext backupContext,
-                       FileSystemOptions opts) {
-               if (name == null)
-                       throw new MaintenanceException("Atomic backup name must be set");
-
-               FileObject targetFo = null;
-               try {
-                       if (backupsBase.startsWith("sftp:"))
-                               SftpFileSystemConfigBuilder.getInstance()
-                                               .setStrictHostKeyChecking(opts, "no");
-                       if (compression == null || compression.equals("none"))
-                               targetFo = fileSystemManager.resolveFile(backupsBase + '/'
-                                               + backupContext.getRelativeFolder() + '/' + name, opts);
-                       else if (compression.equals("bz2"))
-                               targetFo = fileSystemManager.resolveFile("bz2:" + backupsBase
-                                               + '/' + backupContext.getRelativeFolder() + '/' + name
-                                               + ".bz2" + "!" + name, opts);
-                       else if (compression.equals("gz"))
-                               targetFo = fileSystemManager.resolveFile("gz:" + backupsBase
-                                               + '/' + backupContext.getRelativeFolder() + '/' + name
-                                               + ".gz" + "!" + name, opts);
-                       else
-                               throw new MaintenanceException("Unsupported compression "
-                                               + compression);
-
-                       writeBackup(targetFo);
-
-                       return targetFo.toString();
-               } catch (Exception e) {
-                       throw new MaintenanceException("Cannot backup " + name + " to "
-                                       + targetFo, e);
-               } finally {
-                       BackupUtils.closeFOQuietly(targetFo);
-               }
-       }
-
-       public void setName(String name) {
-               this.name = name;
-       }
-
-       public String getName() {
-               return name;
-       }
-
-       public void setCompression(String compression) {
-               this.compression = compression;
-       }
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/AtomicBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/AtomicBackup.java
deleted file mode 100644 (file)
index 0cfcfab..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileSystemOptions;
-
-/** Performs the backup of a single component, typically a database dump */
-public interface AtomicBackup {
-       /** Name identifiying this backup */
-       public String getName();
-
-       /**
-        * Retrieves the data of the component in a format that allows to restore
-        * the component
-        * 
-        * @param backupContext
-        *            the context of this backup
-        * @return the VFS URI of the generated file or directory
-        */
-       public String backup(FileSystemManager fileSystemManager,
-                       String backupsBase, BackupContext backupContext,
-                       FileSystemOptions opts);
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupContext.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupContext.java
deleted file mode 100644 (file)
index 9c1140b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import java.text.DateFormat;
-import java.util.Date;
-
-/**
- * Transient information of a given backup, centralizing common information such
- * as timestamp and location.
- */
-public interface BackupContext {
-       /** Backup date */
-       public Date getTimestamp();
-
-       /** Formatted backup date */
-       public String getTimestampAsString();
-
-       /** System name */
-       public String getSystemName();
-
-       /** Local base */
-       public String getRelativeFolder();
-
-       /** Date format */
-       public DateFormat getDateFormat();
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupFileSystemManager.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupFileSystemManager.java
deleted file mode 100644 (file)
index ad42dd3..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
-import org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider;
-import org.apache.commons.vfs2.provider.ftp.FtpFileProvider;
-import org.apache.commons.vfs2.provider.gzip.GzipFileProvider;
-import org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider;
-import org.apache.commons.vfs2.provider.ram.RamFileProvider;
-import org.apache.commons.vfs2.provider.sftp.SftpFileProvider;
-import org.apache.commons.vfs2.provider.url.UrlFileProvider;
-
-/**
- * Programatically configured VFS file system manager which can be declared as a
- * bean and associated with a life cycle (methods
- * {@link DefaultFileSystemManager#init()} and
- * {@link DefaultFileSystemManager#close()}). Supports bz2, file, ram, gzip,
- * ftp, sftp
- */
-public class BackupFileSystemManager extends DefaultFileSystemManager {
-
-       public BackupFileSystemManager() {
-               super();
-               try {
-                       addProvider("file", new DefaultLocalFileProvider());
-                       addProvider("bz2", new Bzip2FileProvider());
-                       addProvider("ftp", new FtpFileProvider());
-                       addProvider("sftp", new SftpFileProvider());
-                       addProvider("gzip", new GzipFileProvider());
-                       addProvider("ram", new RamFileProvider());
-                       setDefaultProvider(new UrlFileProvider());
-               } catch (FileSystemException e) {
-                       throw new MaintenanceException("Cannot configure backup file provider", e);
-               }
-       }
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupPurge.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupPurge.java
deleted file mode 100644 (file)
index 1d07bbf..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import java.text.DateFormat;
-
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileSystemOptions;
-
-/** Purges previous backups */
-public interface BackupPurge {
-       /**
-        * Purge the backups identified by these arguments. Although these are the
-        * same fields as a {@link BackupContext} we don't pass it as argument since
-        * we want to use this interface to purge remote backups as well (that is,
-        * with a different base), or outside the scope of a running backup.
-        */
-       public void purge(FileSystemManager fileSystemManager, String base,
-                       String name, DateFormat dateFormat, FileSystemOptions opts);
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupUtils.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/BackupUtils.java
deleted file mode 100644 (file)
index bc4d0c8..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import org.apache.commons.vfs2.FileObject;
-
-/** Backup utilities */
-public class BackupUtils {
-       /** Close a file object quietly even if it is null or throws an exception. */
-       public static void closeFOQuietly(FileObject fo) {
-               if (fo != null) {
-                       try {
-                               fo.close();
-                       } catch (Exception e) {
-                               // silent
-                       }
-               }
-       }
-       
-       /** Prevents instantiation */
-       private BackupUtils() {
-       }
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/MaintenanceException.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/MaintenanceException.java
deleted file mode 100644 (file)
index 1532503..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-@Deprecated
-class MaintenanceException extends RuntimeException {
-       private static final long serialVersionUID = -5770049663929537270L;
-
-       public MaintenanceException(String message, Throwable cause) {
-               super(message, cause);
-       }
-
-       public MaintenanceException(String message) {
-               super(message);
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/MySqlBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/MySqlBackup.java
deleted file mode 100644 (file)
index 3f0e670..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import org.apache.commons.vfs2.FileObject;
-
-/** Backups a MySQL database using mysqldump. */
-public class MySqlBackup extends OsCallBackup {
-       private String mysqldumpLocation = "/usr/bin/mysqldump";
-
-       private String dbUser;
-       private String dbPassword;
-       private String dbName;
-
-       public MySqlBackup() {
-       }
-
-       public MySqlBackup(String dbUser, String dbPassword, String dbName) {
-               this.dbUser = dbUser;
-               this.dbPassword = dbPassword;
-               this.dbName = dbName;
-               init();
-       }
-
-       @Override
-       public void init() {
-               if (getName() == null)
-                       setName(dbName + ".mysql");
-               super.init();
-       }
-
-       @Override
-       public void writeBackup(FileObject targetFo) {
-               if (getCommand() == null)
-                       setCommand(mysqldumpLocation
-                                       + " --lock-tables --add-locks --add-drop-table"
-                                       + " -u ${dbUser} --password=${dbPassword} --databases ${dbName}");
-               getVariables().put("dbUser", dbUser);
-               getVariables().put("dbPassword", dbPassword);
-               getVariables().put("dbName", dbName);
-
-               super.writeBackup(targetFo);
-       }
-
-       public void setDbUser(String dbUser) {
-               this.dbUser = dbUser;
-       }
-
-       public void setDbPassword(String dbPassword) {
-               this.dbPassword = dbPassword;
-       }
-
-       public void setDbName(String dbName) {
-               this.dbName = dbName;
-       }
-
-       public void setMysqldumpLocation(String mysqldumpLocation) {
-               this.mysqldumpLocation = mysqldumpLocation;
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/OpenLdapBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/OpenLdapBackup.java
deleted file mode 100644 (file)
index 31914bd..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import org.apache.commons.vfs2.FileObject;
-
-/** Backups an OpenLDAP server using slapcat */
-public class OpenLdapBackup extends OsCallBackup {
-       private String slapcatLocation = "/usr/sbin/slapcat";
-       private String slapdConfLocation = "/etc/openldap/slapd.conf";
-       private String baseDn;
-
-       public OpenLdapBackup() {
-               super();
-       }
-
-       public OpenLdapBackup(String baseDn) {
-               super();
-               this.baseDn = baseDn;
-       }
-
-       @Override
-       public void writeBackup(FileObject targetFo) {
-               if (baseDn == null)
-                       throw new MaintenanceException("Base DN must be set");
-
-               if (getCommand() == null)
-                       setCommand(slapcatLocation
-                                       + " -f ${slapdConfLocation} -b '${baseDn}'");
-               getVariables().put("slapdConfLocation", slapdConfLocation);
-               getVariables().put("baseDn", baseDn);
-
-               super.writeBackup(targetFo);
-       }
-
-       public void setSlapcatLocation(String slapcatLocation) {
-               this.slapcatLocation = slapcatLocation;
-       }
-
-       public void setSlapdConfLocation(String slapdConfLocation) {
-               this.slapdConfLocation = slapdConfLocation;
-       }
-
-       public void setBaseDn(String baseDn) {
-               this.baseDn = baseDn;
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/OsCallBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/OsCallBackup.java
deleted file mode 100644 (file)
index 380dffe..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import java.io.ByteArrayOutputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.commons.exec.CommandLine;
-import org.apache.commons.exec.DefaultExecutor;
-import org.apache.commons.exec.ExecuteException;
-import org.apache.commons.exec.ExecuteStreamHandler;
-import org.apache.commons.exec.Executor;
-import org.apache.commons.exec.PumpStreamHandler;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.vfs2.FileContent;
-import org.apache.commons.vfs2.FileObject;
-import org.argeo.api.cms.CmsLog;
-
-/**
- * Runs an OS command and save its standard output as a file. Typically used for
- * MySQL or OpenLDAP dumps.
- */
-public class OsCallBackup extends AbstractAtomicBackup {
-       private final static CmsLog log = CmsLog.getLog(OsCallBackup.class);
-
-       private String command;
-       private Map<String, String> variables = new HashMap<String, String>();
-       private Executor executor = new DefaultExecutor();
-
-       private Map<String, String> environment = new HashMap<String, String>();
-
-       /** Name of the sudo user, root if "", not sudo if null */
-       private String sudo = null;
-
-       public OsCallBackup() {
-       }
-
-       public OsCallBackup(String name) {
-               super(name);
-       }
-
-       public OsCallBackup(String name, String command) {
-               super(name);
-               this.command = command;
-       }
-
-       @Override
-       public void writeBackup(FileObject targetFo) {
-               String commandToUse = command;
-
-               // sudo
-               if (sudo != null) {
-                       if (sudo.equals(""))
-                               commandToUse = "sudo " + commandToUse;
-                       else
-                               commandToUse = "sudo -u " + sudo + " " + commandToUse;
-               }
-
-               CommandLine commandLine = CommandLine.parse(commandToUse, variables);
-               ByteArrayOutputStream errBos = new ByteArrayOutputStream();
-               if (log.isTraceEnabled())
-                       log.trace(commandLine.toString());
-
-               try {
-                       // stdout
-                       FileContent targetContent = targetFo.getContent();
-                       // stderr
-                       ExecuteStreamHandler streamHandler = new PumpStreamHandler(targetContent.getOutputStream(), errBos);
-                       executor.setStreamHandler(streamHandler);
-                       executor.execute(commandLine, environment);
-               } catch (ExecuteException e) {
-                       byte[] err = errBos.toByteArray();
-                       String errStr = new String(err);
-                       throw new MaintenanceException("Process " + commandLine + " failed (" + e.getExitValue() + "): " + errStr, e);
-               } catch (Exception e) {
-                       byte[] err = errBos.toByteArray();
-                       String errStr = new String(err);
-                       throw new MaintenanceException("Process " + commandLine + " failed: " + errStr, e);
-               } finally {
-                       IOUtils.closeQuietly(errBos);
-               }
-       }
-
-       public void setCommand(String command) {
-               this.command = command;
-       }
-
-       protected String getCommand() {
-               return command;
-       }
-
-       /**
-        * A reference to the environment variables that will be passed to the
-        * process. Empty by default.
-        */
-       protected Map<String, String> getEnvironment() {
-               return environment;
-       }
-
-       protected Map<String, String> getVariables() {
-               return variables;
-       }
-
-       public void setVariables(Map<String, String> variables) {
-               this.variables = variables;
-       }
-
-       public void setExecutor(Executor executor) {
-               this.executor = executor;
-       }
-
-       public void setSudo(String sudo) {
-               this.sudo = sudo;
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/PostgreSqlBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/PostgreSqlBackup.java
deleted file mode 100644 (file)
index 613fd5a..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import org.apache.commons.vfs2.FileObject;
-
-/** Backups a PostgreSQL database using pg_dump. */
-public class PostgreSqlBackup extends OsCallBackup {
-       /**
-        * PostgreSQL password environment variable (see
-        * http://stackoverflow.com/questions
-        * /2893954/how-to-pass-in-password-to-pg-dump)
-        */
-       protected final static String PGPASSWORD = "PGPASSWORD";
-
-       private String pgDumpLocation = "/usr/bin/pg_dump";
-
-       private String dbUser;
-       private String dbPassword;
-       private String dbName;
-
-       public PostgreSqlBackup() {
-               super();
-       }
-
-       public PostgreSqlBackup(String dbUser, String dbPassword, String dbName) {
-               this.dbUser = dbUser;
-               this.dbPassword = dbPassword;
-               this.dbName = dbName;
-               init();
-       }
-
-       @Override
-       public void init() {
-               // disable compression since pg_dump is used with -Fc option
-               setCompression(null);
-
-               if (getName() == null)
-                       setName(dbName + ".pgdump");
-               super.init();
-       }
-
-       @Override
-       public void writeBackup(FileObject targetFo) {
-               if (getCommand() == null) {
-                       getEnvironment().put(PGPASSWORD, dbPassword);
-                       setCommand(pgDumpLocation + " -Fc" + " -U ${dbUser} ${dbName}");
-               }
-               getVariables().put("dbUser", dbUser);
-               getVariables().put("dbPassword", dbPassword);
-               getVariables().put("dbName", dbName);
-
-               super.writeBackup(targetFo);
-       }
-
-       public void setDbUser(String dbUser) {
-               this.dbUser = dbUser;
-       }
-
-       public void setDbPassword(String dbPassword) {
-               this.dbPassword = dbPassword;
-       }
-
-       public void setDbName(String dbName) {
-               this.dbName = dbName;
-       }
-
-       public void setPgDumpLocation(String mysqldumpLocation) {
-               this.pgDumpLocation = mysqldumpLocation;
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SimpleBackupContext.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SimpleBackupContext.java
deleted file mode 100644 (file)
index 9ee6871..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.apache.commons.vfs2.FileSystemManager;
-
-/** Simple implementation of a backup context */
-public class SimpleBackupContext implements BackupContext {
-       private DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmm");
-       private final Date timestamp;
-       private final String name;
-
-       private final FileSystemManager fileSystemManager;
-
-       public SimpleBackupContext(FileSystemManager fileSystemManager,
-                       String backupsBase, String name) {
-               this.name = name;
-               this.timestamp = new Date();
-               this.fileSystemManager = fileSystemManager;
-       }
-
-       public Date getTimestamp() {
-               return timestamp;
-       }
-
-       public String getTimestampAsString() {
-               return dateFormat.format(timestamp);
-       }
-
-       public String getSystemName() {
-               return name;
-       }
-
-       public String getRelativeFolder() {
-               return name + '/' + getTimestampAsString();
-       }
-
-       public DateFormat getDateFormat() {
-               return dateFormat;
-       }
-
-       public FileSystemManager getFileSystemManager() {
-               return fileSystemManager;
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SimpleBackupPurge.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SimpleBackupPurge.java
deleted file mode 100644 (file)
index 0871109..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import java.text.DateFormat;
-import java.time.Period;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.Date;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileSystemOptions;
-import org.apache.commons.vfs2.Selectors;
-import org.argeo.api.cms.CmsLog;
-
-/** Simple backup purge which keeps backups only for a given number of days */
-public class SimpleBackupPurge implements BackupPurge {
-       private final static CmsLog log = CmsLog.getLog(SimpleBackupPurge.class);
-
-       private Integer daysKept = 30;
-
-       @Override
-       public void purge(FileSystemManager fileSystemManager, String base, String name, DateFormat dateFormat,
-                       FileSystemOptions opts) {
-               try {
-                       ZonedDateTime nowDt = ZonedDateTime.now();
-                       FileObject baseFo = fileSystemManager.resolveFile(base + '/' + name, opts);
-
-                       SortedMap<ZonedDateTime, FileObject> toDelete = new TreeMap<ZonedDateTime, FileObject>();
-                       int backupCount = 0;
-
-                       // make sure base dir exists
-                       baseFo.createFolder();
-
-                       // scan backups and list those which should be deleted
-                       for (FileObject backupFo : baseFo.getChildren()) {
-                               String backupName = backupFo.getName().getBaseName();
-                               Date backupDate = dateFormat.parse(backupName);
-                               backupCount++;
-                               ZonedDateTime backupDt = ZonedDateTime.ofInstant(backupDate.toInstant(), ZoneId.systemDefault());
-                               Period sinceThen = Period.between(backupDt.toLocalDate(), nowDt.toLocalDate());
-                               // new Period(backupDt, nowDt);
-                               int days = sinceThen.getDays();
-                               // int days = sinceThen.getMinutes();
-                               if (days > daysKept) {
-                                       toDelete.put(backupDt, backupFo);
-                               }
-                       }
-
-                       if (toDelete.size() != 0 && toDelete.size() == backupCount) {
-                               // all backups would be deleted
-                               // but we want to keep at least one
-                               ZonedDateTime lastBackupDt = toDelete.firstKey();
-                               FileObject keptFo = toDelete.remove(lastBackupDt);
-                               log.warn("Backup " + keptFo + " kept although it is older than " + daysKept + " days.");
-                       }
-
-                       // delete old backups
-                       for (FileObject backupFo : toDelete.values()) {
-                               backupFo.delete(Selectors.SELECT_ALL);
-                               if (log.isDebugEnabled())
-                                       log.debug("Deleted backup " + backupFo);
-                       }
-               } catch (Exception e) {
-                       throw new MaintenanceException("Could not purge previous backups", e);
-               }
-
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SvnBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SvnBackup.java
deleted file mode 100644 (file)
index ea9f844..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import java.io.File;
-
-import org.apache.commons.vfs2.FileObject;
-
-/** Backups a Subversion repository using svnadmin. */
-public class SvnBackup extends OsCallBackup {
-       private String svnadminLocation = "/usr/bin/svnadmin";
-
-       private String repoLocation;
-       private String repoName;
-
-       public SvnBackup() {
-       }
-
-       public SvnBackup(String repoLocation) {
-               this.repoLocation = repoLocation;
-               init();
-       }
-
-       @Override
-       public void init() {
-               // use directory as repo name
-               if (repoName == null)
-                       repoName = new File(repoLocation).getName();
-
-               if (getName() == null)
-                       setName(repoName + ".svndump");
-               super.init();
-       }
-
-       @Override
-       public void writeBackup(FileObject targetFo) {
-               if (getCommand() == null) {
-                       setCommand(svnadminLocation + " dump " + " ${repoLocation}");
-               }
-               getVariables().put("repoLocation", repoLocation);
-
-               super.writeBackup(targetFo);
-       }
-
-       public void setRepoLocation(String repoLocation) {
-               this.repoLocation = repoLocation;
-       }
-
-       public void setRepoName(String repoName) {
-               this.repoName = repoName;
-       }
-
-       public void setSvnadminLocation(String mysqldumpLocation) {
-               this.svnadminLocation = mysqldumpLocation;
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SystemBackup.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/SystemBackup.java
deleted file mode 100644 (file)
index 7f23d72..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-package org.argeo.slc.backup.vfs;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileSystemOptions;
-import org.apache.commons.vfs2.Selectors;
-import org.apache.commons.vfs2.UserAuthenticator;
-import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.util.LangUtils;
-
-/**
- * Combines multiple backups and transfer them to a remote location. Purges
- * remote and local data based on certain criteria.
- */
-public class SystemBackup implements Runnable {
-       private final static CmsLog log = CmsLog.getLog(SystemBackup.class);
-
-       private FileSystemManager fileSystemManager;
-       private UserAuthenticator userAuthenticator = null;
-
-       private String backupsBase;
-       private String systemName;
-
-       private List<AtomicBackup> atomicBackups = new ArrayList<AtomicBackup>();
-       private BackupPurge backupPurge = new SimpleBackupPurge();
-
-       private Map<String, UserAuthenticator> remoteBases = new HashMap<String, UserAuthenticator>();
-
-       @Override
-       public void run() {
-               if (atomicBackups.size() == 0)
-                       throw new MaintenanceException("No atomic backup listed");
-               List<String> failures = new ArrayList<String>();
-
-               SimpleBackupContext backupContext = new SimpleBackupContext(fileSystemManager, backupsBase, systemName);
-
-               // purge older backups
-               FileSystemOptions opts = new FileSystemOptions();
-               try {
-                       DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, userAuthenticator);
-               } catch (Exception e) {
-                       throw new MaintenanceException("Cannot create authentication", e);
-               }
-
-               try {
-
-                       backupPurge.purge(fileSystemManager, backupsBase, systemName, backupContext.getDateFormat(), opts);
-               } catch (Exception e) {
-                       failures.add("Purge " + backupsBase + " failed: " + e.getMessage());
-                       log.error("Purge of " + backupsBase + " failed", e);
-               }
-
-               // perform backup
-               for (AtomicBackup atomickBackup : atomicBackups) {
-                       try {
-                               String target = atomickBackup.backup(fileSystemManager, backupsBase, backupContext, opts);
-                               if (log.isDebugEnabled())
-                                       log.debug("Performed backup " + target);
-                       } catch (Exception e) {
-                               String msg = "Atomic backup " + atomickBackup.getName() + " failed: "
-                                               + LangUtils.chainCausesMessages(e);
-                               failures.add(msg);
-                               log.error(msg);
-                               if (log.isTraceEnabled())
-                                       log.trace("Stacktrace of atomic backup " + atomickBackup.getName() + " failure.", e);
-                       }
-               }
-
-               // dispatch to remote
-               for (String remoteBase : remoteBases.keySet()) {
-                       FileObject localBaseFo = null;
-                       FileObject remoteBaseFo = null;
-                       UserAuthenticator auth = remoteBases.get(remoteBase);
-
-                       // authentication
-                       FileSystemOptions remoteOpts = new FileSystemOptions();
-                       try {
-                               DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(remoteOpts, auth);
-                               backupPurge.purge(fileSystemManager, remoteBase, systemName, backupContext.getDateFormat(), remoteOpts);
-                       } catch (Exception e) {
-                               failures.add("Purge " + remoteBase + " failed: " + e.getMessage());
-                               log.error("Cannot purge " + remoteBase, e);
-                       }
-
-                       try {
-                               localBaseFo = fileSystemManager.resolveFile(backupsBase + '/' + backupContext.getRelativeFolder(),
-                                               opts);
-                               remoteBaseFo = fileSystemManager.resolveFile(remoteBase + '/' + backupContext.getRelativeFolder(),
-                                               remoteOpts);
-                               remoteBaseFo.copyFrom(localBaseFo, Selectors.SELECT_ALL);
-                               if (log.isDebugEnabled())
-                                       log.debug("Copied backup to " + remoteBaseFo + " from " + localBaseFo);
-                               // }
-                       } catch (Exception e) {
-                               failures.add("Dispatch to " + remoteBase + " failed: " + e.getMessage());
-                               log.error("Cannot dispatch backups from " + backupContext.getRelativeFolder() + " to " + remoteBase, e);
-                       }
-                       BackupUtils.closeFOQuietly(localBaseFo);
-                       BackupUtils.closeFOQuietly(remoteBaseFo);
-               }
-
-               int failureCount = 0;
-               if (failures.size() > 0) {
-                       StringBuffer buf = new StringBuffer();
-                       for (String failure : failures) {
-                               buf.append('\n').append(failureCount).append(" - ").append(failure);
-                               failureCount++;
-                       }
-                       throw new MaintenanceException(failureCount + " error(s) when running the backup,"
-                                       + " check the logs and the backups as soon as possible." + buf);
-               }
-       }
-
-       public void setFileSystemManager(FileSystemManager fileSystemManager) {
-               this.fileSystemManager = fileSystemManager;
-       }
-
-       public void setBackupsBase(String backupsBase) {
-               this.backupsBase = backupsBase;
-       }
-
-       public void setSystemName(String name) {
-               this.systemName = name;
-       }
-
-       public void setAtomicBackups(List<AtomicBackup> atomicBackups) {
-               this.atomicBackups = atomicBackups;
-       }
-
-       public void setBackupPurge(BackupPurge backupPurge) {
-               this.backupPurge = backupPurge;
-       }
-
-       public void setUserAuthenticator(UserAuthenticator userAuthenticator) {
-               this.userAuthenticator = userAuthenticator;
-       }
-
-       public void setRemoteBases(Map<String, UserAuthenticator> remoteBases) {
-               this.remoteBases = remoteBases;
-       }
-
-       // public static void main(String args[]) {
-       // while (true) {
-       // try {
-       // StandardFileSystemManager fsm = new StandardFileSystemManager();
-       // fsm.init();
-       //
-       // SystemBackup systemBackup = new SystemBackup();
-       // systemBackup.setSystemName("mySystem");
-       // systemBackup
-       // .setBackupsBase("/home/mbaudier/dev/src/commons/server/runtime/org.argeo.server.core/target");
-       // systemBackup.setFileSystemManager(fsm);
-       //
-       // List<AtomicBackup> atomicBackups = new ArrayList<AtomicBackup>();
-       //
-       // MySqlBackup mySqlBackup = new MySqlBackup("root", "", "test");
-       // atomicBackups.add(mySqlBackup);
-       // PostgreSqlBackup postgreSqlBackup = new PostgreSqlBackup(
-       // "argeo", "argeo", "gis_template");
-       // atomicBackups.add(postgreSqlBackup);
-       // SvnBackup svnBackup = new SvnBackup(
-       // "/home/mbaudier/tmp/testsvnrepo");
-       // atomicBackups.add(svnBackup);
-       //
-       // systemBackup.setAtomicBackups(atomicBackups);
-       //
-       // Map<String, UserAuthenticator> remoteBases = new HashMap<String,
-       // UserAuthenticator>();
-       // StaticUserAuthenticator userAuthenticator = new StaticUserAuthenticator(
-       // null, "demo", "demo");
-       // remoteBases.put("sftp://localhost/home/mbaudier/test",
-       // userAuthenticator);
-       // systemBackup.setRemoteBases(remoteBases);
-       //
-       // systemBackup.run();
-       //
-       // fsm.close();
-       // } catch (FileSystemException e) {
-       // // TODO Auto-generated catch block
-       // e.printStackTrace();
-       // System.exit(1);
-       // }
-       //
-       // // wait
-       // try {
-       // Thread.sleep(120 * 1000);
-       // } catch (InterruptedException e) {
-       // e.printStackTrace();
-       // }
-       // }
-       // }
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/package-info.java b/org.argeo.slc.runtime/src/org/argeo/slc/backup/vfs/package-info.java
deleted file mode 100644 (file)
index f70499d..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Argeo Node backup utilities based on Apache Commons VFS. */
-package org.argeo.slc.backup.vfs;
\ No newline at end of file
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/Echo.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/Echo.java
deleted file mode 100644 (file)
index d773760..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.argeo.slc.cli.posix;
-
-import java.util.List;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.argeo.cms.cli.DescribedCommand;
-
-public class Echo implements DescribedCommand<String> {
-
-       @Override
-       public Options getOptions() {
-               Options options = new Options();
-               options.addOption(Option.builder("n").desc("do not output the trailing newline").build());
-               return options;
-       }
-
-       @Override
-       public String getDescription() {
-               return "Display a line of text";
-       }
-
-       @Override
-       public String getUsage() {
-               return "[STRING]...";
-       }
-
-       @Override
-       public String apply(List<String> args) {
-               CommandLine cl = toCommandLine(args);
-
-               StringBuffer sb = new StringBuffer();
-               for (String s : cl.getArgList()) {
-                       sb.append(s).append(' ');
-               }
-
-               if (cl.hasOption('n')) {
-                       sb.deleteCharAt(sb.length() - 1);
-               } else {
-                       sb.setCharAt(sb.length() - 1, '\n');
-               }
-               return sb.toString();
-       }
-
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/PosixCommands.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/PosixCommands.java
deleted file mode 100644 (file)
index bb5920e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.argeo.slc.cli.posix;
-
-import org.argeo.cms.cli.CommandsCli;
-
-/** POSIX commands. */
-public class PosixCommands extends CommandsCli {
-
-       public PosixCommands(String commandName) {
-               super(commandName);
-               addCommand("echo", new Echo());
-       }
-
-       @Override
-       public String getDescription() {
-               return "Reimplementation of some POSIX commands in plain Java";
-       }
-
-       public static void main(String[] args) {
-               mainImpl(new PosixCommands("argeo-posix"), args);
-       }
-}
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/package-info.java b/org.argeo.slc.runtime/src/org/argeo/slc/cli/posix/package-info.java
deleted file mode 100644 (file)
index f6da265..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Posix CLI commands. */
-package org.argeo.slc.cli.posix;
\ No newline at end of file
diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/runtime/ArgeoCli.java b/org.argeo.slc.runtime/src/org/argeo/slc/runtime/ArgeoCli.java
deleted file mode 100644 (file)
index 3e62f57..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.argeo.slc.runtime;
-
-import org.apache.commons.cli.Option;
-import org.argeo.cms.cli.CommandsCli;
-import org.argeo.slc.cli.posix.PosixCommands;
-
-/** Argeo command line tools. */
-public class ArgeoCli extends CommandsCli {
-
-       public ArgeoCli(String commandName) {
-               super(commandName);
-               // Common options
-               options.addOption(Option.builder("v").hasArg().argName("verbose").desc("verbosity").build());
-               options.addOption(
-                               Option.builder("D").hasArgs().argName("property=value").desc("use value for given property").build());
-
-               addCommandsCli(new PosixCommands("posix"));
-//             addCommandsCli(new FsCommands("fs"));
-//             addCommandsCli(new JcrCommands("jcr"));
-       }
-
-       @Override
-       public String getDescription() {
-               return "Argeo command line utilities";
-       }
-
-       public static void main(String[] args) {
-               mainImpl(new ArgeoCli("argeo"), args);
-       }
-
-}