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.GregorianCalendar;
38 import java.util.HashSet;
39 import java.util.List;
41 import java.util.TimeZone;
43 import org.onap.aaf.auth.common.Define;
44 import org.onap.aaf.auth.dao.CassAccess;
45 import org.onap.aaf.auth.dao.cass.RoleDAO;
46 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
47 import org.onap.aaf.auth.dao.hl.Question;
48 import org.onap.aaf.auth.env.AuthzEnv;
49 import org.onap.aaf.auth.env.AuthzTrans;
50 import org.onap.aaf.auth.layer.Result;
51 import org.onap.aaf.auth.org.Organization;
52 import org.onap.aaf.auth.org.Organization.Identity;
53 import org.onap.aaf.auth.org.OrganizationException;
54 import org.onap.aaf.auth.org.OrganizationFactory;
55 import org.onap.aaf.cadi.Access.Level;
56 import org.onap.aaf.cadi.PropAccess;
57 import org.onap.aaf.cadi.config.Config;
58 import org.onap.aaf.misc.env.APIException;
59 import org.onap.aaf.misc.env.Env;
60 import org.onap.aaf.misc.env.StaticSlot;
61 import org.onap.aaf.misc.env.TimeTaken;
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 {
71 private static String rootNs;
73 private static StaticSlot ssargs;
75 protected static final String STARS = "*****";
77 protected final Cluster cluster;
78 protected static AuthzEnv env;
79 protected static Session session;
80 protected static Set<String> specialNames;
81 protected static List<String> specialDomains;
82 protected static boolean dryRun;
83 protected static String batchEnv;
85 public static final String CASS_ENV = "CASS_ENV";
86 public static final String LOG_DIR = "LOG_DIR";
87 protected static final String PUNT="punt";
88 protected static final String MAX_EMAILS="MAX_EMAILS";
89 protected static final String VERSION="VERSION";
90 public static final String GUI_URL="GUI_URL";
92 protected final Organization org;
96 protected Batch(AuthzEnv env) throws APIException, IOException, OrganizationException {
97 // Be able to change Environments
98 // load extra properties, i.e.
99 // PERF.cassandra.clusters=....
100 batchEnv = env.getProperty(CASS_ENV);
101 if (batchEnv != null) {
102 batchEnv = batchEnv.trim();
103 env.info().log("Redirecting to ",batchEnv,"environment");
105 for (String key : new String[]{
106 CassAccess.CASSANDRA_CLUSTERS,
107 CassAccess.CASSANDRA_CLUSTERS_PORT,
108 CassAccess.CASSANDRA_CLUSTERS_USER_NAME,
109 CassAccess.CASSANDRA_CLUSTERS_PASSWORD,
110 VERSION,GUI_URL,PUNT,MAX_EMAILS,
114 if ((str = env.getProperty(batchEnv+'.'+key))!=null) {
115 env.setProperty(key, str);
121 cluster = CassAccess.cluster(env,batchEnv);
122 env.info().log("cluster name - ",cluster.getClusterName());
123 String dryRunStr = env.getProperty( "DRY_RUN" );
124 if ( dryRunStr == null || "false".equals(dryRunStr.trim()) ) {
128 env.info().log("dryRun set to TRUE");
131 org = OrganizationFactory.init(env);
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());
152 protected abstract void run(AuthzTrans trans);
153 protected abstract void _close(AuthzTrans trans);
155 public String[] args() {
156 return env.get(ssargs);
159 public boolean isDryRun()
164 public boolean isSpecial(String user) {
168 if (specialNames != null && specialNames.contains(user)) {
169 env.info().log("specialName: " + user);
172 if(specialDomains!=null) {
173 for(String sd : specialDomains) {
174 if(user.endsWith(sd)) {
175 env.info().log("specialDomain: " + user + " matches " + sd);
185 protected PrintStream fallout(PrintStream inFallout, String logType)
187 PrintStream fallout = inFallout;
188 if (fallout == null) {
189 File dir = new File("logs");
195 long uniq = System.currentTimeMillis();
197 f = new File(dir, getClass().getSimpleName() + "_" + logType + "_"
200 fallout = new PrintStream(new FileOutputStream(f, true));
205 public Organization getOrgFromID(AuthzTrans trans, String user) {
206 Organization organization;
208 organization = OrganizationFactory.obtain(trans.env(),user.toLowerCase());
209 } catch (OrganizationException e1) {
210 trans.error().log(e1);
214 if (organization == null) {
215 PrintStream fallout = null;
218 fallout = fallout(fallout, "Fallout");
219 fallout.print("INVALID_ID,");
220 fallout.println(user);
221 } catch (Exception e) {
222 env.error().log("Could not write to Fallout File", e);
227 return (organization);
230 public static Row executeDeleteQuery(Statement stmt) {
233 row = session.execute(stmt).one();
240 public static int acquireRunLock(String className) {
241 Boolean testEnv = true;
242 String envStr = env.getProperty("AFT_ENVIRONMENT");
244 if (envStr != null) {
245 if ("AFTPRD".equals(envStr)) {
250 .log("AFT_ENVIRONMENT property is required and was not found. Exiting.");
255 env.info().log("TESTMODE: skipping RunLock");
259 String hostname = null;
261 hostname = InetAddress.getLocalHost().getHostName();
262 } catch (UnknownHostException e) {
264 env.warn().log("Unable to get hostname");
268 ResultSet existing = session.execute(String.format(
269 "select * from authz.run_lock where class = '%s'", className));
271 for (Row row : existing) {
272 long curr = System.currentTimeMillis();
273 ByteBuffer lastRun = row.getBytesUnsafe(2); // Can I get this field
276 long interval = (1 * 60 * 1000); // @@ Create a value in props file
278 long prev = lastRun.getLong();
280 if ((curr - prev) <= interval) {
282 String.format("Too soon! Last run was %d minutes ago.",
283 ((curr - prev) / 1000) / 60));
285 String.format("Min time between runs is %d minutes ",
286 (interval / 1000) / 60));
288 String.format("Last ran on machine: %s at %s",
289 row.getString("host"), row.getDate("start")));
292 env.info().log("Delete old lock");
293 deleteLock(className);
297 GregorianCalendar current = new GregorianCalendar();
299 // We want our time in UTC, hence "+0000"
300 SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+0000");
301 fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
304 .format("INSERT INTO authz.run_lock (class,host,start) VALUES ('%s','%s','%s') IF NOT EXISTS",
305 className, hostname, fmt.format(current.getTime()));
309 Row row = session.execute(cql).one();
310 if (!row.getBool("[applied]")) {
311 env.warn().log("Lightweight Transaction failed to write lock.");
313 String.format("host with lock: %s, running at %s",
314 row.getString("host"), row.getDate("start")));
320 private static void deleteLock( String className) {
321 Row row = session.execute( String.format( "DELETE FROM authz.run_lock WHERE class = '%s' IF EXISTS", className ) ).one();
322 if (! row.getBool("[applied]")) {
323 env.info().log( "delete failed" );
327 private static void transferVMProps(AuthzEnv env, String ... props) {
329 for (String key : props) {
330 if ((value = System.getProperty(key))!=null) {
331 env.setProperty(key, value);
336 // IMPORTANT! VALIDATE Organization isUser method
337 protected void checkOrganizationAcccess(AuthzTrans trans, Question q) throws APIException, OrganizationException {
338 Set<String> testUsers = new HashSet<>();
339 Result<List<RoleDAO.Data>> rrd = q.roleDAO.readNS(trans, rootNs);
341 for (RoleDAO.Data r : rrd.value) {
342 Result<List<UserRoleDAO.Data>> rur = q.userRoleDAO.readByRole(trans, r.fullName());
346 for (UserRoleDAO.Data udd : rur.value) {
347 testUsers.add(udd.user);
350 if (testUsers.size() < 2) {
351 throw new APIException("Not enough Users in Roles for " + rootNs + " to Validate");
355 for (String user : testUsers) {
356 if ((iden = org.getIdentity(trans, user)) == null) {
357 throw new APIException("Failed Organization Entity Validation Check: " + user);
359 trans.info().log("Organization Validation Check: " + iden.id());
365 protected static String logDir() {
366 String ld = env.getProperty(LOG_DIR);
368 if (batchEnv==null) { // Deployed Batch doesn't use different ENVs, and a common logdir
371 ld = "logs/"+batchEnv;
376 protected int count(String str, char c) {
377 if (str==null || str.isEmpty()) {
381 for (int i=str.indexOf(c);i>=0;i=str.indexOf(c,i+1)) {
388 public final void close(AuthzTrans trans) {
393 public static void main(String[] args) {
394 PropAccess access = new PropAccess(args);
395 InputStream is = null;
400 rootNs =Define.ROOT_NS();
401 if(access.getProperty(Config.CADI_PROP_FILES)==null) {
402 File f = new File("authBatch.props");
405 filename = f.getAbsolutePath();
406 is = new FileInputStream(f);
407 propLoc = f.getPath();
409 URL rsrc = ClassLoader.getSystemResource("authBatch.props");
410 filename = rsrc.toString();
411 is = rsrc.openStream();
412 propLoc = rsrc.getPath();
417 System.err.println("authBatch.props must exist in current dir, or in Classpath");
422 if (filename != null) {
423 access.log(Level.INFO,"Instantiated properties from", filename);
426 // Log where Config found
427 access.log(Level.INFO,"Configuring from", propLoc);
430 env = new AuthzEnv(access);
432 transferVMProps(env, CASS_ENV, "DRY_RUN", "NS", "Organization");
434 // Flow all Env Logs to Log4j, with ENV
437 // lfn = new LogFileNamer(logDir(),"").noPID();
438 // lfn.setAppender("authz-batch");
439 // lfn.setAppender("aspr|ASPR");
440 // lfn.setAppender("sync");
441 // lfn.setAppender("jobchange");
442 // lfn.setAppender("validateuser");
443 // aspr = Logger.getLogger("aspr");
444 // Log4JLogTarget.setLog4JEnv("authz-batch", env);
448 // setup ATTUser and Organization Slots before starting this:
450 // env.slot(ATT.ATT_USERSLOT);
452 // OrganizationFactory.setDefaultOrg(env, ATT.class.getName());
453 AuthzTrans trans = env.newTrans();
455 TimeTaken tt = trans.start("Total Run", Env.SUB);
457 int len = args.length;
459 String toolName = args[0];
463 String nargs[] = new String[len];
465 System.arraycopy(args, 1, nargs, 0, len);
468 env.put(ssargs = env.staticSlot("ARGS"), nargs);
471 * Add New Batch Programs (inherit from Batch) here
474 // Might be a Report, Update or Temp Batch
476 String classifier = "";
478 cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.batch.update." + toolName);
479 classifier = "Update:";
480 } catch (ClassNotFoundException e) {
482 cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.batch.reports." + toolName);
483 classifier = "Report:";
484 } catch (ClassNotFoundException e2) {
486 cls = ClassLoader.getSystemClassLoader()
487 .loadClass("org.onap.aaf.auth.batch.temp." + toolName);
488 classifier = "Temp Utility:";
489 } catch (ClassNotFoundException e3) {
495 Constructor<?> cnst = cls.getConstructor(AuthzTrans.class);
496 batch = (Batch) cnst.newInstance(trans);
497 env.info().log("Begin", classifier, toolName);
502 trans.error().log("No Batch named", toolName, "found");
505 * End New Batch Programs (inherit from Batch) here
517 StringBuilder sb = new StringBuilder("Task Times\n");
518 trans.auditTrail(4, sb, AuthzTrans.SUB, AuthzTrans.REMOTE);
519 trans.info().log(sb);
521 } catch (Exception e) {
522 e.printStackTrace(System.err);
523 // Exceptions thrown by DB aren't stopping the whole process.