Divide the MSB source codes into two repos
[msb/apigateway.git] / apiroute / apiroute-service / src / main / java / org / onap / msb / apiroute / wrapper / util / ServiceFilter.java
1 package org.onap.msb.apiroute.wrapper.util;
2
3 import java.util.HashMap;
4 import java.util.HashSet;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Set;
8 import java.util.regex.Pattern;
9
10 import org.apache.commons.lang3.StringUtils;
11 import org.onap.msb.apiroute.api.MicroServiceFullInfo;
12 import org.onap.msb.apiroute.api.Node;
13 import org.onap.msb.apiroute.wrapper.consulextend.model.health.Service;
14 import org.onap.msb.apiroute.wrapper.consulextend.model.health.ServiceHealth;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 import com.orbitz.consul.model.health.HealthCheck;
19
20
21
22 public class ServiceFilter {
23   private static ServiceFilter instance = new ServiceFilter();
24
25   private ServiceFilter() {}
26
27   public static ServiceFilter getInstance() {
28     return instance;
29   }
30
31   private static final Logger LOGGER = LoggerFactory.getLogger(ServiceFilter.class);
32
33
34   /**
35    * Determine whether the service needs to send a notification TODO: filter according to the
36    * agreement, the only notice of agreement for REST \HTTP\ UI interface MSB - REST
37    * 
38    * @param protocol
39    * @return
40    */
41   public boolean isNeedNotifyByProtocol(String protocol) {
42     return CommonUtil.contain(RouteUtil.FILTER_PROTOCOLS, protocol.trim());
43   }
44
45   /**
46    * Determine whether the service needs to send a notification TODO: according to the visual range
47    * filter conditions Regular language: all 、 default 、 !default 、 A、 |A 、 A|B、 !A&!B
48    * 
49    * @param visualRange
50    * @return
51    */
52   public boolean isNeedNotifyByNameSpace(String nameSpace) {
53
54     String namespaceMatches = ConfigUtil.getInstance().getNamespaceMatches();
55     String[] namespaceArray = StringUtils.split(namespaceMatches, "|");
56
57     if (CommonUtil.contain(namespaceArray, "all")) {
58       return true;
59     }
60
61     if (CommonUtil.contain(namespaceArray, "default")) {
62       if (StringUtils.isEmpty(nameSpace) || "default".equals(nameSpace) ) {
63         return true;
64       } else {
65         return false;
66       }
67     }
68
69     if (CommonUtil.contain(namespaceArray, "!default")) {
70       if (StringUtils.isNotEmpty(nameSpace) && !"default".equals(nameSpace)) {
71         return true;
72       } else {
73         return false;
74       }
75     }
76     try {
77       String namespaceReg;
78       if (namespaceMatches.contains("!")) {
79         namespaceReg = "^" + namespaceMatches.replaceAll("!", "").replaceAll("&", "|") + "$";
80         return !Pattern.matches(namespaceReg, nameSpace);
81       } else {
82         namespaceReg = "^" + namespaceMatches + "$";
83         return Pattern.matches(namespaceReg, nameSpace);
84       }
85
86     } catch (Exception e) {
87       LOGGER.error(" Regular " + namespaceMatches + " throw exception:" + e.getMessage());
88       return false;
89     }
90   }
91
92   public boolean isNeedNotifyByVisualRange(String visualRange) {
93
94     String[] routeVisualRangeArray =
95         StringUtils.split(ConfigUtil.getInstance().getVisualRangeMatches(), "|");
96
97     String[] serviceVisualRangeArray = StringUtils.split(visualRange, "|");
98
99     if (CommonUtil.contain(serviceVisualRangeArray, routeVisualRangeArray)) {
100       return true;
101     }
102
103     return false;
104
105   }
106
107   public boolean isNeedNotifyByNetwork_plane_typeMatches(String network_plane_type) {
108
109     String network_plane_typeMatches = ConfigUtil.getInstance().getNetwork_plane_typeMatches();
110     if (StringUtils.isBlank(network_plane_typeMatches))
111       return true;
112
113     String[] routeNetwork_plane_typeArray = StringUtils.split(network_plane_typeMatches, "|");
114
115     String[] serviceVisualRangeArray = StringUtils.split(network_plane_type, "|");
116
117     if (CommonUtil.contain(serviceVisualRangeArray, routeNetwork_plane_typeArray)) {
118       return true;
119     }
120
121     return false;
122
123   }
124
125   /**
126    * Determine whether the service needs to send a notification TODO: according to the visual range
127    * filter conditions
128    * 
129    * @param visualRange
130    * @return
131    */
132   public boolean isNeedNotifyByRouteLabels(Map<String, String> labelMap) {
133
134     Map<String, String> labelMapMatches = ConfigUtil.getInstance().getLabelMapMatches();
135
136     if (labelMapMatches == null || labelMapMatches.isEmpty()) {
137       return true;
138     }
139
140     for (Map.Entry<String, String> entry : labelMapMatches.entrySet()) {
141       String key = entry.getKey();
142       String value = entry.getValue();
143
144       // Multiple values match
145
146       if (StringUtils.isBlank(labelMap.get(key))) {
147         continue;
148       }
149
150       String[] routeLalelsArray = StringUtils.split(value, "|");
151
152       String[] serviceLabelsArray = StringUtils.split(labelMap.get(key), "|");
153
154       if (CommonUtil.contain(routeLalelsArray, serviceLabelsArray)) {
155         return true;
156       }
157
158     }
159
160     return false;
161   }
162
163
164
165   /*
166    * public boolean isNeedNotifyByRoute(String protocol, String namespace, String visualRange,
167    * String network_plane_type, Map<String, String> labelMap) {
168    * 
169    * return isNeedNotifyByProtocol(protocol) && isNeedNotifyByNameSpace(namespace) &&
170    * isNeedNotifyByVisualRange(visualRange) && isNeedNotifyByRouteLabels(labelMap) &&
171    * isNeedNotifyByNetwork_plane_typeMatches(network_plane_type);
172    * 
173    * }
174    */
175
176   public boolean isFilterCheck(ServiceHealth health){
177     return isFilterHealthCheck(health.getChecks()) && isFilterService(health.getService().getTags());
178   }
179   
180   /**
181    * @Title isFilterHealthCheck
182    * @Description TODO(判断服务实例的健康检查信息,全部为passing表示健康检查有效)
183    * @param List<HealthCheck>
184    * @return boolean checkList示例——"Checks" : [{
185                 "Node" : "server",
186                 "CheckID" : "serfHealth",
187                 "Name" : "Serf Health Status",
188                 "Status" : "passing",
189                 "Notes" : "",
190                 "Output" : "Agent alive and reachable",
191                 "ServiceID" : "",
192                 "ServiceName" : "",
193                 "CreateIndex" : 65536,
194                 "ModifyIndex" : 65536
195             }, {
196                 "Node" : "server",
197                 "CheckID" : "service:_tcp_roundrobin_1_10.74.151.26_22",
198                 "Name" : "Service 'tcp_roundrobin_1' check",
199                 "Status" : "critical",
200                 "Notes" : "",
201                 "Output" : "dial tcp: missing port in address ok",
202                 "ServiceID" : "_tcp_roundrobin_1_10.74.151.26_22",
203                 "ServiceName" : "tcp_roundrobin_1",
204                 "CreateIndex" : 75988,
205                 "ModifyIndex" : 76173
206             }
207         ]
208    */
209   public  boolean isFilterHealthCheck(List<HealthCheck> checkList){
210     if(checkList.isEmpty()){
211       return true;
212     }
213     
214     for (HealthCheck check : checkList) {
215       if (!RouteUtil.HEALTH_CHECK_PASSING.equals(check.getStatus())) {
216         return false;
217       }
218     }
219     
220     return true;
221   }
222   
223   
224
225   /**
226    * @Title isFilterService
227    * @Description TODO(判断来自consul的服务信息是否需要过滤)
228    * @param List<String>
229    * @return boolean tagList示例—— [
230    *         "\"base\":{\"protocol\":\"REST\",\"is_manual\":\"true\",\"version\":\"v1\",\"url\":\"/api/msbtest/v1\"}"
231    *         , "\"ns\":{\"namespace\":\"nsName\"}",
232    *         "\"labels\":{\"visualRange\":\"0\",\"network_plane_type\":\"net\",\"customLabel\":\"custom\"}"
233    *         ]
234    */
235   @SuppressWarnings("unchecked")
236   public boolean isFilterService(List<String> tagList) {
237
238     if (tagList == null || tagList.size() == 0)
239       return false;
240
241     String visualRange = "", network_plane_type = "", protocol = "", namespace = "";
242     
243     //针对多版本不同属性的tag会有多个,只要其中一个匹配即通过过滤,默认不通过
244     boolean visualRangeFilter=false,protocolFilter = false, namespaceFilter = false; 
245     boolean hasnamespace=false;
246
247     try {
248
249       for (String tag : tagList) {
250
251         // 提取基础属性tag
252         if (!protocolFilter && tag.startsWith("\"base\"")) {
253           String ms_base_json = tag.split("\"base\":")[1];
254
255           Map<String, String> baseMap =
256               (Map<String, String>) JacksonJsonUtil.jsonToBean(ms_base_json, Map.class);
257
258           if (baseMap.get("protocol") != null) {
259             protocol = baseMap.get("protocol");
260             if ("PORTAL".equalsIgnoreCase(protocol)) {
261               protocol = "HTTP";
262             }
263             
264             if (isNeedNotifyByProtocol(protocol)) {
265               protocolFilter=true;
266             }
267
268           }
269
270           
271
272           continue;
273         }
274
275         // 提取命名空间属性tag
276         if (!namespaceFilter && tag.startsWith("\"ns\"")) {
277           String ms_ns_json = tag.split("\"ns\":")[1];
278           Map<String, String> nsMap =
279               (Map<String, String>) JacksonJsonUtil.jsonToBean(ms_ns_json, Map.class);
280
281           if (nsMap.get("namespace") != null) {
282             namespace = nsMap.get("namespace");
283             hasnamespace=true;
284             
285             if (isNeedNotifyByNameSpace(namespace)) {
286               namespaceFilter=true;
287             }
288           }
289
290           
291           continue;
292         }
293
294         // 提取Label属性tag
295         if (tag.startsWith("\"labels\"")) {
296           String ms_labels_json = "{" + tag.split("\"labels\":\\{")[1];
297           // 自定义label标签属性
298           Map<String, String> labelMap =
299               (Map<String, String>) JacksonJsonUtil.jsonToBean(ms_labels_json, Map.class);
300
301        
302             
303             if (!visualRangeFilter && labelMap.get("visualRange") != null) {
304               visualRange = labelMap.get("visualRange");
305               labelMap.remove("visualRange"); // 自定义标签排除可见范围和网络平面
306         
307             if(isNeedNotifyByVisualRange(visualRange)){
308               visualRangeFilter=true;
309             }
310           }  
311           
312
313           if (labelMap.get("network_plane_type") != null) {
314             network_plane_type = labelMap.get("network_plane_type");
315             labelMap.remove("network_plane_type");
316           }
317           if (!isNeedNotifyByNetwork_plane_typeMatches(network_plane_type)) {
318             return false;
319           }
320
321           if (!isNeedNotifyByRouteLabels(labelMap)) {
322             return false;
323           }
324
325           continue;
326         }
327
328       }
329
330       //针对无命名空间的服务判断是否过滤
331       if (!hasnamespace && isNeedNotifyByNameSpace(namespace)) {
332         namespaceFilter=true;
333       }
334
335       return visualRangeFilter && protocolFilter && namespaceFilter;
336
337
338     } catch (Exception e) {
339       LOGGER.error(" read tag  throw exception", e);
340       return false;
341     }
342
343
344   }
345   
346
347
348   @SuppressWarnings("unchecked")
349   public Map<String, MicroServiceFullInfo> transMicroServiceInfoFromConsul(
350       List<ServiceHealth> serviceNodeList) {
351     // 同名多版本服务MAP
352     Map<String, MicroServiceFullInfo> microServiceInfo4version =
353         new HashMap<String, MicroServiceFullInfo>();
354
355
356     for (ServiceHealth serviceNode : serviceNodeList) {
357
358       MicroServiceFullInfo microServiceInfo = new MicroServiceFullInfo();
359       String url = "";
360       String version = "", visualRange = "", protocol = "", lb_policy = "", namespace =
361           "", host = "", path = "", publish_port = "";
362       boolean enable_ssl = false;
363
364       HashSet<Node> nodes = new HashSet<Node>();
365
366       Service service = serviceNode.getService();
367       String serviceName = service.getService();
368
369       try {
370         List<String> tagList = service.getTags();
371
372         for (String tag : tagList) {
373
374           if (tag.startsWith("\"base\"")) {
375             String ms_base_json = tag.split("\"base\":")[1];
376
377
378             Map<String, String> baseMap =
379                 (Map<String, String>) JacksonJsonUtil.jsonToBean(ms_base_json, Map.class);
380             if (baseMap.get("url") != null) {
381               url = baseMap.get("url");
382             }
383
384             if (baseMap.get("version") != null) {
385               version = baseMap.get("version");
386             }
387
388             if (baseMap.get("protocol") != null) {
389               protocol = baseMap.get("protocol");
390             }
391
392             if (baseMap.get("host") != null) {
393               host = baseMap.get("host");
394             }
395
396             if (baseMap.get("path") != null) {
397               path = baseMap.get("path");
398             }
399
400             if (baseMap.get("publish_port") != null) {
401               publish_port = baseMap.get("publish_port");
402             }
403
404
405             if (baseMap.get("enable_ssl") != null) {
406               enable_ssl = Boolean.valueOf(baseMap.get("enable_ssl"));
407             }
408
409             continue;
410           }
411
412
413
414           if (tag.startsWith("\"ns\"")) {
415             String ms_ns_json = tag.split("\"ns\":")[1];
416             Map<String, String> nsMap =
417                 (Map<String, String>) JacksonJsonUtil.jsonToBean(ms_ns_json, Map.class);
418
419             if (nsMap.get("namespace") != null) {
420               namespace = nsMap.get("namespace");
421             }
422
423             continue;
424           }
425
426           if (tag.startsWith("\"labels\"")) {
427             String ms_labels_json = "{" + tag.split("\"labels\":\\{")[1];
428             Map<String, String> labelMap =
429                 (Map<String, String>) JacksonJsonUtil.jsonToBean(ms_labels_json, Map.class);
430
431
432             if (labelMap.get("visualRange") != null) {
433               visualRange = labelMap.get("visualRange");
434             }
435
436             /*if (labelMap.get("network_plane_type") != null) {
437               network_plane_type = labelMap.get("network_plane_type");
438             }*/
439
440             continue;
441           }
442
443           if (tag.startsWith("\"lb\"")) {
444             String ms_lb_json = tag.split("\"lb\":")[1];
445             Map<String, String> lbMap =
446                 (Map<String, String>) JacksonJsonUtil.jsonToBean(ms_lb_json, Map.class);
447
448             if (lbMap.get("lb_policy") != null) {
449               lb_policy = lbMap.get("lb_policy");
450             }
451             continue;
452           }
453
454         }
455
456
457
458       } catch (Exception e) {
459         LOGGER.error(serviceName + " read tag  throw exception", e);
460       }
461
462       if (!microServiceInfo4version.containsKey(version)) {
463
464         if ("PORTAL".equalsIgnoreCase(protocol)) {
465           protocol = "HTTP";
466           microServiceInfo.setCustom(RouteUtil.CUSTOM_PORTAL);
467         }
468
469         microServiceInfo.setProtocol(protocol);
470         microServiceInfo.setUrl(url);
471         microServiceInfo.setServiceName(serviceName);
472         microServiceInfo.setLb_policy(lb_policy);
473         microServiceInfo.setVisualRange(visualRange);
474
475         microServiceInfo.setEnable_ssl(enable_ssl);
476         microServiceInfo.setVersion(version);
477         microServiceInfo.setNamespace(namespace);
478         microServiceInfo.setHost(host);
479         microServiceInfo.setPath(path);
480         //系统间apigateway 保存publish_port
481         if ("0".equals(ConfigUtil.getInstance().getVisualRangeMatches())) {
482           microServiceInfo.setPublish_port(publish_port);
483         }
484
485         nodes.add(new Node(service.getAddress(), String.valueOf(service.getPort())));
486         microServiceInfo.setNodes(nodes);
487
488         microServiceInfo4version.put(version, microServiceInfo);
489       } else {
490
491         Set<Node> newNodes = microServiceInfo4version.get(version).getNodes();
492         // 默认node是注册信息的IP和port
493         newNodes.add(new Node(service.getAddress(), String.valueOf(service.getPort())));
494
495         // 同名多版本同步
496         microServiceInfo4version.get(version).setNodes(newNodes);
497
498       }
499
500
501       /*
502        * // 健康检查信息 List<Check> checks = value.getChecks(); node.setStatus("passing"); for (Check
503        * check : checks) { if (!"passing".equals(check.getStatus())) {
504        * node.setStatus(check.getStatus()); break; } }
505        */
506
507
508
509     }
510
511     return microServiceInfo4version;
512
513   }
514
515 }