aboutsummaryrefslogtreecommitdiffstats
path: root/app/app/config_binding_service
diff options
context:
space:
mode:
Diffstat (limited to 'app/app/config_binding_service')
-rw-r--r--app/app/config_binding_service/__init__.py46
-rw-r--r--app/app/config_binding_service/client.py297
-rw-r--r--app/app/config_binding_service/controller.py108
-rw-r--r--app/app/config_binding_service/logging.py204
-rw-r--r--app/app/config_binding_service/openapi.yaml112
5 files changed, 0 insertions, 767 deletions
diff --git a/app/app/config_binding_service/__init__.py b/app/app/config_binding_service/__init__.py
deleted file mode 100644
index 306a762..0000000
--- a/app/app/config_binding_service/__init__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# ============LICENSE_START=======================================================
-# Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-
-import os
-import connexion
-
-
-class BadEnviornmentENVNotFound(Exception):
- """
- Specific exception to be raised when a required ENV varaible is missing
- """
- pass
-
-
-def get_consul_uri():
- """
- This method waterfalls reads an envioronmental variable called CONSUL_HOST
- If that doesn't work, it raises an Exception
- """
- if "CONSUL_HOST" in os.environ:
- # WARNING! TODO! Currently the env file does not include the port.
- # But some other people think that the port should be a part of that.
- # For now, I'm hardcoding 8500 until this gets resolved.
- return "http://{0}:{1}".format(os.environ["CONSUL_HOST"], 8500)
- else:
- raise BadEnviornmentENVNotFound("CONSUL_HOST")
-
-
-# this has to be here due to circular dependency
-app = connexion.App(__name__, specification_dir='.')
-app.add_api('openapi.yaml', arguments={'title': 'Config Binding Service'})
diff --git a/app/app/config_binding_service/client.py b/app/app/config_binding_service/client.py
deleted file mode 100644
index c6a6753..0000000
--- a/app/app/config_binding_service/client.py
+++ /dev/null
@@ -1,297 +0,0 @@
-# ============LICENSE_START=======================================================
-# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-
-import re
-from functools import partial, reduce
-import base64
-import copy
-import json
-import requests
-import six
-from config_binding_service import get_consul_uri
-from config_binding_service.logging import utc, metrics
-
-
-CONSUL = get_consul_uri()
-
-template_match_rels = re.compile("\{{2}([^\}\{]*)\}{2}")
-template_match_dmaap = re.compile("<{2}([^><]*)>{2}")
-
-###
-# Cusom Exception
-###
-
-
-class CantGetConfig(Exception):
- """
- Represents an exception where a required key in consul isn't there
- """
-
- def __init__(self, code, response):
- self.code = code
- self.response = response
-
-
-class BadRequest(Exception):
- """
- Exception to be raised when the user tried to do something they shouldn't
- """
-
- def __init__(self, response):
- self.code = 400
- self.response = response
-
-
-###
-# Private Functions
-###
-
-
-def _consul_get_all_as_transaction(service_component_name, raw_request, xer):
- """
- Use Consul's transaction API to get all keys of the form service_component_name:*
- Return a dict with all the values decoded
- """
- payload = [
- {
- "KV": {
- "Verb": "get-tree",
- "Key": service_component_name,
- }
- }]
-
- bts = utc()
- response = requests.put("{0}/v1/txn".format(CONSUL), json=payload)
- metrics(raw_request, bts, xer, "Consul", "/v1/txn".format(service_component_name), response.status_code, __name__, msg="Retrieving Consul transaction for all keys for {0}".format(service_component_name))
-
- try:
- response.raise_for_status()
- except requests.exceptions.HTTPError as exc:
- raise CantGetConfig(exc.response.status_code, exc.response.text)
-
- result = json.loads(response.text)['Results']
-
- new_res = {}
- for res in result:
- key = res["KV"]["Key"]
- val = base64.b64decode(res["KV"]["Value"]).decode("utf-8")
- try:
- new_res[key] = json.loads(val)
- except json.decoder.JSONDecodeError:
- new_res[key] = "INVALID JSON" # TODO, should we just include the original value somehow?
-
- if service_component_name not in new_res:
- raise CantGetConfig(404, "")
-
- return new_res
-
-
-def _get_config_rels_dmaap(service_component_name, raw_request, xer):
- allk = _consul_get_all_as_transaction(service_component_name, raw_request, xer)
- config = allk[service_component_name]
- rels = allk.get(service_component_name + ":rels", [])
- dmaap = allk.get(service_component_name + ":dmaap", {})
- return config, rels, dmaap
-
-
-def _get_connection_info_from_consul(service_component_name):
- """
- Call consul's catalog
- TODO: currently assumes there is only one service
-
- DEPRECATION NOTE:
- This function existed when DCAE was using Consul to resolve service component's connection information.
- This relied on a "rels" key and a Cloudify relationship plugin to set up the magic.
- The consensous is that this feature is no longer used.
- This functionality is very likely deprecated by Kubernetes service discovery mechanism, and DMaaP.
-
- This function also includes logic related to CDAP, which is also likely deprecated.
-
- This code shall remain here for now but is at risk of being deleted in a future release.
- """
- # Note: there should be a metrics log here, but see the deprecation note above; this function is due to be deleted.
- res = requests.get("{0}/v1/catalog/service/{1}".format(CONSUL, service_component_name))
- res.raise_for_status()
- services = res.json()
- if services == []:
- return None # later will get filtered out
- ip_addr = services[0]["ServiceAddress"]
- port = services[0]["ServicePort"]
-
- if "cdap_app" in service_component_name:
- redirectish_url = "http://{0}:{1}/application/{2}".format(ip_addr, port, service_component_name)
- res = requests.get(redirectish_url)
- res.raise_for_status()
- details = res.json()
- # Pick out the details to expose to the component developers. These keys come from the broker API
- return {key: details[key] for key in ["connectionurl", "serviceendpoints"]}
- return "{0}:{1}".format(ip_addr, port)
-
-
-def _replace_rels_template(rels, template_identifier):
- """
- The magic. Replaces a template identifier {{...}} with the entrie(s) from the rels keys
- NOTE: There was a discussion over whether the CBS should treat {{}} as invalid. Mike asked that
- it resolve to the empty list. So, it does resolve it to empty list.
- """
- returnl = []
- for rel in rels:
- if template_identifier in rel and template_identifier != "":
- returnl.append(rel)
- # returnl now contains a list of DNS names (possible empty), now resolve them (or not if they are not regustered)
- return list(filter(lambda x: x is not None, map(_get_connection_info_from_consul, returnl)))
-
-
-def _replace_dmaap_template(dmaap, template_identifier):
- """
- This one liner could have been just put inline in the caller but maybe this will get more complex in future
- Talked to Mike, default value if key is not found in dmaap key should be {}
- """
- return {} if (template_identifier not in dmaap or template_identifier == "<<>>") else dmaap[template_identifier]
-
-
-def _replace_value(v, rels, dmaap):
- """
- Takes a value v that was some value in the templatized configuration, determines whether it needs replacement (either {{}} or <<>>), and if so, replaces it.
- Otherwise just returns v
-
- implementation notes:
- - the split below sees if we have v = x,y,z... so we can support {{x,y,z,....}}
- - the lambda is because we can't fold operators in Python, wanted fold(+, L) where + when applied to lists in python is list concatenation
- """
- if isinstance(v, six.string_types): # do not try to replace anything that is not a string
- match_on_rels = re.match(template_match_rels, v)
- if match_on_rels:
- # now holds just x,.. of {{x,...}}
- template_identifier = match_on_rels.groups()[0].strip()
- rtpartial = partial(_replace_rels_template, rels)
- return reduce(lambda a, b: a + b, map(rtpartial, template_identifier.split(",")), [])
- match_on_dmaap = re.match(template_match_dmaap, v)
- if match_on_dmaap:
- template_identifier = match_on_dmaap.groups()[0].strip()
- """
- Here is what Mike said:
- 1) want simple replacement of "<< >>" with dmaap key value
- 2) never need to support <<f1,f2>> whereas we do support {{sct1,sct2}}
- The consequence is that if you give the CBS a dmaap key like {"foo" : {...}} you are going to get back {...}, but rels always returns [...].
- So now component developers have to possible handle dicts and [], and we have to communicate that to them
- """
- return _replace_dmaap_template(dmaap, template_identifier)
- return v # was not a match or was not a string, return value as is
-
-
-def _recurse(config, rels, dmaap):
- """
- Recurse throug a configuration, or recursively a sub elemebt of it.
- If it's a dict: recurse over all the values
- If it's a list: recurse over all the values
- If it's a string: return the replacement
- If none of the above, just return the item.
- """
- if isinstance(config, list):
- return [_recurse(item, rels, dmaap) for item in config]
- if isinstance(config, dict):
- for key in config:
- config[key] = _recurse(config[key], rels, dmaap)
- return config
- if isinstance(config, six.string_types):
- return _replace_value(config, rels, dmaap)
- # not a dict, not a list, not a string, nothing to do.
- return config
-
-
-#########
-# PUBLIC API
-#########
-
-
-def resolve(service_component_name, raw_request, xer):
- """
- Return the bound config of service_component_name
-
- raw_request and xer are needed to form the correct metrics log
- """
- config, rels, dmaap = _get_config_rels_dmaap(service_component_name, raw_request, xer)
- return _recurse(config, rels, dmaap)
-
-
-def resolve_override(config, rels=[], dmaap={}):
- """
- Explicitly take in a config, rels, dmaap and try to resolve it.
- Useful for testing where you dont want to put the test values in consul
- """
- # use deepcopy to make sure that config is not touched
- return _recurse(copy.deepcopy(config), rels, dmaap)
-
-
-def resolve_all(service_component_name, raw_request, xer):
- """
- Return config, policies, and any other k such that service_component_name:k exists (other than :dmaap and :rels)
-
- raw_request and xer are needed to form the correct metrics log
- """
- allk = _consul_get_all_as_transaction(service_component_name, raw_request, xer)
- returnk = {}
-
- # replace the config with the resolved config
- returnk["config"] = resolve_override(allk[service_component_name],
- allk.get("{0}:rels".format(service_component_name), []),
- allk.get("{0}:dmaap".format(service_component_name), {}))
-
- # concatenate the items
- for k in allk:
- if "policies" in k:
- if "policies" not in returnk:
- returnk["policies"] = {}
- returnk["policies"]["event"] = {}
- returnk["policies"]["items"] = []
-
- if k.endswith(":policies/event"):
- returnk["policies"]["event"] = allk[k]
- elif ":policies/items" in k:
- returnk["policies"]["items"].append(allk[k])
- else:
- if not(k == service_component_name or k.endswith(":rels") or k.endswith(":dmaap")):
- # this would blow up if you had a key in consul without a : but this shouldnt happen
- suffix = k.split(":")[1]
- returnk[suffix] = allk[k]
-
- return returnk
-
-
-def get_key(key, service_component_name, raw_request, xer):
- """
- Try to fetch a key k from Consul of the form service_component_name:k
-
- raw_request and xer are needed to form the correct metrics log
- """
- if key == "policies":
- raise BadRequest(
- ":policies is a complex folder and should be retrieved using the service_component_all API")
-
- bts = utc()
- path = "v1/kv/{0}:{1}".format(service_component_name, key)
- response = requests.get("{0}/{1}".format(CONSUL, path))
- metrics(raw_request, bts, xer, "Consul", path, response.status_code, __name__, msg="Retrieving single Consul key {0} for {1}".format(key, service_component_name))
-
- try:
- response.raise_for_status()
- except requests.exceptions.HTTPError as exc:
- raise CantGetConfig(exc.response.status_code, exc.response.text)
- rest = json.loads(response.text)[0]
- return json.loads(base64.b64decode(rest["Value"]).decode("utf-8"))
diff --git a/app/app/config_binding_service/controller.py b/app/app/config_binding_service/controller.py
deleted file mode 100644
index c2eb21c..0000000
--- a/app/app/config_binding_service/controller.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# ============LICENSE_START=======================================================
-# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-
-import json
-import requests
-import connexion
-import uuid
-from flask import Response
-from config_binding_service import client, get_consul_uri
-from config_binding_service.logging import audit, utc, error, metrics
-
-
-def _get_helper(json_expecting_func, **kwargs):
- """
- Helper function used by several functions below
- """
- try:
- payload = json_expecting_func(**kwargs)
- response, status_code, mimetype = json.dumps(payload), 200, "application/json"
- except client.BadRequest as exc:
- response, status_code, mimetype = exc.response, exc.code, "text/plain"
- except client.CantGetConfig as exc:
- response, status_code, mimetype = exc.response, exc.code, "text/plain"
- except Exception:
- response, status_code, mimetype = "Unknown error", 500, "text/plain"
- return response, status_code, mimetype
-
-
-def _get_or_generate_xer(raw_request):
- """get or generate the transaction id"""
- xer = raw_request.headers.get("x-onap-requestid", None)
- if xer is None:
- # some components are still using the old name
- xer = raw_request.headers.get("x-ecomp-requestid", None)
- if xer is None:
- # the user did NOT supply a request id, generate one
- xer = str(uuid.uuid4())
- return xer
-
-
-def bind_all(service_component_name):
- """
- Get all the keys in Consul for this SCN, and bind the config
- """
- xer = _get_or_generate_xer(connexion.request)
- bts = utc()
- response, status_code, mimetype = _get_helper(client.resolve_all, service_component_name=service_component_name, raw_request=connexion.request, xer=xer)
- audit(connexion.request, bts, xer, status_code, __name__, "called for component {0}".format(service_component_name))
- # Even though some older components might be using the ecomp name, we return the proper one
- return Response(response=response, status=status_code, mimetype=mimetype, headers={"x-onap-requestid": xer})
-
-
-def bind_config_for_scn(service_component_name):
- """
- Bind just the config for this SCN
- """
- xer = _get_or_generate_xer(connexion.request)
- bts = utc()
- response, status_code, mimetype = _get_helper(client.resolve, service_component_name=service_component_name, raw_request=connexion.request, xer=xer)
- audit(connexion.request, bts, xer, status_code, __name__, "called for component {0}".format(service_component_name))
- return Response(response=response, status=status_code, mimetype=mimetype, headers={"x-onap-requestid": xer})
-
-
-def get_key(key, service_component_name):
- """
- Get a single key k of the form service_component_name:k from Consul.
- Should not be used and will return a BAD REQUEST for k=policies because it's a complex object
- """
- xer = _get_or_generate_xer(connexion.request)
- bts = utc()
- response, status_code, mimetype = _get_helper(client.get_key, key=key, service_component_name=service_component_name, raw_request=connexion.request, xer=xer)
- audit(connexion.request, bts, xer, status_code, __name__, "called for component {0}".format(service_component_name))
- return Response(response=response, status=status_code, mimetype=mimetype, headers={"x-onap-requestid": xer})
-
-
-def healthcheck():
- """
- CBS Healthcheck
- """
- xer = _get_or_generate_xer(connexion.request)
- path = "v1/catalog/service/config_binding_service"
- bts = utc()
- res = requests.get("{0}/{1}".format(get_consul_uri(), path))
- status = res.status_code
- if status == 200:
- msg = "CBS is alive and Consul connection OK"
- else:
- msg = "CBS is alive but cannot reach Consul"
- # treating this as a WARN because this could be a temporary network glitch. Also per EELF guidelines this is a 200 ecode (availability)
- error(connexion.request, xer, "WARN", 200, tgt_entity="Consul", tgt_path="/v1/catalog/service/config_binding_service", msg=msg)
- metrics(connexion.request, bts, xer, "Consul", path, res.status_code, __name__, msg="Checking Consul connectivity during CBS healthcheck, {0}".format(msg))
- audit(connexion.request, bts, xer, status, __name__, msg=msg)
- return Response(response=msg, status=status)
diff --git a/app/app/config_binding_service/logging.py b/app/app/config_binding_service/logging.py
deleted file mode 100644
index b6275a7..0000000
--- a/app/app/config_binding_service/logging.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# ============LICENSE_START=======================================================
-# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
-# ================================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-
-from logging import getLogger, Formatter
-from logging.handlers import RotatingFileHandler
-from os import makedirs
-import datetime
-
-
-_AUDIT_LOGGER = getLogger("defaultlogger")
-_ERROR_LOGGER = getLogger("defaultlogger")
-_METRICS_LOGGER = getLogger("defaultlogger")
-
-
-def _create_logger(name, logfile):
- """
- Create a RotatingFileHandler and a streamhandler for stdout
- https://docs.python.org/3/library/logging.handlers.html
- what's with the non-pythonic naming in these stdlib methods? Shameful.
- """
- logger = getLogger(name)
- file_handler = RotatingFileHandler(logfile,
- maxBytes=10000000, backupCount=2) # 10 meg with one backup..
- formatter = Formatter('%(message)s')
- file_handler.setFormatter(formatter)
- logger.setLevel("DEBUG")
- logger.addHandler(file_handler)
- return logger
-
-
-def create_loggers():
- """
- Public method to set the global logger, launched from Run
- This is *not* launched during unit testing, so unit tests do not create/write log files
- """
- makedirs("/opt/logs", exist_ok=True)
-
- # create the audit log
- aud_file = "/opt/logs/audit.log"
- open(aud_file, 'a').close() # this is like "touch"
- global _AUDIT_LOGGER
- _AUDIT_LOGGER = _create_logger("config_binding_service_audit", aud_file)
-
- # create the error log
- err_file = "/opt/logs/error.log"
- open(err_file, 'a').close() # this is like "touch"
- global _ERROR_LOGGER
- _ERROR_LOGGER = _create_logger("config_binding_service_error", err_file)
-
- # create the metrics log
- met_file = "/opt/logs/metrics.log"
- open(met_file, 'a').close() # this is like "touch"
- global _METRICS_LOGGER
- _METRICS_LOGGER = _create_logger("config_binding_service_metrics", met_file)
-
-
-def utc():
- """gets current time in utc"""
- return datetime.datetime.utcnow()
-
-
-def audit(raw_request, bts, xer, rcode, calling_mod, msg="n/a"):
- """
- write an EELF audit record per https://wiki.onap.org/download/attachments/1015849/ONAP%20application%20logging%20guidelines.pdf?api=v2
- %The audit fields implemented:
-
- 1 BeginTimestamp Implemented (bts)
- 2 EndTimestamp Auto Injected when this is called
- 3 RequestID Implemented (xer)
- 5 threadId n/a
- 7 serviceName Implemented (from Req)
- 9 StatusCode Auto injected based on rcode
- 10 ResponseCode Implemented (rcode)
- 13 Category log level - all audit records are INFO.
- 15 Server IP address Implemented (from Req)
- 16 ElapsedTime Auto Injected (milliseconds)
- 17 Server This is running in a Docker container so this is not applicable, my HOSTNAME is always "config_binding_service"
- 18 ClientIPaddress Implemented (from Req)
- 19 class name Implemented (mod), though docs say OOP, I am using the python module here
- 20 Unused ...implemented....
- 21-25 Custom n/a
- 26 detailMessage Implemented (msg)
-
- Not implemented
- 4 serviceInstanceID - ?
- 6 physical/virtual server name (Optional)
- 8 PartnerName - nothing in the request tells me this
- 11 Response Description - the CBS follows standard HTTP error codes so look them up
- 12 instanceUUID - Optional
- 14 Severity (Optional)
- """
- ets = utc()
-
- _AUDIT_LOGGER.info("{bts}|{ets}|{xer}||n/a||{path}||{status}|{rcode}|||INFO||{servip}|{et}|config_binding_service|{clientip}|{calling_mod}|||||||{msg}".format(
- bts=bts.isoformat(),
- ets=ets.isoformat(),
- xer=xer, rcode=rcode,
- path=raw_request.path.split("/")[1],
- status="COMPLETE" if rcode < 400 else "ERROR",
- servip=raw_request.host.split(":")[0],
- et=int((ets - bts).microseconds / 1000), # supposed to be in milleseconds
- clientip=raw_request.remote_addr,
- calling_mod=calling_mod, msg=msg
- ))
-
-
-def error(raw_request, xer, severity, ecode, tgt_entity="n/a", tgt_path="n/a", msg="n/a", adv_msg="n/a"):
- """
- write an EELF error record per
- the error fields implemented:
-
- 1 Timestamp Auto Injected when this is called
- 2 RequestID Implemented (xer)
- 3 ThreadID n/a
- 4 ServiceName Implemented (from Req)
- 6 TargetEntity Implemented (tgt_entity)
- 7 TargetServiceName Implemented (tgt_path)/
- 8 ErrorCategory Implemented (severity)
- 9. ErrorCode Implemented (ecode)
- 10 ErrorDescription Implemented (msg)
- 11. detailMessage Implemented (adv_msg)
-
- Not implemented:
- 5 PartnerName - nothing in the request tells me this
- """
- ets = utc()
-
- _ERROR_LOGGER.error("{ets}|{xer}|n/a|{path}||{tge}|{tgp}|{sev}|{ecode}|{msg}|{amsg}".format(
- ets=ets,
- xer=xer,
- path=raw_request.path.split("/")[1],
- tge=tgt_entity,
- tgp=tgt_path,
- sev=severity,
- ecode=ecode,
- msg=msg,
- amsg=adv_msg))
-
-
-def metrics(raw_request, bts, xer, target, target_path, rcode, calling_mod, msg="n/a"):
- """
- write an EELF metrics record per https://wiki.onap.org/download/attachments/1015849/ONAP%20application%20logging%20guidelines.pdf?api=v2
- %The metrics fields implemented:
-
- 1 BeginTimestamp Implemented (bts)
- 2 EndTimestamp Auto Injected when this is called
- 3 RequestID Implemented (xer)
- 5 threadId n/a
- 7 serviceName Implemented (from Req)
- 9 TargetEntity Implemented (target)
- 10 TargetServiceName Implemented (target_path)
- 11 StatusCode Implemented (based on rcode)
- 12 Response Code Implemented (rcode)
- 15 Category log level all metrics records are INFO.
- 17 Server IP address Implemented (from Req)
- 18 ElapsedTime Auto Injected (milliseconds)
- 19 Server This is running in a Docker container so this is not applicable, my HOSTNAME is always "config_binding_service"
- 20 ClientIPaddress Implemented (from Req)
- 21 class name Implemented (mod), though docs say OOP, I am using the python module here
- 22 Unused ...implemented....
- 24 TargetVirtualEntity n/a
- 25-28 Custom n/a
- 29 detailMessage Implemented (msg)
-
- Not implemented
- 4 serviceInstanceID - ?
- 6 physical/virtual server name (Optional)
- 8 PartnerName - nothing in the request tells me this
- 13 Response Description - the CBS follows standard HTTP error codes so look them up
- 14 instanceUUID - Optional
- 16 Severity (Optional)
- 23 ProcessKey - optional
- """
- ets = utc()
-
- _METRICS_LOGGER.info("{bts}|{ets}|{xer}||n/a||{path}||{tge}|{tgp}|{status}|{rcode}|||INFO||{servip}|{et}|config_binding_service|{clientip}|{calling_mod}|||n/a|||||{msg}".format(
- bts=bts.isoformat(),
- ets=ets.isoformat(),
- xer=xer,
- path=raw_request.path.split("/")[1],
- tge=target,
- tgp=target_path,
- status="COMPLETE" if rcode < 400 else "ERROR",
- rcode=rcode,
- servip=raw_request.host.split(":")[0],
- et=int((ets - bts).microseconds / 1000), # supposed to be in milleseconds
- clientip=raw_request.remote_addr,
- calling_mod=calling_mod, msg=msg
- ))
diff --git a/app/app/config_binding_service/openapi.yaml b/app/app/config_binding_service/openapi.yaml
deleted file mode 100644
index bc4dd49..0000000
--- a/app/app/config_binding_service/openapi.yaml
+++ /dev/null
@@ -1,112 +0,0 @@
-openapi: 3.0.0
-info:
- version: 2.3.0
- title: Config Binding Service
-paths:
- '/service_component/{service_component_name}':
- parameters:
- - name: service_component_name
- in: path
- description: >-
- Service Component Name. service_component_name must be a key in
- consul.
- required: true
- schema:
- type: string
- get:
- description: >-
- Binds the configuration for service_component_name and returns the bound
- configuration as a JSON
- operationId: config_binding_service.controller.bind_config_for_scn
- responses:
- '200':
- description: OK; the bound config is returned as an object
- content:
- '*/*':
- schema:
- type: object
- '404':
- description: there is no configuration in Consul for this component
- '/service_component_all/{service_component_name}':
- parameters:
- - name: service_component_name
- in: path
- description: >-
- Service Component Name. service_component_name must be a key in
- consul.
- required: true
- schema:
- type: string
- get:
- description: >-
- Binds the configuration for service_component_name and returns the bound
- configuration, policies, and any other keys that are in Consul
- operationId: config_binding_service.controller.bind_all
- responses:
- '200':
- description: >-
- OK; returns {config : ..., policies : ....., k : ...} for all other
- k in Consul
- content:
- '*/*':
- schema:
- type: object
- '404':
- description: there is no configuration in Consul for this component
- '/{key}/{service_component_name}':
- parameters:
- - name: key
- in: path
- description: >-
- this endpoint tries to pull service_component_name:key; key is the key
- after the colon
- required: true
- schema:
- type: string
- - name: service_component_name
- in: path
- description: Service Component Name.
- required: true
- schema:
- type: string
- get:
- description: >-
- this is an endpoint that fetches a generic service_component_name:key
- out of Consul. The idea is that we don't want to tie components to
- Consul directly in case we swap out the backend some day, so the CBS
- abstracts Consul from clients. The structuring and weird collision of
- this new API with the above is unfortunate but due to legacy concerns.
- operationId: config_binding_service.controller.get_key
- responses:
- '200':
- description: 'OK; returns service_component_name:key'
- content:
- '*/*':
- schema:
- type: object
- '400':
- description: >-
- bad request. Currently this is only returned on :policies, which is
- a complex object, and should be gotten through service_component_all
- content:
- '*/*':
- schema:
- type: string
- '404':
- description: key does not exist
- content:
- '*/*':
- schema:
- type: string
- /healthcheck:
- get:
- description: >-
- This is the health check endpoint. If this returns a 200, the server is
- alive and consul can be reached. If not a 200, either dead, or no
- connection to consul
- operationId: config_binding_service.controller.healthcheck
- responses:
- '200':
- description: Successful response
- '503':
- description: the config binding service cannot reach Consul