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.config;
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;
35 import org.onap.dmaap.datarouter.node.DestInfo;
36 import org.onap.dmaap.datarouter.node.DestInfoBuilder;
37 import org.onap.dmaap.datarouter.node.IsFrom;
38 import org.onap.dmaap.datarouter.node.Target;
39 import org.onap.dmaap.datarouter.node.utils.NodeUtils;
42 * Processed configuration for this node.
44 * <p>The NodeConfig represents a processed configuration from the Data Router provisioning server. Each time
45 * configuration data is received from the provisioning server, a new NodeConfig is created and the previous one
48 public class NodeConfig {
50 private static final String PUBLISHER_NOT_PERMITTED = "Publisher not permitted for this feed";
51 private static final EELFLogger logger = EELFManager.getInstance().getLogger(NodeConfig.class);
52 private final HashMap<String, String> params = new HashMap<>();
53 private final HashMap<String, Feed> feeds = new HashMap<>();
54 private final HashMap<String, DestInfo> nodeinfo = new HashMap<>();
55 private final HashMap<String, DestInfo> subinfo = new HashMap<>();
56 private final HashMap<String, IsFrom> nodes = new HashMap<>();
57 private final HashMap<String, ProvSubscription> provSubscriptions = new HashMap<>();
58 private final String myname;
59 private String myauth;
60 private final DestInfo[] alldests;
64 * Process the raw provisioning data to configure this node.
66 * @param pd The parsed provisioning data
67 * @param myname My name as seen by external systems
68 * @param spooldir The directory where temporary files live
69 * @param port The port number for URLs
70 * @param nodeauthkey The keying string used to generate node authentication credentials
72 public NodeConfig(ProvData pd, String myname, String spooldir, int port, String nodeauthkey) {
74 for (ProvParam p : pd.getParams()) {
75 params.put(p.getName(), p.getValue());
77 ArrayList<DestInfo> destInfos = addDestInfoToNodeConfig(pd, myname, spooldir, port, nodeauthkey);
78 PathFinder pf = new PathFinder(myname, nodeinfo.keySet().toArray(new String[0]), pd.getHops());
79 HashMap<String, ArrayList<Redirection>> rdtab = addSubRedirInfoToNodeConfig(pd);
80 HashMap<String, HashMap<String, String>> pfutab = addFeedUsersToNodeConfig(pd);
81 HashMap<String, String> egrtab = addEgressRoutesToNodeConfig(pd, myname);
82 HashMap<String, ArrayList<SubnetMatcher>> pfstab = addFeedSubnetToNodeConfig(pd);
83 HashSet<String> allfeeds = addFeedsToNodeConfig(pd);
84 HashMap<String, StringBuilder> feedTargets = addSubsToNodeConfig(pd, spooldir, destInfos, pf, egrtab, allfeeds);
85 alldests = destInfos.toArray(new DestInfo[0]);
86 addFeedTargetsToNodeConfig(pd, rdtab, pfutab, pfstab, feedTargets);
90 private ArrayList<DestInfo> addDestInfoToNodeConfig(ProvData pd, String myname, String spooldir, int port,
92 ArrayList<DestInfo> destInfos = new ArrayList<>();
93 myauth = NodeUtils.getNodeAuthHdr(myname, nodeauthkey);
94 for (ProvNode pn : pd.getNodes()) {
95 String commonName = pn.getCName();
96 if (nodeinfo.get(commonName) != null) {
99 DestInfo di = new DestInfoBuilder().setName("n:" + commonName).setSpool(spooldir + "/n/" + commonName)
101 .setLogdata("n2n-" + commonName).setUrl("https://" + commonName + ":" + port + "/internal/publish")
102 .setAuthuser(commonName).setAuthentication(myauth).setMetaonly(false).setUse100(true)
103 .setPrivilegedSubscriber(false).setFollowRedirects(false).setDecompress(false).createDestInfo();
104 (new File(di.getSpool())).mkdirs();
105 String auth = NodeUtils.getNodeAuthHdr(commonName, nodeauthkey);
107 nodeinfo.put(commonName, di);
108 nodes.put(auth, new IsFrom(commonName));
114 private HashMap<String, ArrayList<Redirection>> addSubRedirInfoToNodeConfig(ProvData pd) {
115 HashMap<String, ArrayList<Redirection>> rdtab = new HashMap<>();
116 for (ProvForceIngress pfi : pd.getForceIngress()) {
117 ArrayList<Redirection> redirections = rdtab.get(pfi.getFeedId());
118 if (redirections == null) {
119 redirections = new ArrayList<>();
120 rdtab.put(pfi.getFeedId(), redirections);
122 Redirection redirection = new Redirection();
123 if (pfi.getSubnet() != null) {
124 redirection.snm = new SubnetMatcher(pfi.getSubnet());
126 redirection.user = pfi.getUser();
127 redirection.nodes = pfi.getNodes();
128 redirections.add(redirection);
134 private HashMap<String, HashMap<String, String>> addFeedUsersToNodeConfig(ProvData pd) {
135 HashMap<String, HashMap<String, String>> pfutab = new HashMap<>();
136 for (ProvFeedUser pfu : pd.getFeedUsers()) {
137 HashMap<String, String> userInfo = pfutab.get(pfu.getFeedId());
138 if (userInfo == null) {
139 userInfo = new HashMap<>();
140 pfutab.put(pfu.getFeedId(), userInfo);
142 userInfo.put(pfu.getCredentials(), pfu.getUser());
148 private HashMap<String, String> addEgressRoutesToNodeConfig(ProvData pd, String myname) {
149 HashMap<String, String> egrtab = new HashMap<>();
150 for (ProvForceEgress pfe : pd.getForceEgress()) {
151 if (pfe.getNode().equals(myname) || nodeinfo.get(pfe.getNode()) == null) {
154 egrtab.put(pfe.getSubId(), pfe.getNode());
160 private HashMap<String, ArrayList<SubnetMatcher>> addFeedSubnetToNodeConfig(ProvData pd) {
161 HashMap<String, ArrayList<SubnetMatcher>> pfstab = new HashMap<>();
162 for (ProvFeedSubnet pfs : pd.getFeedSubnets()) {
163 ArrayList<SubnetMatcher> subnetMatchers = pfstab.get(pfs.getFeedId());
164 if (subnetMatchers == null) {
165 subnetMatchers = new ArrayList<>();
166 pfstab.put(pfs.getFeedId(), subnetMatchers);
168 subnetMatchers.add(new SubnetMatcher(pfs.getCidr()));
174 private HashSet<String> addFeedsToNodeConfig(ProvData pd) {
175 HashSet<String> allfeeds = new HashSet<>();
176 for (ProvFeed pfx : pd.getFeeds()) {
177 if (pfx.getStatus() == null) {
178 allfeeds.add(pfx.getId());
185 private HashMap<String, StringBuilder> addSubsToNodeConfig(ProvData pd, String spooldir,
186 ArrayList<DestInfo> destInfos, PathFinder pf, HashMap<String, String> egrtab, HashSet<String> allfeeds) {
187 HashMap<String, StringBuilder> feedTargets = new HashMap<>();
188 for (ProvSubscription provSubscription : pd.getSubscriptions()) {
189 String subId = provSubscription.getSubId();
190 String feedId = provSubscription.getFeedId();
191 if (isFeedOrSubKnown(allfeeds, subId, feedId)) {
196 sididx = Integer.parseInt(subId);
197 sididx -= sididx % 100;
198 } catch (Exception e) {
199 logger.error("NODE0517 Exception NodeConfig: " + e);
201 String subscriptionDirectory = sididx + "/" + subId;
202 DestInfo destinationInfo = new DestInfo("s:" + subId,
203 spooldir + "/s/" + subscriptionDirectory, provSubscription);
204 (new File(destinationInfo.getSpool())).mkdirs();
205 destInfos.add(destinationInfo);
206 provSubscriptions.put(subId, provSubscription);
207 subinfo.put(subId, destinationInfo);
208 String egr = egrtab.get(subId);
210 subId = pf.getPath(egr) + subId;
212 StringBuilder sb = feedTargets.get(feedId);
214 sb = new StringBuilder();
215 feedTargets.put(feedId, sb);
217 sb.append(' ').append(subId);
222 private void addFeedTargetsToNodeConfig(ProvData pd, HashMap<String, ArrayList<Redirection>> rdtab,
223 HashMap<String, HashMap<String, String>> pfutab, HashMap<String, ArrayList<SubnetMatcher>> pfstab,
224 HashMap<String, StringBuilder> feedTargets) {
225 for (ProvFeed pfx : pd.getFeeds()) {
226 String fid = pfx.getId();
227 Feed feed = feeds.get(fid);
232 feeds.put(fid, feed);
233 feed.createdDate = pfx.getCreatedDate();
234 feed.loginfo = pfx.getLogData();
235 feed.status = pfx.getStatus();
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 delete file is allowed.
335 * @param subId The ID of the subscription being requested.
337 public boolean isDeletePermitted(String subId) {
338 ProvSubscription provSubscription = provSubscriptions.get(subId);
339 return provSubscription.isPrivilegedSubscriber();
343 * Get authenticated user.
345 public String getAuthUser(String feedid, String credentials) {
346 return (feeds.get(feedid).authusers.get(credentials));
350 * Check if the request should be redirected to a different ingress node.
352 public String getIngressNode(String feedid, String user, String ip) {
353 Feed feed = feeds.get(feedid);
354 if (feed.redirections.length == 0) {
357 byte[] addr = NodeUtils.getInetAddress(ip);
358 for (Redirection r : feed.redirections) {
359 if ((r.user != null && !user.equals(r.user)) || (r.snm != null && !r.snm.matches(addr))) {
362 for (String n : r.nodes) {
363 if (myname.equals(n)) {
367 if (r.nodes.length == 0) {
370 return (r.nodes[rrcntr++ % r.nodes.length]);
376 * Get a provisioned configuration parameter.
378 public String getProvParam(String name) {
379 return (params.get(name));
383 * Get all the DestInfos.
385 public DestInfo[] getAllDests() {
390 * Get the targets for a feed.
392 * @param feedid The feed ID
393 * @return The targets this feed should be delivered to
395 public Target[] getTargets(String feedid) {
396 if (feedid == null) {
397 return (new Target[0]);
399 Feed feed = feeds.get(feedid);
401 return (new Target[0]);
403 return (feed.targets);
407 * Get the creation date for a feed.
409 * @param feedid The feed ID
410 * @return the timestamp of creation date of feed id passed
412 public String getCreatedDate(String feedid) {
413 Feed feed = feeds.get(feedid);
414 return (feed.createdDate);
418 * Get the feed ID for a subscription.
420 * @param subid The subscription ID
421 * @return The feed ID
423 public String getFeedId(String subid) {
424 DestInfo di = subinfo.get(subid);
428 return (di.getLogData());
432 * Get the spool directory for a subscription.
434 * @param subid The subscription ID
435 * @return The spool directory
437 public String getSpoolDir(String subid) {
438 DestInfo di = subinfo.get(subid);
442 return (di.getSpool());
446 * Get the Authorization value this node uses.
448 * @return The Authorization header value for this node
450 public String getMyAuth() {
454 private boolean isFeedOrSubKnown(HashSet<String> allfeeds, String subId, String feedId) {
455 return !allfeeds.contains(feedId) || subinfo.get(subId) != null;
458 private void addTargetWithRouting(HashMap<String, Target> tmap, ArrayList<Target> targets, String target,
460 String node = target.substring(0, index);
461 String rtg = target.substring(index + 1);
462 DestInfo di = nodeinfo.get(node);
464 targets.add(new Target(null, target));
466 Target tt = tmap.get(node);
468 tt = new Target(di, rtg);
477 private void addTarget(HashSet<String> subset, ArrayList<Target> targets, String target) {
478 DestInfo destInfo = subinfo.get(target);
479 if (destInfo == null) {
480 targets.add(new Target(null, target));
482 if (!subset.contains(target)) {
484 targets.add(new Target(destInfo, null));
490 * Raw configuration entry for a data router node.
492 public static class ProvNode {
494 private String cname;
497 * Construct a node configuration entry.
499 * @param cname The cname of the node.
501 public ProvNode(String cname) {
506 * Get the cname of the node.
508 public String getCName() {
514 * Raw configuration entry for a provisioning parameter.
516 public static class ProvParam {
519 private String value;
522 * Construct a provisioning parameter configuration entry.
524 * @param name The name of the parameter.
525 * @param value The value of the parameter.
527 public ProvParam(String name, String value) {
533 * Get the name of the parameter.
535 public String getName() {
540 * Get the value of the parameter.
542 public String getValue() {
548 * Raw configuration entry for a data feed.
550 public static class ProvFeed {
552 private final String id;
553 private final String logdata;
554 private final String status;
555 private final String createdDate;
558 * Construct a feed configuration entry.
560 * @param id The feed ID of the entry.
561 * @param logdata String for log entries about the entry.
562 * @param status The reason why this feed cannot be used (Feed has been deleted, Feed has been suspended) or
563 * null if it is valid.
565 public ProvFeed(String id, String logdata, String status, String createdDate) {
567 this.logdata = logdata;
568 this.status = status;
569 this.createdDate = createdDate;
573 * Get the created date of the data feed.
575 public String getCreatedDate() {
576 return (createdDate);
580 * Get the feed id of the data feed.
582 public String getId() {
587 * Get the log data of the data feed.
589 public String getLogData() {
594 * Get the status of the data feed.
596 public String getStatus() {
602 * Raw configuration entry for a feed user.
604 public static class ProvFeedUser {
606 private final String feedid;
607 private final String user;
608 private final String credentials;
611 * Construct a feed user configuration entry.
613 * @param feedid The feed id.
614 * @param user The user that will publish to the feed.
615 * @param credentials The Authorization header the user will use to publish.
617 public ProvFeedUser(String feedid, String user, String credentials) {
618 this.feedid = feedid;
620 this.credentials = credentials;
624 * Get the feed id of the feed user.
626 public String getFeedId() {
631 * Get the user for the feed user.
633 public String getUser() {
638 * Get the credentials for the feed user.
640 public String getCredentials() {
641 return (credentials);
646 * Raw configuration entry for a feed subnet.
648 public static class ProvFeedSubnet {
650 private final String feedid;
651 private final String cidr;
654 * Construct a feed subnet configuration entry.
656 * @param feedid The feed ID
657 * @param cidr The CIDR allowed to publish to the feed.
659 public ProvFeedSubnet(String feedid, String cidr) {
660 this.feedid = feedid;
665 * Get the feed id of the feed subnet.
667 public String getFeedId() {
672 * Get the CIDR of the feed subnet.
674 public String getCidr() {
680 * Raw configuration entry for a subscription.
682 public static class ProvSubscription {
684 private final String subid;
685 private final String feedid;
686 private final String url;
687 private final String authuser;
688 private final String credentials;
689 private final boolean metaonly;
690 private final boolean use100;
691 private final boolean privilegedSubscriber;
692 private final boolean followRedirect;
693 private final boolean decompress;
696 * Construct a subscription configuration entry.
698 * @param subid The subscription ID
699 * @param feedid The feed ID
700 * @param url The base delivery URL (not including the fileid)
701 * @param authuser The user in the credentials used to deliver
702 * @param credentials The credentials used to authenticate to the delivery URL exactly as they go in the
703 * Authorization header.
704 * @param metaonly Is this a meta data only subscription?
705 * @param use100 Should we send Expect: 100-continue?
706 * @param privilegedSubscriber Can we wait to receive a delete file call before deleting file
707 * @param followRedirect Is follow redirect of destination enabled?
708 * @param decompress To see if they want their information compressed or decompressed
710 public ProvSubscription(String subid, String feedid, String url, String authuser, String credentials,
711 boolean metaonly, boolean use100, boolean privilegedSubscriber, boolean followRedirect,
712 boolean decompress) {
714 this.feedid = feedid;
716 this.authuser = authuser;
717 this.credentials = credentials;
718 this.metaonly = metaonly;
719 this.use100 = use100;
720 this.privilegedSubscriber = privilegedSubscriber;
721 this.followRedirect = followRedirect;
722 this.decompress = decompress;
726 * Get the subscription ID.
728 public String getSubId() {
735 public String getFeedId() {
740 * Get the delivery URL.
742 public String getURL() {
749 public String getAuthUser() {
754 * Get the delivery credentials.
756 public String getCredentials() {
757 return (credentials);
761 * Is this a meta data only subscription.
763 public boolean isMetaDataOnly() {
768 * Should we send Expect: 100-continue.
770 public boolean isUsing100() {
775 * Can we wait to receive a delete file call before deleting file.
777 public boolean isPrivilegedSubscriber() {
778 return (privilegedSubscriber);
782 * Should I decompress the file before sending it on.
784 public boolean isDecompress() {
789 * New field is added - FOLLOW_REDIRECTS feature iTrack:DATARTR-17 - 1706 Get the followRedirect of this
792 public boolean getFollowRedirect() {
793 return (followRedirect);
798 * Raw configuration entry for controlled ingress to the data router node.
800 public static class ProvForceIngress {
802 private final String feedid;
803 private final String subnet;
804 private final String user;
805 private final String[] nodes;
808 * Construct a forced ingress configuration entry.
810 * @param feedid The feed ID that this entry applies to
811 * @param subnet The CIDR for which publisher IP addresses this entry applies to or "" if it applies to all
812 * publisher IP addresses
813 * @param user The publishing user this entry applies to or "" if it applies to all publishing users.
814 * @param nodes The array of FQDNs of the data router nodes to redirect publication attempts to.
816 public ProvForceIngress(String feedid, String subnet, String user, String[] nodes) {
817 this.feedid = feedid;
818 this.subnet = subnet;
822 this.nodes = new String[0];
824 this.nodes = Arrays.copyOf(nodes, nodes.length);
831 public String getFeedId() {
838 public String getSubnet() {
845 public String getUser() {
852 public String[] getNodes() {
858 * Raw configuration entry for controlled egress from the data router.
860 public static class ProvForceEgress {
862 private final String subid;
863 private final String node;
866 * Construct a forced egress configuration entry.
868 * @param subid The subscription ID the subscription with forced egress
869 * @param node The node handling deliveries for this subscription
871 public ProvForceEgress(String subid, String node) {
877 * Get the subscription ID.
879 public String getSubId() {
886 public String getNode() {
892 * Raw configuration entry for routing within the data router network.
894 public static class ProvHop {
896 private final String from;
897 private final String to;
898 private final String via;
901 * Construct a hop entry.
903 * @param from The FQDN of the node with the data to be delivered
904 * @param to The FQDN of the node that will deliver to the subscriber
905 * @param via The FQDN of the node where the from node should send the data
907 public ProvHop(String from, String to, String via) {
914 * A human readable description of this entry.
916 public String toString() {
917 return ("Hop " + from + "->" + to + " via " + via);
923 public String getFrom() {
930 public String getTo() {
935 * Get the next intermediate node.
937 public String getVia() {
942 private static class Redirection {
949 private static class Feed {
953 SubnetMatcher[] subnets;
954 HashMap<String, String> authusers = new HashMap<>();
955 Redirection[] redirections;