Mass removal of all Tabs (Style Warnings)
[aaf/authz.git] / auth / auth-batch / src / main / java / org / onap / aaf / auth / Batch.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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====================================================
19  *
20  */
21
22 package org.onap.aaf.auth;
23
24 import java.io.File;
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;
32 import java.net.URL;
33 import java.net.UnknownHostException;
34 import java.nio.ByteBuffer;
35 import java.text.SimpleDateFormat;
36 import java.util.GregorianCalendar;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.Set;
40 import java.util.TimeZone;
41
42 import org.apache.log4j.Logger;
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.PropAccess;
56 import org.onap.aaf.misc.env.APIException;
57 import org.onap.aaf.misc.env.Env;
58 import org.onap.aaf.misc.env.StaticSlot;
59 import org.onap.aaf.misc.env.TimeTaken;
60 import org.onap.aaf.misc.env.impl.Log4JLogTarget;
61 import org.onap.aaf.misc.env.log4j.LogFileNamer;
62
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;
68
69 public abstract class Batch {
70
71     private static String rootNs;
72
73     private static StaticSlot ssargs;
74
75     protected static final String STARS = "*****";
76
77     protected final Cluster cluster; 
78     protected static AuthzEnv env;
79     protected static Session session;
80     protected static Logger aspr;
81     protected static Set<String> specialNames;
82     protected static boolean dryRun; 
83     protected static String batchEnv;
84
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";
91     
92     protected final Organization org;
93
94
95     
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");
104             String str;
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,
111                     LOG_DIR,
112                     "SPECIAL_NAMES"
113                     }) {
114                 if((str = env.getProperty(batchEnv+'.'+key))!=null) {
115                     env.setProperty(key, str);
116                 }
117             }
118         }
119
120         // Setup for Dry Run
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()) ) {
125             dryRun = false;
126         } else {
127             dryRun = true;
128             env.info().log("dryRun set to TRUE");
129         }
130
131         org = OrganizationFactory.init(env);
132         org.setTestMode(dryRun);
133
134         // Special names to allow behaviors beyond normal rules
135         specialNames = new HashSet<>();
136         String names = env.getProperty( "SPECIAL_NAMES" );
137         if ( names != null )
138         {
139             env.info().log("Loading SPECIAL_NAMES");
140             for (String s :names.split(",") )
141             {
142                 env.info().log("\tspecial: " + s );
143                 specialNames.add( s.trim() );
144             }
145         }
146     }
147
148     protected abstract void run(AuthzTrans trans);
149     protected abstract void _close(AuthzTrans trans);
150     
151     public String[] args() {
152         return env.get(ssargs);
153     }
154     
155     public boolean isDryRun()
156     {
157         return dryRun;
158     }
159     
160     public boolean isSpecial(String user) {
161         if (specialNames != null && specialNames.contains(user)) {
162             env.info().log("specialName: " + user);
163
164             return (true);
165         } else {
166             return (false);
167         }
168     }
169     
170     public boolean isMechID(String user) {
171         if (user.matches("m[0-9][0-9][0-9][0-9][0-9]")) {
172             return (true);
173         } else {
174             return (false);
175         }
176     }
177
178     protected PrintStream fallout(PrintStream inFallout, String logType)
179             throws IOException {
180         PrintStream fallout = inFallout;
181         if (fallout == null) {
182             File dir = new File("logs");
183             if (!dir.exists()) {
184                 dir.mkdirs();
185             }
186
187             File f = null;
188             long uniq = System.currentTimeMillis();
189
190             f = new File(dir, getClass().getSimpleName() + "_" + logType + "_"
191                     + uniq + ".log");
192
193             fallout = new PrintStream(new FileOutputStream(f, true));
194         }
195         return fallout;
196     }
197
198     public Organization getOrgFromID(AuthzTrans trans, String user) {
199         Organization organization;
200         try {
201             organization = OrganizationFactory.obtain(trans.env(),user.toLowerCase());
202         } catch (OrganizationException e1) {
203             trans.error().log(e1);
204             organization=null;
205         }
206
207         if (organization == null) {
208             PrintStream fallout = null;
209
210             try {
211                 fallout = fallout(fallout, "Fallout");
212                 fallout.print("INVALID_ID,");
213                 fallout.println(user);
214             } catch (Exception e) {
215                 env.error().log("Could not write to Fallout File", e);
216             }
217             return (null);
218         }
219
220         return (organization);
221     }
222     
223     public static Row executeDeleteQuery(Statement stmt) {
224         Row row = null;
225         if (!dryRun) {
226             row = session.execute(stmt).one();
227         }
228
229         return (row);
230
231     }
232         
233     public static int acquireRunLock(String className) {
234         Boolean testEnv = true;
235         String envStr = env.getProperty("AFT_ENVIRONMENT");
236
237         if (envStr != null) {
238             if ("AFTPRD".equals(envStr)) {
239                 testEnv = false;
240             }
241         } else {
242             env.fatal()
243                     .log("AFT_ENVIRONMENT property is required and was not found. Exiting.");
244             System.exit(1);
245         }
246
247         if (testEnv) {
248             env.info().log("TESTMODE: skipping RunLock");
249             return (1);
250         }
251
252         String hostname = null;
253         try {
254             hostname = InetAddress.getLocalHost().getHostName();
255         } catch (UnknownHostException e) {
256             e.printStackTrace();
257             env.warn().log("Unable to get hostname");
258             return (0);
259         }
260
261         ResultSet existing = session.execute(String.format(
262                 "select * from authz.run_lock where class = '%s'", className));
263
264         for (Row row : existing) {
265             long curr = System.currentTimeMillis();
266             ByteBuffer lastRun = row.getBytesUnsafe(2); // Can I get this field
267                                                         // by name?
268
269             long interval = (1 * 60 * 1000); // @@ Create a value in props file
270                                                 // for this
271             long prev = lastRun.getLong();
272
273             if ((curr - prev) <= interval) {
274                 env.warn().log(
275                         String.format("Too soon! Last run was %d minutes ago.",
276                                 ((curr - prev) / 1000) / 60));
277                 env.warn().log(
278                         String.format("Min time between runs is %d minutes ",
279                                 (interval / 1000) / 60));
280                 env.warn().log(
281                         String.format("Last ran on machine: %s at %s",
282                                 row.getString("host"), row.getDate("start")));
283                 return (0);
284             } else {
285                 env.info().log("Delete old lock");
286                 deleteLock(className);
287             }
288         }
289
290         GregorianCalendar current = new GregorianCalendar();
291
292         // We want our time in UTC, hence "+0000"
293         SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+0000");
294         fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
295
296         String cql = String
297                 .format("INSERT INTO authz.run_lock (class,host,start) VALUES ('%s','%s','%s') IF NOT EXISTS",
298                         className, hostname, fmt.format(current.getTime()));
299
300         env.info().log(cql);
301
302         Row row = session.execute(cql).one();
303         if (!row.getBool("[applied]")) {
304             env.warn().log("Lightweight Transaction failed to write lock.");
305             env.warn().log(
306                     String.format("host with lock: %s, running at %s",
307                             row.getString("host"), row.getDate("start")));
308             return (0);
309         }
310         return (1);
311     }
312     
313     private static void deleteLock( String className) {
314         Row row = session.execute( String.format( "DELETE FROM authz.run_lock WHERE class = '%s' IF EXISTS", className ) ).one();
315         if (! row.getBool("[applied]")) {
316             env.info().log( "delete failed" );
317         }
318     }
319
320     private static void transferVMProps(AuthzEnv env, String ... props) {
321         String value;
322         for(String key : props) {
323             if((value = System.getProperty(key))!=null) {
324                 env.setProperty(key, value);
325             }
326         }
327     }
328     
329     // IMPORTANT! VALIDATE Organization isUser method
330     protected void checkOrganizationAcccess(AuthzTrans trans, Question q) throws APIException, OrganizationException {
331             Set<String> testUsers = new HashSet<>();
332             Result<List<RoleDAO.Data>> rrd = q.roleDAO.readNS(trans, rootNs);
333             if (rrd.isOK()) {
334                 for (RoleDAO.Data r : rrd.value) {
335                     Result<List<UserRoleDAO.Data>> rur = q.userRoleDAO.readByRole(trans, r.fullName());
336                     if (!rur.isOK()) {
337                         continue;
338                     }
339                     for (UserRoleDAO.Data udd : rur.value) {
340                         testUsers.add(udd.user);
341                     }
342                 }
343                 if (testUsers.size() < 2) {
344                     throw new APIException("Not enough Users in Roles for " + rootNs + " to Validate");
345                 }
346
347                 Identity iden;
348                 for (String user : testUsers) {
349                     if ((iden = org.getIdentity(trans, user)) == null) {
350                         throw new APIException("Failed Organization Entity Validation Check: " + user);
351                     } else {
352                         trans.info().log("Organization Validation Check: " + iden.id());
353                     }
354                 }
355             }
356         }
357     
358     protected static String logDir() {
359         String ld = env.getProperty(LOG_DIR);
360         if(ld==null) {
361             if(batchEnv==null) { // Deployed Batch doesn't use different ENVs, and a common logdir
362                 ld = "logs/";
363             } else {
364                 ld = "logs/"+batchEnv;
365             }
366         }
367         return ld;
368     }
369     protected int count(String str, char c) {
370         if(str==null || str.isEmpty()) {
371             return 0;
372         } else {
373             int count=1;
374             for(int i=str.indexOf(c);i>=0;i=str.indexOf(c,i+1)) {
375                 ++count;
376             }
377             return count;
378         }
379     }
380
381     public final void close(AuthzTrans trans) {
382         _close(trans);
383         cluster.close();
384     }
385
386     public static void main(String[] args) {
387         PropAccess access = new PropAccess(args);
388         InputStream is = null;
389         String filename;
390         String propLoc;
391         try {
392             Define.set(access);
393             rootNs =Define.ROOT_NS();
394             
395             File f = new File("etc/authzBatch.props");
396             try {
397                 if (f.exists()) {
398                     filename = f.getAbsolutePath();
399                     is = new FileInputStream(f);
400                     propLoc = f.getPath();
401                 } else {
402                     URL rsrc = ClassLoader.getSystemResource("authBatch.props");
403                     filename = rsrc.toString();
404                     is = rsrc.openStream();
405                     propLoc = rsrc.getPath();
406                 }
407                 access.load(is);
408             } finally {
409                 if (is == null) {
410                     System.err.println("authBatch.props must exist in etc dir, or in Classpath");
411                     System.exit(1);
412                 }
413                 is.close();
414             }
415
416             env = new AuthzEnv(access);
417
418             transferVMProps(env, CASS_ENV, "DRY_RUN", "NS", "Organization");
419
420             // Flow all Env Logs to Log4j, with ENV
421
422             LogFileNamer lfn;
423             lfn = new LogFileNamer(logDir(),"").noPID();
424             lfn.setAppender("authz-batch");
425             lfn.setAppender("aspr|ASPR");
426             lfn.setAppender("sync");
427             lfn.setAppender("jobchange");
428             lfn.setAppender("validateuser");
429             aspr = Logger.getLogger("aspr");
430             Log4JLogTarget.setLog4JEnv("authz-batch", env);
431             if (filename != null) {
432                 env.init().log("Instantiated properties from", filename);
433             }
434
435             // Log where Config found
436             env.info().log("Configuring from", propLoc);
437             propLoc = null;
438
439             Batch batch = null;
440             // setup ATTUser and Organization Slots before starting this:
441             // TODO redo this
442             // env.slot(ATT.ATT_USERSLOT);
443             //
444             // OrganizationFactory.setDefaultOrg(env, ATT.class.getName());
445             AuthzTrans trans = env.newTrans();
446
447             TimeTaken tt = trans.start("Total Run", Env.SUB);
448             try {
449                 int len = args.length;
450                 if (len > 0) {
451                     String toolName = args[0];
452                     len -= 1;
453                     if (len < 0)
454                         len = 0;
455                     String nargs[] = new String[len];
456                     if (len > 0) {
457                         System.arraycopy(args, 1, nargs, 0, len);
458                     }
459
460                     env.put(ssargs = env.staticSlot("ARGS"), nargs);
461
462                     /*
463                      * Add New Batch Programs (inherit from Batch) here
464                      */
465
466                     // Might be a Report, Update or Temp Batch
467                     Class<?> cls;
468                     String classifier = "";
469                     try {
470                         cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.update." + toolName);
471                         classifier = "Update:";
472                     } catch (ClassNotFoundException e) {
473                         try {
474                             cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.reports." + toolName);
475                             classifier = "Report:";
476                         } catch (ClassNotFoundException e2) {
477                             try {
478                                 cls = ClassLoader.getSystemClassLoader()
479                                         .loadClass("org.onap.aaf.auth.temp." + toolName);
480                                 classifier = "Temp Utility:";
481                             } catch (ClassNotFoundException e3) {
482                                 cls = null;
483                             }
484                         }
485                     }
486                     if (cls != null) {
487                         Constructor<?> cnst = cls.getConstructor(new Class[] { AuthzTrans.class });
488                         batch = (Batch) cnst.newInstance(trans);
489                         env.info().log("Begin", classifier, toolName);
490                     }
491                 
492
493                     if (batch == null) {
494                         trans.error().log("No Batch named", toolName, "found");
495                     }
496                     /*
497                      * End New Batch Programs (inherit from Batch) here
498                      */
499
500                 }
501                 if (batch != null) {
502                     batch.run(trans);
503                 }
504             } finally {
505                 tt.done();
506                 if (batch != null) {
507                     batch.close(trans);
508                 }
509                 StringBuilder sb = new StringBuilder("Task Times\n");
510                 trans.auditTrail(4, sb, AuthzTrans.SUB, AuthzTrans.REMOTE);
511                 trans.info().log(sb);
512             }
513         } catch (Exception e) {
514             e.printStackTrace(System.err);
515             // Exceptions thrown by DB aren't stopping the whole process.
516             System.exit(1);
517         }
518     }
519
520 }
521