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;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.HashMap;
33 import java.util.HashSet;
36 * Processed configuration for this node.
38 * <p>The NodeConfig represents a processed configuration from the Data Router provisioning server. Each time
39 * configuration data is received from the provisioning server, a new NodeConfig is created and the previous one
42 public class NodeConfig {
44 private static final String PUBLISHER_NOT_PERMITTED = "Publisher not permitted for this feed";
45 private static EELFLogger logger = EELFManager.getInstance().getLogger(NodeConfig.class);
46 private HashMap<String, String> params = new HashMap<>();
47 private HashMap<String, Feed> feeds = new HashMap<>();
48 private HashMap<String, DestInfo> nodeinfo = new HashMap<>();
49 private HashMap<String, DestInfo> subinfo = new HashMap<>();
50 private HashMap<String, IsFrom> nodes = new HashMap<>();
51 private HashMap<String, ProvSubscription> provSubscriptions = new HashMap<>();
52 private String myname;
53 private String myauth;
54 private DestInfo[] alldests;
58 * Process the raw provisioning data to configure this node.
60 * @param pd The parsed provisioning data
61 * @param myname My name as seen by external systems
62 * @param spooldir The directory where temporary files live
63 * @param port The port number for URLs
64 * @param nodeauthkey The keying string used to generate node authentication credentials
66 public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {
68 for (ProvParam p : pd.getParams()) {
69 params.put(p.getName(), p.getValue());
71 ArrayList<DestInfo> destInfos = new ArrayList<>();
72 myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);
73 for (ProvNode pn : pd.getNodes()) {
74 String commonName = pn.getCName();
75 if (nodeinfo.get(commonName) != null) {
78 DestInfo di = new DestInfoBuilder().setName("n:" + commonName).setSpool(spooldir + "/n/" + commonName)
80 .setLogdata("n2n-" + commonName).setUrl("https://" + commonName + ":" + port + "/internal/publish")
81 .setAuthuser(commonName).setAuthentication(myauth).setMetaonly(false).setUse100(true)
82 .setPrivilegedSubscriber(false).setFollowRedirects(false).setDecompress(false).createDestInfo();
83 (new File(di.getSpool())).mkdirs();
84 String auth = NodeUtils.getNodeAuthHdr(commonName, nodeauthkey);
86 nodeinfo.put(commonName, di);
87 nodes.put(auth, new IsFrom(commonName));
89 PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[0]), pd.getHops());
90 HashMap<String, ArrayList<Redirection>> rdtab = new HashMap<>();
91 for (ProvForceIngress pfi : pd.getForceIngress()) {
92 ArrayList<Redirection> v = rdtab.get(pfi.getFeedId());
94 v = new ArrayList<>();
95 rdtab.put(pfi.getFeedId(), v);
97 Redirection r = new Redirection();
98 if (pfi.getSubnet() != null) {
99 r.snm = new SubnetMatcher(pfi.getSubnet());
101 r.user = pfi.getUser();
102 r.nodes = pfi.getNodes();
105 HashMap<String, HashMap<String, String>> pfutab = new HashMap<>();
106 for (ProvFeedUser pfu : pd.getFeedUsers()) {
107 HashMap<String, String> t = pfutab.get(pfu.getFeedId());
110 pfutab.put(pfu.getFeedId(), t);
112 t.put(pfu.getCredentials(), pfu.getUser());
114 HashMap<String, String> egrtab = new HashMap<>();
115 for (ProvForceEgress pfe : pd.getForceEgress()) {
116 if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {
119 egrtab.put(pfe.getSubId(), pfe.getNode());
121 HashMap<String, ArrayList<SubnetMatcher>> pfstab = new HashMap<>();
122 for (ProvFeedSubnet pfs : pd.getFeedSubnets()) {
123 ArrayList<SubnetMatcher> v = pfstab.get(pfs.getFeedId());
125 v = new ArrayList<>();
126 pfstab.put(pfs.getFeedId(), v);
128 v.add(new SubnetMatcher(pfs.getCidr()));
130 HashMap<String, StringBuilder> feedTargets = new HashMap<>();
131 HashSet<String> allfeeds = new HashSet<>();
132 for (ProvFeed pfx : pd.getFeeds()) {
133 if (pfx.getStatus() == null) {
134 allfeeds.add(pfx.getId());
137 for (ProvSubscription provSubscription : pd.getSubscriptions()) {
138 String subId = provSubscription.getSubId();
139 String feedId = provSubscription.getFeedId();
140 if (isFeedOrSubKnown(allfeeds, subId, feedId)) {
145 sididx = Integer.parseInt(subId);
146 sididx -= sididx % 100;
147 } catch (Exception e) {
148 logger.error("NODE0517 Exception NodeConfig: " + e);
150 String subscriptionDirectory = sididx + "/" + subId;
151 DestInfo destinationInfo = new DestInfo("s:" + subId,
152 spooldir + "/s/" + subscriptionDirectory, provSubscription);
153 (new File(destinationInfo.getSpool())).mkdirs();
154 destInfos.add(destinationInfo);
155 provSubscriptions.put(subId, provSubscription);
156 subinfo.put(subId, destinationInfo);
157 String egr = egrtab.get(subId);
159 subId = pf.getPath(egr) + subId;
161 StringBuilder sb = feedTargets.get(feedId);
163 sb = new StringBuilder();
164 feedTargets.put(feedId, sb);
166 sb.append(' ').append(subId);
168 alldests = destInfos.toArray(new DestInfo[0]);
169 for (ProvFeed pfx : pd.getFeeds()) {
170 String fid = pfx.getId();
171 Feed f = feeds.get(fid);
177 f.createdDate = pfx.getCreatedDate();
178 f.loginfo = pfx.getLogData();
179 f.status = pfx.getStatus();
181 * AAF changes: TDP EPIC US# 307413
182 * Passing aafInstance from ProvFeed to identify legacy/AAF feeds
184 f.aafInstance = pfx.getAafInstance();
185 ArrayList<SubnetMatcher> v1 = pfstab.get(fid);
187 f.subnets = new SubnetMatcher[0];
189 f.subnets = v1.toArray(new SubnetMatcher[0]);
191 HashMap<String, String> h1 = pfutab.get(fid);
196 ArrayList<Redirection> v2 = rdtab.get(fid);
198 f.redirections = new Redirection[0];
200 f.redirections = v2.toArray(new Redirection[0]);
202 StringBuilder sb = feedTargets.get(fid);
204 f.targets = new Target[0];
206 f.targets = parseRouting(sb.toString());
212 * Parse a target string into an array of targets
214 * @param routing Target string
215 * @return Array of targets.
217 public Target[] parseRouting(String routing) {
218 routing = routing.trim();
219 if ("".equals(routing)) {
220 return (new Target[0]);
222 String[] xx = routing.split("\\s+");
223 HashMap<String, Target> tmap = new HashMap<>();
224 HashSet<String> subset = new HashSet<>();
225 ArrayList<Target> tv = new ArrayList<>();
226 for (int i = 0; i < xx.length; i++) {
228 int j = t.indexOf('/');
230 addTarget(subset, tv, t);
232 addTargetWithRouting(tmap, tv, t, j);
235 return (tv.toArray(new Target[0]));
239 * Check whether this is a valid node-to-node transfer
241 * @param credentials Credentials offered by the supposed node
242 * @param ip IP address the request came from
244 public boolean isAnotherNode(String credentials, String ip) {
245 IsFrom n = nodes.get(credentials);
246 return (n != null && n.isFrom(ip));
250 * Check whether publication is allowed.
252 * @param feedid The ID of the feed being requested.
253 * @param credentials The offered credentials
254 * @param ip The requesting IP address
256 public String isPublishPermitted(String feedid, String credentials, String ip) {
257 Feed f = feeds.get(feedid);
258 String nf = "Feed does not exist";
265 String user = f.authusers.get(credentials);
267 return (PUBLISHER_NOT_PERMITTED);
269 if (f.subnets.length == 0) {
272 byte[] addr = NodeUtils.getInetAddress(ip);
273 for (SubnetMatcher snm : f.subnets) {
274 if (snm.matches(addr)) {
278 return (PUBLISHER_NOT_PERMITTED);
282 * Check whether delete file is allowed.
284 * @param subId The ID of the subscription being requested.
286 public boolean isDeletePermitted(String subId) {
287 ProvSubscription provSubscription = provSubscriptions.get(subId);
288 return provSubscription.isPrivilegedSubscriber();
292 * Check whether publication is allowed for AAF Feed.
294 * @param feedid The ID of the feed being requested.
295 * @param ip The requesting IP address
297 public String isPublishPermitted(String feedid, String ip) {
298 Feed f = feeds.get(feedid);
299 String nf = "Feed does not exist";
306 if (f.subnets.length == 0) {
309 byte[] addr = NodeUtils.getInetAddress(ip);
310 for (SubnetMatcher snm : f.subnets) {
311 if (snm.matches(addr)) {
315 return PUBLISHER_NOT_PERMITTED;
319 * Get authenticated user
321 public String getAuthUser(String feedid, String credentials) {
322 return (feeds.get(feedid).authusers.get(credentials));
326 * AAF changes: TDP EPIC US# 307413 Check AAF_instance for feed ID
328 * @param feedid The ID of the feed specified
330 public String getAafInstance(String feedid) {
331 Feed f = feeds.get(feedid);
332 return f.aafInstance;
336 * Check if the request should be redirected to a different ingress node
338 public String getIngressNode(String feedid, String user, String ip) {
339 Feed f = feeds.get(feedid);
340 if (f.redirections.length == 0) {
343 byte[] addr = NodeUtils.getInetAddress(ip);
344 for (Redirection r : f.redirections) {
345 if ((r.user != null && !user.equals(r.user)) || (r.snm != null && !r.snm.matches(addr))) {
348 for (String n : r.nodes) {
349 if (myname.equals(n)) {
353 if (r.nodes.length == 0) {
356 return (r.nodes[rrcntr++ % r.nodes.length]);
362 * Get a provisioned configuration parameter
364 public String getProvParam(String name) {
365 return (params.get(name));
369 * Get all the DestInfos
371 public DestInfo[] getAllDests() {
376 * Get the targets for a feed
378 * @param feedid The feed ID
379 * @return The targets this feed should be delivered to
381 public Target[] getTargets(String feedid) {
382 if (feedid == null) {
383 return (new Target[0]);
385 Feed f = feeds.get(feedid);
387 return (new Target[0]);
393 * Get the creation date for a feed
395 * @param feedid The feed ID
396 * @return the timestamp of creation date of feed id passed
398 public String getCreatedDate(String feedid) {
399 Feed f = feeds.get(feedid);
400 return (f.createdDate);
404 * Get the feed ID for a subscription
406 * @param subid The subscription ID
407 * @return The feed ID
409 public String getFeedId(String subid) {
410 DestInfo di = subinfo.get(subid);
414 return (di.getLogData());
418 * Get the spool directory for a subscription
420 * @param subid The subscription ID
421 * @return The spool directory
423 public String getSpoolDir(String subid) {
424 DestInfo di = subinfo.get(subid);
428 return (di.getSpool());
432 * Get the Authorization value this node uses
434 * @return The Authorization header value for this node
436 public String getMyAuth() {
440 private boolean isFeedOrSubKnown(HashSet<String> allfeeds, String subId, String feedId) {
441 return !allfeeds.contains(feedId) || subinfo.get(subId) != null;
444 private void addTargetWithRouting(HashMap<String, Target> tmap, ArrayList<Target> tv, String t, int j) {
445 String node = t.substring(0, j);
446 String rtg = t.substring(j + 1);
447 DestInfo di = nodeinfo.get(node);
449 tv.add(new Target(null, t));
451 Target tt = tmap.get(node);
453 tt = new Target(di, rtg);
462 private void addTarget(HashSet<String> subset, ArrayList<Target> tv, String t) {
463 DestInfo di = subinfo.get(t);
465 tv.add(new Target(null, t));
467 if (!subset.contains(t)) {
469 tv.add(new Target(di, null));
475 * Raw configuration entry for a data router node
477 public static class ProvNode {
479 private String cname;
482 * Construct a node configuration entry.
484 * @param cname The cname of the node.
486 public ProvNode(String cname) {
491 * Get the cname of the node
493 public String getCName() {
499 * Raw configuration entry for a provisioning parameter
501 public static class ProvParam {
504 private String value;
507 * Construct a provisioning parameter configuration entry.
509 * @param name The name of the parameter.
510 * @param value The value of the parameter.
512 public ProvParam(String name, String value) {
518 * Get the name of the parameter.
520 public String getName() {
525 * Get the value of the parameter.
527 public String getValue() {
533 * Raw configuration entry for a data feed.
535 public static class ProvFeed {
538 private String logdata;
539 private String status;
540 private String createdDate;
542 * AAF changes: TDP EPIC US# 307413
543 * Passing aafInstance from to identify legacy/AAF feeds
545 private String aafInstance;
548 * Construct a feed configuration entry.
550 * @param id The feed ID of the entry.
551 * @param logdata String for log entries about the entry.
552 * @param status The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or
553 * null if it is valid.
555 public ProvFeed(String id, String logdata, String status, String createdDate, String aafInstance) {
557 this.logdata = logdata;
558 this.status = status;
559 this.createdDate = createdDate;
560 this.aafInstance = aafInstance;
564 * Get the created date of the data feed.
566 public String getCreatedDate() {
567 return (createdDate);
571 * Get the aafInstance of the data feed.
573 public String getAafInstance() {
578 * Get the feed id of the data feed.
580 public String getId() {
585 * Get the log data of the data feed.
587 public String getLogData() {
592 * Get the status of the data feed.
594 public String getStatus() {
600 * Raw configuration entry for a feed user.
602 public static class ProvFeedUser {
604 private String feedid;
606 private String credentials;
609 * Construct a feed user configuration entry
611 * @param feedid The feed id.
612 * @param user The user that will publish to the feed.
613 * @param credentials The Authorization header the user will use to publish.
615 public ProvFeedUser(String feedid, String user, String credentials) {
616 this.feedid = feedid;
618 this.credentials = credentials;
622 * Get the feed id of the feed user.
624 public String getFeedId() {
629 * Get the user for the feed user.
631 public String getUser() {
636 * Get the credentials for the feed user.
638 public String getCredentials() {
639 return (credentials);
644 * Raw configuration entry for a feed subnet
646 public static class ProvFeedSubnet {
648 private String feedid;
652 * Construct a feed subnet configuration entry
654 * @param feedid The feed ID
655 * @param cidr The CIDR allowed to publish to the feed.
657 public ProvFeedSubnet(String feedid, String cidr) {
658 this.feedid = feedid;
663 * Get the feed id of the feed subnet.
665 public String getFeedId() {
670 * Get the CIDR of the feed subnet.
672 public String getCidr() {
678 * Raw configuration entry for a subscription
680 public static class ProvSubscription {
682 private String subid;
683 private String feedid;
685 private String authuser;
686 private String credentials;
687 private boolean metaonly;
688 private boolean use100;
689 private boolean privilegedSubscriber;
690 private boolean followRedirect;
691 private boolean decompress;
694 * Construct a subscription configuration entry
696 * @param subid The subscription ID
697 * @param feedid The feed ID
698 * @param url The base delivery URL (not including the fileid)
699 * @param authuser The user in the credentials used to deliver
700 * @param credentials The credentials used to authenticate to the delivery URL exactly as they go in the
701 * Authorization header.
702 * @param metaonly Is this a meta data only subscription?
703 * @param use100 Should we send Expect: 100-continue?
704 * @param privilegedSubscriber Can we wait to receive a delete file call before deleting file
705 * @param followRedirect Is follow redirect of destination enabled?
706 * @param decompress To see if they want their information compressed or decompressed
708 public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials,
709 boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean followRedirect,
710 boolean decompress) {
712 this.feedid = feedid;
714 this.authuser = authuser;
715 this.credentials = credentials;
716 this.metaonly = metaonly;
717 this.use100 = use100;
718 this.privilegedSubscriber = privilegedSubscriber;
719 this.followRedirect = followRedirect;
720 this.decompress = decompress;
724 * Get the subscription ID
726 public String getSubId() {
733 public String getFeedId() {
738 * Get the delivery URL
740 public String getURL() {
747 public String getAuthUser() {
752 * Get the delivery credentials
754 public String getCredentials() {
755 return (credentials);
759 * Is this a meta data only subscription?
761 public boolean isMetaDataOnly() {
766 * Should we send Expect: 100-continue?
768 public boolean isUsing100() {
773 * Can we wait to receive a delete file call before deleting file
775 public boolean isPrivilegedSubscriber() {
776 return (privilegedSubscriber);
780 * Should i decompress the file before sending it on
782 public boolean isDecompress() {
787 * New field is added - FOLLOW_REDIRECTS feature iTrack:DATARTR-17 - 1706 Get the followRedirect of this
790 boolean getFollowRedirect() {
791 return (followRedirect);
796 * Raw configuration entry for controlled ingress to the data router node
798 public static class ProvForceIngress {
800 private String feedid;
801 private String subnet;
803 private String[] nodes;
806 * Construct a forced ingress configuration entry
808 * @param feedid The feed ID that this entry applies to
809 * @param subnet The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all
810 * publisher IP addresses
811 * @param user The publishing user this entry applies to or "" if it applies to all publishing users.
812 * @param nodes The array of FQDNs of the data router nodes to redirect publication attempts to.
814 public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {
815 this.feedid = feedid;
816 this.subnet = subnet;
820 this.nodes = new String[0];
822 this.nodes = Arrays.copyOf(nodes, nodes.length);
829 public String getFeedId() {
836 public String getSubnet() {
843 public String getUser() {
850 public String[] getNodes() {
856 * Raw configuration entry for controlled egress from the data router
858 public static class ProvForceEgress {
860 private String subid;
864 * Construct a forced egress configuration entry
866 * @param subid The subscription ID the subscription with forced egress
867 * @param node The node handling deliveries for this subscription
869 public ProvForceEgress(String subid, String node) {
875 * Get the subscription ID
877 public String getSubId() {
884 public String getNode() {
890 * Raw configuration entry for routing within the data router network
892 public static class ProvHop {
899 * Construct a hop entry
901 * @param from The FQDN of the node with the data to be delivered
902 * @param to The FQDN of the node that will deliver to the subscriber
903 * @param via The FQDN of the node where the from node should send the data
905 public ProvHop(String from, String to, String via) {
912 * A human readable description of this entry
914 public String toString() {
915 return ("Hop " + from + "->" + to + " via " + via);
921 public String getFrom() {
928 public String getTo() {
933 * Get the next intermediate node
935 public String getVia() {
940 private static class Redirection {
947 private static class Feed {
951 SubnetMatcher[] subnets;
952 HashMap<String, String> authusers = new HashMap<>();
953 Redirection[] redirections;