1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# config_binding_service
============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.
# Changelog
All changes are logged in Changelog.md
# 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.
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
See the Swagger spec.
# 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.
# 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.
Specifically, if the CBS sees:
```
X's configuration:
{
...
config_key : << F >> // will try to resolve via X:dmaap and look for F
config_key : {{ F }} // will try to resolve via X:rels and look for F
}
```
# A note about directory structure
This project uses https://hub.docker.com/r/tiangolo/uwsgi-nginx-flask/
This is a solution that runs a productionalized setup using NGINX+uwsgi+Flask (Flask is not meant to be run as a real webserver per their docs). This project requires the app/app structure. Tox still works from the root due to tox magic.
This structure, combined with Sonar limitations, leads to an unfortunate need of having three nested poms. There is a top level pom, a tiny pom in /app, and the "main" pom in /app/app.
# Development
## Version changes
An unforunate consequence of the nested poms is that development changes require a version bump in several places. They are:
1. Changelod.md
2. version.properties
3. top level pom
4. pom in /app
5. pom in /app/app
6. setup.py in /app/app
Additionally, if the development leads to an API change,
7. openapi.yaml in /app/app/config_binding_service
## Testing
You need `tox`.
To recreate the tox that the ONAP build process calls, from /app/app, *not in a virtual env*, just run:
```
tox
```
For local development, there is a tox that outputs to an html website that is easier to read and navigate then xml. From the *root*, run
```
tox -c tox-local.ini
```
# Deployment
## Ports, HTTPS key/cert location
The CBS frontend (NGINX) exposes 10000 and 443. It runs HTTP on 10000 and HTTPS on 443. 80 is also exposed by the parent Dockerfile but nothing is listening there so it can be ignored.
The dockerimage mounts it's own self signed certificate. If deploying into a production level scenario, *you should overwrite this cert!*! It expects a key to be mounted at `/etc/nginx/ssl/nginx.key` and a cert to be mounted at `/etc/nginx/ssl/nginx.crt`. For example, a snippet from a `docker run` command:
```
... -v /host/path/to/nginx.key:/etc/nginx/ssl/nginx.key -v /host/path/to/nginx.crt:/etc/nginx/ssl/nginx.crt ...
```
These ports can be mapped to whatever extnernally. To keep the legacy behavior of prior ONAP releases of HTTP on 10000, map 10000:10000. Or, you can now make 10000 HTTPS by mapping 10000:443. This is determined by the deployment blueprint.
## Non-K8, Registrator, Consul setup
This section only pertains to a very specific setup of using Registrator and Consul (registrator to register a Consul healthcheck, and relying on Consul health checking). This section does *not* pertain to a Kubernetes deployment that uses K8 "readiness probes" instead of Consul.
There is a combination of issues, rooting from a bug in registrator:
1. https://jira.onap.org/browse/DCAEGEN2-482
2. https://github.com/gliderlabs/registrator/issues/605
That causes the Consul registration to be suffixed with ports, breaking the expected service name (`config_binding_service`), **even if** those ports are not mapped externally. That is, even if only one of the two ports (10000,443) is mapped, due to the above-linked bug, the service name will be wrong in Consul.
The solution is to run the container with a series of ENV variables. If you want the healthchecks to go over HTTPS, you also need to run the latest version on `master` in registrator. The old (3 year old) release of `v7` does not allow for HTTPS healthchecks. The below example fixes the service name, turns OFF HTTP healthchecks, and turns ON HTTPS healthchecks (only works with latest registrator):
```
ENV SERVICE_10000_IGNORE true
ENV SERVICE_443_NAME config_binding_service
ENV SERVICE_443_CHECK_HTTPS /healthcheck
ENV SERVICE_443_CHECK_INTERVAL 15s
```
E.g., in Docker run terminology:
```
... -e SERVICE_10000_IGNORE=true -e SERVICE_443_NAME=config_binding_service -e SERVICE_443_CHECK_HTTPS=/healthcheck -e SERVICE_443_CHECK_INTERVAL=15s ...
```
If you wish to turn ON HTTP healthchecks and turn OFF HTTPS healthchecks, swith 10000 and 443 above. That will work even with `v7` of registrator (that is, `SERVICE_x_CHECK_HTTP` was already supported)
## Running locally for development (no docker)
It is recommended that you do this step in a virtualenv.
(set -x is Fish notaion, change for Bash etc. accordingly)
```
pip install --ignore-installed .; set -x CONSUL_HOST <YOUR_HOST>; ./main.py
```
|