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;
34 import org.jetbrains.annotations.NotNull;
37 * Processed configuration for this node.
39 * <p>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 {
45 private static final String PUBLISHER_NOT_PERMITTED = "Publisher not permitted for this feed";
46 private static EELFLogger logger = EELFManager.getInstance().getLogger(NodeConfig.class);
47 private HashMap<String, String> params = new HashMap<>();
48 private HashMap<String, Feed> feeds = new HashMap<>();
49 private HashMap<String, DestInfo> nodeinfo = new HashMap<>();
50 private HashMap<String, DestInfo> subinfo = new HashMap<>();
51 private HashMap<String, IsFrom> nodes = new HashMap<>();
52 private HashMap<String, ProvSubscription> provSubscriptions = new HashMap<>();
53 private String myname;
54 private String myauth;
55 private DestInfo[] alldests;
59 * Process the raw provisioning data to configure this node.
61 * @param pd The parsed provisioning data
62 * @param myname My name as seen by external systems
63 * @param spooldir The directory where temporary files live
64 * @param port The port number for URLs
65 * @param nodeauthkey The keying string used to generate node authentication credentials
67 public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {
69 for (ProvParam p : pd.getParams()) {
70 params.put(p.getName(), p.getValue());
72 ArrayList<DestInfo> destInfos = addDestInfoToNodeConfig(pd, myname, spooldir, port, nodeauthkey);
73 PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[0]), pd.getHops());
74 HashMap<String, ArrayList<Redirection>> rdtab = addSubRedirInfoToNodeConfig(pd);
75 HashMap<String, HashMap<String, String>> pfutab = addFeedUsersToNodeConfig(pd);
76 HashMap<String, String> egrtab = addEgressRoutesToNodeConfig(pd, myname);
77 HashMap<String, ArrayList<SubnetMatcher>> pfstab = addFeedSubnetToNodeConfig(pd);
78 HashSet<String> allfeeds = addFeedsToNodeConfig(pd);
79 HashMap<String, StringBuilder> feedTargets = addSubsToNodeConfig(pd, spooldir, destInfos, pf, egrtab, allfeeds);
80 alldests = destInfos.toArray(new DestInfo[0]);
81 addFeedTargetsToNodeConfig(pd, rdtab, pfutab, pfstab, feedTargets);
85 private ArrayList<DestInfo> addDestInfoToNodeConfig(ProvData pd, String myname, String spooldir, int port,
87 ArrayList<DestInfo> destInfos = new ArrayList<>();
88 myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);
89 for (ProvNode pn : pd.getNodes()) {
90 String commonName = pn.getCName();
91 if (nodeinfo.get(commonName) != null) {
94 DestInfo di = new DestInfoBuilder().setName("n:" + commonName).setSpool(spooldir + "/n/" + commonName)
96 .setLogdata("n2n-" + commonName).setUrl("https://" + commonName + ":" + port + "/internal/publish")
97 .setAuthuser(commonName).setAuthentication(myauth).setMetaonly(false).setUse100(true)
98 .setPrivilegedSubscriber(false).setFollowRedirects(false).setDecompress(false).createDestInfo();
99 (new File(di.getSpool())).mkdirs();
100 String auth = NodeUtils.getNodeAuthHdr(commonName, nodeauthkey);
102 nodeinfo.put(commonName, di);
103 nodes.put(auth, new IsFrom(commonName));
109 private HashMap<String, ArrayList<Redirection>> addSubRedirInfoToNodeConfig(ProvData pd) {
110 HashMap<String, ArrayList<Redirection>> rdtab = new HashMap<>();
111 for (ProvForceIngress pfi : pd.getForceIngress()) {
112 ArrayList<Redirection> redirections = rdtab.get(pfi.getFeedId());
113 if (redirections == null) {
114 redirections = new ArrayList<>();
115 rdtab.put(pfi.getFeedId(), redirections);
117 Redirection redirection = new Redirection();
118 if (pfi.getSubnet() != null) {
119 redirection.snm = new SubnetMatcher(pfi.getSubnet());
121 redirection.user = pfi.getUser();
122 redirection.nodes = pfi.getNodes();
123 redirections.add(redirection);
129 private HashMap<String, HashMap<String, String>> addFeedUsersToNodeConfig(ProvData pd) {
130 HashMap<String, HashMap<String, String>> pfutab = new HashMap<>();
131 for (ProvFeedUser pfu : pd.getFeedUsers()) {
132 HashMap<String, String> userInfo = pfutab.get(pfu.getFeedId());
133 if (userInfo == null) {
134 userInfo = new HashMap<>();
135 pfutab.put(pfu.getFeedId(), userInfo);
137 userInfo.put(pfu.getCredentials(), pfu.getUser());
143 private HashMap<String, String> addEgressRoutesToNodeConfig(ProvData pd, String myname) {
144 HashMap<String, String> egrtab = new HashMap<>();
145 for (ProvForceEgress pfe : pd.getForceEgress()) {
146 if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {
149 egrtab.put(pfe.getSubId(), pfe.getNode());
155 private HashMap<String, ArrayList<SubnetMatcher>> addFeedSubnetToNodeConfig(ProvData pd) {
156 HashMap<String, ArrayList<SubnetMatcher>> pfstab = new HashMap<>();
157 for (ProvFeedSubnet pfs : pd.getFeedSubnets()) {
158 ArrayList<SubnetMatcher> subnetMatchers = pfstab.get(pfs.getFeedId());
159 if (subnetMatchers == null) {
160 subnetMatchers = new ArrayList<>();
161 pfstab.put(pfs.getFeedId(), subnetMatchers);
163 subnetMatchers.add(new SubnetMatcher(pfs.getCidr()));
169 private HashSet<String> addFeedsToNodeConfig(ProvData pd) {
170 HashSet<String> allfeeds = new HashSet<>();
171 for (ProvFeed pfx : pd.getFeeds()) {
172 if (pfx.getStatus() == null) {
173 allfeeds.add(pfx.getId());
180 private HashMap<String, StringBuilder> addSubsToNodeConfig(ProvData pd, String spooldir,
181 ArrayList<DestInfo> destInfos, PathFinder pf, HashMap<String, String> egrtab, HashSet<String> allfeeds) {
182 HashMap<String, StringBuilder> feedTargets = new HashMap<>();
183 for (ProvSubscription provSubscription : pd.getSubscriptions()) {
184 String subId = provSubscription.getSubId();
185 String feedId = provSubscription.getFeedId();
186 if (isFeedOrSubKnown(allfeeds, subId, feedId)) {
191 sididx = Integer.parseInt(subId);
192 sididx -= sididx % 100;
193 } catch (Exception e) {
194 logger.error("NODE0517 Exception NodeConfig: " + e);
196 String subscriptionDirectory = sididx + "/" + subId;
197 DestInfo destinationInfo = new DestInfo("s:" + subId,
198 spooldir + "/s/" + subscriptionDirectory, provSubscription);
199 (new File(destinationInfo.getSpool())).mkdirs();
200 destInfos.add(destinationInfo);
201 provSubscriptions.put(subId, provSubscription);
202 subinfo.put(subId, destinationInfo);
203 String egr = egrtab.get(subId);
205 subId = pf.getPath(egr) + subId;
207 StringBuilder sb = feedTargets.get(feedId);
209 sb = new StringBuilder();
210 feedTargets.put(feedId, sb);
212 sb.append(' ').append(subId);
217 private void addFeedTargetsToNodeConfig(ProvData pd, HashMap<String, ArrayList<Redirection>> rdtab,
218 HashMap<String, HashMap<String, String>> pfutab, HashMap<String, ArrayList<SubnetMatcher>> pfstab,
219 HashMap<String, StringBuilder> feedTargets) {
220 for (ProvFeed pfx : pd.getFeeds()) {
221 String fid = pfx.getId();
222 Feed feed = feeds.get(fid);
227 feeds.put(fid, feed);
228 feed.createdDate = pfx.getCreatedDate();
229 feed.loginfo = pfx.getLogData();
230 feed.status = pfx.getStatus();
232 * AAF changes: TDP EPIC US# 307413
233 * Passing aafInstance from ProvFeed to identify legacy/AAF feeds
235 feed.aafInstance = pfx.getAafInstance();
236 ArrayList<SubnetMatcher> v1 = pfstab.get(fid);
238 feed.subnets = new SubnetMatcher[0];
240 feed.subnets = v1.toArray(new SubnetMatcher[0]);
242 HashMap<String, String> h1 = pfutab.get(fid);
247 ArrayList<Redirection> v2 = rdtab.get(fid);
249 feed.redirections = new Redirection[0];
251 feed.redirections = v2.toArray(new Redirection[0]);
253 StringBuilder sb = feedTargets.get(fid);
255 feed.targets = new Target[0];
257 feed.targets = parseRouting(sb.toString());
263 * Parse a target string into an array of targets.
265 * @param routing Target string
266 * @return Array of targets.
268 public Target[] parseRouting(String routing) {
269 routing = routing.trim();
270 if ("".equals(routing)) {
271 return (new Target[0]);
273 String[] routingTable = routing.split("\\s+");
274 HashMap<String, Target> tmap = new HashMap<>();
275 HashSet<String> subset = new HashSet<>();
276 ArrayList<Target> targets = new ArrayList<>();
277 for (int i = 0; i < routingTable.length; i++) {
278 String target = routingTable[i];
279 int index = target.indexOf('/');
281 addTarget(subset, targets, target);
283 addTargetWithRouting(tmap, targets, target, index);
286 return (targets.toArray(new Target[0]));
290 * Check whether this is a valid node-to-node transfer.
292 * @param credentials Credentials offered by the supposed node
293 * @param ip IP address the request came from
295 public boolean isAnotherNode(String credentials, String ip) {
296 IsFrom node = nodes.get(credentials);
297 return (node != null && node.isFrom(ip));
301 * Check whether publication is allowed.
303 * @param feedid The ID of the feed being requested.
304 * @param credentials The offered credentials
305 * @param ip The requesting IP address
307 public String isPublishPermitted(String feedid, String credentials, String ip) {
308 Feed feed = feeds.get(feedid);
309 String nf = "Feed does not exist";
316 String user = feed.authusers.get(credentials);
318 return (PUBLISHER_NOT_PERMITTED);
320 if (feed.subnets.length == 0) {
323 byte[] addr = NodeUtils.getInetAddress(ip);
324 for (SubnetMatcher snm : feed.subnets) {
325 if (snm.matches(addr)) {
329 return (PUBLISHER_NOT_PERMITTED);
333 * Check whether publication is allowed for AAF Feed.
335 * @param feedid The ID of the feed being requested.
336 * @param ip The requesting IP address
338 public String isPublishPermitted(String feedid, String ip) {
339 Feed feed = feeds.get(feedid);
340 String nf = "Feed does not exist";
347 if (feed.subnets.length == 0) {
350 byte[] addr = NodeUtils.getInetAddress(ip);
351 for (SubnetMatcher snm : feed.subnets) {
352 if (snm.matches(addr)) {
356 return PUBLISHER_NOT_PERMITTED;
360 * Check whether delete file is allowed.
362 * @param subId The ID of the subscription being requested.
364 public boolean isDeletePermitted(String subId) {
365 ProvSubscription provSubscription = provSubscriptions.get(subId);
366 return provSubscription.isPrivilegedSubscriber();
370 * Get authenticated user.
372 public String getAuthUser(String feedid, String credentials) {
373 return (feeds.get(feedid).authusers.get(credentials));
377 * AAF changes: TDP EPIC US# 307413 Check AAF_instance for feed ID.
379 * @param feedid The ID of the feed specified
381 public String getAafInstance(String feedid) {
382 Feed feed = feeds.get(feedid);
383 return feed.aafInstance;
387 * Check if the request should be redirected to a different ingress node.
389 public String getIngressNode(String feedid, String user, String ip) {
390 Feed feed = feeds.get(feedid);
391 if (feed.redirections.length == 0) {
394 byte[] addr = NodeUtils.getInetAddress(ip);
395 for (Redirection r : feed.redirections) {
396 if ((r.user != null && !user.equals(r.user)) || (r.snm != null && !r.snm.matches(addr))) {
399 for (String n : r.nodes) {
400 if (myname.equals(n)) {
404 if (r.nodes.length == 0) {
407 return (r.nodes[rrcntr++ % r.nodes.length]);
413 * Get a provisioned configuration parameter.
415 public String getProvParam(String name) {
416 return (params.get(name));
420 * Get all the DestInfos.
422 public DestInfo[] getAllDests() {
427 * Get the targets for a feed.
429 * @param feedid The feed ID
430 * @return The targets this feed should be delivered to
432 public Target[] getTargets(String feedid) {
433 if (feedid == null) {
434 return (new Target[0]);
436 Feed feed = feeds.get(feedid);
438 return (new Target[0]);
440 return (feed.targets);
444 * Get the creation date for a feed.
446 * @param feedid The feed ID
447 * @return the timestamp of creation date of feed id passed
449 public String getCreatedDate(String feedid) {
450 Feed feed = feeds.get(feedid);
451 return (feed.createdDate);
455 * Get the feed ID for a subscription.
457 * @param subid The subscription ID
458 * @return The feed ID
460 public String getFeedId(String subid) {
461 DestInfo di = subinfo.get(subid);
465 return (di.getLogData());
469 * Get the spool directory for a subscription.
471 * @param subid The subscription ID
472 * @return The spool directory
474 public String getSpoolDir(String subid) {
475 DestInfo di = subinfo.get(subid);
479 return (di.getSpool());
483 * Get the Authorization value this node uses.
485 * @return The Authorization header value for this node
487 public String getMyAuth() {
491 private boolean isFeedOrSubKnown(HashSet<String> allfeeds, String subId, String feedId) {
492 return !allfeeds.contains(feedId) || subinfo.get(subId) != null;
495 private void addTargetWithRouting(HashMap<String, Target> tmap, ArrayList<Target> targets, String target,
497 String node = target.substring(0, index);
498 String rtg = target.substring(index + 1);
499 DestInfo di = nodeinfo.get(node);
501 targets.add(new Target(null, target));
503 Target tt = tmap.get(node);
505 tt = new Target(di, rtg);
514 private void addTarget(HashSet<String> subset, ArrayList<Target> targets, String target) {
515 DestInfo destInfo = subinfo.get(target);
516 if (destInfo == null) {
517 targets.add(new Target(null, target));
519 if (!subset.contains(target)) {
521 targets.add(new Target(destInfo, null));
527 * Raw configuration entry for a data router node.
529 public static class ProvNode {
531 private String cname;
534 * Construct a node configuration entry.
536 * @param cname The cname of the node.
538 public ProvNode(String cname) {
543 * Get the cname of the node.
545 public String getCName() {
551 * Raw configuration entry for a provisioning parameter.
553 public static class ProvParam {
556 private String value;
559 * Construct a provisioning parameter configuration entry.
561 * @param name The name of the parameter.
562 * @param value The value of the parameter.
564 public ProvParam(String name, String value) {
570 * Get the name of the parameter.
572 public String getName() {
577 * Get the value of the parameter.
579 public String getValue() {
585 * Raw configuration entry for a data feed.
587 public static class ProvFeed {
590 private String logdata;
591 private String status;
592 private String createdDate;
594 * AAF changes: TDP EPIC US# 307413
595 * Passing aafInstance from to identify legacy/AAF feeds
597 private String aafInstance;
600 * Construct a feed configuration entry.
602 * @param id The feed ID of the entry.
603 * @param logdata String for log entries about the entry.
604 * @param status The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or
605 * null if it is valid.
607 public ProvFeed(String id, String logdata, String status, String createdDate, String aafInstance) {
609 this.logdata = logdata;
610 this.status = status;
611 this.createdDate = createdDate;
612 this.aafInstance = aafInstance;
616 * Get the created date of the data feed.
618 public String getCreatedDate() {
619 return (createdDate);
623 * Get the aafInstance of the data feed.
625 public String getAafInstance() {
630 * Get the feed id of the data feed.
632 public String getId() {
637 * Get the log data of the data feed.
639 public String getLogData() {
644 * Get the status of the data feed.
646 public String getStatus() {
652 * Raw configuration entry for a feed user.
654 public static class ProvFeedUser {
656 private String feedid;
658 private String credentials;
661 * Construct a feed user configuration entry.
663 * @param feedid The feed id.
664 * @param user The user that will publish to the feed.
665 * @param credentials The Authorization header the user will use to publish.
667 public ProvFeedUser(String feedid, String user, String credentials) {
668 this.feedid = feedid;
670 this.credentials = credentials;
674 * Get the feed id of the feed user.
676 public String getFeedId() {
681 * Get the user for the feed user.
683 public String getUser() {
688 * Get the credentials for the feed user.
690 public String getCredentials() {
691 return (credentials);
696 * Raw configuration entry for a feed subnet.
698 public static class ProvFeedSubnet {
700 private String feedid;
704 * Construct a feed subnet configuration entry.
706 * @param feedid The feed ID
707 * @param cidr The CIDR allowed to publish to the feed.
709 public ProvFeedSubnet(String feedid, String cidr) {
710 this.feedid = feedid;
715 * Get the feed id of the feed subnet.
717 public String getFeedId() {
722 * Get the CIDR of the feed subnet.
724 public String getCidr() {
730 * Raw configuration entry for a subscription.
732 public static class ProvSubscription {
734 private String subid;
735 private String feedid;
737 private String authuser;
738 private String credentials;
739 private boolean metaonly;
740 private boolean use100;
741 private boolean privilegedSubscriber;
742 private boolean followRedirect;
743 private boolean decompress;
746 * Construct a subscription configuration entry.
748 * @param subid The subscription ID
749 * @param feedid The feed ID
750 * @param url The base delivery URL (not including the fileid)
751 * @param authuser The user in the credentials used to deliver
752 * @param credentials The credentials used to authenticate to the delivery URL exactly as they go in the
753 * Authorization header.
754 * @param metaonly Is this a meta data only subscription?
755 * @param use100 Should we send Expect: 100-continue?
756 * @param privilegedSubscriber Can we wait to receive a delete file call before deleting file
757 * @param followRedirect Is follow redirect of destination enabled?
758 * @param decompress To see if they want their information compressed or decompressed
760 public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials,
761 boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean followRedirect,
762 boolean decompress) {
764 this.feedid = feedid;
766 this.authuser = authuser;
767 this.credentials = credentials;
768 this.metaonly = metaonly;
769 this.use100 = use100;
770 this.privilegedSubscriber = privilegedSubscriber;
771 this.followRedirect = followRedirect;
772 this.decompress = decompress;
776 * Get the subscription ID.
778 public String getSubId() {
785 public String getFeedId() {
790 * Get the delivery URL.
792 public String getURL() {
799 public String getAuthUser() {
804 * Get the delivery credentials.
806 public String getCredentials() {
807 return (credentials);
811 * Is this a meta data only subscription.
813 public boolean isMetaDataOnly() {
818 * Should we send Expect: 100-continue.
820 public boolean isUsing100() {
825 * Can we wait to receive a delete file call before deleting file.
827 public boolean isPrivilegedSubscriber() {
828 return (privilegedSubscriber);
832 * Should I decompress the file before sending it on.
834 public boolean isDecompress() {
839 * New field is added - FOLLOW_REDIRECTS feature iTrack:DATARTR-17 - 1706 Get the followRedirect of this
842 boolean getFollowRedirect() {
843 return (followRedirect);
848 * Raw configuration entry for controlled ingress to the data router node.
850 public static class ProvForceIngress {
852 private String feedid;
853 private String subnet;
855 private String[] nodes;
858 * Construct a forced ingress configuration entry.
860 * @param feedid The feed ID that this entry applies to
861 * @param subnet The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all
862 * publisher IP addresses
863 * @param user The publishing user this entry applies to or "" if it applies to all publishing users.
864 * @param nodes The array of FQDNs of the data router nodes to redirect publication attempts to.
866 public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {
867 this.feedid = feedid;
868 this.subnet = subnet;
872 this.nodes = new String[0];
874 this.nodes = Arrays.copyOf(nodes, nodes.length);
881 public String getFeedId() {
888 public String getSubnet() {
895 public String getUser() {
902 public String[] getNodes() {
908 * Raw configuration entry for controlled egress from the data router.
910 public static class ProvForceEgress {
912 private String subid;
916 * Construct a forced egress configuration entry.
918 * @param subid The subscription ID the subscription with forced egress
919 * @param node The node handling deliveries for this subscription
921 public ProvForceEgress(String subid, String node) {
927 * Get the subscription ID.
929 public String getSubId() {
936 public String getNode() {
942 * Raw configuration entry for routing within the data router network.
944 public static class ProvHop {
951 * Construct a hop entry.
953 * @param from The FQDN of the node with the data to be delivered
954 * @param to The FQDN of the node that will deliver to the subscriber
955 * @param via The FQDN of the node where the from node should send the data
957 public ProvHop(String from, String to, String via) {
964 * A human readable description of this entry.
966 public String toString() {
967 return ("Hop " + from + "->" + to + " via " + via);
973 public String getFrom() {
980 public String getTo() {
985 * Get the next intermediate node.
987 public String getVia() {
992 private static class Redirection {
999 private static class Feed {
1003 SubnetMatcher[] subnets;
1004 HashMap<String, String> authusers = new HashMap<>();
1005 Redirection[] redirections;