2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.auth.batch;
25 import java.io.FileInputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.PrintStream;
30 import java.lang.reflect.Constructor;
31 import java.net.InetAddress;
33 import java.net.UnknownHostException;
34 import java.nio.ByteBuffer;
35 import java.text.SimpleDateFormat;
36 import java.util.ArrayList;
37 import java.util.Date;
38 import java.util.GregorianCalendar;
39 import java.util.HashSet;
40 import java.util.List;
42 import java.util.TimeZone;
44 import org.apache.log4j.Logger;
45 import org.onap.aaf.auth.common.Define;
46 import org.onap.aaf.auth.dao.CassAccess;
47 import org.onap.aaf.auth.env.AuthzEnv;
48 import org.onap.aaf.auth.env.AuthzTrans;
49 import org.onap.aaf.auth.log4j.Log4JAccessAppender;
50 import org.onap.aaf.auth.org.Organization;
51 import org.onap.aaf.auth.org.OrganizationException;
52 import org.onap.aaf.auth.org.OrganizationFactory;
53 import org.onap.aaf.cadi.Access.Level;
54 import org.onap.aaf.cadi.PropAccess;
55 import org.onap.aaf.cadi.config.Config;
56 import org.onap.aaf.misc.env.APIException;
57 import org.onap.aaf.misc.env.Env;
58 import org.onap.aaf.misc.env.TimeTaken;
59 import org.onap.aaf.misc.env.util.Chrono;
60 import org.onap.aaf.misc.env.util.Split;
61 import org.onap.aaf.misc.env.util.StringBuilderOutputStream;
63 import com.datastax.driver.core.Cluster;
64 import com.datastax.driver.core.ResultSet;
65 import com.datastax.driver.core.Row;
66 import com.datastax.driver.core.Session;
67 import com.datastax.driver.core.Statement;
69 public abstract class Batch {
70 protected static final String STARS = "*****";
72 protected static Cluster cluster;
73 protected static AuthzEnv env;
74 protected static Session session;
75 protected static Set<String> specialNames;
76 protected static List<String> specialDomains;
77 protected static boolean dryRun;
78 protected static String batchEnv;
80 private static File logdir;
82 private static String[] batchArgs;
84 public static final String CASS_ENV = "CASS_ENV";
85 public static final String LOG_DIR = "LOG_DIR";
86 protected static final String MAX_EMAILS="MAX_EMAILS";
87 protected static final String VERSION="VERSION";
88 public static final String GUI_URL="GUI_URL";
90 protected final Organization org;
91 protected String version;
92 protected static final Date now = new Date();
93 protected static final Date never = new Date(0);
95 protected Batch(AuthzEnv env) throws APIException, IOException, OrganizationException {
96 if (batchEnv != null) {
97 env.info().log("Redirecting to ",batchEnv,"environment");
99 for (String key : new String[]{
100 CassAccess.CASSANDRA_CLUSTERS,
101 CassAccess.CASSANDRA_CLUSTERS_PORT,
102 CassAccess.CASSANDRA_CLUSTERS_USER_NAME,
103 CassAccess.CASSANDRA_CLUSTERS_PASSWORD,
104 VERSION,GUI_URL,MAX_EMAILS,
109 if ((str = env.getProperty(batchEnv+'.'+key))!=null) {
110 env.setProperty(key, str);
117 cluster = CassAccess.cluster(env,batchEnv);
119 env.info().log("cluster name - ",cluster.getClusterName());
120 String dryRunStr = env.getProperty( "DRY_RUN" );
121 if ( dryRunStr == null || "false".equals(dryRunStr.trim()) ) {
125 env.info().log("dryRun set to TRUE");
128 org = OrganizationFactory.init(env);
130 throw new OrganizationException("Organization MUST be defined for Batch");
132 org.setTestMode(dryRun);
134 // Special names to allow behaviors beyond normal rules
135 specialNames = new HashSet<>();
136 specialDomains = new ArrayList<>();
137 String names = env.getProperty( "SPECIAL_NAMES" );
140 env.info().log("Loading SPECIAL_NAMES");
141 for (String s :names.split(",") ) {
142 env.info().log("\tspecial: " + s );
143 if(s.indexOf('@')>0) {
144 specialNames.add( s.trim() );
146 specialDomains.add(s.trim());
151 version = env.getProperty(VERSION,Config.AAF_DEFAULT_API_VERSION);
154 protected abstract void run(AuthzTrans trans);
155 protected void _close(AuthzTrans trans) {}
157 public String[] args() {
161 public boolean isDryRun()
166 public boolean isSpecial(String user) {
170 if (specialNames != null && specialNames.contains(user)) {
171 env.info().log("specialName: " + user);
174 if(specialDomains!=null) {
175 for(String sd : specialDomains) {
176 if(user.endsWith(sd)) {
177 env.info().log("specialDomain: " + user + " matches " + sd);
187 protected PrintStream fallout(PrintStream inFallout, String logType)
189 PrintStream fallout = inFallout;
190 if (fallout == null) {
191 File dir = new File("logs");
197 long uniq = System.currentTimeMillis();
199 f = new File(dir, getClass().getSimpleName() + "_" + logType + "_"
202 fallout = new PrintStream(new FileOutputStream(f, true));
207 public Organization getOrgFromID(AuthzTrans trans, String user) {
208 Organization organization;
210 organization = OrganizationFactory.obtain(trans.env(),user.toLowerCase());
211 } catch (OrganizationException e1) {
212 trans.error().log(e1);
216 if (organization == null) {
217 PrintStream fallout = null;
220 fallout = fallout(fallout, "Fallout");
221 fallout.print("INVALID_ID,");
222 fallout.println(user);
223 } catch (Exception e) {
224 env.error().log("Could not write to Fallout File", e);
229 return (organization);
232 public static Row executeDeleteQuery(Statement stmt) {
235 row = session.execute(stmt).one();
242 public static int acquireRunLock(String className) {
243 Boolean testEnv = true;
244 String envStr = env.getProperty("AFT_ENVIRONMENT");
246 if (envStr != null) {
247 if ("AFTPRD".equals(envStr)) {
252 .log("AFT_ENVIRONMENT property is required and was not found. Exiting.");
257 env.info().log("TESTMODE: skipping RunLock");
261 String hostname = null;
263 hostname = InetAddress.getLocalHost().getHostName();
264 } catch (UnknownHostException e) {
265 env.warn().log("Unable to get hostname : "+e.getMessage());
269 ResultSet existing = session.execute(String.format(
270 "select * from authz.run_lock where class = '%s'", className));
272 for (Row row : existing) {
273 long curr = System.currentTimeMillis();
274 ByteBuffer lastRun = row.getBytesUnsafe(2); // Can I get this field
277 long interval = (1 * 60 * 1000); // @@ Create a value in props file
279 long prev = lastRun.getLong();
281 if ((curr - prev) <= interval) {
283 String.format("Too soon! Last run was %d minutes ago.",
284 ((curr - prev) / 1000) / 60));
286 String.format("Min time between runs is %d minutes ",
287 (interval / 1000) / 60));
289 String.format("Last ran on machine: %s at %s",
290 row.getString("host"), row.getDate("start")));
293 env.info().log("Delete old lock");
294 deleteLock(className);
298 GregorianCalendar current = new GregorianCalendar();
300 // We want our time in UTC, hence "+0000"
301 SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+0000");
302 fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
305 .format("INSERT INTO authz.run_lock (class,host,start) VALUES ('%s','%s','%s') IF NOT EXISTS",
306 className, hostname, fmt.format(current.getTime()));
310 Row row = session.execute(cql).one();
311 if (!row.getBool("[applied]")) {
312 env.warn().log("Lightweight Transaction failed to write lock.");
314 String.format("host with lock: %s, running at %s",
315 row.getString("host"), row.getDate("start")));
321 private static void deleteLock( String className) {
322 Row row = session.execute( String.format( "DELETE FROM authz.run_lock WHERE class = '%s' IF EXISTS", className ) ).one();
323 if (! row.getBool("[applied]")) {
324 env.info().log( "delete failed" );
328 private static void transferVMProps(AuthzEnv env, String ... props) {
330 for (String key : props) {
331 if ((value = System.getProperty(key))!=null) {
332 env.setProperty(key, value);
337 protected static File logDir() {
339 String ld = env.getProperty(LOG_DIR);
341 if (batchEnv==null) { // Deployed Batch doesn't use different ENVs, and a common logdir
344 ld = "logs/"+batchEnv;
347 logdir = new File(ld);
348 if(!logdir.exists()) {
354 protected int count(String str, char c) {
355 if (str==null || str.isEmpty()) {
359 for (int i=str.indexOf(c);i>=0;i=str.indexOf(c,i+1)) {
366 public final void close(AuthzTrans trans) {
372 if(cluster!=null && !cluster.isClosed()) {
377 public static void main(String[] args) {
378 // Use a StringBuilder to save off logs until a File can be setup
379 StringBuilderOutputStream sbos = new StringBuilderOutputStream();
380 PropAccess access = new PropAccess(new PrintStream(sbos),args);
381 access.log(Level.INFO, "------- Starting Batch ------\n Args: ");
382 for(String s: args) {
383 sbos.getBuffer().append(s);
384 sbos.getBuffer().append(' ');
386 sbos.getBuffer().append('\n');
388 InputStream is = null;
394 if(access.getProperty(Config.CADI_PROP_FILES)==null) {
395 File f = new File("authBatch.props");
398 filename = f.getAbsolutePath();
399 is = new FileInputStream(f);
400 propLoc = f.getPath();
402 URL rsrc = ClassLoader.getSystemResource("authBatch.props");
403 filename = rsrc.toString();
404 is = rsrc.openStream();
405 propLoc = rsrc.getPath();
410 System.err.println("authBatch.props must exist in current dir, or in Classpath");
415 if (filename != null) {
416 access.log(Level.INFO,"Instantiated properties from", filename);
419 // Log where Config found
420 access.log(Level.INFO,"Configuring from", propLoc);
424 env = new AuthzEnv(access);
426 transferVMProps(env, CASS_ENV, "DRY_RUN", "NS", "Organization");
428 // Be able to change Environments
429 // load extra properties, i.e.
430 // PERF.cassandra.clusters=....
431 batchEnv = env.getProperty(CASS_ENV);
433 batchEnv = batchEnv.trim();
436 File logFile = new File(logDir() + "/batch" + Chrono.dateOnlyStamp(new Date()) + ".log" );
437 PrintStream batchLog = new PrintStream(new FileOutputStream(logFile,true));
439 access.setStreamLogIt(batchLog);
441 batchLog.print(sbos.getBuffer());
443 Logger.getRootLogger().addAppender(new Log4JAccessAppender(access));
446 AuthzTrans trans = env.newTrans();
448 TimeTaken tt = trans.start("Total Run", Env.SUB);
450 int len = args.length;
452 String toolName = args[0];
456 batchArgs = new String[len];
458 System.arraycopy(args, 1, batchArgs, 0, len);
461 * Add New Batch Programs (inherit from Batch) here
464 // Might be a Report, Update or Temp Batch
466 String classifier = "";
468 String[] pkgs = new String[] {
469 "org.onap.aaf.auth.batch.update",
470 "org.onap.aaf.auth.batch.reports",
471 "org.onap.aaf.auth.batch.temp"
474 String ebp = env.getProperty("EXTRA_BATCH_PKGS");
476 String[] ebps = Split.splitTrim(':', ebp);
477 String[] temp = new String[ebps.length + pkgs.length];
478 System.arraycopy(pkgs,0, temp, 0, pkgs.length);
479 System.arraycopy(ebps,0,temp,pkgs.length,ebps.length);
483 for(String p : pkgs) {
485 cls = ClassLoader.getSystemClassLoader().loadClass(p + '.' + toolName);
486 int lastDot = p.lastIndexOf('.');
487 if(p.length()>0 || p.length()!=lastDot) {
488 StringBuilder sb = new StringBuilder();
489 sb.append(Character.toUpperCase(p.charAt(++lastDot)));
490 while(++lastDot<p.length()) {
491 sb.append(p.charAt(lastDot));
494 classifier = sb.toString();
497 } catch (ClassNotFoundException e) {
502 Constructor<?> cnst = cls.getConstructor(AuthzTrans.class);
503 batch = (Batch) cnst.newInstance(trans);
504 System.out.println(batch.getClass().getCanonicalName());
505 env.info().log("Begin", classifier, toolName);
510 trans.error().log("No Batch named", toolName, "found");
513 * End New Batch Programs (inherit from Batch) here
519 for(String s : batchArgs) {
520 System.out.println(s);
523 } catch (Exception e) {
524 trans.error().log(e);
525 if(cluster!=null && !cluster.isClosed()) {
528 trans.error().log(e);
536 StringBuilder sb = new StringBuilder("Task Times\n");
537 trans.auditTrail(4, sb, AuthzTrans.SUB, AuthzTrans.REMOTE);
538 trans.info().log(sb);
540 } catch (Exception e) {
546 } catch (Exception e) {
547 if(cluster!=null && !cluster.isClosed()) {
550 env.warn().log(System.err);