Merge "Add OTI event-handler project"
[dcaegen2/platform.git] / oti / event-handler / otihandler / config.py
1 # ================================================================================
2 # Copyright (c) 2019-2020 AT&T Intellectual Property. All rights reserved.
3 # ================================================================================
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
17 """read and use the config"""
18
19 import copy
20 import json
21 import logging
22 import logging.config
23 import os
24
25 from otihandler.consul_client import ConsulClient
26
27 logging.basicConfig(
28     filename='logs/oti_handler.log', \
29     format='%(asctime)s.%(msecs)03d %(levelname)+8s ' + \
30            '%(threadName)s %(name)s.%(funcName)s: %(message)s', \
31     datefmt='%Y%m%d_%H%M%S', level=logging.DEBUG)
32
33 class Config(object):
34     """main config of the application"""
35
36     CONFIG_FILE_PATH = "etc/config.json"
37     LOGGER_CONFIG_FILE_PATH = "etc/common_logger.config"
38     SERVICE_NAME = "oti_handler"
39
40     FIELD_SYSTEM = "system"
41     FIELD_WSERVICE_PORT = "wservice_port"
42     FIELD_TLS = "tls"
43
44     _logger = logging.getLogger("oti_handler.config")
45     config = None
46
47     cloudify_proto = None
48     cloudify_addr = None
49     cloudify_port = None
50     cloudify_user = None
51     cloudify_pass = None
52     cloudify = None
53     consul_url = "http://consul:8500"
54     tls_cacert_file = None
55     tls_server_cert_file = None
56     tls_private_key_file = None
57     tls_server_ca_chain_file = None
58     wservice_port = 9443
59
60     @staticmethod
61     def _get_tls_file_path(tls_config, cert_directory, tls_name):
62         """calc file path and verify its existance"""
63
64         file_name = tls_config.get(tls_name)
65         if not file_name:
66             return None
67         tls_file_path = os.path.join(cert_directory, file_name)
68         if not os.path.isfile(tls_file_path) or not os.access(tls_file_path, os.R_OK):
69             Config._logger.error("invalid %s: %s", tls_name, tls_file_path)
70             return None
71         return tls_file_path
72
73     @staticmethod
74     def _set_tls_config(tls_config):
75         """verify and set tls certs in config"""
76
77         try:
78             Config.tls_cacert_file = None
79             Config.tls_server_cert_file = None
80             Config.tls_private_key_file = None
81             Config.tls_server_ca_chain_file = None
82
83             if not (tls_config and isinstance(tls_config, dict)):
84                 Config._logger.info("no tls in config: %s", json.dumps(tls_config))
85                 return
86
87             cert_directory = tls_config.get("cert_directory")
88
89             if not (cert_directory and isinstance(cert_directory, str)):
90                 Config._logger.warning("unexpected tls.cert_directory: %r", cert_directory)
91                 return
92
93             cert_directory = os.path.join(
94                 os.path.dirname(os.path.dirname(os.path.realpath(__file__))), str(cert_directory))
95             if not (cert_directory and os.path.isdir(cert_directory)):
96                 Config._logger.warning("ignoring invalid cert_directory: %s", cert_directory)
97                 return
98
99             Config.tls_cacert_file = Config._get_tls_file_path(tls_config, cert_directory, "cacert")
100             Config.tls_server_cert_file = Config._get_tls_file_path(tls_config, cert_directory,
101                                                                     "server_cert")
102             Config.tls_private_key_file = Config._get_tls_file_path(tls_config, cert_directory,
103                                                                     "private_key")
104             Config.tls_server_ca_chain_file = Config._get_tls_file_path(tls_config, cert_directory,
105                                                                         "server_ca_chain")
106
107         finally:
108             Config._logger.info("tls_cacert_file = %s", Config.tls_cacert_file)
109             Config._logger.info("tls_server_cert_file = %s", Config.tls_server_cert_file)
110             Config._logger.info("tls_private_key_file = %s", Config.tls_private_key_file)
111             Config._logger.info("tls_server_ca_chain_file = %s", Config.tls_server_ca_chain_file)
112
113     @staticmethod
114     def merge(new_config):
115         """merge the new_config into current config - override the values"""
116
117         if not new_config:
118             return
119
120         if not Config.config:
121             Config.config = new_config
122             return
123
124         new_config = copy.deepcopy(new_config)
125         Config.config.update(new_config)
126
127     @staticmethod
128     def get_system_name():
129         """find the name of the oti_handler system
130         to be used as the key in consul-kv for config of oti_handler
131         """
132
133         return (Config.config or {}).get(Config.FIELD_SYSTEM, Config.SERVICE_NAME)
134
135     @staticmethod
136     def discover():
137         """bring and merge the config settings from Consul"""
138
139         system_key = Config.get_system_name()
140         new_config = ConsulClient.get_value(system_key)
141
142         if not new_config or not isinstance(new_config, dict):
143             Config._logger.warn("unexpected config from Consul: %s", new_config)
144             return
145
146         Config._logger.debug("loaded config from Consul(%s): %s",
147             system_key, json.dumps(new_config))
148         Config._logger.debug("config before merge from Consul: %s", json.dumps(Config.config))
149         Config.merge(new_config.get(Config.SERVICE_NAME))
150         Config._logger.debug("merged config from Consul: %s", json.dumps(Config.config))
151
152     @staticmethod
153     def load_from_file(file_path=None):
154         """read and store the config from config file"""
155
156         if not file_path:
157             file_path = Config.CONFIG_FILE_PATH
158
159         loaded_config = None
160         if os.access(file_path, os.R_OK):
161             with open(file_path, 'r') as config_json:
162                 loaded_config = json.load(config_json)
163
164         if not loaded_config:
165             Config._logger.info("config not loaded from file: %s", file_path)
166             return
167
168         Config._logger.info("config loaded from file: %s", file_path)
169         logging_config = loaded_config.get("logging")
170         if logging_config:
171             logging.config.dictConfig(logging_config)
172
173         Config.wservice_port = loaded_config.get(Config.FIELD_WSERVICE_PORT, Config.wservice_port)
174
175         local_config = loaded_config.get(Config.SERVICE_NAME, {})
176         Config._set_tls_config(local_config.get(Config.FIELD_TLS))
177
178         Config.merge(loaded_config.get(Config.SERVICE_NAME))
179         return True