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