Initial Interface for remote Configuration
[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