View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.maintenance.backup.vfs;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.commons.vfs2.FileObject;
26  import org.apache.commons.vfs2.FileSystemException;
27  import org.apache.commons.vfs2.FileSystemManager;
28  import org.apache.commons.vfs2.FileSystemOptions;
29  import org.apache.commons.vfs2.Selectors;
30  import org.apache.commons.vfs2.UserAuthenticator;
31  import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder;
32  import org.argeo.maintenance.MaintenanceException;
33  import org.argeo.util.LangUtils;
34  
35  /**
36   * Combines multiple backups and transfer them to a remote location. Purges
37   * remote and local data based on certain criteria.
38   */
39  public class SystemBackup implements Runnable {
40  	private final static Log log = LogFactory.getLog(SystemBackup.class);
41  
42  	private FileSystemManager fileSystemManager;
43  	private UserAuthenticator userAuthenticator = null;
44  
45  	private String backupsBase;
46  	private String systemName;
47  
48  	private List<AtomicBackup> atomicBackups = new ArrayList<AtomicBackup>();
49  	private BackupPurge backupPurge = new SimpleBackupPurge();
50  
51  	private Map<String, UserAuthenticator> remoteBases = new HashMap<String, UserAuthenticator>();
52  
53  	@Override
54  	public void run() {
55  		if (atomicBackups.size() == 0)
56  			throw new MaintenanceException("No atomic backup listed");
57  		List<String> failures = new ArrayList<String>();
58  
59  		SimpleBackupContext backupContext = new SimpleBackupContext(fileSystemManager, backupsBase, systemName);
60  
61  		// purge older backups
62  		FileSystemOptions opts = new FileSystemOptions();
63  		try {
64  			DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts, userAuthenticator);
65  		} catch (FileSystemException e) {
66  			throw new MaintenanceException("Cannot create authentication", e);
67  		}
68  
69  		try {
70  
71  			backupPurge.purge(fileSystemManager, backupsBase, systemName, backupContext.getDateFormat(), opts);
72  		} catch (Exception e) {
73  			failures.add("Purge " + backupsBase + " failed: " + e.getMessage());
74  			log.error("Purge of " + backupsBase + " failed", e);
75  		}
76  
77  		// perform backup
78  		for (AtomicBackup atomickBackup : atomicBackups) {
79  			try {
80  				String target = atomickBackup.backup(fileSystemManager, backupsBase, backupContext, opts);
81  				if (log.isDebugEnabled())
82  					log.debug("Performed backup " + target);
83  			} catch (Exception e) {
84  				String msg = "Atomic backup " + atomickBackup.getName() + " failed: "
85  						+ LangUtils.chainCausesMessages(e);
86  				failures.add(msg);
87  				log.error(msg);
88  				if (log.isTraceEnabled())
89  					log.trace("Stacktrace of atomic backup " + atomickBackup.getName() + " failure.", e);
90  			}
91  		}
92  
93  		// dispatch to remote
94  		for (String remoteBase : remoteBases.keySet()) {
95  			FileObject localBaseFo = null;
96  			FileObject remoteBaseFo = null;
97  			UserAuthenticator auth = remoteBases.get(remoteBase);
98  
99  			// authentication
100 			FileSystemOptions remoteOpts = new FileSystemOptions();
101 			try {
102 				DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(remoteOpts, auth);
103 				backupPurge.purge(fileSystemManager, remoteBase, systemName, backupContext.getDateFormat(), remoteOpts);
104 			} catch (Exception e) {
105 				failures.add("Purge " + remoteBase + " failed: " + e.getMessage());
106 				log.error("Cannot purge " + remoteBase, e);
107 			}
108 
109 			try {
110 				localBaseFo = fileSystemManager.resolveFile(backupsBase + '/' + backupContext.getRelativeFolder(),
111 						opts);
112 				remoteBaseFo = fileSystemManager.resolveFile(remoteBase + '/' + backupContext.getRelativeFolder(),
113 						remoteOpts);
114 				remoteBaseFo.copyFrom(localBaseFo, Selectors.SELECT_ALL);
115 				if (log.isDebugEnabled())
116 					log.debug("Copied backup to " + remoteBaseFo + " from " + localBaseFo);
117 				// }
118 			} catch (Exception e) {
119 				failures.add("Dispatch to " + remoteBase + " failed: " + e.getMessage());
120 				log.error("Cannot dispatch backups from " + backupContext.getRelativeFolder() + " to " + remoteBase, e);
121 			}
122 			BackupUtils.closeFOQuietly(localBaseFo);
123 			BackupUtils.closeFOQuietly(remoteBaseFo);
124 		}
125 
126 		int failureCount = 0;
127 		if (failures.size() > 0) {
128 			StringBuffer buf = new StringBuffer();
129 			for (String failure : failures) {
130 				buf.append('\n').append(failureCount).append(" - ").append(failure);
131 				failureCount++;
132 			}
133 			throw new MaintenanceException(failureCount + " error(s) when running the backup,"
134 					+ " check the logs and the backups as soon as possible." + buf);
135 		}
136 	}
137 
138 	public void setFileSystemManager(FileSystemManager fileSystemManager) {
139 		this.fileSystemManager = fileSystemManager;
140 	}
141 
142 	public void setBackupsBase(String backupsBase) {
143 		this.backupsBase = backupsBase;
144 	}
145 
146 	public void setSystemName(String name) {
147 		this.systemName = name;
148 	}
149 
150 	public void setAtomicBackups(List<AtomicBackup> atomicBackups) {
151 		this.atomicBackups = atomicBackups;
152 	}
153 
154 	public void setBackupPurge(BackupPurge backupPurge) {
155 		this.backupPurge = backupPurge;
156 	}
157 
158 	public void setUserAuthenticator(UserAuthenticator userAuthenticator) {
159 		this.userAuthenticator = userAuthenticator;
160 	}
161 
162 	public void setRemoteBases(Map<String, UserAuthenticator> remoteBases) {
163 		this.remoteBases = remoteBases;
164 	}
165 
166 	// public static void main(String args[]) {
167 	// while (true) {
168 	// try {
169 	// StandardFileSystemManager fsm = new StandardFileSystemManager();
170 	// fsm.init();
171 	//
172 	// SystemBackup systemBackup = new SystemBackup();
173 	// systemBackup.setSystemName("mySystem");
174 	// systemBackup
175 	// .setBackupsBase("/home/mbaudier/dev/src/commons/server/runtime/org.argeo.server.core/target");
176 	// systemBackup.setFileSystemManager(fsm);
177 	//
178 	// List<AtomicBackup> atomicBackups = new ArrayList<AtomicBackup>();
179 	//
180 	// MySqlBackup mySqlBackup = new MySqlBackup("root", "", "test");
181 	// atomicBackups.add(mySqlBackup);
182 	// PostgreSqlBackup postgreSqlBackup = new PostgreSqlBackup(
183 	// "argeo", "argeo", "gis_template");
184 	// atomicBackups.add(postgreSqlBackup);
185 	// SvnBackup svnBackup = new SvnBackup(
186 	// "/home/mbaudier/tmp/testsvnrepo");
187 	// atomicBackups.add(svnBackup);
188 	//
189 	// systemBackup.setAtomicBackups(atomicBackups);
190 	//
191 	// Map<String, UserAuthenticator> remoteBases = new HashMap<String,
192 	// UserAuthenticator>();
193 	// StaticUserAuthenticator userAuthenticator = new StaticUserAuthenticator(
194 	// null, "demo", "demo");
195 	// remoteBases.put("sftp://localhost/home/mbaudier/test",
196 	// userAuthenticator);
197 	// systemBackup.setRemoteBases(remoteBases);
198 	//
199 	// systemBackup.run();
200 	//
201 	// fsm.close();
202 	// } catch (FileSystemException e) {
203 	// // TODO Auto-generated catch block
204 	// e.printStackTrace();
205 	// System.exit(1);
206 	// }
207 	//
208 	// // wait
209 	// try {
210 	// Thread.sleep(120 * 1000);
211 	// } catch (InterruptedException e) {
212 	// e.printStackTrace();
213 	// }
214 	// }
215 	// }
216 }