1 /*******************************************************************************
2 * ============LICENSE_START==================================================
4 * * ===========================================================================
5 * * Copyright © 2017 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====================================================
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 ******************************************************************************/
25 package org.onap.dmaap.datarouter.node;
27 import com.att.eelf.configuration.EELFLogger;
28 import com.att.eelf.configuration.EELFManager;
31 import java.util.Arrays;
32 import java.util.HashSet;
33 import java.util.Hashtable;
34 import java.util.Vector;
37 * Processed configuration for this node.
39 * The NodeConfig represents a processed configuration from the Data Router provisioning server. Each time
40 * configuration data is received from the provisioning server, a new NodeConfig is created and the previous one
43 public class NodeConfig {
44 private static EELFLogger logger = EELFManager.getInstance().getLogger(NodeConfig.class);
46 * Raw configuration entry for a data router node
48 public static class ProvNode {
53 * Construct a node configuration entry.
55 * @param cname The cname of the node.
57 public ProvNode(String cname) {
62 * Get the cname of the node
64 public String getCName() {
70 * Raw configuration entry for a provisioning parameter
72 public static class ProvParam {
78 * Construct a provisioning parameter configuration entry.
80 * @param name The name of the parameter.
81 * @param value The value of the parameter.
83 public ProvParam(String name, String value) {
89 * Get the name of the parameter.
91 public String getName() {
96 * Get the value of the parameter.
98 public String getValue() {
104 * Raw configuration entry for a data feed.
106 public static class ProvFeed {
109 private String logdata;
110 private String status;
111 private String createdDate;
113 * AAF changes: TDP EPIC US# 307413
114 * Passing aafInstance from to identify legacy/AAF feeds
116 private String aafInstance;
119 * Construct a feed configuration entry.
121 * @param id The feed ID of the entry.
122 * @param logdata String for log entries about the entry.
123 * @param status The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or
124 * null if it is valid.
126 public ProvFeed(String id, String logdata, String status, String createdDate, String aafInstance) {
128 this.logdata = logdata;
129 this.status = status;
130 this.createdDate = createdDate;
131 this.aafInstance = aafInstance;
135 * Get the created date of the data feed.
137 public String getCreatedDate()
143 * Get the aafInstance of the data feed.
145 public String getAafInstance() {
150 * Get the feed id of the data feed.
152 public String getId() {
157 * Get the log data of the data feed.
159 public String getLogData() {
164 * Get the status of the data feed.
166 public String getStatus() {
172 * Raw configuration entry for a feed user.
174 public static class ProvFeedUser {
176 private String feedid;
178 private String credentials;
181 * Construct a feed user configuration entry
183 * @param feedid The feed id.
184 * @param user The user that will publish to the feed.
185 * @param credentials The Authorization header the user will use to publish.
187 public ProvFeedUser(String feedid, String user, String credentials) {
188 this.feedid = feedid;
190 this.credentials = credentials;
194 * Get the feed id of the feed user.
196 public String getFeedId() {
201 * Get the user for the feed user.
203 public String getUser() {
208 * Get the credentials for the feed user.
210 public String getCredentials() {
211 return (credentials);
216 * Raw configuration entry for a feed subnet
218 public static class ProvFeedSubnet {
220 private String feedid;
224 * Construct a feed subnet configuration entry
226 * @param feedid The feed ID
227 * @param cidr The CIDR allowed to publish to the feed.
229 public ProvFeedSubnet(String feedid, String cidr) {
230 this.feedid = feedid;
235 * Get the feed id of the feed subnet.
237 public String getFeedId() {
242 * Get the CIDR of the feed subnet.
244 public String getCidr() {
250 * Raw configuration entry for a subscription
252 public static class ProvSubscription {
254 private String subid;
255 private String feedid;
257 private String authuser;
258 private String credentials;
259 private boolean metaonly;
260 private boolean use100;
261 private boolean privilegedSubscriber;
262 private boolean followRedirect;
263 private boolean decompress;
266 * Construct a subscription configuration entry
268 * @param subid The subscription ID
269 * @param feedid The feed ID
270 * @param url The base delivery URL (not including the fileid)
271 * @param authuser The user in the credentials used to deliver
272 * @param credentials The credentials used to authenticate to the delivery URL exactly as they go in the
273 * Authorization header.
274 * @param metaonly Is this a meta data only subscription?
275 * @param use100 Should we send Expect: 100-continue?
276 * @param privilegedSubscriber Can we wait to receive a delete file call before deleting file
277 * @param followRedirect Is follow redirect of destination enabled?
278 * @param decompress To see if they want their information compressed or decompressed
280 public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials, boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean followRedirect, boolean decompress) {
282 this.feedid = feedid;
284 this.authuser = authuser;
285 this.credentials = credentials;
286 this.metaonly = metaonly;
287 this.use100 = use100;
288 this.privilegedSubscriber = privilegedSubscriber;
289 this.followRedirect = followRedirect;
290 this.decompress = decompress;
294 * Get the subscription ID
296 public String getSubId() {
303 public String getFeedId() {
308 * Get the delivery URL
310 public String getURL() {
317 public String getAuthUser() {
322 * Get the delivery credentials
324 public String getCredentials() {
325 return (credentials);
329 * Is this a meta data only subscription?
331 public boolean isMetaDataOnly() {
336 * Should we send Expect: 100-continue?
338 public boolean isUsing100() {
343 * Can we wait to receive a delete file call before deleting file
345 public boolean isPrivilegedSubscriber() {
346 return (privilegedSubscriber);
350 * Should i decompress the file before sending it on
352 public boolean isDecompress() {
357 * New field is added - FOLLOW_REDIRECTS feature iTrack:DATARTR-17 - 1706
358 * Get the followRedirect of this destination
360 boolean getFollowRedirect() {
361 return(followRedirect);
366 * Raw configuration entry for controlled ingress to the data router node
368 public static class ProvForceIngress {
370 private String feedid;
371 private String subnet;
373 private String[] nodes;
376 * Construct a forced ingress configuration entry
378 * @param feedid The feed ID that this entry applies to
379 * @param subnet The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all
380 * publisher IP addresses
381 * @param user The publishing user this entry applies to or "" if it applies to all publishing users.
382 * @param nodes The array of FQDNs of the data router nodes to redirect publication attempts to.
384 public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {
385 this.feedid = feedid;
386 this.subnet = subnet;
390 this.nodes = new String[0];
392 this.nodes = Arrays.copyOf(nodes, nodes.length);
399 public String getFeedId() {
406 public String getSubnet() {
413 public String getUser() {
420 public String[] getNodes() {
426 * Raw configuration entry for controlled egress from the data router
428 public static class ProvForceEgress {
430 private String subid;
434 * Construct a forced egress configuration entry
436 * @param subid The subscription ID the subscription with forced egress
437 * @param node The node handling deliveries for this subscription
439 public ProvForceEgress(String subid, String node) {
445 * Get the subscription ID
447 public String getSubId() {
454 public String getNode() {
460 * Raw configuration entry for routing within the data router network
462 public static class ProvHop {
469 * A human readable description of this entry
471 public String toString() {
472 return ("Hop " + from + "->" + to + " via " + via);
476 * Construct a hop entry
478 * @param from The FQDN of the node with the data to be delivered
479 * @param to The FQDN of the node that will deliver to the subscriber
480 * @param via The FQDN of the node where the from node should send the data
482 public ProvHop(String from, String to, String via) {
491 public String getFrom() {
498 public String getTo() {
503 * Get the next intermediate node
505 public String getVia() {
510 private static class Redirection {
517 private static class Feed {
521 SubnetMatcher[] subnets;
522 Hashtable<String, String> authusers = new Hashtable<String, String>();
523 Redirection[] redirections;
529 private Hashtable<String, String> params = new Hashtable<>();
530 private Hashtable<String, Feed> feeds = new Hashtable<>();
531 private Hashtable<String, DestInfo> nodeinfo = new Hashtable<>();
532 private Hashtable<String, DestInfo> subinfo = new Hashtable<>();
533 private Hashtable<String, IsFrom> nodes = new Hashtable<>();
534 private Hashtable<String, ProvSubscription> provSubscriptions = new Hashtable<>();
535 private String myname;
536 private String myauth;
537 private DestInfo[] alldests;
541 * Process the raw provisioning data to configure this node
543 * @param pd The parsed provisioning data
544 * @param myname My name as seen by external systems
545 * @param spooldir The directory where temporary files live
546 * @param port The port number for URLs
547 * @param nodeauthkey The keying string used to generate node authentication credentials
549 public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {
550 this.myname = myname;
551 for (ProvParam p : pd.getParams()) {
552 params.put(p.getName(), p.getValue());
554 Vector<DestInfo> destInfos = new Vector<>();
555 myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);
556 for (ProvNode pn : pd.getNodes()) {
557 String cName = pn.getCName();
558 if (nodeinfo.get(cName) != null) {
561 String auth = NodeUtils.getNodeAuthHdr(cName, nodeauthkey);
562 DestInfo di = new DestInfo("n:" + cName, spooldir + "/n/" + cName, null, "n2n-" + cName,
563 "https://" + cName + ":" + port + "/internal/publish", cName, myauth, false, true, false, false, false);
564 (new File(di.getSpool())).mkdirs();
566 nodeinfo.put(cName, di);
567 nodes.put(auth, new IsFrom(cName));
569 PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[0]), pd.getHops());
570 Hashtable<String, Vector<Redirection>> rdtab = new Hashtable<>();
571 for (ProvForceIngress pfi : pd.getForceIngress()) {
572 Vector<Redirection> v = rdtab.get(pfi.getFeedId());
575 rdtab.put(pfi.getFeedId(), v);
577 Redirection r = new Redirection();
578 if (pfi.getSubnet() != null) {
579 r.snm = new SubnetMatcher(pfi.getSubnet());
581 r.user = pfi.getUser();
582 r.nodes = pfi.getNodes();
585 Hashtable<String, Hashtable<String, String>> pfutab = new Hashtable<>();
586 for (ProvFeedUser pfu : pd.getFeedUsers()) {
587 Hashtable<String, String> t = pfutab.get(pfu.getFeedId());
589 t = new Hashtable<>();
590 pfutab.put(pfu.getFeedId(), t);
592 t.put(pfu.getCredentials(), pfu.getUser());
594 Hashtable<String, String> egrtab = new Hashtable<>();
595 for (ProvForceEgress pfe : pd.getForceEgress()) {
596 if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {
599 egrtab.put(pfe.getSubId(), pfe.getNode());
601 Hashtable<String, Vector<SubnetMatcher>> pfstab = new Hashtable<>();
602 for (ProvFeedSubnet pfs : pd.getFeedSubnets()) {
603 Vector<SubnetMatcher> v = pfstab.get(pfs.getFeedId());
606 pfstab.put(pfs.getFeedId(), v);
608 v.add(new SubnetMatcher(pfs.getCidr()));
610 Hashtable<String, StringBuffer> feedTargets = new Hashtable<>();
611 HashSet<String> allfeeds = new HashSet<>();
612 for (ProvFeed pfx : pd.getFeeds()) {
613 if (pfx.getStatus() == null) {
614 allfeeds.add(pfx.getId());
617 for (ProvSubscription provSubscription : pd.getSubscriptions()) {
618 String subId = provSubscription.getSubId();
619 String feedId = provSubscription.getFeedId();
620 if (!allfeeds.contains(feedId)) {
623 if (subinfo.get(subId) != null) {
628 sididx = Integer.parseInt(subId);
629 sididx -= sididx % 100;
630 } catch (Exception e) {
631 logger.error("NODE0517 Exception NodeConfig: "+e);
633 String subscriptionDirectory = sididx + "/" + subId;
634 DestInfo destinationInfo = new DestInfo("s:" + subId,
635 spooldir + "/s/" + subscriptionDirectory, provSubscription);
636 (new File(destinationInfo.getSpool())).mkdirs();
637 destInfos.add(destinationInfo);
638 provSubscriptions.put(subId, provSubscription);
639 subinfo.put(subId, destinationInfo);
640 String egr = egrtab.get(subId);
642 subId = pf.getPath(egr) + subId;
644 StringBuffer sb = feedTargets.get(feedId);
646 sb = new StringBuffer();
647 feedTargets.put(feedId, sb);
649 sb.append(' ').append(subId);
651 alldests = destInfos.toArray(new DestInfo[0]);
652 for (ProvFeed pfx : pd.getFeeds()) {
653 String fid = pfx.getId();
654 Feed f = feeds.get(fid);
660 f.createdDate = pfx.getCreatedDate();
661 f.loginfo = pfx.getLogData();
662 f.status = pfx.getStatus();
664 * AAF changes: TDP EPIC US# 307413
665 * Passing aafInstance from ProvFeed to identify legacy/AAF feeds
667 f.aafInstance = pfx.getAafInstance();
668 Vector<SubnetMatcher> v1 = pfstab.get(fid);
670 f.subnets = new SubnetMatcher[0];
672 f.subnets = v1.toArray(new SubnetMatcher[0]);
674 Hashtable<String, String> h1 = pfutab.get(fid);
676 h1 = new Hashtable<String, String>();
679 Vector<Redirection> v2 = rdtab.get(fid);
681 f.redirections = new Redirection[0];
683 f.redirections = v2.toArray(new Redirection[0]);
685 StringBuffer sb = feedTargets.get(fid);
687 f.targets = new Target[0];
689 f.targets = parseRouting(sb.toString());
695 * Parse a target string into an array of targets
697 * @param routing Target string
698 * @return Array of targets.
700 public Target[] parseRouting(String routing) {
701 routing = routing.trim();
702 if ("".equals(routing)) {
703 return (new Target[0]);
705 String[] xx = routing.split("\\s+");
706 Hashtable<String, Target> tmap = new Hashtable<String, Target>();
707 HashSet<String> subset = new HashSet<String>();
708 Vector<Target> tv = new Vector<Target>();
709 Target[] ret = new Target[xx.length];
710 for (int i = 0; i < xx.length; i++) {
712 int j = t.indexOf('/');
714 DestInfo di = subinfo.get(t);
716 tv.add(new Target(null, t));
718 if (!subset.contains(t)) {
720 tv.add(new Target(di, null));
724 String node = t.substring(0, j);
725 String rtg = t.substring(j + 1);
726 DestInfo di = nodeinfo.get(node);
728 tv.add(new Target(null, t));
730 Target tt = tmap.get(node);
732 tt = new Target(di, rtg);
741 return (tv.toArray(new Target[0]));
745 * Check whether this is a valid node-to-node transfer
747 * @param credentials Credentials offered by the supposed node
748 * @param ip IP address the request came from
750 public boolean isAnotherNode(String credentials, String ip) {
751 IsFrom n = nodes.get(credentials);
752 return (n != null && n.isFrom(ip));
756 * Check whether publication is allowed.
758 * @param feedid The ID of the feed being requested.
759 * @param credentials The offered credentials
760 * @param ip The requesting IP address
762 public String isPublishPermitted(String feedid, String credentials, String ip) {
763 Feed f = feeds.get(feedid);
764 String nf = "Feed does not exist";
771 String user = f.authusers.get(credentials);
773 return ("Publisher not permitted for this feed");
775 if (f.subnets.length == 0) {
778 byte[] addr = NodeUtils.getInetAddress(ip);
779 for (SubnetMatcher snm : f.subnets) {
780 if (snm.matches(addr)) {
784 return ("Publisher not permitted for this feed");
788 * Check whether delete file is allowed.
790 * @param subId The ID of the subscription being requested.
792 public boolean isDeletePermitted(String subId) {
793 ProvSubscription provSubscription = provSubscriptions.get(subId);
794 return provSubscription.isPrivilegedSubscriber();
798 * Check whether publication is allowed for AAF Feed.
799 * @param feedid The ID of the feed being requested.
800 * @param ip The requesting IP address
802 public String isPublishPermitted(String feedid, String ip) {
803 Feed f = feeds.get(feedid);
804 String nf = "Feed does not exist";
811 if (f.subnets.length == 0) {
814 byte[] addr = NodeUtils.getInetAddress(ip);
815 for (SubnetMatcher snm: f.subnets) {
816 if (snm.matches(addr)) {
820 return("Publisher not permitted for this feed");
824 * Get authenticated user
826 public String getAuthUser(String feedid, String credentials) {
827 return (feeds.get(feedid).authusers.get(credentials));
831 * AAF changes: TDP EPIC US# 307413
832 * Check AAF_instance for feed ID
833 * @param feedid The ID of the feed specified
835 public String getAafInstance(String feedid) {
836 Feed f = feeds.get(feedid);
837 return f.aafInstance;
841 * Check if the request should be redirected to a different ingress node
843 public String getIngressNode(String feedid, String user, String ip) {
844 Feed f = feeds.get(feedid);
845 if (f.redirections.length == 0) {
848 byte[] addr = NodeUtils.getInetAddress(ip);
849 for (Redirection r : f.redirections) {
850 if (r.user != null && !user.equals(r.user)) {
853 if (r.snm != null && !r.snm.matches(addr)) {
856 for (String n : r.nodes) {
857 if (myname.equals(n)) {
861 if (r.nodes.length == 0) {
864 return (r.nodes[rrcntr++ % r.nodes.length]);
870 * Get a provisioned configuration parameter
872 public String getProvParam(String name) {
873 return (params.get(name));
877 * Get all the DestInfos
879 public DestInfo[] getAllDests() {
884 * Get the targets for a feed
886 * @param feedid The feed ID
887 * @return The targets this feed should be delivered to
889 public Target[] getTargets(String feedid) {
890 if (feedid == null) {
891 return (new Target[0]);
893 Feed f = feeds.get(feedid);
895 return (new Target[0]);
901 * Get the creation date for a feed
902 * @param feedid The feed ID
903 * @return the timestamp of creation date of feed id passed
905 public String getCreatedDate(String feedid) {
906 Feed f = feeds.get(feedid);
907 return(f.createdDate);
911 * Get the feed ID for a subscription
913 * @param subid The subscription ID
914 * @return The feed ID
916 public String getFeedId(String subid) {
917 DestInfo di = subinfo.get(subid);
921 return (di.getLogData());
925 * Get the spool directory for a subscription
927 * @param subid The subscription ID
928 * @return The spool directory
930 public String getSpoolDir(String subid) {
931 DestInfo di = subinfo.get(subid);
935 return (di.getSpool());
939 * Get the Authorization value this node uses
941 * @return The Authorization header value for this node
943 public String getMyAuth() {