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.DestInfoBuilder().setName("n:" + cName).setSpool(spooldir + "/n/" + cName).setSubid(null)
563 .setLogdata("n2n-" + cName).setUrl("https://" + cName + ":" + port + "/internal/publish")
564 .setAuthuser(cName).setAuthentication(myauth).setMetaonly(false).setUse100(true)
565 .setPrivilegedSubscriber(false).setFollowRedirects(false).setDecompress(false).createDestInfo();
566 (new File(di.getSpool())).mkdirs();
568 nodeinfo.put(cName, di);
569 nodes.put(auth, new IsFrom(cName));
571 PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[0]), pd.getHops());
572 Hashtable<String, Vector<Redirection>> rdtab = new Hashtable<>();
573 for (ProvForceIngress pfi : pd.getForceIngress()) {
574 Vector<Redirection> v = rdtab.get(pfi.getFeedId());
577 rdtab.put(pfi.getFeedId(), v);
579 Redirection r = new Redirection();
580 if (pfi.getSubnet() != null) {
581 r.snm = new SubnetMatcher(pfi.getSubnet());
583 r.user = pfi.getUser();
584 r.nodes = pfi.getNodes();
587 Hashtable<String, Hashtable<String, String>> pfutab = new Hashtable<>();
588 for (ProvFeedUser pfu : pd.getFeedUsers()) {
589 Hashtable<String, String> t = pfutab.get(pfu.getFeedId());
591 t = new Hashtable<>();
592 pfutab.put(pfu.getFeedId(), t);
594 t.put(pfu.getCredentials(), pfu.getUser());
596 Hashtable<String, String> egrtab = new Hashtable<>();
597 for (ProvForceEgress pfe : pd.getForceEgress()) {
598 if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {
601 egrtab.put(pfe.getSubId(), pfe.getNode());
603 Hashtable<String, Vector<SubnetMatcher>> pfstab = new Hashtable<>();
604 for (ProvFeedSubnet pfs : pd.getFeedSubnets()) {
605 Vector<SubnetMatcher> v = pfstab.get(pfs.getFeedId());
608 pfstab.put(pfs.getFeedId(), v);
610 v.add(new SubnetMatcher(pfs.getCidr()));
612 Hashtable<String, StringBuffer> feedTargets = new Hashtable<>();
613 HashSet<String> allfeeds = new HashSet<>();
614 for (ProvFeed pfx : pd.getFeeds()) {
615 if (pfx.getStatus() == null) {
616 allfeeds.add(pfx.getId());
619 for (ProvSubscription provSubscription : pd.getSubscriptions()) {
620 String subId = provSubscription.getSubId();
621 String feedId = provSubscription.getFeedId();
622 if (!allfeeds.contains(feedId)) {
625 if (subinfo.get(subId) != null) {
630 sididx = Integer.parseInt(subId);
631 sididx -= sididx % 100;
632 } catch (Exception e) {
633 logger.error("NODE0517 Exception NodeConfig: "+e);
635 String subscriptionDirectory = sididx + "/" + subId;
636 DestInfo destinationInfo = new DestInfo("s:" + subId,
637 spooldir + "/s/" + subscriptionDirectory, provSubscription);
638 (new File(destinationInfo.getSpool())).mkdirs();
639 destInfos.add(destinationInfo);
640 provSubscriptions.put(subId, provSubscription);
641 subinfo.put(subId, destinationInfo);
642 String egr = egrtab.get(subId);
644 subId = pf.getPath(egr) + subId;
646 StringBuffer sb = feedTargets.get(feedId);
648 sb = new StringBuffer();
649 feedTargets.put(feedId, sb);
651 sb.append(' ').append(subId);
653 alldests = destInfos.toArray(new DestInfo[0]);
654 for (ProvFeed pfx : pd.getFeeds()) {
655 String fid = pfx.getId();
656 Feed f = feeds.get(fid);
662 f.createdDate = pfx.getCreatedDate();
663 f.loginfo = pfx.getLogData();
664 f.status = pfx.getStatus();
666 * AAF changes: TDP EPIC US# 307413
667 * Passing aafInstance from ProvFeed to identify legacy/AAF feeds
669 f.aafInstance = pfx.getAafInstance();
670 Vector<SubnetMatcher> v1 = pfstab.get(fid);
672 f.subnets = new SubnetMatcher[0];
674 f.subnets = v1.toArray(new SubnetMatcher[0]);
676 Hashtable<String, String> h1 = pfutab.get(fid);
678 h1 = new Hashtable<String, String>();
681 Vector<Redirection> v2 = rdtab.get(fid);
683 f.redirections = new Redirection[0];
685 f.redirections = v2.toArray(new Redirection[0]);
687 StringBuffer sb = feedTargets.get(fid);
689 f.targets = new Target[0];
691 f.targets = parseRouting(sb.toString());
697 * Parse a target string into an array of targets
699 * @param routing Target string
700 * @return Array of targets.
702 public Target[] parseRouting(String routing) {
703 routing = routing.trim();
704 if ("".equals(routing)) {
705 return (new Target[0]);
707 String[] xx = routing.split("\\s+");
708 Hashtable<String, Target> tmap = new Hashtable<String, Target>();
709 HashSet<String> subset = new HashSet<String>();
710 Vector<Target> tv = new Vector<Target>();
711 Target[] ret = new Target[xx.length];
712 for (int i = 0; i < xx.length; i++) {
714 int j = t.indexOf('/');
716 DestInfo di = subinfo.get(t);
718 tv.add(new Target(null, t));
720 if (!subset.contains(t)) {
722 tv.add(new Target(di, null));
726 String node = t.substring(0, j);
727 String rtg = t.substring(j + 1);
728 DestInfo di = nodeinfo.get(node);
730 tv.add(new Target(null, t));
732 Target tt = tmap.get(node);
734 tt = new Target(di, rtg);
743 return (tv.toArray(new Target[0]));
747 * Check whether this is a valid node-to-node transfer
749 * @param credentials Credentials offered by the supposed node
750 * @param ip IP address the request came from
752 public boolean isAnotherNode(String credentials, String ip) {
753 IsFrom n = nodes.get(credentials);
754 return (n != null && n.isFrom(ip));
758 * Check whether publication is allowed.
760 * @param feedid The ID of the feed being requested.
761 * @param credentials The offered credentials
762 * @param ip The requesting IP address
764 public String isPublishPermitted(String feedid, String credentials, String ip) {
765 Feed f = feeds.get(feedid);
766 String nf = "Feed does not exist";
773 String user = f.authusers.get(credentials);
775 return ("Publisher not permitted for this feed");
777 if (f.subnets.length == 0) {
780 byte[] addr = NodeUtils.getInetAddress(ip);
781 for (SubnetMatcher snm : f.subnets) {
782 if (snm.matches(addr)) {
786 return ("Publisher not permitted for this feed");
790 * Check whether delete file is allowed.
792 * @param subId The ID of the subscription being requested.
794 public boolean isDeletePermitted(String subId) {
795 ProvSubscription provSubscription = provSubscriptions.get(subId);
796 return provSubscription.isPrivilegedSubscriber();
800 * Check whether publication is allowed for AAF Feed.
801 * @param feedid The ID of the feed being requested.
802 * @param ip The requesting IP address
804 public String isPublishPermitted(String feedid, String ip) {
805 Feed f = feeds.get(feedid);
806 String nf = "Feed does not exist";
813 if (f.subnets.length == 0) {
816 byte[] addr = NodeUtils.getInetAddress(ip);
817 for (SubnetMatcher snm: f.subnets) {
818 if (snm.matches(addr)) {
822 return("Publisher not permitted for this feed");
826 * Get authenticated user
828 public String getAuthUser(String feedid, String credentials) {
829 return (feeds.get(feedid).authusers.get(credentials));
833 * AAF changes: TDP EPIC US# 307413
834 * Check AAF_instance for feed ID
835 * @param feedid The ID of the feed specified
837 public String getAafInstance(String feedid) {
838 Feed f = feeds.get(feedid);
839 return f.aafInstance;
843 * Check if the request should be redirected to a different ingress node
845 public String getIngressNode(String feedid, String user, String ip) {
846 Feed f = feeds.get(feedid);
847 if (f.redirections.length == 0) {
850 byte[] addr = NodeUtils.getInetAddress(ip);
851 for (Redirection r : f.redirections) {
852 if (r.user != null && !user.equals(r.user)) {
855 if (r.snm != null && !r.snm.matches(addr)) {
858 for (String n : r.nodes) {
859 if (myname.equals(n)) {
863 if (r.nodes.length == 0) {
866 return (r.nodes[rrcntr++ % r.nodes.length]);
872 * Get a provisioned configuration parameter
874 public String getProvParam(String name) {
875 return (params.get(name));
879 * Get all the DestInfos
881 public DestInfo[] getAllDests() {
886 * Get the targets for a feed
888 * @param feedid The feed ID
889 * @return The targets this feed should be delivered to
891 public Target[] getTargets(String feedid) {
892 if (feedid == null) {
893 return (new Target[0]);
895 Feed f = feeds.get(feedid);
897 return (new Target[0]);
903 * Get the creation date for a feed
904 * @param feedid The feed ID
905 * @return the timestamp of creation date of feed id passed
907 public String getCreatedDate(String feedid) {
908 Feed f = feeds.get(feedid);
909 return(f.createdDate);
913 * Get the feed ID for a subscription
915 * @param subid The subscription ID
916 * @return The feed ID
918 public String getFeedId(String subid) {
919 DestInfo di = subinfo.get(subid);
923 return (di.getLogData());
927 * Get the spool directory for a subscription
929 * @param subid The subscription ID
930 * @return The spool directory
932 public String getSpoolDir(String subid) {
933 DestInfo di = subinfo.get(subid);
937 return (di.getSpool());
941 * Get the Authorization value this node uses
943 * @return The Authorization header value for this node
945 public String getMyAuth() {