blob: 4e6bc3d11c860205eda685d4848b5b58feaab992 [file] [log] [blame]
alex_sh9d980ce2017-08-23 17:30:56 -04001# ================================================================================
Lusheng Ji967cc9a2018-02-12 10:45:42 -05002# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
alex_sh9d980ce2017-08-23 17:30:56 -04003# ================================================================================
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15# ============LICENSE_END=========================================================
16#
17# ECOMP is a trademark and service mark of AT&T Intellectual Property.
18
Alex Shatovf53e5e72018-01-11 11:15:56 -050019"""client to talk to consul at the standard port 8500"""
20
alex_sh9d980ce2017-08-23 17:30:56 -040021import base64
Alex Shatovb9b955c2018-03-08 13:12:23 -050022import json
23import logging
24
alex_sh9d980ce2017-08-23 17:30:56 -040025import requests
26
Alex Shatovb9b955c2018-03-08 13:12:23 -050027from .customize import CustomizerUser
Alex Shatov1d693372018-08-24 13:15:04 -040028from .onap.audit import AuditHttpCode, Metrics
29
Alex Shatovb9b955c2018-03-08 13:12:23 -050030
alex_sh9d980ce2017-08-23 17:30:56 -040031class DiscoveryClient(object):
32 """talking to consul at http://consul:8500
33
34 relies on proper --add-host "consul:<consul-agent ip>" in
35 docker run command that runs along the consul-agent:
36
37 docker run --name ${APPNAME} -d
38 -e HOSTNAME
39 --add-host "consul:<consul-agent ip>"
40 -v ${BASEDIR}/logs:${TARGETDIR}/logs
41 -v ${BASEDIR}/etc:${TARGETDIR}/etc
42 -p <outport>:<innerport>
43 ${APPNAME}:latest
44 """
Alex Shatov1d693372018-08-24 13:15:04 -040045 CONSUL_ENTITY = "consul"
alex_sh9d980ce2017-08-23 17:30:56 -040046 CONSUL_SERVICE_MASK = "http://consul:8500/v1/catalog/service/{0}"
47 CONSUL_KV_MASK = "http://consul:8500/v1/kv/{0}"
alex_sh9d980ce2017-08-23 17:30:56 -040048 _logger = logging.getLogger("policy_handler.discovery")
49
alex_sh9d980ce2017-08-23 17:30:56 -040050 @staticmethod
Alex Shatov1d693372018-08-24 13:15:04 -040051 def _discover_service(audit, service_name, service_path):
52 """find the service record in consul"""
53 response = requests.get(service_path)
54 DiscoveryClient._logger.info(audit.info("response {} from {}: {}".format(
55 response.status_code, service_path, response.text)))
56
57 response.raise_for_status()
58 status_code = response.status_code
59 service = response.json()[0]
60 return (status_code,
61 CustomizerUser.get_customizer().get_service_url(audit, service_name, service))
62
63 @staticmethod
Alex Shatovb9b955c2018-03-08 13:12:23 -050064 def get_service_url(audit, service_name):
alex_sh9d980ce2017-08-23 17:30:56 -040065 """find the service record in consul"""
66 service_path = DiscoveryClient.CONSUL_SERVICE_MASK.format(service_name)
Alex Shatov1d693372018-08-24 13:15:04 -040067 metrics = Metrics(aud_parent=audit, targetEntity=DiscoveryClient.CONSUL_ENTITY,
68 targetServiceName=service_path)
Alex Shatovb9b955c2018-03-08 13:12:23 -050069
Alex Shatov1d693372018-08-24 13:15:04 -040070 log_line = "get from {} at {}".format(DiscoveryClient.CONSUL_ENTITY, service_path)
Alex Shatovb9b955c2018-03-08 13:12:23 -050071
Alex Shatov1d693372018-08-24 13:15:04 -040072 DiscoveryClient._logger.info(metrics.metrics_start(log_line))
73 status_code = None
74 try:
75 (status_code,
76 service_url) = DiscoveryClient._discover_service(audit, service_name, service_path)
77 except Exception as ex:
78 error_code = (AuditHttpCode.SERVICE_UNAVAILABLE_ERROR.value
79 if isinstance(ex, requests.exceptions.RequestException)
80 else AuditHttpCode.SERVER_INTERNAL_ERROR.value)
81 error_msg = ("failed {}/{} to {} {}: {}".format(status_code, error_code, log_line,
82 type(ex).__name__, str(ex)))
83 DiscoveryClient._logger.exception(error_msg)
84 metrics.set_http_status_code(error_code)
85 audit.set_http_status_code(error_code)
86 metrics.metrics(error_msg)
87 return None
Alex Shatovb9b955c2018-03-08 13:12:23 -050088
Alex Shatovb9b955c2018-03-08 13:12:23 -050089 if not service_url:
Alex Shatov1d693372018-08-24 13:15:04 -040090 error_code = AuditHttpCode.DATA_ERROR.value
91 error_msg = "failed {}/{} to {}".format(status_code, error_code, log_line)
92 DiscoveryClient._logger.error(audit.error(error_msg))
93 metrics.set_http_status_code(error_code)
94 audit.set_http_status_code(error_code)
95 metrics.metrics(error_msg)
96 return None
Alex Shatovb9b955c2018-03-08 13:12:23 -050097
Alex Shatov1d693372018-08-24 13:15:04 -040098 log_line = "response {} {}".format(status_code, log_line)
99 DiscoveryClient._logger.info(audit.info("got service_url: {} after {}"
100 .format(service_url, log_line)))
101
102 metrics.set_http_status_code(status_code)
103 audit.set_http_status_code(status_code)
104 metrics.metrics(log_line)
Alex Shatovb9b955c2018-03-08 13:12:23 -0500105 return service_url
alex_sh9d980ce2017-08-23 17:30:56 -0400106
107 @staticmethod
Alex Shatov1d693372018-08-24 13:15:04 -0400108 def _get_value_from_kv(url):
109 """get the value from consul-kv at discovery url"""
110 response = requests.get(url)
alex_sh9d980ce2017-08-23 17:30:56 -0400111 response.raise_for_status()
Alex Shatov1369bea2018-01-10 11:00:50 -0500112 data = response.json()
Alex Shatov1369bea2018-01-10 11:00:50 -0500113 value = base64.b64decode(data[0]["Value"]).decode("utf-8")
Alex Shatov1d693372018-08-24 13:15:04 -0400114 return response.status_code, json.loads(value)
115
116 @staticmethod
117 def get_value(audit, key):
118 """get the value for the key from consul-kv"""
119 discovery_url = DiscoveryClient.CONSUL_KV_MASK.format(key)
120 metrics = Metrics(aud_parent=audit, targetEntity=DiscoveryClient.CONSUL_ENTITY,
121 targetServiceName=discovery_url)
122
123 log_line = "get from {} at {}".format(DiscoveryClient.CONSUL_ENTITY, discovery_url)
124
125 DiscoveryClient._logger.info(metrics.metrics_start(log_line))
126 try:
127 status_code, value = DiscoveryClient._get_value_from_kv(discovery_url)
128 except Exception as ex:
129 error_code = (AuditHttpCode.SERVICE_UNAVAILABLE_ERROR.value
130 if isinstance(ex, requests.exceptions.RequestException)
131 else AuditHttpCode.SERVER_INTERNAL_ERROR.value)
132 error_msg = ("failed {}/{} to {} {}: {}".format(status_code, error_code, log_line,
133 type(ex).__name__, str(ex)))
134 DiscoveryClient._logger.exception(error_msg)
135 metrics.set_http_status_code(error_code)
136 audit.set_http_status_code(error_code)
137 metrics.metrics(error_msg)
138 return None
139
140 log_line = "response {} {}".format(status_code, log_line)
141 metrics.set_http_status_code(status_code)
142 audit.set_http_status_code(status_code)
143 metrics.metrics(log_line)
144 return value