aboutsummaryrefslogtreecommitdiffstats
path: root/config_binding_service/client.py
diff options
context:
space:
mode:
Diffstat (limited to 'config_binding_service/client.py')
-rw-r--r--config_binding_service/client.py181
1 files changed, 0 insertions, 181 deletions
diff --git a/config_binding_service/client.py b/config_binding_service/client.py
deleted file mode 100644
index 02354ee..0000000
--- a/config_binding_service/client.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# ============LICENSE_START=======================================================
-# org.onap.dcae
-# ================================================================================
-# Copyright (c) 2017 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
-import requests
-import copy
-import base64
-import json
-import six
-from config_binding_service import get_consul_uri, get_logger
-from functools import partial, reduce
-
-_logger = get_logger(__name__)
-CONSUL = get_consul_uri()
-
-template_match_rels = re.compile("\{{2}([^\}\{]*)\}{2}")
-template_match_dmaap = re.compile("<{2}([^><]*)>{2}")
-
-###
-# Cusom Exception
-###
-class CantGetConfig(Exception):
- def __init__(self, code, response):
- self.code = code
- self.response = response
-###
-# Private Functions
-###
-def _consul_get_key(key):
- """
- Try to fetch a key from Consul.
- No error checking here, let caller deal with it
- """
- _logger.info("Fetching {0}".format(key))
- response = requests.get("{0}/v1/kv/{1}".format(CONSUL, key))
- response.raise_for_status()
- D = json.loads(response.text)[0]
- return json.loads(base64.b64decode(D["Value"]).decode("utf-8"))
-
-def _get_config_rels_dmaap(service_component_name):
- try:
- config = _consul_get_key(service_component_name) #not ok if no config
- except requests.exceptions.HTTPError as e:
- #might be a 404, or could be not even able to reach consul (503?), bubble up the requests error
- raise CantGetConfig(e.response.status_code, e.response.text)
-
- rels = []
- dmaap = {}
- try: #Not all nodes have relationships, so catch the error here and return [] if so
- rels = _consul_get_key("{0}:rel".format(service_component_name))
- except requests.exceptions.HTTPError: #ok if no rels key, might just have dmaap key
- pass
- try:
- dmaap = _consul_get_key("{0}:dmaap".format(service_component_name))
- except requests.exceptions.HTTPError: #ok if no dmaap key
- pass
- 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
-
- TODO: WARNING: FIXTHIS: CALLINTHENATIONALARMY:
- This tries to determine that a service_component_name is a cdap application by inspecting service_component_name and name munging. However, this would force all CDAP applications to have cdap_app in their name. A much better way to do this is to do some kind of catalog_lookup here, OR MAYBE change this API so that the component_type is passed in somehow. THis is a gaping TODO.
- """
- _logger.info("Retrieving connection information for {0}".format(service_component_name))
- res = requests.get("{0}/v1/catalog/service/{1}".format(CONSUL, service_component_name))
- res.raise_for_status()
- services = res.json()
- if services == []:
- _logger.info("Warning: config and rels keys were both valid, but there is no component named {0} registered in Consul!".format(service_component_name))
- return None #later will get filtered out
- else:
- ip = services[0]["ServiceAddress"]
- port = services[0]["ServicePort"]
- if "cdap_app" in service_component_name:
- redirectish_url = "http://{0}:{1}/application/{2}".format(ip, port, service_component_name)
- _logger.info("component is a CDAP application; trying the broker redirect on {0}".format(redirectish_url))
- r = requests.get(redirectish_url)
- r.raise_for_status()
- details = r.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"] }
- else:
- return "{0}:{1}".format(ip, 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 r in rels:
- if template_identifier in r and template_identifier is not "":
- returnl.append(r)
- #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:
- template_identifier = match_on_rels.groups()[0].strip() #now holds just x,.. of {{x,...}}
- 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):
- for key in config:
- v = config[key]
- if isinstance(v, list):
- replacement = [_recurse(item, rels, dmaap) for item in v]
- elif isinstance(v,dict):
- replacement = _recurse(v, rels, dmaap)
- else:
- replacement = _replace_value(config[key], rels, dmaap)
- config[key] = replacement
- return config
-
-#########
-# PUBLIC API
-#########
-def resolve(service_component_name):
- """
- Return the bound config of service_component_name
- """
- config, rels, dmaap = _get_config_rels_dmaap(service_component_name)
- _logger.info("Fetching {0}: config={1}, rels={2}".format(service_component_name, json.dumps(config), rels))
- 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)