summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTommy Carpenter <tommy@research.att.com>2018-02-15 13:14:33 -0500
committerTommy Carpenter <tommy@research.att.com>2018-02-15 14:50:29 -0500
commit857c41af07fd88b50c2e960071611f425268e486 (patch)
tree6c70be46b3f7e04e6df5b56369a068814a6f5d51
parente2f8b1019b0c64747d2dca8801f1c0c9b2fbb12a (diff)
Add DTI and Policy to ONAP CBS
Issue-ID: DCAEGEN2-341 Change-Id: Iead3b6568ec379988b840b5a01c7744c29b5fcf4 Signed-off-by: Tommy Carpenter <tommy@research.att.com>
-rw-r--r--Changelog.md17
-rw-r--r--Dockerfile1
-rw-r--r--README.md31
-rwxr-xr-xbin/run.py7
-rw-r--r--config_binding_service/__init__.py12
-rw-r--r--config_binding_service/client.py65
-rw-r--r--config_binding_service/controller.py40
-rw-r--r--config_binding_service/swagger/swagger.yaml44
-rw-r--r--pom.xml4
-rw-r--r--setup.py18
-rw-r--r--tests/test_binding.py72
11 files changed, 241 insertions, 70 deletions
diff --git a/Changelog.md b/Changelog.md
index 9985855..4a8ea05 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,13 +1,20 @@
# Change Log
All notable changes to this project will be documented in this file.
-The format is based on [Keep a Changelog](http://keepachangelog.com/)
+The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+## [1.3.0]
+* Sync ONAP with Internal CBS
+* Add tests (Currently 62%)
+* Update docker python version to 3.6
+* Move installation of reqs into Docker container
+
## [1.2.0]
-* Remove waterfalled CONSUL_HOST
+* Remove waterfalled CONSUL_HOST
* Add ONAP liscenses
* Remove references to specific telco and it's IPs in tests
+* [Internal version conflict]: Add dti and policies endpoints
## [1.1.0]
* Add a healthcheck endpoint
@@ -15,11 +22,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.0.1]
* Fix {{}} to resolve to [] instead of whatever is in rels key
-* Remove all impure tests. All tests are now unit tests.
+* Remove all impure tests. All tests are now unit tests.
## [1.0.0]
-* GLORIOUS CHANGE! At some point, CASK fixed a bug where if you sent a configuration JSON to CDAP that contained a value that was not a string, it would blow up. This allows me to remove the endpoint specific to CDAP components so the same endpoint is now used for Docker and CDAP.
-* Props to Terry Troutman for helping me discover this.
+* GLORIOUS CHANGE! At some point, CASK fixed a bug where if you sent a configuration JSON to CDAP that contained a value that was not a string, it would blow up. This allows me to remove the endpoint specific to CDAP components so the same endpoint is now used for Docker and CDAP.
+* Props to Terry Troutman for helping me discover this.
* Removes some impure tests. Still some impurity there
## [0.9.0]
diff --git a/Dockerfile b/Dockerfile
index 1163e9f..6ae7150 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,6 +7,7 @@ ADD . /tmp
RUN pip install --upgrade pip
#do the install
WORKDIR /tmp
+RUN pip install -r requirements.txt
RUN pip install -e .
EXPOSE 10000
diff --git a/README.md b/README.md
index 39c740b..e430e22 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,35 @@
# config_binding_service
-# Interface Diagram
+# Interface Diagram
This repo is the thing in red:
![Alt text](doc/cbs_diagram.png?raw=true)
-# Overview
+# Overview
DCAE has a "templating language" built into components' configurations, as explained further below.
The orchestrator populates one/two keys (depending on the blueprint) into Consul that are used to *bind* component configurations config, a "rels key" and a "dmaap key".
-If component A wants to connect to a component of type B, then A's rels key holds what specific service component name of B that A should connect to over direct HTTP.
-Service component name here means the full name that the component of type B is registered under in Consul (there can be multiple components of type B registered in Consul).
-The CBS (config binding service) then pulls down that rels key, fetches the connection information about that B (IP:Port), and replaces it into A's config.
+If component A wants to connect to a component of type B, then A's rels key holds what specific service component name of B that A should connect to over direct HTTP.
+Service component name here means the full name that the component of type B is registered under in Consul (there can be multiple components of type B registered in Consul).
+The CBS (config binding service) then pulls down that rels key, fetches the connection information about that B (IP:Port), and replaces it into A's config.
There is also a "dmaap key", which is the same concept, except what gets injected is a JSON of DMaaP connection information instead of an IP:Port.
+In addition, this service provides the capability to retrieve either the DTI events (not history) or the policies for a given service_component.
+
# Usage
hit `url_of_this/service_component/service_component_name` and you are returned your bound config.
+hit `url_of_this/dtievents/service_component_name` and you are returned the dti events for your service_component.
+
+hit `url_of_this/policies/service_component_name` and you are returned the policies for your service_component.
+
(Note: there is also a backdoor in the `client` module that allows you to pass in a direct JSON and a direct rels, but this isn't exposed via the HTTP API as of now)
# Assumptions
1. `CONSUL_HOST` is set as an environmental variable where this binding service is run. If it is not, it defaults to the Rework Consul which is probably not what you want.
2. `service_component_name` is in consul as a key and holds the config
-3. `service_component_name:rel` is in consul as a key *if* you are expecting a direct HTTP resolution, and holds the service component names of connections.
-4. `service_component_name:dmaap` is in consul *if* you are expecting a DMaaP resolution, and holds the components DMaaP information.
+3. `service_component_name:rel` is in consul as a key *if* you are expecting a direct HTTP resolution, and holds the service component names of connections.
+4. `service_component_name:dmaap` is in consul *if* you are expecting a DMaaP resolution, and holds the components DMaaP information.
# Templating Language
The CBS tries to resolve a component's configuration with a templating language. We have two templating languages embedded in our component's configuration (`{{...}}` and `<<...>>`). There are two because the CBS has to be able to distinguish between a rels-key-resolve and a dmaap-key-resolve. That is, if component X is trying to bind their component, and they want to talk to Y, someone has to tell the CBS whether they are trying to talk via IP:port or a feed.
@@ -39,7 +45,14 @@ X's configuration:
}
```
-# Tests And Test Coverage
+# Testing
+You need tox:
```
-tox -c tox-local.ini
+pip install tox
```
+Then from the root dir, *not in a virtual env*, just run:
+```
+tox
+```
+You may have to alter the tox.ini for the python envs you wish to test with.
+
diff --git a/bin/run.py b/bin/run.py
index d32960f..2a4f4ce 100755
--- a/bin/run.py
+++ b/bin/run.py
@@ -1,7 +1,9 @@
#!/usr/bin/env python3
+# ============LICENSE_START=======================================================
+# org.onap.dcae
# ================================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# 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.
@@ -18,7 +20,6 @@
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-
import connexion
import sys
from config_binding_service import get_logger
@@ -29,6 +30,6 @@ if __name__ == '__main__':
try:
app = connexion.App(__name__, specification_dir='../config_binding_service/swagger/')
app.add_api('swagger.yaml', arguments={'title': 'Config Binding Service'})
- app.run(host='0.0.0.0', port=10000, debug=False)
+ app.run(host='0.0.0.0', port=10000, debug=False)
except Exception as e:
_logger.error("Fatal error. Could not start webserver due to: {0}".format(e))
diff --git a/config_binding_service/__init__.py b/config_binding_service/__init__.py
index 51d3246..c50f47f 100644
--- a/config_binding_service/__init__.py
+++ b/config_binding_service/__init__.py
@@ -1,14 +1,14 @@
# ============LICENSE_START=======================================================
# org.onap.dcae
# ================================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# 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
-#
+#
+# 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.
@@ -17,6 +17,7 @@
# ============LICENSE_END=========================================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
import os
import logging
@@ -45,8 +46,9 @@ def get_consul_uri():
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.
+ # 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")
+
diff --git a/config_binding_service/client.py b/config_binding_service/client.py
index 02354ee..6b53996 100644
--- a/config_binding_service/client.py
+++ b/config_binding_service/client.py
@@ -1,14 +1,14 @@
# ============LICENSE_START=======================================================
# org.onap.dcae
# ================================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# 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
-#
+#
+# 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.
@@ -17,6 +17,7 @@
# ============LICENSE_END=========================================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
import re
import requests
import copy
@@ -44,7 +45,7 @@ class CantGetConfig(Exception):
###
def _consul_get_key(key):
"""
- Try to fetch a key from Consul.
+ Try to fetch a key from Consul.
No error checking here, let caller deal with it
"""
_logger.info("Fetching {0}".format(key))
@@ -78,7 +79,7 @@ def _get_connection_info_from_consul(service_component_name):
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.
+ 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))
@@ -87,7 +88,7 @@ def _get_connection_info_from_consul(service_component_name):
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:
+ else:
ip = services[0]["ServiceAddress"]
port = services[0]["ServicePort"]
if "cdap_app" in service_component_name:
@@ -100,11 +101,11 @@ def _get_connection_info_from_consul(service_component_name):
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
+ 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 = []
@@ -125,7 +126,7 @@ 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
@@ -150,16 +151,24 @@ def _replace_value(v, rels, dmaap):
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
+ """
+ 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]
+ elif isinstance(config,dict):
+ for key in config:
+ config[key] = _recurse(config[key], rels, dmaap)
+ return config
+ elif isinstance(config, six.string_types):
+ return _replace_value(config, rels, dmaap)
+ else:
+ #not a dict, not a list, not a string, nothing to do.
+ return config
#########
# PUBLIC API
@@ -179,3 +188,19 @@ def resolve_override(config, rels=[], dmaap={}):
"""
#use deepcopy to make sure that config is not touched
return _recurse(copy.deepcopy(config), rels, dmaap)
+
+def resolve_DTI(service_component_name):
+ try:
+ config = _consul_get_key("{}:dti".format(service_component_name))
+ 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)
+ return config
+
+def resolve_policies(service_component_name):
+ try:
+ config = _consul_get_key("{}:policies".format(service_component_name))
+ 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)
+ return config
diff --git a/config_binding_service/controller.py b/config_binding_service/controller.py
index a74d60f..ec6f05e 100644
--- a/config_binding_service/controller.py
+++ b/config_binding_service/controller.py
@@ -1,14 +1,14 @@
# ============LICENSE_START=======================================================
# org.onap.dcae
# ================================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# 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
-#
+#
+# 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.
@@ -17,16 +17,46 @@
# ============LICENSE_END=========================================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
from config_binding_service import client, get_consul_uri, get_logger
import requests
from flask import request, Response
import json
+_logger = get_logger(__name__)
+
+def dtievents(service_component_name):
+ try:
+ dti = client.resolve_DTI(service_component_name)
+ return Response(response=json.dumps(dti),
+ status=200,
+ mimetype="application/json")
+ except client.CantGetConfig as e:
+ return Response(status=e.code,
+ response=e.response)
+ except Exception as e:
+ _logger.error(e)
+ return Response(response="Unknown error: please report",
+ status=500)
+
+def policies(service_component_name):
+ try:
+ dti = client.resolve_policies(service_component_name)
+ return Response(response=json.dumps(dti),
+ status=200,
+ mimetype="application/json")
+ except client.CantGetConfig as e:
+ return Response(status=e.code,
+ response=e.response)
+ except Exception as e:
+ _logger.error(e)
+ return Response(response="Unknown error: please report",
+ status=500)
def bind_config_for_scn(service_component_name):
try:
bound = client.resolve(service_component_name)
return Response(response=json.dumps(bound),
- status=200,
+ status=200,
mimetype="application/json")
except client.CantGetConfig as e:
return Response(status=e.code,
diff --git a/config_binding_service/swagger/swagger.yaml b/config_binding_service/swagger/swagger.yaml
index ecedb75..31fc42a 100644
--- a/config_binding_service/swagger/swagger.yaml
+++ b/config_binding_service/swagger/swagger.yaml
@@ -1,5 +1,7 @@
+# ============LICENSE_START=======================================================
+# org.onap.dcae
# ================================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# 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.
@@ -15,10 +17,12 @@
# ============LICENSE_END=========================================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+
---
swagger: "2.0"
info:
- version: "1.0.0"
+ version: "1.3.0"
title: "Config Binding Service"
paths:
/service_component/{service_component_name}:
@@ -34,10 +38,44 @@ paths:
responses:
200:
description: OK; the bound config is returned as an object
- schema:
+ schema:
type: object
404:
description: there is no configuration in Consul for this component
+ /dti/{service_component_name}:
+ parameters:
+ - name: "service_component_name"
+ in: "path"
+ description: "Service Component Name. service_component_name:dti must be a key in consul."
+ required: true
+ type: "string"
+ get:
+ description: "Returns as JSON the value for service_component_name:dti"
+ operationId: "config_binding_service.controller.dtievents"
+ responses:
+ 200:
+ description: OK; the KV value is returned as an object
+ schema:
+ type: object
+ 404:
+ description: there is no configuration in Consul for this component's DTI events
+ /policies/{service_component_name}:
+ parameters:
+ - name: "service_component_name"
+ in: "path"
+ description: "Service Component Name. service_component_name:policies must be a key in consul."
+ required: true
+ type: "string"
+ get:
+ description: "Returns as JSON the value for service_component_name:policies"
+ operationId: "config_binding_service.controller.policies"
+ responses:
+ 200:
+ description: OK; the KV value is returned as an object
+ schema:
+ type: object
+ 404:
+ description: there is no configuration in Consul for this component's policies
/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"
diff --git a/pom.xml b/pom.xml
index d5755ec..f8c1452 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property.
<sonar.skip>false</sonar.skip>
<sonar.sources>.</sonar.sources>
<sonar.junit.reportspath>xunit-reports/xunit-result-configbinding.xml</sonar.junit.reportspath>
- <!--
+ <!--
<sonar.python.coverage.reportpath>coverage.xml</sonar.python.coverage.reportpath>
see https://docs.sonarqube.org/display/plug/python+coverage+results+import
ant pattern describing the path to coverage reports, relative to projects root. leave unset to use the default ("coverage-reports/coverage-*.xml").
@@ -111,7 +111,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property.
</execution>
</executions>
</plugin>
- <!-- maven-install-plugin is called during "install" phase by default behavior. it tries to copy stuff under
+ <!-- maven-install-plugin is called during "install" phase by default behavior. it tries to copy stuff under
target dir to ~/.m2. we do not need it -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
diff --git a/setup.py b/setup.py
index cc28a43..b57713c 100644
--- a/setup.py
+++ b/setup.py
@@ -1,14 +1,14 @@
# ============LICENSE_START=======================================================
# org.onap.dcae
# ================================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# 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
-#
+#
+# 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.
@@ -17,24 +17,22 @@
# ============LICENSE_END=========================================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
import os
from setuptools import setup, find_packages
from pip.req import parse_requirements
from pip.download import PipSession
-import pip
-pip.main(['install','-r','requirements.txt'])
-
setup(
name='config_binding_service',
- version='1.2.0',
+ version='1.3.0',
packages=find_packages(),
author = "Tommy Carpenter",
- author_email = "tommy at research dot a t t dot com",
+ author_email = "tommy@research.att.com",
description='Service to fetch and bind configurations',
license = "",
keywords = "",
- url = "ONAP URL TBD",
+ url = "https://gerrit.onap.org/r/#/admin/projects/dcaegen2/platform/configbinding",
zip_safe=False,
scripts = ["bin/run.py"]
)
diff --git a/tests/test_binding.py b/tests/test_binding.py
index 3bbe5d9..60c0809 100644
--- a/tests/test_binding.py
+++ b/tests/test_binding.py
@@ -1,14 +1,14 @@
# ============LICENSE_START=======================================================
# org.onap.dcae
# ================================================================================
-# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# 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
-#
+#
+# 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.
@@ -17,9 +17,12 @@
# ============LICENSE_END=========================================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-from config_binding_service import client
+
+from config_binding_service import client, controller
import pytest
import json
+from requests.exceptions import HTTPError, RequestException
+from requests import Response
def monkeyed_get_connection_info_from_consul(service_component_name):
#shared monkeypatch. probably somewhat lazy because the function htis patches can be broken up.
@@ -38,6 +41,46 @@ def monkeyed_get_connection_info_from_consul(service_component_name):
broker_port = 444
return "http://{0}:{1}/application/{2}".format(broker_ip, broker_port, service_component_name)
+class FakeResponse():
+ def __init__(self, status_code, text):
+ self.text = text
+ self.status_code = status_code
+
+def monkeyed_consul_get_key(k):
+ if k == "dti_exists_test:dti":
+ return {"foo" : "bar"}
+ elif k == "dti_NOTexists_test:dti":
+ raise HTTPError(response = FakeResponse(text= "", status_code = 404))
+ elif k == "policies_exists_test:policies":
+ return {"foo2" : "bar2"}
+ elif k == "policies_NOTexists_test:policies":
+ raise HTTPError(response = FakeResponse(text= "", status_code = 404))
+
+def test_dti_policies(monkeypatch):
+ monkeypatch.setattr('config_binding_service.client._consul_get_key', monkeyed_consul_get_key)
+
+ assert client.resolve_DTI("dti_exists_test") == {"foo" : "bar"}
+ with pytest.raises(client.CantGetConfig):
+ client.resolve_DTI("dti_NOTexists_test")
+
+ R = controller.dtievents("dti_exists_test")
+ assert(json.loads(R.data) == {"foo" : "bar"})
+ assert(R.status_code == 200)
+
+ R = controller.dtievents("dti_NOTexists_test")
+ assert(R.status_code == 404)
+
+ assert client.resolve_policies("policies_exists_test") == {"foo2" : "bar2"}
+ with pytest.raises(client.CantGetConfig):
+ client.resolve_policies("policies_NOTexists_test")
+
+ R = controller.policies("policies_exists_test")
+ assert(json.loads(R.data) == {"foo2" : "bar2"})
+ assert(R.status_code == 200)
+
+ R = controller.policies("policies_NOTexists_test")
+ assert(R.status_code == 404)
+
def test_bad_config_http():
test_config = {'yeahhhhh' : "{{}}"}
test_rels = ["testing_bravo.somedomain.com"]
@@ -56,6 +99,19 @@ def test_config(monkeypatch):
test_bind_1 = client.resolve_override(test_config, test_rels)
assert test_bind_1 == {'autoderegisterafter': '10m', 'cdap_to_manage': {'some_nested_thing': ['666.666.666.666:666']}, 'bindingttw': 5, 'hcinterval': '5s'}
+def test_config_with_list(monkeypatch):
+ monkeypatch.setattr('config_binding_service.client._get_connection_info_from_consul', monkeyed_get_connection_info_from_consul)
+ test_config_1 = {"dcae_target_type": ["vhss-ems", "pcrf-oam"], "downstream-laika": "{{ laika }}", "some-param": "Lorem ipsum dolor sit amet"}
+ test_rels_1 = ["3df5292249ae4a949f173063617cea8d_docker-snmp-polling-firstnet-m"]
+ test_bind_1 = client.resolve_override(test_config_1, test_rels_1, {})
+ assert(test_bind_1 == {'dcae_target_type': ['vhss-ems', 'pcrf-oam'], 'downstream-laika': [], 'some-param': 'Lorem ipsum dolor sit amet'})
+
+ test_config_2 = {"foo" : ["{{cdap}}", "notouching", "<<yo>>"]}
+ test_rels_2 = ["cdap"]
+ test_dmaap_2={"yo" : "im here"}
+ test_bind_2 = client.resolve_override(test_config_2, test_rels_2, test_dmaap_2)
+ assert(test_bind_2 == {"foo" : [['666.666.666.666:666'], "notouching", "im here"]})
+
def test_non_existent(monkeypatch):
#test a valid config-rels but the key is not in Consul
monkeypatch.setattr('config_binding_service.client._get_connection_info_from_consul', monkeyed_get_connection_info_from_consul)
@@ -68,7 +124,7 @@ def test_cdap(monkeypatch):
#user override to test CDAP functionality
monkeypatch.setattr('config_binding_service.client._get_connection_info_from_consul', monkeyed_get_connection_info_from_consul)
test_rels = ["testing_alpha.somedomain.com", "testing_bravo.somedomain.com", "testing_charlie.somedomain.com", "testing_charlie.somedomain.com", "cdap"]
- test_config = { "streams_publishes" : "{{alpha}}",
+ test_config = { "streams_publishes" : "{{alpha}}",
"services_calls" : [{"somekey" : "{{charlie}}"}], #should be dumped
"cdap_to_manage": {'some_nested_thing' : "{{cdap}}"} #no dumps
}
@@ -98,7 +154,7 @@ def test_multiple_service_types(monkeypatch):
config2 = {"two there one not exist" : "{{alpha,bravo,notexist}}"}
test_bind_2 = client.resolve_override(config2, test_rels)
assert(test_bind_2 == {"two there one not exist" : ['6.6.6.6:666', '7.7.7.7:777']})
-
+
#test 3: two resolve, one is in rels key but not registered
config3 = {"two there one unregistered" : "{{alpha,bravo,unregistered}}"}
test_rels3 = ["testing_alpha.somedomain.com", "testing_bravo.somedomain.com", "unregistered.somedomain.com"]
@@ -114,7 +170,7 @@ def test_dmaap(monkeypatch):
#matches
test_bind_2 = client.resolve_override(config, dmaap={"XXX" : "ABSOLVEME"})
assert(test_bind_2 == {"TODAY IS YOUR LUCKY DAY" : "ABSOLVEME"})
-
+
def test_both(monkeypatch):
#test rels and http