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