Add Artifact Manager service.
[ccsdk/cds.git] / ms / artifact-manager / manager / configuration.py
1 """Copyright 2019 Deutsche Telekom.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7     http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 """
15 import logging
16 import os
17 from configparser import ConfigParser, SectionProxy
18 from distutils.util import strtobool
19 from logging import Logger
20 from pathlib import Path, PurePath
21 from typing import NoReturn
22
23 from onaplogging import monkey
24 from onaplogging.mdcformatter import MDCFormatter  # noqa
25
26 monkey.patch_loggingYaml()
27
28
29 DEFAUL_CONFIGURATION_FILE: str = str(PurePath(Path().absolute(), "../configuration.ini"))
30 SUPPLIED_CONFIGURATION_FILE: str = os.environ.get("CONFIGURATION")
31 CONFIGURATION_FILE: str = str(os.path.expanduser(Path(SUPPLIED_CONFIGURATION_FILE or DEFAUL_CONFIGURATION_FILE)))
32
33
34 class ArtifactManagerConfiguration:
35     """ServerConfiguration class loads configuration from config INI files."""
36
37     def __init__(self, config_file_path: str) -> NoReturn:
38         """Initialize configuration class instance.
39
40         Configuration is loaded from file provided as a parameter. Environment variables are loaded also.
41         Logger for object is created with the name same as the class name.
42         :param config_file_path: Path to configuration file.
43         """
44         self.config_file_path = config_file_path
45         self.config = ConfigParser(os.environ)
46         self.config.read(config_file_path, encoding="utf-8")
47
48     @property
49     def configuration_directory(self) -> str:
50         """Get directory path to a directory with configuration ini file.
51
52         This is used to handle relative file paths in config file.
53         """
54         return os.path.dirname(self.config_file_path)
55
56     def get_section(self, section_name: str) -> SectionProxy:
57         """Get the section from configuration file.
58
59         :param section_name: Name of the section to get
60         :raises: KeyError
61         :return: SectionProxy object for given section name
62         """
63         return self.config[section_name]
64
65     def __getitem__(self, key: str) -> SectionProxy:
66         """Get the section from configuration file.
67
68         This method just calls the get_section method but allows us to use it as key lookup
69
70         :param section_name: Name of the section to get
71         :raises: KeyError
72         :return: SectionProxy object for given section name
73         """
74         return self.get_section(key)
75
76     def get_property(self, section_name: str, property_name: str) -> str:
77         """Get the property value from *section_name* section.
78
79         :param section_name: Name of the section config file section on which property is set
80         :param property_name: Name of the property to get
81         :raises: configparser.NoOptionError
82         :return: String value of the property
83         """
84         return self.config.get(section_name, property_name)
85
86     def artifact_manager_property(self, property_name: str) -> str:
87         """Get the property value from *artifactManagerServer* section.
88
89         :param property_name: Name of the property to get
90         :raises: configparser.NoOptionError
91         :return: String value of the property
92         """
93         return self.config.get("artifactManagerServer", property_name)
94
95
96 config = ArtifactManagerConfiguration(CONFIGURATION_FILE)
97
98
99 def prepare_logger(log_file_path: str, development_mode: bool, config: ArtifactManagerConfiguration) -> callable:
100     """Base MDC logger configuration.
101
102     Level depends on the *development_mode* flag: DEBUG if development_mode is set or INFO otherwise.
103     Console handler is created from MDC settings from onappylog library.
104
105     :param log_file_path: Path to the log file, where logs are going to be saved.
106     :param development_mode: Boolean type value which means if logger should be setup in development mode or not
107     :param config: Configuration class so we can fetch app settings (paths) to logger.
108     :return: callable
109     """
110     logging_level: int = logging.DEBUG if development_mode else logging.INFO
111     logging.basicConfig(filename=log_file_path, level=logging_level)
112     logging.config.yamlConfig(
113         filepath=Path(config.configuration_directory, config["artifactManagerServer"]["logConfig"])
114     )
115
116     console: logging.StreamHandler = logging.StreamHandler()
117     console.setLevel(logging_level)
118     formatter: logging.Formatter = MDCFormatter(
119         fmt="%(asctime)s:[%(name)s] %(created)f %(module)s %(funcName)s %(pathname)s %(process)d %(levelno)s :[ %(threadName)s  %(thread)d]: [%(mdc)s]: [%(filename)s]-[%(lineno)d] [%(levelname)s]:%(message)s",  # noqa
120         mdcfmt="{RequestID} {InvocationID} {ServiceName} {PartnerName} {BeginTimestamp} {EndTimestamp} {ElapsedTime} {StatusCode} {TargetEntity} {TargetServiceName} {Server}",  # noqa
121         # Important: We cannot use %f here because this datetime format is used by time library, not datetime.
122         datefmt="%Y-%m-%dT%H:%M:%S%z",
123     )
124     console.setFormatter(formatter)
125
126     def get_logger(name: str) -> Logger:
127         """Get a new logger with predefined MDC handler."""
128         logger: Logger = logging.getLogger(name)
129         logger.addHandler(console)
130         return logger
131
132     return get_logger
133
134
135 get_logger = prepare_logger(
136     config.artifact_manager_property("logFile"),
137     strtobool(config["artifactManagerServer"].get("debug", "false")),
138     config,
139 )