blob: 6c6f196f58c5ff09caa8dfab24001bb3e00e6c42 [file] [log] [blame]
Mark Beierl821bfc92023-01-24 21:15:25 -05001#!/usr/bin/python3
2# -*- coding: utf-8 -*-
3
4##
Mark Beierl821bfc92023-01-24 21:15:25 -05005#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17##
18
Mark Beierl821bfc92023-01-24 21:15:25 -050019import asyncio
20import getopt
21import logging
22import logging.handlers
23import sys
24import yaml
25
Mark Beierl821bfc92023-01-24 21:15:25 -050026from osm_common.dbbase import DbException
Patricia Reinoso02a39fd2023-03-08 17:13:56 +000027from osm_common.temporal_constants import LCM_TASK_QUEUE
Mark Beierl821bfc92023-01-24 21:15:25 -050028from osm_lcm.data_utils.database.database import Database
29from osm_lcm.data_utils.lcm_config import LcmCfg
Patricia Reinoso199fbfc2023-03-02 08:53:58 +000030from osm_lcm.lcm_utils import LcmException
Mark Beierl821bfc92023-01-24 21:15:25 -050031from os import path
Patricia Reinoso02a39fd2023-03-08 17:13:56 +000032from osm_lcm.temporal.vim_activities import VimDbActivity, JujuPaasConnector
33from osm_lcm.temporal.vim_workflows import (
34 VimCreateWorkflow,
35 VimDeleteWorkflow,
36 VimUpdateWorkflow,
37)
Mark Beierl821bfc92023-01-24 21:15:25 -050038from temporalio.client import Client
39from temporalio.worker import Worker
40
41
42class NGLcm:
Mark Beierl821bfc92023-01-24 21:15:25 -050043 main_config = LcmCfg()
44
Patricia Reinoso199fbfc2023-03-02 08:53:58 +000045 def __init__(self, config_file):
Mark Beierl821bfc92023-01-24 21:15:25 -050046 """
47 Init, Connect to database, filesystem storage, and messaging
Patricia Reinoso199fbfc2023-03-02 08:53:58 +000048 :param config_file: two level dictionary with configuration. Top level should contain 'database', 'storage',
Mark Beierl821bfc92023-01-24 21:15:25 -050049 :return: None
50 """
51 self.db = None
Mark Beierl821bfc92023-01-24 21:15:25 -050052 self.logger = logging.getLogger("lcm")
Patricia Reinoso199fbfc2023-03-02 08:53:58 +000053 self._load_configuration(config_file)
54 self._configure_logging()
Mark Beierl821bfc92023-01-24 21:15:25 -050055
56 try:
57 self.db = Database(self.main_config.to_dict()).instance.db
Mark Beierl90f700d2023-02-09 15:01:33 -050058 except DbException as e:
Mark Beierl821bfc92023-01-24 21:15:25 -050059 self.logger.critical(str(e), exc_info=True)
60 raise LcmException(str(e))
61
Patricia Reinoso199fbfc2023-03-02 08:53:58 +000062 def _load_configuration(self, config_file):
63 config = self._read_config_file(config_file)
64 self.main_config.set_from_dict(config)
65 self.main_config.transform()
66 self.main_config.load_from_env()
67 self.logger.critical("Loaded configuration:" + str(self.main_config.to_dict()))
68
69 def _read_config_file(self, config_file):
70 try:
71 with open(config_file) as f:
72 return yaml.safe_load(f)
73 except Exception as e:
74 self.logger.critical("At config file '{}': {}".format(config_file, e))
75 exit(1)
76
77 @staticmethod
78 def _get_log_formatter_simple():
79 log_format_simple = (
80 "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(message)s"
81 )
82 return logging.Formatter(log_format_simple, datefmt="%Y-%m-%dT%H:%M:%S")
83
84 def _create_file_handler(self):
85 return logging.handlers.RotatingFileHandler(
86 self.main_config.globalConfig.logfile,
87 maxBytes=100e6,
88 backupCount=9,
89 delay=0,
90 )
91
92 def _log_other_modules(self):
93 for logger in ("message", "database", "storage", "tsdb", "temporal"):
94 logger_config = self.main_config.to_dict()[logger]
95 logger_module = logging.getLogger(logger_config["logger_name"])
96 if logger_config["logfile"]:
97 file_handler = logging.handlers.RotatingFileHandler(
98 logger_config["logfile"], maxBytes=100e6, backupCount=9, delay=0
99 )
100 file_handler.setFormatter(self._get_log_formatter_simple())
101 logger_module.addHandler(file_handler)
102 if logger_config["loglevel"]:
103 logger_module.setLevel(logger_config["loglevel"])
104
105 def _configure_logging(self):
106 if self.main_config.globalConfig.logfile:
107 file_handler = self._create_file_handler()
108 file_handler.setFormatter(self._get_log_formatter_simple())
109 self.logger.addHandler(file_handler)
110
111 if not self.main_config.globalConfig.to_dict()["nologging"]:
112 str_handler = logging.StreamHandler()
113 str_handler.setFormatter(self._get_log_formatter_simple())
114 self.logger.addHandler(str_handler)
115
116 if self.main_config.globalConfig.to_dict()["loglevel"]:
117 self.logger.setLevel(self.main_config.globalConfig.loglevel)
118
119 self._log_other_modules()
120 self.logger.critical("starting osm/nglcm")
121
Mark Beierl821bfc92023-01-24 21:15:25 -0500122 async def start(self):
Mark Beierl821bfc92023-01-24 21:15:25 -0500123 temporal_api = (
124 f"{self.main_config.temporal.host}:{str(self.main_config.temporal.port)}"
125 )
Mark Beierl821bfc92023-01-24 21:15:25 -0500126 client = await Client.connect(temporal_api)
Patricia Reinoso02a39fd2023-03-08 17:13:56 +0000127 data_activity_instance = VimDbActivity(self.db)
128 paas_connector_instance = JujuPaasConnector(self.db)
Mark Beierl821bfc92023-01-24 21:15:25 -0500129
Patricia Reinoso02a39fd2023-03-08 17:13:56 +0000130 workflows = [VimCreateWorkflow, VimDeleteWorkflow, VimUpdateWorkflow]
131 activities = [
132 data_activity_instance.update_vim_operation_state,
133 data_activity_instance.update_vim_state,
134 data_activity_instance.delete_vim_record,
135 paas_connector_instance.test_vim_connectivity,
Mark Beierl821bfc92023-01-24 21:15:25 -0500136 ]
Mark Beierl821bfc92023-01-24 21:15:25 -0500137
138 worker = Worker(
Patricia Reinoso02a39fd2023-03-08 17:13:56 +0000139 client,
140 task_queue=LCM_TASK_QUEUE,
141 workflows=workflows,
142 activities=activities,
Mark Beierl821bfc92023-01-24 21:15:25 -0500143 )
144
Patricia Reinoso02a39fd2023-03-08 17:13:56 +0000145 self.logger.info("Starting LCM temporal worker")
Mark Beierl821bfc92023-01-24 21:15:25 -0500146 await worker.run()
147
Mark Beierl821bfc92023-01-24 21:15:25 -0500148
Mark Beierl821bfc92023-01-24 21:15:25 -0500149if __name__ == "__main__":
Mark Beierl821bfc92023-01-24 21:15:25 -0500150 try:
151 opts, args = getopt.getopt(
152 sys.argv[1:], "hc:", ["config=", "help", "health-check"]
153 )
154 # TODO add "log-socket-host=", "log-socket-port=", "log-file="
155 config_file = None
156 for o, a in opts:
157 if o in ("-c", "--config"):
158 config_file = a
159 else:
160 assert False, "Unhandled option"
161
162 if config_file:
163 if not path.isfile(config_file):
164 print(
165 "configuration file '{}' does not exist".format(config_file),
166 file=sys.stderr,
167 )
168 exit(1)
169 else:
170 for config_file in (
171 __file__[: __file__.rfind(".")] + ".cfg",
172 "./lcm.cfg",
173 "/etc/osm/lcm.cfg",
174 ):
175 print(f"{config_file}")
176 if path.isfile(config_file):
177 break
178 else:
179 print(
180 "No configuration file 'lcm.cfg' found neither at local folder nor at /etc/osm/",
181 file=sys.stderr,
182 )
183 exit(1)
184 lcm = NGLcm(config_file)
185 asyncio.run(lcm.start())
186 except (LcmException, getopt.GetoptError) as e:
187 print(str(e), file=sys.stderr)
188 # usage()
189 exit(1)