diff options
author | Instrumental <jonathan.gathman@att.com> | 2019-03-07 12:58:39 -0600 |
---|---|---|
committer | Instrumental <jonathan.gathman@att.com> | 2019-03-07 12:58:54 -0600 |
commit | a174f8ddbc5eb78a648fb68b33ef18cb64d81fda (patch) | |
tree | d27c01bcd63fd6a7bff00687c6f33423a3a40e8c /auth/auth-batch/src/main/java | |
parent | 9dc1cd2632d1dda9c8f072e99616e73e0517f1aa (diff) |
Improve Batches
Issue-ID: AAF-740
Change-Id: Ib3e8a3f977964eed2e992dc02154dd3bc90492df
Signed-off-by: Instrumental <jonathan.gathman@att.com>
Diffstat (limited to 'auth/auth-batch/src/main/java')
14 files changed, 612 insertions, 220 deletions
diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/Pending.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/Pending.java index 2e7997b4..3072038a 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/Pending.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/Pending.java @@ -105,4 +105,5 @@ public class Pending { public boolean newApprovals() { return hasNew; } + }
\ No newline at end of file diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/URApprovalSet.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/URApprovalSet.java index 858690ac..2c1ffe6d 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/URApprovalSet.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/approvalsets/URApprovalSet.java @@ -21,6 +21,7 @@ package org.onap.aaf.auth.batch.approvalsets; import java.io.IOException; +import java.util.Date; import java.util.GregorianCalendar; import java.util.List; @@ -40,7 +41,7 @@ import org.onap.aaf.misc.env.util.Chrono; public class URApprovalSet extends ApprovalSet { - private boolean ownerSuperApprove; + private boolean ownerSuperApprove = true; public URApprovalSet(final AuthzTrans trans, final GregorianCalendar start, final DataView dv, final Loader<UserRoleDAO.Data> lurdd) throws IOException, CadiException { super(start, "user_role", dv); @@ -49,6 +50,8 @@ public class URApprovalSet extends ApprovalSet { setConstruct(urdd.bytify()); setMemo(getMemo(urdd)); setExpires(org.expiration(null, Organization.Expiration.UserInRole)); + setTargetKey(urdd.role); + setTargetDate(urdd.expires); Result<RoleDAO.Data> r = dv.roleByName(trans, urdd.role); if(r.notOKorIsEmpty()) { @@ -88,18 +91,13 @@ public class URApprovalSet extends ApprovalSet { } } - if(isOwner && ownerSuperApprove) { + if(isOwner) { try { List<Identity> apprs = org.getApprovers(trans, urdd.user); if(apprs!=null) { for(Identity i : apprs) { ApprovalDAO.Data add = newApproval(urdd); - Identity reportsTo = i.responsibleTo(); - if(reportsTo!=null) { - add.approver = reportsTo.fullID(); - } else { - throw new CadiException("No Supervisor for '" + urdd.user + '\''); - } + add.approver = i.fullID(); add.type = org.getApproverType(); ladd.add(add); } @@ -110,8 +108,16 @@ public class URApprovalSet extends ApprovalSet { } } - public void ownerSuperApprove() { - ownerSuperApprove = true; + private void setTargetDate(Date expires) { + fdd.target_date = expires; + } + + private void setTargetKey(String key) { + fdd.target_key = key; + } + + public void ownerSuperApprove(boolean set) { + ownerSuperApprove = set; } private ApprovalDAO.Data newApproval(UserRoleDAO.Data urdd) throws CadiException { diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Approval.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Approval.java index 2cc6907b..1bc82f5e 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Approval.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/Approval.java @@ -57,13 +57,13 @@ public class Approval implements CacheChange.Data { public final ApprovalDAO.Data add; private String role; - public Approval(UUID id, UUID ticket, String approver, Date last_notified, + public Approval(UUID id, UUID ticket, String approver,// Date last_notified, String user, String memo, String operation, String status, String type, long updated) { add = new ApprovalDAO.Data(); add.id = id; add.ticket = ticket; add.approver = approver; - add.last_notified = last_notified; +// add.last_notified = last_notified; add.user = user; add.memo = memo; add.operation = operation; @@ -125,8 +125,8 @@ public class Approval implements CacheChange.Data { } } - public static void row(CSV.Writer cw, Approval app) { - cw.row("approval",app.add.id,app.add.ticket,app.add.user,app.role,app.add.memo); + public static void row(CSV.RowSetter crs, Approval app) { + crs.row("approval",app.add.id,app.add.ticket,app.add.user,app.role,app.add.memo); } @@ -211,41 +211,41 @@ public class Approval implements CacheChange.Data { } } - public void update(AuthzTrans trans, ApprovalDAO apprDAO, boolean dryRun) { - if (dryRun) { - trans.info().printf("Would update Approval %s, %s, last_notified %s",add.id,add.status,add.last_notified); - } else { - trans.info().printf("Update Approval %s, %s, last_notified %s",add.id,add.status,add.last_notified); - apprDAO.update(trans, add); - } - } +// public void update(AuthzTrans trans, ApprovalDAO apprDAO, boolean dryRun) { +// if (dryRun) { +// trans.info().printf("Would update Approval %s, %s, last_notified %s",add.id,add.status,add.last_notified); +// } else { +// trans.info().printf("Update Approval %s, %s, last_notified %s",add.id,add.status,add.last_notified); +// apprDAO.update(trans, add); +// } +// } public static Creator<Approval> v2_0_17 = new Creator<Approval>() { @Override public Approval create(Row row) { - return new Approval(row.getUUID(0), row.getUUID(1), row.getString(2), row.getTimestamp(3), - row.getString(4),row.getString(5),row.getString(6),row.getString(7),row.getString(8) - ,row.getLong(9)/1000); + return new Approval(row.getUUID(0), row.getUUID(1), row.getString(2), + row.getString(3),row.getString(4),row.getString(5),row.getString(6),row.getString(7), + row.getLong(8)/1000); } @Override public String select() { - return "select id,ticket,approver,last_notified,user,memo,operation,status,type,WRITETIME(status) from authz.approval"; + return "select id,ticket,approver,user,memo,operation,status,type,WRITETIME(status) from authz.approval"; } }; - /** - * @return the lastNotified - */ - public Date getLast_notified() { - return add.last_notified; - } - /** - * @param lastNotified the lastNotified to set - */ - public void setLastNotified(Date last_notified) { - add.last_notified = last_notified; - } +// /** +// * @return the lastNotified +// */ +// public Date getLast_notified() { +// return add.last_notified; +// } +// /** +// * @param lastNotified the lastNotified to set +// */ +// public void setLastNotified(Date last_notified) { +// add.last_notified = last_notified; +// } /** * @return the status */ diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/BatchDataView.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/BatchDataView.java index 37def6d6..83945ee6 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/BatchDataView.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/BatchDataView.java @@ -134,12 +134,12 @@ public class BatchDataView implements DataView { public Result<ApprovalDAO.Data> insert(AuthzTrans trans, ApprovalDAO.Data add) { cqlBatch.preLoop(); StringBuilder sb = cqlBatch.inc(); - sb.append("INSERT INTO authz.approval (id,approver,last_notified,memo,operation,status,ticket,type,user) VALUES ("); + sb.append("INSERT INTO authz.approval (id,approver,memo,operation,status,ticket,type,user) VALUES ("); sb.append(add.id.toString()); sb.append(COMMA_QUOTE); sb.append(add.approver); - sb.append(QUOTE_COMMA_QUOTE); - sb.append(Chrono.utcStamp(add.last_notified)); +// sb.append(QUOTE_COMMA_QUOTE); +// sb.append(Chrono.utcStamp(add.last_notified)); sb.append(QUOTE_COMMA_QUOTE); sb.append(add.memo.replace("'", "''")); sb.append(QUOTE_COMMA_QUOTE); @@ -160,7 +160,7 @@ public class BatchDataView implements DataView { public Result<FutureDAO.Data> insert(AuthzTrans trans, FutureDAO.Data fdd) { cqlBatch.preLoop(); StringBuilder sb = cqlBatch.inc(); - sb.append("INSERT INTO authz.future (id,construct,expires,memo,start,target) VALUES ("); + sb.append("INSERT INTO authz.future (id,construct,expires,memo,start,target,target_key,target_date) VALUES ("); sb.append(fdd.id.toString()); sb.append(','); fdd.construct.hasArray(); @@ -173,6 +173,14 @@ public class BatchDataView implements DataView { sb.append(Chrono.utcStamp(fdd.expires)); sb.append(QUOTE_COMMA_QUOTE); sb.append(fdd.target); + if(fdd.target_key==null) { + sb.append("',,'"); + } else { + sb.append(QUOTE_COMMA_QUOTE); + sb.append(fdd.target_key==null?"":fdd.target_key); + sb.append(QUOTE_COMMA_QUOTE); + } + sb.append(Chrono.utcStamp(fdd.target_date)); sb.append(QUOTE_PAREN_SEMI); return Result.ok(fdd); } diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/LastNotified.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/LastNotified.java new file mode 100644 index 00000000..22231f3a --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/helpers/LastNotified.java @@ -0,0 +1,90 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Modifications Copyright (C) 2018 IBM. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.auth.batch.helpers; + +import java.util.Date; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.onap.aaf.auth.batch.helpers.Notification.TYPE; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; + +public class LastNotified { + private Map<String,Date> lastNotified = new TreeMap<>(); + private Session session; + + public LastNotified(Session session) { + this.session = session; + } + + public void add(Set<String> users) { + StringBuilder query = new StringBuilder(); + startNotifyQuery(query); + int cnt = 0; + for(String user : users) { + if(++cnt>1) { + query.append(','); + } + query.append('\''); + query.append(user); + query.append('\''); + if(cnt>=30) { + endNotifyQuery(query, Notification.TYPE.OA); + add(session.execute(query.toString()),lastNotified); + query.setLength(0); + startNotifyQuery(query); + cnt=0; + } + } + if(cnt>0) { + endNotifyQuery(query, Notification.TYPE.OA); + add(session.execute(query.toString()),lastNotified); + } + } + + public Date lastNotified(String user) { + return lastNotified.get(user); + } + + private void add(ResultSet result, Map<String, Date> lastNotified) { + for(Iterator<Row> iter = result.iterator(); iter.hasNext();) { + Row r = iter.next(); + lastNotified.put(r.getString(0), r.getTimestamp(1)); + } + } + + private void startNotifyQuery(StringBuilder query) { + query.append("SELECT user,last FROM authz.notify WHERE user in ("); + } + + private void endNotifyQuery(StringBuilder query, TYPE oa) { + query.append(") AND type="); + query.append(oa.idx()); + query.append(';'); + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Analyze.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Analyze.java index 35020836..a0dce749 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Analyze.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Analyze.java @@ -231,7 +231,7 @@ public class Analyze extends Batch { ++state[type][pending]; Pending n = pendingTemp.get(appr.getApprover()); if(n==null) { - pendingTemp.put(appr.getApprover(),new Pending(appr.getLast_notified())); + pendingTemp.put(appr.getApprover(),new Pending()); } else { n.inc(); } @@ -288,7 +288,7 @@ public class Analyze extends Batch { for(Entry<String, Pending> es : pendingApprs.entrySet()) { Pending p = es.getValue(); - if(p.earliest() == null || p.earliest().after(remind)) { + if(p.newApprovals() || p.earliest() == null || p.earliest().after(remind)) { p.row(approveCW,es.getKey()); } } diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Notify.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Notify.java index 0524c5cb..1c1f660c 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Notify.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/Notify.java @@ -20,38 +20,38 @@ */package org.onap.aaf.auth.batch.reports; import java.io.BufferedReader; - import java.io.File; - import java.io.FileReader; - import java.io.IOException; - import java.lang.reflect.Constructor; - import java.lang.reflect.InvocationTargetException; - import java.util.ArrayList; - import java.util.HashSet; - import java.util.List; - import java.util.Set; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; - import org.onap.aaf.auth.batch.Batch; - import org.onap.aaf.auth.batch.reports.bodies.NotifyBody; - import org.onap.aaf.auth.env.AuthzTrans; - import org.onap.aaf.auth.org.Mailer; - import org.onap.aaf.auth.org.Organization.Identity; - import org.onap.aaf.auth.org.OrganizationException; - import org.onap.aaf.cadi.Access; - import org.onap.aaf.cadi.CadiException; - import org.onap.aaf.cadi.client.Holder; - import org.onap.aaf.cadi.util.CSV; - import org.onap.aaf.misc.env.APIException; - import org.onap.aaf.misc.env.util.Chrono; +import org.onap.aaf.auth.batch.Batch; +import org.onap.aaf.auth.batch.reports.bodies.NotifyBody; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.Mailer; +import org.onap.aaf.auth.org.Organization.Identity; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.CadiException; +import org.onap.aaf.cadi.client.Holder; +import org.onap.aaf.cadi.util.CSV; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.util.Chrono; public class Notify extends Batch { private static final String HTML_CSS = "HTML_CSS"; private final Mailer mailer; private final String header; private final String footer; - private Set<File> notifyFile; + private final int maxEmails; + private final int indent; + private final boolean urgent; public final String guiURL; - private int maxEmails; - private int indent; public Notify(AuthzTrans trans) throws APIException, IOException, OrganizationException { super(trans.env()); @@ -59,9 +59,9 @@ String mailFrom = env.getProperty("MAIL_FROM"); String header_html = env.getProperty("HEADER_HTML"); String footer_html = env.getProperty("FOOTER_HTML"); - String maxEmails = env.getProperty("MAX_EMAIL"); + String str = env.getProperty("MAX_EMAIL"); guiURL = env.getProperty("GUI_URL"); - this.maxEmails = maxEmails==null?1:Integer.parseInt(maxEmails); + maxEmails = str==null||str.isEmpty()?Integer.MAX_VALUE:Integer.parseInt(str); if(mailerCls==null || mailFrom==null || guiURL==null || header_html==null || footer_html==null) { throw new APIException("Notify requires MAILER, MAILER_FROM, GUI_URL, HEADER_HTML and FOOTER_HTML properties"); } @@ -101,9 +101,12 @@ } else { indent = 6; //arbitrary } + } else { + indent = 6; } - + urgent = false; + sb.setLength(0); br = new BufferedReader(new FileReader(footer_html)); try { @@ -116,46 +119,45 @@ br.close(); } - // Class Load possible data - NotifyBody.load(env.access()); - - // Create Intermediate Output - File logDir = logDir(); - notifyFile = new HashSet<>(); - if(args().length>0) { - for(int i=0;i<args().length;++i) { - notifyFile.add(new File(logDir, args()[i])); - } - } else { - String fmt = "%s"+Chrono.dateOnlyStamp()+".csv"; - File file; - for(NotifyBody nb : NotifyBody.getAll()) { - file = new File(logDir,String.format(fmt, nb.name())); - if(file.exists()) { - trans.info().printf("Processing '%s' in %s",nb.type(),file.getCanonicalPath()); - notifyFile.add(file); - } else { - trans.info().printf("No Files found for %s",nb.name()); - } - } - } } + /* + * Note: We try to put things related to Notify as Main Class in Run, where we might have put in + * Constructor, so that we can have other Classes call just the "notify" method. + */ @Override protected void run(AuthzTrans trans) { - List<String> toList = new ArrayList<>(); - List<String> ccList = new ArrayList<>(); AuthzTrans noAvg = trans.env().newTransNoAvg(); - String subject = "Test Notify"; - boolean urgent = false; - - - final Notify notify = this; final Holder<List<String>> info = new Holder<>(null); final Set<String> errorSet = new HashSet<>(); try { + // Class Load possible data + NotifyBody.load(env.access()); + + + // Create Intermediate Output + File logDir = logDir(); + Set<File> notifyFile = new HashSet<>(); + if(args().length>0) { + for(int i=0;i<args().length;++i) { + notifyFile.add(new File(logDir, args()[i])); + } + } else { + String fmt = "%s"+Chrono.dateOnlyStamp()+".csv"; + File file; + for(NotifyBody nb : NotifyBody.getAll()) { + file = new File(logDir,String.format(fmt, nb.name())); + if(file.exists()) { + trans.info().printf("Processing '%s' in %s",nb.type(),file.getCanonicalPath()); + notifyFile.add(file); + } else { + trans.info().printf("No Files found for %s",nb.name()); + } + } + } + for(File f : notifyFile) { CSV csv = new CSV(env.access(),f); try { @@ -167,8 +169,7 @@ } if(info.get()==null) { throw new CadiException("First line of Feed MUST contain 'info' record"); - } - String key = row.get(0)+'|'+info.get().get(1); + } String key = row.get(0)+'|'+info.get().get(1); NotifyBody body = NotifyBody.get(key); if(body==null) { errorSet.add("No NotifyBody defined for " + key); @@ -185,78 +186,93 @@ // now create Notification for(NotifyBody nb : NotifyBody.getAll()) { - String run = nb.type()+nb.name(); - String test = dryRun?run:null; - ONE_EMAIL: - for(String id : nb.users()) { + notify(noAvg, nb); + } - toList.clear(); - ccList.clear(); - try { - Identity identity = trans.org().getIdentity(noAvg, id); - if(identity==null) { - trans.warn().printf("%s is invalid for this Organization. Skipping notification.",id); - } else { - if(!identity.isPerson()) { - identity = identity.responsibleTo(); - } - if(identity==null) { - trans.warn().printf("Responsible Identity %s is invalid for this Organization. Skipping notification.",id); - } else { - for(int i=1;i<=nb.escalation();++i) { - if(identity != null) { - if(i==1) { - toList.add(identity.email()); - List<String> dels = identity.delegate(); - if(dels!=null) { - for(String d : dels) { - toList.add(d); - } - } - } else { - Identity s = identity.responsibleTo(); - if(s==null) { - trans.error().printf("Identity %s has no %s", identity.fullID(), - identity.isPerson()?"supervisor":"sponsor"); - } else { - ccList.add(s.email()); - } - } + } catch (APIException | IOException e1) { + trans.error().log(e1); + } finally { + for(String s : errorSet) { + trans.audit().log(s); + } + } + } + + public int notify(AuthzTrans trans, NotifyBody nb) { + List<String> toList = new ArrayList<>(); + List<String> ccList = new ArrayList<>(); + + String run = nb.type()+nb.name(); + String test = dryRun?run:null; + String last = null; + + ONE_EMAIL: + for(String id : nb.users()) { + last = id; + toList.clear(); + ccList.clear(); + try { + Identity identity = trans.org().getIdentity(trans, id); + if(identity==null) { + trans.warn().printf("%s is invalid for this Organization. Skipping notification.",id); + } else { + if(!identity.isPerson()) { + identity = identity.responsibleTo(); + } + if(identity==null) { + trans.warn().printf("Responsible Identity %s is invalid for this Organization. Skipping notification.",id); + } else { + for(int i=1;i<=nb.escalation();++i) { + if(identity != null) { + if(i==1) { // self and Delegates + toList.add(identity.email()); + List<String> dels = identity.delegate(); + if(dels!=null) { + for(String d : dels) { + toList.add(d); } } - - StringBuilder content = new StringBuilder(); - content.append(String.format(header,version,Identity.mixedCase(identity.firstName()))); - - nb.body(noAvg, content, indent, notify, id); - content.append(footer); - - if(mailer.sendEmail(noAvg, test, toList, ccList, nb.subject(),content.toString(), urgent)) { - nb.inc(); + } else { + Identity s = identity.responsibleTo(); + if(s==null) { + trans.error().printf("Identity %s has no %s", identity.fullID(), + identity.isPerson()?"supervisor":"sponsor"); } else { - trans.error().log("Mailer failed to send Mail"); - } - if(maxEmails>0 && nb.count()>=maxEmails) { - break ONE_EMAIL; + ccList.add(s.email()); } } } - } catch (OrganizationException e) { - trans.error().log(e); } - } - trans.info().printf("Emailed %d for %s",nb.count(),run); - } + StringBuilder content = new StringBuilder(); + content.append(String.format(header,version,Identity.mixedCase(identity.firstName()))); - } finally { - for(String s : errorSet) { - trans.audit().log(s); + nb.body(trans, content, indent, this, id); + content.append(footer); + + if(mailer.sendEmail(trans, test, toList, ccList, nb.subject(),content.toString(), urgent)) { + nb.inc(); + } else { + trans.error().log("Mailer failed to send Mail"); + } + if(maxEmails>0 && nb.count()>=maxEmails) { + break ONE_EMAIL; + } + } + } + } catch (OrganizationException e) { + trans.error().log(e); } } + if(nb.count()<=1) { + trans.info().printf("Notified %s for %s",last,run); + } else { + trans.info().printf("Emailed %d for %s",nb.count(),run); + } + return nb.count(); } - @Override + @Override protected void _close(AuthzTrans trans) { } diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyBody.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyBody.java index 034286cf..bf20eb41 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyBody.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyBody.java @@ -195,16 +195,24 @@ public abstract class NotifyBody { } } - protected void println(StringBuilder sb, int indent, Object ... objs) { + protected void print(StringBuilder sb, int indent, Object ... objs) { for(int i=0;i<indent;++i) { sb.append(' '); } for(Object o : objs) { sb.append(o.toString()); } + } + + protected void println(StringBuilder sb, int indent, Object ... objs) { + print(sb,indent,objs); sb.append('\n'); } - + + protected void printf(StringBuilder sb, int indent, String fmt, Object ... objs) { + print(sb,indent,String.format(fmt, objs)); + } + protected String printCell(StringBuilder sb, int indent, String current, String prev) { if(current.equals(prev)) { println(sb,indent,DUPL); diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyCredBody.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyCredBody.java index deac3e41..94502d9f 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyCredBody.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyCredBody.java @@ -36,7 +36,8 @@ public abstract class NotifyCredBody extends NotifyBody { super(access,"cred",name); // Default - explanation = "The following Credentials are expiring on the dates shown. " + explanation = "The following Credentials that you are responsible for " + + "are expiring on the dates shown. " + "Failure to act before the expiration date will cause your App's " + "Authentications to fail." + "<h3>Instructions for 'Password':</h3><ul>" diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyPendingApprBody.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyPendingApprBody.java index 502464e9..df28503c 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyPendingApprBody.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/NotifyPendingApprBody.java @@ -27,64 +27,27 @@ import org.onap.aaf.auth.env.AuthzTrans; import org.onap.aaf.cadi.Access; public class NotifyPendingApprBody extends NotifyBody { - private final String explanation; public NotifyPendingApprBody(Access access) { super(access,"appr","PendingApproval"); - explanation = "The following Approvals are awaiting your action. "; } @Override public boolean body(AuthzTrans trans, StringBuilder sb, int indent, Notify n, String id) { - println(sb,indent,explanation); -/* println(sb,indent,"<table>"); - indent+=2; - println(sb,indent,"<tr>"); - indent+=2; - println(sb,indent,"<th>Fully Qualified ID</th>"); - println(sb,indent,"<th>Unique ID</th>"); - println(sb,indent,"<th>Type</th>"); - println(sb,indent,"<th>Expires</th>"); - println(sb,indent,"<th>Warnings</th>"); - indent-=2; - println(sb,indent,"</tr>"); - String theid, type, info, expires, warnings; - GregorianCalendar gc = new GregorianCalendar(); + boolean rv = false; for(List<String> row : rows.get(id)) { - theid=row.get(1); - switch(row.get(3)) { - case "1": - case "2": - type = "Password"; - break; - case "200": - type = "x509 (Certificate)"; - break; - default: - type = "Unknown, see AAF GUI"; - break; + String qty = row.get(2); + if("1".equals(qty)) { + printf(sb,indent,"You have an Approval in the AAF %s Environment awaiting your decision.\n",row.get(3)); + } else { + printf(sb,indent,"You have %s Approvals in the AAF %s Environment awaiting your decision.\n",qty,row.get(3)); } - theid = "<a href=\""+n.guiURL+"/creddetail?ns="+row.get(2)+"\">"+theid+"</a>"; - gc.setTimeInMillis(Long.parseLong(row.get(5))); - expires = Chrono.niceUTCStamp(gc); - info = row.get(6); - //TODO get Warnings - warnings = ""; - - println(sb,indent,"<tr>"); - indent+=2; - printCell(sb,indent,theid); - printCell(sb,indent,info); - printCell(sb,indent,type); - printCell(sb,indent,expires); - printCell(sb,indent,warnings); - indent-=2; - println(sb,indent,"</tr>"); + printf(sb,indent,"<br><br><b>ACTION:</b> <i>Click on</i> <a href=\"%s/approve\">AAF Approval Page</a>",n.guiURL); + rv = true; + break; // only one } - indent-=2; - println(sb,indent,"</table>"); - */ - return true; + + return rv; } @Override @@ -100,4 +63,14 @@ public class NotifyPendingApprBody extends NotifyBody { return String.format("AAF Pending Approval Notification (ENV: %s)",env); } + /* (non-Javadoc) + * @see org.onap.aaf.auth.batch.reports.bodies.NotifyBody#store(java.util.List) + */ + @Override + public void store(List<String> row) { + // Notify Pending is setup for 1 Notification at a time + super.rows.clear(); + super.store(row); + } + } diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/TwoMonthNotifyCredBody.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/TwoMonthNotifyCredBody.java new file mode 100644 index 00000000..eb52c6d0 --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/reports/bodies/TwoMonthNotifyCredBody.java @@ -0,0 +1,37 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.auth.batch.reports.bodies; + +import java.io.IOException; + +import org.onap.aaf.auth.batch.helpers.ExpireRange; +import org.onap.aaf.cadi.Access; + +public class TwoMonthNotifyCredBody extends NotifyCredBody { + public TwoMonthNotifyCredBody(Access access) throws IOException { + super(access, ExpireRange.TWO_MONTH); + } + + @Override + public String subject() { + return String.format("AAF Two Month Credential Notification (ENV: %s)",env); + } +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/temp/DataMigrateDublin.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/temp/DataMigrateDublin.java new file mode 100644 index 00000000..4851662b --- /dev/null +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/temp/DataMigrateDublin.java @@ -0,0 +1,215 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.auth.batch.temp; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.onap.aaf.auth.batch.Batch; +import org.onap.aaf.auth.batch.BatchPrincipal; +import org.onap.aaf.auth.batch.helpers.CQLBatch; +import org.onap.aaf.auth.batch.helpers.CQLBatchLoop; +import org.onap.aaf.auth.dao.cass.CredDAO; +import org.onap.aaf.auth.env.AuthzTrans; +import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.cadi.Hash; +import org.onap.aaf.cadi.configure.Factory; +import org.onap.aaf.misc.env.APIException; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; + +public class DataMigrateDublin extends Batch { + private final SecureRandom sr; + private final AuthzTrans noAvg; + + public DataMigrateDublin(AuthzTrans trans) throws APIException, IOException, OrganizationException { + super(trans.env()); + trans.info().log("Starting Connection Process"); + + noAvg = env.newTransNoAvg(); + noAvg.setUser(new BatchPrincipal("Migrate")); + + TimeTaken tt0 = trans.start("Cassandra Initialization", Env.SUB); + try { + TimeTaken tt = trans.start("Connect to Cluster", Env.REMOTE); + try { + session = cluster.connect(); + } finally { + tt.done(); + } + } finally { + tt0.done(); + } + + sr = new SecureRandom(); + } + + @Override + protected void run(AuthzTrans trans) { + /////////////////////////// + trans.info().log("Add UniqueTag to Passwords"); + + CQLBatchLoop cbl = new CQLBatchLoop(new CQLBatch(noAvg.info(),session), 50, dryRun); + try { + ResultSet rs = session.execute("SELECT id,type,expires,cred,tag FROM authz.cred"); + Iterator<Row> iter = rs.iterator(); + Row row; + int count = 0; + byte[] babytes = new byte[6]; + Map<String, List<CredInfo>> mlci = new TreeMap<>(); + Map<String, String> ba_tag = new TreeMap<>(); + while(iter.hasNext()) { + ++count; + row = iter.next(); + String tag = row.getString(4); + int type = row.getInt(1); + switch(type) { + case CredDAO.BASIC_AUTH: + case CredDAO.BASIC_AUTH_SHA256: + String key = row.getString(0) + '|' + type + '|' + Hash.toHex(row.getBytesUnsafe(3).array()); + String btag = ba_tag.get(key); + if(btag == null) { + if(tag==null || tag.isEmpty()) { + sr.nextBytes(babytes); + btag = Hash.toHexNo0x(babytes); + } else { + btag = tag; + } + ba_tag.put(key, btag); + } + + if(!btag.equals(tag)) { + cbl.preLoop(); + update(cbl,row,btag); + } + break; + case CredDAO.CERT_SHA256_RSA: + if(tag==null || tag.isEmpty()) { + String id = row.getString(0); + List<CredInfo> ld = mlci.get(id); + if(ld==null) { + ld = new ArrayList<>(); + mlci.put(id,ld); + } + ld.add(new CredInfo(id,row.getInt(1),row.getTimestamp(2))); + } + break; + } + } + cbl.flush(); + trans.info().printf("Processes %d cred records, updated %d records in %d batches.", count, cbl.total(), cbl.batches()); + count = 0; + + cbl.reset(); + + trans.info().log("Add Serial to X509 Creds"); + rs = session.execute("SELECT ca, id, x509 FROM authz.x509"); + iter = rs.iterator(); + while(iter.hasNext()) { + ++count; + row = iter.next(); + String ca = row.getString(0); + String id = row.getString(1); + List<CredInfo> list = mlci.get(id); + if(list!=null) { + ByteBuffer bb = row.getBytesUnsafe(2); + if(bb!=null) { + Collection<? extends Certificate> x509s = Factory.toX509Certificate(bb.array()); + for(Certificate c : x509s) { + X509Certificate xc = (X509Certificate)c; + for(CredInfo ci : list) { + if(xc.getNotAfter().equals(ci.expires)) { + cbl.preLoop(); + ci.update(cbl, ca + '|' + xc.getSerialNumber()); + break; + } + } + } + } + } + } + cbl.flush(); + trans.info().printf("Processed %d x509 records, updated %d records in %d batches.", count, cbl.total(), cbl.batches()); + count = 0; + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static class CredInfo { + public final String id; + public final int type; + public final Date expires; + + public CredInfo(String id, int type, Date expires) { + this.id = id; + this.type = type; + this.expires = expires; + } + + public void update(CQLBatchLoop cbl, String newtag) { + StringBuilder sb = cbl.inc(); + sb.append("UPDATE authz.cred SET tag='"); + sb.append(newtag); + sb.append("' WHERE id='"); + sb.append(id); + sb.append("' AND type="); + sb.append(type); + sb.append(" AND expires=dateof(maxtimeuuid("); + sb.append(expires.getTime()); + sb.append("));"); + } + } + + private void update(CQLBatchLoop cbl, Row row, String newtag) { + StringBuilder sb = cbl.inc(); + sb.append("UPDATE authz.cred SET tag='"); + sb.append(newtag); + sb.append("' WHERE id='"); + sb.append(row.getString(0)); + sb.append("' AND type="); + sb.append(row.getInt(1)); + sb.append(" AND expires=dateof(maxtimeuuid("); + Date lc = row.getTimestamp(2); + sb.append(lc.getTime()); + sb.append("));"); + } + + @Override + protected void _close(AuthzTrans trans) { + trans.info().log("End " + this.getClass().getSimpleName() + " processing" ); + session.close(); + } + +} diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Approvals.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Approvals.java index 2047098a..03c812ae 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Approvals.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Approvals.java @@ -38,15 +38,21 @@ import org.onap.aaf.auth.batch.approvalsets.ApprovalSet; import org.onap.aaf.auth.batch.approvalsets.Pending; import org.onap.aaf.auth.batch.approvalsets.URApprovalSet; import org.onap.aaf.auth.batch.helpers.BatchDataView; +import org.onap.aaf.auth.batch.helpers.CQLBatch; +import org.onap.aaf.auth.batch.helpers.CQLBatchLoop; +import org.onap.aaf.auth.batch.helpers.LastNotified; import org.onap.aaf.auth.batch.helpers.NS; import org.onap.aaf.auth.batch.helpers.Notification; +import org.onap.aaf.auth.batch.helpers.Notification.TYPE; import org.onap.aaf.auth.batch.helpers.Role; import org.onap.aaf.auth.batch.helpers.UserRole; +import org.onap.aaf.auth.batch.reports.Notify; import org.onap.aaf.auth.batch.reports.bodies.NotifyPendingApprBody; import org.onap.aaf.auth.dao.cass.UserRoleDAO; import org.onap.aaf.auth.env.AuthzTrans; import org.onap.aaf.auth.layer.Result; import org.onap.aaf.auth.org.OrganizationException; +import org.onap.aaf.cadi.Access; import org.onap.aaf.cadi.CadiException; import org.onap.aaf.cadi.client.Holder; import org.onap.aaf.cadi.util.CSV; @@ -56,15 +62,18 @@ import org.onap.aaf.misc.env.Trans; import org.onap.aaf.misc.env.util.Chrono; public class Approvals extends Batch { - private final AuthzTrans noAvg; + private final Access access; + private final AuthzTrans noAvg; private BatchDataView dataview; private List<CSV> csvList; private GregorianCalendar now; + private final Notify notify; public Approvals(AuthzTrans trans) throws APIException, IOException, OrganizationException { super(trans.env()); - + notify = new Notify(trans); + access = env.access(); noAvg = env.newTransNoAvg(); noAvg.setUser(new BatchPrincipal("batch:Approvals")); session = cluster.connect(); @@ -94,13 +103,13 @@ public class Approvals extends Batch { trans.error().printf("CSV File %s does not exist",f.getAbsolutePath()); } } - } @Override protected void run(AuthzTrans trans) { Map<String,Pending> mpending = new TreeMap<>(); Holder<Integer> count = new Holder<>(0); + final CQLBatchLoop cbl = new CQLBatchLoop(new CQLBatch(noAvg.info(),session),100,dryRun); for(CSV approveCSV : csvList) { TimeTaken tt = trans.start("Load Analyzed Reminders",Trans.SUB,approveCSV.name()); try { @@ -170,19 +179,36 @@ public class Approvals extends Batch { trans.info().printf("Processed %d UserRoles", count.get()); count.set(0); - NotifyPendingApprBody npab; + NotifyPendingApprBody npab = new NotifyPendingApprBody(access); + GregorianCalendar gc = new GregorianCalendar(); gc.add(GregorianCalendar.DAY_OF_MONTH, 7); Date oneWeek = gc.getTime(); + CSV.Saver rs = new CSV.Saver(); + + tt = trans.start("Obtain Last Notifications", Trans.SUB); + LastNotified lastN; + try { + lastN = new LastNotified(session); + lastN.add(mpending.keySet()); + } finally { + tt.done(); + } Pending p; tt = trans.start("Notify for Pending", Trans.SUB); try { for(Entry<String, Pending> es : mpending.entrySet()) { p = es.getValue(); - Date earliest = p.earliest(); - if(p.newApprovals() || earliest==null || earliest.before(oneWeek) ) { - System.out.println("update"); + Date dateLastNotified = lastN.lastNotified(es.getKey()); + if(p.newApprovals() || dateLastNotified==null || dateLastNotified.after(oneWeek) ) { + rs.row("appr", es.getKey(),p.qty(),batchEnv); + npab.store(rs.asList()); + if(notify.notify(noAvg, npab)>0) { + // Update + cbl.preLoop(); + update(cbl.inc(),es.getKey(),Notification.TYPE.OA); + } } } } finally { @@ -192,7 +218,16 @@ public class Approvals extends Batch { } } - @Override + private void update(StringBuilder sb, String user, TYPE oa) { + sb.append("UPDATE authz.notify SET last=dateof(now()) WHERE user='"); + sb.append(user); + sb.append("' AND type="); + sb.append(oa.idx()); + sb.append(';'); + + } + + @Override protected void _close(AuthzTrans trans) { if(session!=null) { session.close(); diff --git a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Remove.java b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Remove.java index a0fdcc50..7a30dc5f 100644 --- a/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Remove.java +++ b/auth/auth-batch/src/main/java/org/onap/aaf/auth/batch/update/Remove.java @@ -138,6 +138,8 @@ public class Remove extends Batch { if(!ur.get()) { ur.set(true); } + //TODO If deleted because Role is no longer there, double check... + UserRole.batchDelete(cbl.inc(),row); hdd.target=UserRoleDAO.TABLE; hdd.subject=UserRole.histSubject(row); |