|
| 1 | +/** |
| 2 | +* Module: ConfigInventory.java |
| 3 | +* |
| 4 | +* Written by Ray Wilson |
| 5 | +* |
| 6 | +* Description: Parse DataPower export files and put the data into a csv file. |
| 7 | +* The output file will be stored written in the base directory of the export. |
| 8 | +* This file can then be imported into your favorite spreadsheet. |
| 9 | +* |
| 10 | +* History: |
| 11 | +* 2017-07-06 v0.0.1 Created. |
| 12 | +* 2017-07-07 v0.1.0 Basic functionality achieved. |
| 13 | +* 2017-07-08 v1.0.0 Added auto extract and removal of extracted folders. |
| 14 | +* v2.0.0 Added Configuration Details option to the data collected on each gateway |
| 15 | +* Added the ability to turn on debug from the command line |
| 16 | +* 2017-07-25 v2.5.0 Moving it to the new package structure for PrairieLand. |
| 17 | +* Added a -all switch to get all named objects |
| 18 | +* Rewrote the core to use the DOM model and XML tools for java better. |
| 19 | +* |
| 20 | +* KNOWN ISSUES: |
| 21 | +* Not the most efficient file handling but it works and it's not a "performance" |
| 22 | +* software so for now I'm willing to live with it. |
| 23 | +* |
| 24 | +* Author: Ray Wilson |
| 25 | + |
| 26 | +* |
| 27 | +* Date: 2017-07-06 |
| 28 | +* |
| 29 | +* Copyright (C) 2017 Paul Ray Wilson |
| 30 | +* |
| 31 | +* This program is free software: you can redistribute it and/or modify |
| 32 | +* it under the terms of the GNU General Public License as published by |
| 33 | +* the Free Software Foundation, either version 3 of the License, or |
| 34 | +* (at your option) any later version. |
| 35 | +* |
| 36 | +* This program is distributed in the hope that it will be useful, |
| 37 | +* but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 38 | +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 39 | +* GNU General Public License for more details. |
| 40 | +* |
| 41 | +* You should have received a copy of the GNU General Public License |
| 42 | +* along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 43 | +* |
| 44 | +*/ |
| 45 | + |
| 46 | +package org.prairieland.datapower.ConfigInventory; |
| 47 | +import org.prairieland.util.pXML; |
| 48 | +import org.prairieland.util.pDPutil; |
| 49 | +import org.prairieland.util.pUtil; |
| 50 | + |
| 51 | +import java.io.*; |
| 52 | +import java.util.Scanner; |
| 53 | +import java.nio.file.*; |
| 54 | +import org.w3c.dom.*; |
| 55 | +import java.nio.file.attribute.BasicFileAttributes; |
| 56 | +import java.util.stream.Collectors; |
| 57 | +import java.util.Enumeration; |
| 58 | +import java.util.zip.*; |
| 59 | + |
| 60 | +public class ConfigInventory { |
| 61 | + public static String zipFile = ""; |
| 62 | + public static String tmpDir = ""; |
| 63 | + public static String csvFile = ""; |
| 64 | + public static boolean DEBUG = false; |
| 65 | + public static boolean DETAILS = false; |
| 66 | + public static boolean GETALL = false; |
| 67 | + public static String EXP = "export.xml"; // Export file name to work with ... all of them should be the same. |
| 68 | + |
| 69 | + /** main() |
| 70 | + * |
| 71 | + * This is the "main" method that checks for command line arguments and |
| 72 | + * for starting the createInventory method below where all the actual work will happen |
| 73 | + * |
| 74 | + */ |
| 75 | + public static void main(String arg[]) throws Exception { |
| 76 | + |
| 77 | + // Validate the command line arguments. |
| 78 | + boolean argsValid = checkArgs(arg); // Check command line arugments |
| 79 | + |
| 80 | + if (!argsValid) { |
| 81 | + System.out.println("\n==============================================================================="); |
| 82 | + System.out.println(" "); |
| 83 | + System.out.println("Usage: java -jar ConfigInventory.jar zipFile tmpDir csvFile [-h (-details | -all) -debug]"); |
| 84 | + System.out.println(" Where:"); |
| 85 | + System.out.println(" zipFile = Absolute path to the DataPower complete appliance export zip file"); |
| 86 | + System.out.println(" tmpDir = Absolute path to temporary directory to extract zip files including a tailing /"); |
| 87 | + System.out.println(" csvFile = Absolute path and name of the output csv file"); |
| 88 | + System.out.println(" -h = Optional: This message"); |
| 89 | + System.out.println(" -details = Optional: When present adds the object details to the output - ! used with -all"); |
| 90 | + System.out.println(" -all = Optional: When present generates a list of all named objects - ! used with -details"); |
| 91 | + System.out.println(" -debug = Optional: When present generates VERY verbose DEBUG messages in the console"); |
| 92 | + System.out.println(" "); |
| 93 | + System.out.println("Example > java -jar /Classes/ConfigInventory.jar /dir/IDG-20-A.zip /dir/dp-export/ /dir/IDG-20-report.csv"); |
| 94 | + System.out.println(" "); |
| 95 | + System.out.println("===============================================================================\n"); |
| 96 | + System.exit(0); |
| 97 | + } else { |
| 98 | + try { |
| 99 | + zipFile = arg[0]; |
| 100 | + tmpDir = arg[1]; |
| 101 | + csvFile = arg[2]; |
| 102 | + |
| 103 | + // This is where the work happens .... |
| 104 | + String result = createInventory(); |
| 105 | + System.out.println(result); |
| 106 | + } catch (Exception e) { |
| 107 | + System.err.println(e.getMessage()); |
| 108 | + System.exit(0); |
| 109 | + } |
| 110 | + } |
| 111 | + } |
| 112 | + /* ===== END OF public static void main(String arg[]) =====*/ |
| 113 | + |
| 114 | + |
| 115 | + /** createInventory() |
| 116 | + * |
| 117 | + * This is the module where the following happens: |
| 118 | + * 1) The zip file from the DataPower Export is extracted |
| 119 | + * 2) Basic appliance information collected from export.xml in the root of the extract |
| 120 | + * 3) A list of domains is read from the export.xml file in the root of the extract |
| 121 | + * 4) For each domain in the list |
| 122 | + * 5) The zip file for that domain is extracted |
| 123 | + * 6) The export.xml file in that domain is examined and information on gateways collected. |
| 124 | + * 7) All the upziped files and folders are removed. (still pending) |
| 125 | + * |
| 126 | + * return - String - The results of the doWork opperation. |
| 127 | + */ |
| 128 | + public static String createInventory () { |
| 129 | + if(DEBUG) {System.out.println("DEBUG :: Entering createInventory");} |
| 130 | + |
| 131 | + // Create helper classes |
| 132 | + pXML px = new pXML(); |
| 133 | + pDPutil dp = new pDPutil(); |
| 134 | + pUtil pu = new pUtil(); |
| 135 | + |
| 136 | + File fout = new File(csvFile); |
| 137 | + try { |
| 138 | + // Create the output file if it does not exist. |
| 139 | + if(!fout.exists()){ |
| 140 | + fout.createNewFile(); |
| 141 | + if(DEBUG){System.out.println("DEBUG :: Creating output file - " + csvFile);} |
| 142 | + } |
| 143 | + // Output file handle for writing |
| 144 | + BufferedWriter out = new BufferedWriter(new FileWriter(csvFile,true)); |
| 145 | + |
| 146 | + // Extract the main export file. It will contain multiple zip files with it for each domain |
| 147 | + // on the appliance. We will unzip those later in the loop where we gather the gateway informaiton |
| 148 | + pu.unZipIt(zipFile, tmpDir); |
| 149 | + |
| 150 | + // ****** |
| 151 | + // Get the data we want from the root export file about the appliance itself. |
| 152 | + // ****** |
| 153 | + // Open the export file in the root folder to get some some of the data |
| 154 | + String content = new Scanner(new File(tmpDir+EXP)).useDelimiter("\\Z").next(); |
| 155 | + |
| 156 | + // Get the node that contains the export details from the root export.xml file |
| 157 | + NodeList epxDetails = px.getAllNodes(content,"export-details"); |
| 158 | + |
| 159 | + // Get the Date-Time of the export and write it to the file. |
| 160 | + String expDate = px.getAllNodes(content,"current-date").item(0).getTextContent(); |
| 161 | + String expTime = px.getAllNodes(content,"current-time").item(0).getTextContent(); |
| 162 | + out.write("Export Date, "+ expDate + " - " + expTime + "\n"); out.flush(); |
| 163 | + if(DEBUG){ System.out.println("DEBUG :: Export Date :"+expDate+" "+expTime); } |
| 164 | + |
| 165 | + // Get the Device Name and write it to the file. |
| 166 | + String deviceName = px.getAllNodes(content,"device-name").item(0).getTextContent(); |
| 167 | + out.write("Device Name,"+deviceName+"\n"); out.flush(); |
| 168 | + if(DEBUG){ System.out.println("DEBUG :: Device Name :"+deviceName ); } |
| 169 | + |
| 170 | + // Get the Product ID and write it to the file. |
| 171 | + String productId = px.getAllNodes(content, "product-id").item(0).getTextContent(); |
| 172 | + out.write("Product ID,"+productId+"\n"); out.flush(); |
| 173 | + if(DEBUG){ System.out.println("DEBUG :: Product ID :"+productId ); } |
| 174 | + |
| 175 | + // Get the serial number and write it to the file. |
| 176 | + String serialNum = px.getAllNodes(content,"serial-number").item(0).getTextContent(); |
| 177 | + out.write("Serial Number,"+serialNum+"\n"); out.flush(); |
| 178 | + if(DEBUG){ System.out.println("DEBUG :: Serial No :"+serialNum ); } |
| 179 | + |
| 180 | + // Get the firmware version level and write it to the file. |
| 181 | + String firmwareVer = px.getAllNodes(content,"firmware-version").item(0).getTextContent(); |
| 182 | + out.write("Firmware Version,"+firmwareVer+"\n"); out.flush(); |
| 183 | + if(DEBUG){ System.out.println("DEBUG :: Firmware :"+firmwareVer ); } |
| 184 | + |
| 185 | + // Get a list of domains on the appliance from the base export.xml file. |
| 186 | + NodeList domainList = px.getAllNodes(content,"domain"); |
| 187 | + |
| 188 | + // Write the header for the list of gateways based on the DETAILS switch. |
| 189 | + if(DETAILS){ |
| 190 | + out.write("\n,\nDomain, Object Type, Object Name, Object Attribute, Attribute Value"); out.flush(); |
| 191 | + } else { |
| 192 | + out.write("\n,\nDomain, Object Type, Object Name"); out.flush(); |
| 193 | + } |
| 194 | + |
| 195 | + // ****** |
| 196 | + // Now get the object information from each domain. |
| 197 | + // ****** |
| 198 | + for(int k = 1; k < domainList.getLength(); k++) { |
| 199 | + |
| 200 | + String thisDomainName = px.getElementAtrribute(domainList.item(k), "name"); |
| 201 | + if(DEBUG){ System.out.println("\n\nDEBUG :: ++++++++++\nDEBUG :: ++++++++++ Working in Domain :" + thisDomainName + " ++++++++++\nDEBUG :: ++++++++++"); } |
| 202 | + |
| 203 | + // Extract the zip file for this domain |
| 204 | + String thisZipFile = tmpDir+thisDomainName+".zip"; |
| 205 | + String thisTmpDir = tmpDir+thisDomainName+"/"; |
| 206 | + pu.unZipIt(thisZipFile, thisTmpDir); |
| 207 | + |
| 208 | + // Read in the export.xml file for this domain. |
| 209 | + String domainExportFile = thisTmpDir+"/"+EXP; |
| 210 | + File expFile = new File(domainExportFile); |
| 211 | + |
| 212 | + // Create a workList of objects to return from each domain. |
| 213 | + String[] workList = null; |
| 214 | + if(GETALL){ |
| 215 | + if(DEBUG) {System.out.println("DEBUG :: Using getAllObjectsList to generate the workList.");} |
| 216 | + workList = dp.getAllObjectsList(expFile); |
| 217 | + } else { |
| 218 | + if(DEBUG) {System.out.println("DEBUG :: Using OBJECT_LIST for workList.");} |
| 219 | + workList = dp.OBJECT_LIST; |
| 220 | + } |
| 221 | + |
| 222 | + // Create on big string from the export.xml file for this domain. |
| 223 | + String domainContent = new Scanner(expFile).useDelimiter("\\Z").next(); |
| 224 | + |
| 225 | + // Write out the domain name to the file with a blank line before it. |
| 226 | + out.write(", \n"+thisDomainName+"\n"); out.flush(); |
| 227 | + |
| 228 | + // Generate an object list for each object in the dp.OBJECT_LIST ... found in pDPutil.java |
| 229 | + for(int l=0; l< workList.length; l++){ |
| 230 | + if(DEBUG){ System.out.println("\nDEBUG :: +++++ Searching for " + workList[l] + " objects in " + thisDomainName); } |
| 231 | + |
| 232 | + // The list of object for this OBJECT_LISTtype. |
| 233 | + NodeList thisList = px.getAllNodes(domainContent, workList[l]); |
| 234 | + if(DEBUG){ System.out.println("DEBUG :: Found " + thisList.getLength() + " object(s) of type : " + workList[l] ); } |
| 235 | + |
| 236 | + // Check to see if there are any gateways in the list. |
| 237 | + if(thisList.getLength() > 0){ |
| 238 | + for(int m = 0; m < thisList.getLength(); m++){ |
| 239 | + // Only process elements that have name attribute (some are only for when the element is used ... bug in IBM export.xml format.) |
| 240 | + if (px.getElementAtrribute(thisList.item(m), "name").length() > 1) { |
| 241 | + if(DEBUG){ System.out.println("DEBUG :: === " + (m+1) + " === Working element -" + px.getElementAtrribute(thisList.item(m), "name")+"-"); } |
| 242 | + // Write the type and name of each gateway in the list out to the file. |
| 243 | + out.write("," + workList[l] + "," + px.getElementAtrribute(thisList.item(m), "name") + "\n"); out.flush(); |
| 244 | + if(DETAILS){ |
| 245 | + // Get the element for the object, including all child elements. |
| 246 | + if(DEBUG){ System.out.println("DEBUG :: Requesting Element: " + workList[l] + " with the name " + px.getElementAtrribute(thisList.item(m), "name")); } |
| 247 | + |
| 248 | + // From the Node of this OBJECT get all of the applicable Attributes of the object from dp.DETAIL_LIST ... found in pDPutil.java |
| 249 | + for(int n = 0; n < dp.DETAIL_LIST.length; n++){ |
| 250 | + NodeList aList = px.getAllNodes(px.xmlNodeToString(thisList.item(m)), dp.DETAIL_LIST[n]); |
| 251 | + for (int p = 0; p < aList.getLength(); p++) { |
| 252 | + if(DEBUG){ System.out.println("DEBUG :: Found " + dp.DETAIL_LIST[n] + " - " + aList.item(p).getTextContent()); } |
| 253 | + |
| 254 | + // If the object admin state is disabled make a marker under the name to let someone know. |
| 255 | + if(dp.DETAIL_LIST[n].equals("mAdminState") && aList.item(p).getTextContent().equals("disabled")) { |
| 256 | + out.write(",X^_DISABLED_^X, ," + dp.DETAIL_LIST[n] + "," + aList.item(p).getTextContent() + "\n"); out.flush(); |
| 257 | + } else { |
| 258 | + out.write(", , ," + dp.DETAIL_LIST[n] + "," + aList.item(p).getTextContent() + "\n"); out.flush(); |
| 259 | + } |
| 260 | + } |
| 261 | + } |
| 262 | + } |
| 263 | + } |
| 264 | + } |
| 265 | + } |
| 266 | + } |
| 267 | + } |
| 268 | + // House keeping, Flush the buffer for the csvFile and close it. |
| 269 | + out.flush(); |
| 270 | + out.close(); |
| 271 | + // Remove the extracted files |
| 272 | + pu.killDir(tmpDir); |
| 273 | + } catch (Exception ex) { |
| 274 | + System.out.println(":: ERROR ::"); |
| 275 | + ex.printStackTrace(); |
| 276 | + } |
| 277 | + return("INVENTORY COMPLETE: The file "+csvFile+" has been created"); |
| 278 | + } |
| 279 | + /* ===== END OF createInventory() =====*/ |
| 280 | + |
| 281 | + |
| 282 | + /** checkArgs(String[]) |
| 283 | + * This is method validates the command line arguments as best as we can. |
| 284 | + * Needless to say, it's barely idiot proof .. but there is no what it's stupid proof. :) |
| 285 | + * param - arg[] |
| 286 | + * return - boolean - true of no errors detected else false. |
| 287 | + */ |
| 288 | + public static boolean checkArgs(String[] arg){ |
| 289 | + boolean valid = true; |
| 290 | + |
| 291 | + if(arg.length < 3) { return false; } |
| 292 | + |
| 293 | + // Check for the zip file |
| 294 | + File zFile = new File(arg[0]); |
| 295 | + if (!zFile.exists()) { valid = false; System.out.println("ERROR :: zipFile -" + arg[0] + "- is not valid"); } |
| 296 | + |
| 297 | + // Check for a temporary directory name. It does not have to exist, so just check that it's on the command line. |
| 298 | + if(!(arg[1].length() > 0)) { valid = false; System.out.println("ERROR :: tmpDir -" + arg[1] + "- is not valid"); } |
| 299 | + |
| 300 | + // Check for a csvFile name. |
| 301 | + if(!(arg[2].length() > 0)) { valid = false; System.out.println("ERROR :: csvFile -" + arg[2] + "- is not valid"); } |
| 302 | + |
| 303 | + // OPTIONAL SWITCH PARAMETERS |
| 304 | + if(arg.length > 3){ |
| 305 | + for(int j = 3; j < arg.length; j++) { |
| 306 | + switch (arg[j]) { |
| 307 | + case "-h": // Check for help switch |
| 308 | + valid=false; |
| 309 | + break; |
| 310 | + case "-details": |
| 311 | + DETAILS=true; // Set the DETAILS switch |
| 312 | + break; |
| 313 | + case "-all": |
| 314 | + GETALL=true; // Set the GETALL switch |
| 315 | + DETAILS=false; // unSet the DETAILS switch - really fubars the output if you use both. |
| 316 | + break; |
| 317 | + case "-debug": |
| 318 | + DEBUG=true; // Set the DEBUG switch |
| 319 | + break; |
| 320 | + default: |
| 321 | + System.out.println("ERROR :: switch -" + arg[j] + "- is not valid"); |
| 322 | + valid=false; |
| 323 | + break; |
| 324 | + } |
| 325 | + } |
| 326 | + } |
| 327 | + if(DEBUG) { |
| 328 | + System.out.println(); |
| 329 | + for(int i=0;i<arg.length;i++) { System.out.println("DEBUG :: arg " + i + " -" + arg[i] + "-"); } |
| 330 | + System.out.println("DEBUG :: DETAILS = " + DETAILS); |
| 331 | + System.out.println("DEBUG :: GETALL = " + GETALL); |
| 332 | + System.out.println("DEBUG :: DEBUG = " + DEBUG); |
| 333 | + } |
| 334 | + return valid; |
| 335 | + } |
| 336 | + /* ===== END OF checkArgs(String[]) =====*/ |
| 337 | + |
| 338 | +} |
| 339 | +/* ===== END OF Class ConfigInventory =====*/ |
| 340 | + |
0 commit comments