blob: 83f54ac6bc16fb3a3cb28f1c198bf6653d20696f [file] [log] [blame]
alex_sh9d980ce2017-08-23 17:30:56 -04001# ================================================================================
Alex Shatov9a4d3c52019-04-01 11:32:06 -04002# Copyright (c) 2017-2019 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#
alex_sh9d980ce2017-08-23 17:30:56 -040017
Alex Shatov209f8232018-09-20 15:15:45 -040018"""client to talk to consul services and kv"""
Alex Shatovf53e5e72018-01-11 11:15:56 -050019
alex_sh9d980ce2017-08-23 17:30:56 -040020import base64
Alex Shatovb9b955c2018-03-08 13:12:23 -050021import json
Alex Shatovb9b955c2018-03-08 13:12:23 -050022
alex_sh9d980ce2017-08-23 17:30:56 -040023import requests
24
Alex Shatov209f8232018-09-20 15:15:45 -040025from .config import Config
Alex Shatovb9b955c2018-03-08 13:12:23 -050026from .customize import CustomizerUser
Alex Shatov1d693372018-08-24 13:15:04 -040027from .onap.audit import AuditHttpCode, Metrics
Alex Shatov9a4d3c52019-04-01 11:32:06 -040028from .utils import Utils
Alex Shatov1d693372018-08-24 13:15:04 -040029
Alex Shatov9a4d3c52019-04-01 11:32:06 -040030_LOGGER = Utils.get_logger(__file__)
Alex Shatovb9b955c2018-03-08 13:12:23 -050031
alex_sh9d980ce2017-08-23 17:30:56 -040032class DiscoveryClient(object):
Alex Shatov209f8232018-09-20 15:15:45 -040033 """talking to consul at Config.consul_url
34
35 Config.consul_url is populated
36 from env var $CONSUL_URL
37 if not provided, then from consul_url in etc/config.json
38 if not provided, then from hardcoded value of http://consul:8500
alex_sh9d980ce2017-08-23 17:30:56 -040039
40 relies on proper --add-host "consul:<consul-agent ip>" in
41 docker run command that runs along the consul-agent:
42
43 docker run --name ${APPNAME} -d
Alex Shatov209f8232018-09-20 15:15:45 -040044 -e HOSTNAME -e CONSUL_URL
alex_sh9d980ce2017-08-23 17:30:56 -040045 --add-host "consul:<consul-agent ip>"
46 -v ${BASEDIR}/logs:${TARGETDIR}/logs
47 -v ${BASEDIR}/etc:${TARGETDIR}/etc
48 -p <outport>:<innerport>
49 ${APPNAME}:latest
50 """
Alex Shatov1d693372018-08-24 13:15:04 -040051 CONSUL_ENTITY = "consul"
Alex Shatov209f8232018-09-20 15:15:45 -040052 CONSUL_SERVICE_MASK = "{}/v1/catalog/service/{}"
53 CONSUL_KV_MASK = "{}/v1/kv/{}"
alex_sh9d980ce2017-08-23 17:30:56 -040054
alex_sh9d980ce2017-08-23 17:30:56 -040055 @staticmethod
Alex Shatov1d693372018-08-24 13:15:04 -040056 def _discover_service(audit, service_name, service_path):
57 """find the service record in consul"""
Alex Shatova39f4e82018-12-05 15:23:50 -050058 response = requests.get(service_path, timeout=Config.consul_timeout_in_secs)
Alex Shatov9a4d3c52019-04-01 11:32:06 -040059 _LOGGER.info(audit.info("response {} from {}: {}".format(
Alex Shatov1d693372018-08-24 13:15:04 -040060 response.status_code, service_path, response.text)))
61
62 response.raise_for_status()
63 status_code = response.status_code
64 service = response.json()[0]
65 return (status_code,
66 CustomizerUser.get_customizer().get_service_url(audit, service_name, service))
67
68 @staticmethod
Alex Shatovb9b955c2018-03-08 13:12:23 -050069 def get_service_url(audit, service_name):
alex_sh9d980ce2017-08-23 17:30:56 -040070 """find the service record in consul"""
Alex Shatov209f8232018-09-20 15:15:45 -040071 service_path = DiscoveryClient.CONSUL_SERVICE_MASK.format(Config.consul_url, service_name)
Alex Shatov1d693372018-08-24 13:15:04 -040072 metrics = Metrics(aud_parent=audit, targetEntity=DiscoveryClient.CONSUL_ENTITY,
73 targetServiceName=service_path)
Alex Shatovb9b955c2018-03-08 13:12:23 -050074
Alex Shatov1d693372018-08-24 13:15:04 -040075 log_line = "get from {} at {}".format(DiscoveryClient.CONSUL_ENTITY, service_path)
Alex Shatovb9b955c2018-03-08 13:12:23 -050076
Alex Shatov9a4d3c52019-04-01 11:32:06 -040077 _LOGGER.info(metrics.metrics_start(log_line))
Alex Shatov1d693372018-08-24 13:15:04 -040078 status_code = None
79 try:
80 (status_code,
81 service_url) = DiscoveryClient._discover_service(audit, service_name, service_path)
82 except Exception as ex:
83 error_code = (AuditHttpCode.SERVICE_UNAVAILABLE_ERROR.value
84 if isinstance(ex, requests.exceptions.RequestException)
85 else AuditHttpCode.SERVER_INTERNAL_ERROR.value)
86 error_msg = ("failed {}/{} to {} {}: {}".format(status_code, error_code, log_line,
87 type(ex).__name__, str(ex)))
Alex Shatov9a4d3c52019-04-01 11:32:06 -040088 _LOGGER.exception(error_msg)
Alex Shatov1d693372018-08-24 13:15:04 -040089 metrics.set_http_status_code(error_code)
90 audit.set_http_status_code(error_code)
91 metrics.metrics(error_msg)
92 return None
Alex Shatovb9b955c2018-03-08 13:12:23 -050093
Alex Shatovb9b955c2018-03-08 13:12:23 -050094 if not service_url:
Alex Shatov1d693372018-08-24 13:15:04 -040095 error_code = AuditHttpCode.DATA_ERROR.value
96 error_msg = "failed {}/{} to {}".format(status_code, error_code, log_line)
Alex Shatov9a4d3c52019-04-01 11:32:06 -040097 _LOGGER.error(audit.error(error_msg))
Alex Shatov1d693372018-08-24 13:15:04 -040098 metrics.set_http_status_code(error_code)
99 audit.set_http_status_code(error_code)
100 metrics.metrics(error_msg)
101 return None
Alex Shatovb9b955c2018-03-08 13:12:23 -0500102
Alex Shatov1d693372018-08-24 13:15:04 -0400103 log_line = "response {} {}".format(status_code, log_line)
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400104 _LOGGER.info(audit.info("got service_url: {} after {}".format(service_url, log_line)))
Alex Shatov1d693372018-08-24 13:15:04 -0400105
106 metrics.set_http_status_code(status_code)
107 audit.set_http_status_code(status_code)
108 metrics.metrics(log_line)
Alex Shatovb9b955c2018-03-08 13:12:23 -0500109 return service_url
alex_sh9d980ce2017-08-23 17:30:56 -0400110
111 @staticmethod
Alex Shatov1d693372018-08-24 13:15:04 -0400112 def _get_value_from_kv(url):
113 """get the value from consul-kv at discovery url"""
Alex Shatova39f4e82018-12-05 15:23:50 -0500114 response = requests.get(url, timeout=Config.consul_timeout_in_secs)
alex_sh9d980ce2017-08-23 17:30:56 -0400115 response.raise_for_status()
Alex Shatov1369bea2018-01-10 11:00:50 -0500116 data = response.json()
Alex Shatov1369bea2018-01-10 11:00:50 -0500117 value = base64.b64decode(data[0]["Value"]).decode("utf-8")
Alex Shatov1d693372018-08-24 13:15:04 -0400118 return response.status_code, json.loads(value)
119
120 @staticmethod
121 def get_value(audit, key):
122 """get the value for the key from consul-kv"""
Alex Shatov209f8232018-09-20 15:15:45 -0400123 discovery_url = DiscoveryClient.CONSUL_KV_MASK.format(Config.consul_url, key)
Alex Shatov1d693372018-08-24 13:15:04 -0400124 metrics = Metrics(aud_parent=audit, targetEntity=DiscoveryClient.CONSUL_ENTITY,
125 targetServiceName=discovery_url)
126
127 log_line = "get from {} at {}".format(DiscoveryClient.CONSUL_ENTITY, discovery_url)
128
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400129 _LOGGER.info(metrics.metrics_start(log_line))
Alex Shatova39f4e82018-12-05 15:23:50 -0500130 status_code = None
Alex Shatov1d693372018-08-24 13:15:04 -0400131 try:
132 status_code, value = DiscoveryClient._get_value_from_kv(discovery_url)
133 except Exception as ex:
134 error_code = (AuditHttpCode.SERVICE_UNAVAILABLE_ERROR.value
135 if isinstance(ex, requests.exceptions.RequestException)
136 else AuditHttpCode.SERVER_INTERNAL_ERROR.value)
137 error_msg = ("failed {}/{} to {} {}: {}".format(status_code, error_code, log_line,
138 type(ex).__name__, str(ex)))
Alex Shatov9a4d3c52019-04-01 11:32:06 -0400139 _LOGGER.exception(error_msg)
Alex Shatov1d693372018-08-24 13:15:04 -0400140 metrics.set_http_status_code(error_code)
141 audit.set_http_status_code(error_code)
142 metrics.metrics(error_msg)
143 return None
144
145 log_line = "response {} {}".format(status_code, log_line)
146 metrics.set_http_status_code(status_code)
147 audit.set_http_status_code(status_code)
148 metrics.metrics(log_line)
149 return value