1 5 package com.tc.reporter; 6 7 import org.apache.xmlbeans.XmlException; 8 9 import com.tc.config.Loader; 10 import com.tc.config.schema.dynamic.ParameterSubstituter; 11 import com.tc.sysinfo.EnvStats; 12 import com.tc.util.ArchiveBuilder; 13 import com.tc.util.ZipBuilder; 14 import com.terracottatech.config.Client; 15 import com.terracottatech.config.Server; 16 import com.terracottatech.config.Servers; 17 import com.terracottatech.config.TcConfigDocument.TcConfig; 18 19 import java.io.File ; 20 import java.io.IOException ; 21 import java.text.DateFormat ; 22 import java.text.SimpleDateFormat ; 23 import java.util.Date ; 24 import java.util.HashSet ; 25 import java.util.Set ; 26 27 import javax.xml.namespace.QName ; 28 29 33 public final class ArchiveUtil { 34 35 private final boolean isFull; 36 private final boolean isClient; 37 private final File tcConfig; 38 private final File archiveFile; 39 private static final String STDOUT = "stdout:"; 40 private static final String STDERR = "stderr:"; 41 private static final String ARCHIVE_FILE_NAME = "tc-archive"; 42 private static final String INVALID = "Invalid Arguments:\n\n"; 43 private static final String DASH_N = "-n"; 44 private static final String DASH_C = "-c"; 45 private static final String USAGE = "** Terracotta Archive Tool **\n\n" 46 + "A utility for archiving Terracotta environment information.\n\n" 47 + "\tValid Arguments are:\n\n\t[" 48 + DASH_N 49 + "] (No Data - excludes data files)\n\t[" 50 + DASH_C 51 + "] (Client - include files from the dso client)" 52 + "\n\t<path to terracotta config xml file (tc-config.xml)>" 53 + " | <path to data and/or logs directory>" 54 + "\n\t[<output filename in .zip format>]\n\nExamples:\n\n\t" 55 + "# java " 56 + ArchiveUtil.class.getName() 57 + " tc-config.xml /home/someuser/tc-archive_server.zip" 58 + "\n\tor\n\t# java " 59 + ArchiveUtil.class.getName() 60 + " /export1/terracotta/server-logs" 61 + "\n\nUsage Summary:\n\n\tTypically you will use this tool to create a full " 62 + "archive of the Terracotta server instance.\n\t" 63 + "You may also want to create archives on the DSO client machines using" 64 + " the -c option. There are two\n\tscenarios where you may " 65 + "need to use the directory location instead of the config file path." 66 + "\n\n\t\t1. The DSO client may not have a local copy of the tc-config.xml" 67 + "\n\t\t2. The tc-config.xml logs and data elements may contain wildcards" 68 + " which use timestamps or \n\t\t environment variables which cannot be" 69 + " resolved.\n\nNotes:\n\n\tThe execution command may vary:" 70 + "\n\t\t# ./archive-util ...\n\n\tSpecifying a directory location as the" 71 + " first command will recursively archive it's entire contents"; 72 73 private static final Set validDashArgs = new HashSet (); 74 static { 75 validDashArgs.add(DASH_N); 76 validDashArgs.add(DASH_C); 77 } 78 79 private ArchiveUtil(boolean isFull, boolean isClient, File archivePath, File fileName) { 80 this.isFull = isFull; 81 this.isClient = isClient; 82 this.tcConfig = archivePath; 83 if (fileName == null) { 84 File userDir = new File (System.getProperty("user.dir")); 85 if (!userDir.exists()) throw new RuntimeException ( 86 "Unexpected error - system property user.dir does not resolve to an actual directory: " + userDir); 87 DateFormat df = new SimpleDateFormat ("y-M-d"); 88 String name = ARCHIVE_FILE_NAME + "_" + df.format(new Date (System.currentTimeMillis())) + ".zip"; 89 this.archiveFile = new File (userDir + File.separator + name); 90 } else { 91 this.archiveFile = fileName; 92 } 93 } 94 95 private static void quit(String msg) { 96 System.err.println(msg); 97 System.exit(0); 98 } 99 100 private static void escape(String msg, Exception e) { 101 System.out.println(INVALID + msg); 102 if (e != null) e.printStackTrace(); 103 System.exit(0); 104 } 105 106 public static void main(String [] args) { 107 if (args.length < 1) escape(USAGE, null); 108 boolean dashArgs = true; 109 int locationCmd = -1; 110 int fileArg = -1; 111 Set dashSet = new HashSet (2); 112 for (int i = 0; i < args.length; i++) { 113 if (args[i].startsWith("-")) { 114 if (!dashArgs) escape(USAGE, null); 115 if (validDashArgs.contains(args[i])) dashSet.add(args[i]); 116 else escape(USAGE, null); 117 } else { 118 dashArgs = false; 119 if (fileArg + locationCmd > 1) escape(USAGE, null); 120 if (locationCmd < 0) locationCmd = i; 121 else if (fileArg < 0) fileArg = i; 122 if (fileArg + locationCmd == -2) escape(USAGE, null); 123 } 124 } 125 if (dashSet.size() > 2) escape(USAGE, null); 126 boolean dashC = dashSet.contains(DASH_C); 127 boolean dashN = dashSet.contains(DASH_N); 128 129 if (locationCmd < 0) escape( 130 "Please specify the Terracotta config file location or logs/data directory location\n\n" + USAGE, null); 131 File tcConfigFile = new File (args[locationCmd]); 132 if (!tcConfigFile.exists()) escape("\tTerracotta Configuration file: " + tcConfigFile + "\n\tdoes not exist\n\n" 133 + USAGE, null); 134 File outputFile = null; 135 if (fileArg > 0) { 136 outputFile = new File (new File (args[fileArg]).getAbsolutePath()); 137 if (!new File (outputFile.getParent()).exists()) escape( 138 "\tThe directory specified for the output file does not exist", null); 139 } 140 try { 141 new ArchiveUtil(!dashN, dashC, tcConfigFile, outputFile).createArchive(); 142 } catch (IOException e) { 143 escape("\tUnable to read Terracotta configuration file\n", e); 144 } catch (XmlException e) { 145 escape("\tUnable to parse Terracotta configuration file\n", e); 146 } 147 } 148 149 private File makeAbsolute(File file) { 150 if (file.isAbsolute()) return file; 151 return new File (tcConfig.getParent() + File.separator + file); 152 } 153 154 private File getClientLogsLocation(TcConfig configBeans) throws IOException , XmlException { 155 Client clients = configBeans.getClients(); 156 if (clients == null) quit("The Terracotta config specified doesn't contain the <clients> element.\nYou may have provided a server config by mistake."); 157 String logs = clients.getLogs(); 158 if (isStdX(logs)) return null; 159 if (logs == null) logs = Client.type.getElementProperty(QName.valueOf("logs")).getDefaultText(); 160 String clientLogs = ParameterSubstituter.substitute(logs); 161 File clientLogsDir = makeAbsolute(new File (clientLogs)); 162 if (!clientLogsDir.exists()) quit("\nError occured while parsing: " + tcConfig 163 + "\n\tUnable to locate client log files at: " + clientLogs); 164 return clientLogsDir; 165 } 166 167 private boolean isStdX(String value) { 168 if (value == null) return false; 169 return (value.equals(STDOUT) || value.equals(STDERR)); 170 } 171 172 private Server[] getServersElement(TcConfig configBeans) throws IOException , XmlException { 173 Servers servers = configBeans.getServers(); 174 if (servers == null) quit("The Terracotta config specified doesn't contain the <servers> element"); 175 return servers.getServerArray(); 176 } 177 178 private File [] getServerLogsLocation(TcConfig configBeans) throws IOException , XmlException { 179 Server[] servers = getServersElement(configBeans); 180 String [] logs = new String [servers.length]; 181 File [] logFiles = new File [servers.length]; 182 for (int i = 0; i < servers.length; i++) { 183 logs[i] = servers[i].getLogs(); 184 if (isStdX(logs[i])) logs[i] = null; 185 if (logs[i] == null) logs[i] = Server.type.getElementProperty(QName.valueOf("logs")).getDefaultText(); 186 logs[i] = ParameterSubstituter.substitute(logs[i]); 187 File serverLogsDir = makeAbsolute(new File (logs[i])); 188 if (!serverLogsDir.exists()) quit("\nError occured while parsing: " + tcConfig 189 + "\n\tUnable to resolve the server log location element to an actual file: " + logs[i]); 190 logFiles[i] = serverLogsDir; 191 } 192 return logFiles; 193 } 194 195 private File [] getServerDataLocation(TcConfig configBeans) throws IOException , XmlException { 196 if (!isFull) return null; 197 Server[] servers = getServersElement(configBeans); 198 String [] serverData = new String [servers.length]; 199 File [] dataFiles = new File [servers.length]; 200 for (int i = 0; i < servers.length; i++) { 201 serverData[i] = servers[i].getData(); 202 if (serverData[i] == null) serverData[i] = Server.type.getElementProperty(QName.valueOf("data")).getDefaultText(); 203 serverData[i] = ParameterSubstituter.substitute(serverData[i]); 204 File serverDataDir = makeAbsolute(new File (serverData[i])); 205 if (!serverDataDir.exists()) quit("\nError occured while parsing: " + tcConfig 206 + "\n\tUnable to resolve the server data location element to an actual file: " + serverData[i]); 207 dataFiles[i] = serverDataDir; 208 } 209 return dataFiles; 210 } 211 212 private void createPathArchive() { 213 try { 214 System.out.println("Archiving:\n----------------------------------------"); 215 ArchiveBuilder zip = new ZipBuilder(archiveFile, true); 216 zip.putEntry("env-stats", EnvStats.report().getBytes()); 217 zip.putTraverseDirectory(tcConfig, tcConfig.getName()); 218 zip.finish(); 219 } catch (IOException e) { 220 System.out.println("Unexpected error - unable to write Terracotta archive: " + archiveFile); 221 e.printStackTrace(); 222 System.exit(1); 223 } 224 System.out.println("\n\nWrote archive to:" + archiveFile); 225 } 226 227 private void createArchive() throws IOException , XmlException { 228 if (tcConfig.isDirectory()) { 229 createPathArchive(); 230 return; 231 } 232 TcConfig configBeans = new Loader().parse(tcConfig).getTcConfig(); 233 File clientLogsDir = null; 234 File [] serverLogsDir = null; 235 File [] serverDataDir = null; 236 if (isClient) { 237 clientLogsDir = getClientLogsLocation(configBeans); 238 } else { 239 serverLogsDir = getServerLogsLocation(configBeans); 240 serverDataDir = getServerDataLocation(configBeans); 241 } 242 try { 243 ArchiveBuilder zip = new ZipBuilder(archiveFile, true); 244 System.out.println("Archiving:"); 245 zip.putEntry(tcConfig.getName(), zip.readFile(tcConfig)); 246 if (isClient) { 247 if (clientLogsDir != null) zip.putTraverseDirectory(clientLogsDir, clientLogsDir.getName()); 248 } else { 249 for (int i = 0; i < serverLogsDir.length; i++) { 250 if (serverLogsDir[i] != null) zip.putTraverseDirectory(serverLogsDir[i], serverLogsDir[i].getName()); 251 } 252 if (serverDataDir != null) { 253 for (int i = 0; i < serverDataDir.length; i++) { 254 zip.putTraverseDirectory(serverDataDir[i], serverDataDir[i].getName()); 255 } 256 } 257 } 258 zip.finish(); 259 } catch (IOException e) { 260 System.out.println("Unexpected error - unable to write Terracotta archive: " + archiveFile); 261 e.printStackTrace(); 262 System.exit(1); 263 } 264 System.out.println("\n\nWrote archive to:" + archiveFile); 265 } 266 } 267 | Popular Tags |