diff options
author | Harry Huang <huangxiangyu5@huawei.com> | 2017-11-17 14:53:44 +0800 |
---|---|---|
committer | Harry Huang <huangxiangyu5@huawei.com> | 2017-12-21 16:36:30 +0800 |
commit | 8646b8d62cf4ca7b6bccae537a0c9e72ba45eab3 (patch) | |
tree | 73a9a983e0dd1423e9df928a78a5023a09d5a7f9 /compass-tasks-base/log_analyzor | |
parent | 6234176ae292a75dcda5520324cb7857d6105988 (diff) |
Merge compass-tasks-osa and compass-tasks-k8s
JIRA: COMPASS-568
rename compass-tasks to compass-tasks-base.
add both osa and k8s support in compass-tasks
Change-Id: I438f5b17e509d4cb751ced0ffe640ec70899882f
Signed-off-by: Harry Huang <huangxiangyu5@huawei.com>
Diffstat (limited to 'compass-tasks-base/log_analyzor')
-rw-r--r-- | compass-tasks-base/log_analyzor/__init__.py | 13 | ||||
-rw-r--r-- | compass-tasks-base/log_analyzor/adapter_matcher.py | 126 | ||||
-rw-r--r-- | compass-tasks-base/log_analyzor/environment.py | 29 | ||||
-rw-r--r-- | compass-tasks-base/log_analyzor/file_matcher.py | 252 | ||||
-rw-r--r-- | compass-tasks-base/log_analyzor/line_matcher.py | 206 | ||||
-rw-r--r-- | compass-tasks-base/log_analyzor/progress_calculator.py | 208 |
6 files changed, 834 insertions, 0 deletions
diff --git a/compass-tasks-base/log_analyzor/__init__.py b/compass-tasks-base/log_analyzor/__init__.py new file mode 100644 index 0000000..4ee55a4 --- /dev/null +++ b/compass-tasks-base/log_analyzor/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# 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. diff --git a/compass-tasks-base/log_analyzor/adapter_matcher.py b/compass-tasks-base/log_analyzor/adapter_matcher.py new file mode 100644 index 0000000..8630e01 --- /dev/null +++ b/compass-tasks-base/log_analyzor/adapter_matcher.py @@ -0,0 +1,126 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# 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. + +"""Module to provider installing progress calculation for the adapter. + + .. moduleauthor:: Xiaodong Wang <xiaodongwang@huawei.com> +""" +import logging +import re + + +class AdapterItemMatcher(object): + """Progress matcher for the os installing or package installing.""" + + def __init__(self, file_matchers): + self.file_matchers_ = file_matchers + + def __repr__(self): + return '%r[file_matchers: %r]' % ( + self.__class__.__name__, self.file_matchers_ + ) + + def update_progress( + self, file_reader_factory, name, state, log_history_mapping + ): + """Update progress. + + :param name: the fullname of the installing host. + :type name: str + :param progress: Progress instance to update. + """ + for file_matcher in self.file_matchers_: + filename = file_matcher.filename_ + if filename not in log_history_mapping: + log_history_mapping[filename] = { + 'filename': filename, + 'partial_line': '', + 'position': 0, + 'line_matcher_name': 'start', + 'percentage': 0.0, + 'message': '', + 'severity': 'INFO' + } + log_history = log_history_mapping[filename] + file_matcher.update_progress( + file_reader_factory, name, state, log_history + ) + + +class OSMatcher(object): + """Progress matcher for os installer.""" + + def __init__( + self, os_installer_name, + os_pattern, item_matcher, + file_reader_factory + ): + self.name_ = re.compile(os_installer_name) + self.os_regex_ = re.compile(os_pattern) + self.matcher_ = item_matcher + self.file_reader_factory_ = file_reader_factory + + def __repr__(self): + return '%r[name:%r, os_pattern:%r, matcher:%r]' % ( + self.__class__.__name__, self.name_.pattern, + self.os_regex_.pattern, self.matcher_) + + def match(self, os_installer_name, os_name): + """Check if the os matcher is acceptable.""" + if os_name is None: + return False + else: + return all([ + self.name_.match(os_installer_name), + self.os_regex_.match(os_name) + ]) + + def update_progress(self, name, state, log_history_mapping): + """Update progress.""" + self.matcher_.update_progress( + self.file_reader_factory_, name, state, log_history_mapping) + + +class PackageMatcher(object): + """Progress matcher for package installer.""" + + def __init__( + self, package_installer_name, adapter_pattern, + item_matcher, file_reader_factory + ): + self.name_ = re.compile(package_installer_name) + self.adapter_regex_ = re.compile(adapter_pattern) + self.matcher_ = item_matcher + self.file_reader_factory_ = file_reader_factory + + def __repr__(self): + return '%s[name:%s, adapter_pattern:%s, matcher:%s]' % ( + self.__class__.__name__, self.name_.pattern, + self.adapter_regex_.pattern, self.matcher_) + + def match(self, package_installer_name, adapter_name): + """Check if the package matcher is acceptable.""" + if package_installer_name is None: + return False + else: + return all([ + self.name_.match(package_installer_name), + self.adapter_regex_.match(adapter_name) + ]) + + def update_progress(self, name, state, log_history_mapping): + """Update progress.""" + self.matcher_.update_progress( + self.file_reader_factory_, name, state, log_history_mapping + ) diff --git a/compass-tasks-base/log_analyzor/environment.py b/compass-tasks-base/log_analyzor/environment.py new file mode 100644 index 0000000..80ff738 --- /dev/null +++ b/compass-tasks-base/log_analyzor/environment.py @@ -0,0 +1,29 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# 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. + +"""module to provide environment to load progress calculator configurations. + + .. moduleauthor:: Xiaodong Wang <xiaodongwang@huawei.com> +""" +from compass.log_analyzor.adapter_matcher import AdapterItemMatcher +from compass.log_analyzor.file_matcher import FileMatcher +from compass.log_analyzor.file_matcher import FileReaderFactory +from compass.log_analyzor.line_matcher import IncrementalProgress +from compass.log_analyzor.line_matcher import LineMatcher +from compass.utils import setting_wrapper as setting +from compass.utils import util + + +ENV_GLOBALS = globals() +ENV_LOCALS = locals() diff --git a/compass-tasks-base/log_analyzor/file_matcher.py b/compass-tasks-base/log_analyzor/file_matcher.py new file mode 100644 index 0000000..be3143b --- /dev/null +++ b/compass-tasks-base/log_analyzor/file_matcher.py @@ -0,0 +1,252 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# 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. + +"""Module to update intalling progress by processing log file. + + .. moduleauthor:: Xiaodong Wang <xiaodongwang@huawei.com> +""" +import logging +import os.path + +from compass.utils import setting_wrapper as setting + + +class FileFilter(object): + """base class to filter log file.""" + def __repr__(self): + return self.__class__.__name__ + + def filter(self, pathname): + """Filter log file. + + :param pathname: the absolute path name to the log file. + """ + raise NotImplementedError(str(self)) + + +class CompositeFileFilter(FileFilter): + """filter log file based on the list of filters.""" + def __init__(self, filters): + self.filters_ = filters + + def __str__(self): + return 'CompositeFileFilter[%s]' % self.filters_ + + def append_filter(self, file_filter): + """append filter.""" + self.filters_.append(file_filter) + + def filter(self, pathname): + """filter log file.""" + for file_filter in self.filters_: + if not file_filter.filter(pathname): + return False + + return True + + +class FilterFileExist(FileFilter): + """filter log file if not exists.""" + def filter(self, pathname): + """filter log file.""" + file_exist = os.path.isfile(pathname) + if not file_exist: + logging.debug("%s is not exist", pathname) + + return file_exist + + +def get_file_filter(): + """get file filter""" + composite_filter = CompositeFileFilter([FilterFileExist()]) + return composite_filter + + +class FileReader(object): + """Class to read log file. + + The class provide support to read log file from the position + it has read last time. and update the position when it finish + reading the log. + """ + def __init__(self, pathname, log_history): + self.pathname_ = pathname + self.log_history_ = log_history + + def __repr__(self): + return ( + '%s[pathname:%s, log_history:%s]' % ( + self.__class__.__name__, self.pathname_, + self.log_history_ + ) + ) + + def readline(self): + """Generate each line of the log file.""" + old_position = self.log_history_['position'] + position = self.log_history_['position'] + partial_line = self.log_history_['partial_line'] + try: + with open(self.pathname_) as logfile: + logfile.seek(position) + while True: + line = logfile.readline() + partial_line += line + position = logfile.tell() + if position > self.log_history_['position']: + self.log_history_['position'] = position + + if partial_line.endswith('\n'): + self.log_history_['partial_line'] = '' + yield partial_line + partial_line = self.log_history_['partial_line'] + else: + self.log_history_['partial_line'] = partial_line + break + if partial_line: + yield partial_line + + except Exception as error: + logging.error('failed to processing file %s', self.pathname_) + raise error + + logging.debug( + 'processing file %s log %s bytes to position %s', + self.pathname_, position - old_position, position + ) + + +class FileReaderFactory(object): + """factory class to create FileReader instance.""" + + def __init__(self, logdir): + self.logdir_ = logdir + self.filefilter_ = get_file_filter() + + def __str__(self): + return '%s[logdir: %s filefilter: %s]' % ( + self.__class__.__name__, self.logdir_, self.filefilter_) + + def get_file_reader(self, hostname, filename, log_history): + """Get FileReader instance. + + :param fullname: fullname of installing host. + :param filename: the filename of the log file. + + :returns: :class:`FileReader` instance if it is not filtered. + """ + pathname = os.path.join(self.logdir_, hostname, filename) + logging.debug('get FileReader from %s', pathname) + if not self.filefilter_.filter(pathname): + logging.debug('%s is filtered', pathname) + return None + + return FileReader(pathname, log_history) + + +class FileMatcher(object): + """File matcher to get the installing progress from the log file.""" + def __init__(self, line_matchers, min_progress, max_progress, filename): + if not 0.0 <= min_progress <= max_progress <= 1.0: + raise IndexError( + '%s restriction is not mat: 0.0 <= min_progress' + '(%s) <= max_progress(%s) <= 1.0' % ( + self.__class__.__name__, + min_progress, + max_progress)) + if 'start' not in line_matchers: + raise KeyError( + 'key `start` does not in line matchers %s' % line_matchers + ) + self.line_matchers_ = line_matchers + self.min_progress_ = min_progress + self.max_progress_ = max_progress + self.progress_diff_ = max_progress - min_progress + self.filename_ = filename + + def __repr__(self): + return ( + '%r[filename: %r, progress:[%r:%r], ' + 'line_matchers: %r]' % ( + self.__class__.__name__, self.filename_, + self.min_progress_, + self.max_progress_, self.line_matchers_) + ) + + def update_progress_from_log_history(self, state, log_history): + file_percentage = log_history['percentage'] + percentage = max( + self.min_progress_, + min( + self.max_progress_, + self.min_progress_ + file_percentage * self.progress_diff_ + ) + ) + if ( + percentage > state['percentage'] or + ( + percentage == state['percentage'] and + log_history['message'] != state['message'] + ) + ): + state['percentage'] = percentage + state['message'] = log_history['message'] + state['severity'] = log_history['severity'] + else: + logging.debug( + 'ingore update state %s from log history %s ' + 'since the updated progress %s lag behind', + state, log_history, percentage + ) + + def update_progress(self, file_reader_factory, name, state, log_history): + """update progress from file. + + :param fullname: the fullname of the installing host. + :type fullname: str + :param total_progress: Progress instance to update. + + the function update installing progress by reading the log file. + It contains a list of line matcher, when one log line matches + with current line matcher, the installing progress is updated. + and the current line matcher got updated. + Notes: some line may be processed multi times. The case is the + last line of log file is processed in one run, while in the other + run, it will be reprocessed at the beginning because there is + no line end indicator for the last line of the file. + """ + file_reader = file_reader_factory.get_file_reader( + name, self.filename_, log_history) + if not file_reader: + return + + line_matcher_name = log_history['line_matcher_name'] + for line in file_reader.readline(): + if line_matcher_name not in self.line_matchers_: + logging.debug('early exit at\n%s\nbecause %s is not in %s', + line, line_matcher_name, self.line_matchers_) + break + + same_line_matcher_name = line_matcher_name + while same_line_matcher_name in self.line_matchers_: + line_matcher = self.line_matchers_[same_line_matcher_name] + same_line_matcher_name, line_matcher_name = ( + line_matcher.update_progress(line, log_history) + ) + log_history['line_matcher_name'] = line_matcher_name + logging.debug( + 'updated log history %s after processing %s', + log_history, self + ) + self.update_progress_from_log_history(state, log_history) diff --git a/compass-tasks-base/log_analyzor/line_matcher.py b/compass-tasks-base/log_analyzor/line_matcher.py new file mode 100644 index 0000000..ada9ed6 --- /dev/null +++ b/compass-tasks-base/log_analyzor/line_matcher.py @@ -0,0 +1,206 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# 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. + +"""Module to get the progress when found match with a line of the log.""" +import logging +import re + +from abc import ABCMeta + +from compass.utils import util + + +class ProgressCalculator(object): + """base class to generate progress.""" + + __metaclass__ = ABCMeta + + @classmethod + def update_progress( + cls, progress_data, message, + severity, log_history + ): + """Update progress with the given progress_data, message and severity. + + :param progress_data: installing progress. + :type progress_data: float between 0 to 1. + :param message: installing progress message. + :param severity: installing message severity. + :param progress: :class:`Progress` instance to update + """ + # the progress is only updated when the new progress + # is greater than the stored progress or the progress + # to update is the same but the message is different. + if ( + progress_data > log_history['percentage'] or ( + progress_data == log_history['percentage'] and + message != log_history['message'] + ) + ): + log_history['percentage'] = progress_data + if message: + log_history['message'] = message + if severity: + log_history['severity'] = severity + logging.debug('update progress to %s', log_history) + else: + logging.debug('ignore update progress %s to %s', + progress_data, log_history) + + def update(self, message, severity, log_history): + """vritual method to update progress by message and severity. + + :param message: installing message. + :param severity: installing severity. + """ + raise NotImplementedError(str(self)) + + def __repr__(self): + return self.__class__.__name__ + + +class IncrementalProgress(ProgressCalculator): + """Class to increment the progress.""" + + def __init__(self, min_progress, + max_progress, incremental_ratio): + super(IncrementalProgress, self).__init__() + if not 0.0 <= min_progress <= max_progress <= 1.0: + raise IndexError( + '%s restriction is not mat: 0.0 <= min_progress(%s)' + ' <= max_progress(%s) <= 1.0' % ( + self.__class__.__name__, min_progress, max_progress)) + + if not 0.0 <= incremental_ratio <= 1.0: + raise IndexError( + '%s restriction is not mat: ' + '0.0 <= incremental_ratio(%s) <= 1.0' % ( + self.__class__.__name__, incremental_ratio)) + + self.min_progress_ = min_progress + self.max_progress_ = max_progress + self.incremental_progress_ = ( + incremental_ratio * (max_progress - min_progress)) + + def __str__(self): + return '%s[%s:%s:%s]' % ( + self.__class__.__name__, + self.min_progress_, + self.max_progress_, + self.incremental_progress_ + ) + + def update(self, message, severity, log_history): + """update progress from message and severity.""" + progress_data = max( + self.min_progress_, + min( + self.max_progress_, + log_history['percentage'] + self.incremental_progress_ + ) + ) + self.update_progress(progress_data, + message, severity, log_history) + + +class RelativeProgress(ProgressCalculator): + """class to update progress to the given relative progress.""" + + def __init__(self, progress): + super(RelativeProgress, self).__init__() + if not 0.0 <= progress <= 1.0: + raise IndexError( + '%s restriction is not mat: 0.0 <= progress(%s) <= 1.0' % ( + self.__class__.__name__, progress)) + + self.progress_ = progress + + def __str__(self): + return '%s[%s]' % (self.__class__.__name__, self.progress_) + + def update(self, message, severity, log_history): + """update progress from message and severity.""" + self.update_progress( + self.progress_, message, severity, log_history) + + +class SameProgress(ProgressCalculator): + """class to update message and severity for progress.""" + + def update(self, message, severity, log_history): + """update progress from the message and severity.""" + self.update_progress(log_history['percentage'], message, + severity, log_history) + + +class LineMatcher(object): + """Progress matcher for each line.""" + + def __init__(self, pattern, progress=None, + message_template='', severity=None, + unmatch_sameline_next_matcher_name='', + unmatch_nextline_next_matcher_name='', + match_sameline_next_matcher_name='', + match_nextline_next_matcher_name=''): + self.regex_ = re.compile(pattern) + if not progress: + self.progress_ = SameProgress() + elif isinstance(progress, ProgressCalculator): + self.progress_ = progress + elif isinstance(progress, (int, long, float)): + self.progress_ = RelativeProgress(progress) + else: + raise TypeError( + 'progress unsupport type %s: %s' % ( + type(progress), progress)) + + self.message_template_ = message_template + self.severity_ = severity + self.unmatch_sameline_ = unmatch_sameline_next_matcher_name + self.unmatch_nextline_ = unmatch_nextline_next_matcher_name + self.match_sameline_ = match_sameline_next_matcher_name + self.match_nextline_ = match_nextline_next_matcher_name + + def __repr__(self): + return '%r[pattern:%r, message_template:%r, severity:%r]' % ( + self.__class__.__name__, self.regex_.pattern, + self.message_template_, self.severity_) + + def update_progress(self, line, log_history): + """Update progress by the line. + + :param line: one line in log file to indicate the installing progress. + .. note:: + The line may be partial if the latest line of the log file is + not the whole line. But the whole line may be resent + in the next run. + :param progress: the :class:`Progress` instance to update. + """ + mat = self.regex_.search(line) + if not mat: + return ( + self.unmatch_sameline_, + self.unmatch_nextline_) + + try: + message = self.message_template_ % mat.groupdict() + except Exception as error: + logging.error('failed to get message %s %% %s in line matcher %s', + self.message_template_, mat.groupdict(), self) + raise error + + self.progress_.update(message, self.severity_, log_history) + return ( + self.match_sameline_, + self.match_nextline_) diff --git a/compass-tasks-base/log_analyzor/progress_calculator.py b/compass-tasks-base/log_analyzor/progress_calculator.py new file mode 100644 index 0000000..b0f35f2 --- /dev/null +++ b/compass-tasks-base/log_analyzor/progress_calculator.py @@ -0,0 +1,208 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# 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. + +"""module to provide updating installing process function. + + .. moduleauthor:: Xiaodong Wang <xiaodongwang@huawei.com> +""" +import logging + +from compass.log_analyzor.adapter_matcher import OSMatcher +from compass.log_analyzor.adapter_matcher import PackageMatcher +from compass.log_analyzor.environment import ENV_GLOBALS +from compass.log_analyzor.environment import ENV_LOCALS +from compass.log_analyzor.file_matcher import FileReaderFactory + +from compass.utils import setting_wrapper as setting +from compass.utils import util + +OS_ADAPTER_CONFIGURATIONS = None +PACKAGE_ADAPTER_CONFIGURATIONS = None +PROGRESS_CALCULATOR_CONFIGURATIONS = None + + +def _load_calculator_configurations(force=False): + global PROGRESS_CALCULATOR_CONFIGURATIONS + if force or PROGRESS_CALCULATOR_CONFIGURATIONS is None: + env_locals = {} + env_locals.update(ENV_GLOBALS) + env_locals.update(ENV_LOCALS) + PROGRESS_CALCULATOR_CONFIGURATIONS = util.load_configs( + setting.PROGRESS_CALCULATOR_DIR, + env_locals=env_locals + ) + if not PROGRESS_CALCULATOR_CONFIGURATIONS: + logging.info('No configuration found for progress calculator.') + + global OS_ADAPTER_CONFIGURATIONS + if force or OS_ADAPTER_CONFIGURATIONS is None: + OS_ADAPTER_CONFIGURATIONS = [] + for progress_calculator_configuration in ( + PROGRESS_CALCULATOR_CONFIGURATIONS + ): + if 'OS_LOG_CONFIGURATIONS' in ( + progress_calculator_configuration + ): + os_installer_configurations = ( + progress_calculator_configuration['OS_LOG_CONFIGURATIONS'] + ) + for os_installer_configuration in os_installer_configurations: + OS_ADAPTER_CONFIGURATIONS.append(OSMatcher( + os_installer_name=( + os_installer_configuration['os_installer_name'] + ), + os_pattern=os_installer_configuration['os_pattern'], + item_matcher=( + os_installer_configuration['item_matcher'] + ), + file_reader_factory=FileReaderFactory( + os_installer_configuration['logdir'] + ) + )) + if not OS_ADAPTER_CONFIGURATIONS: + logging.info( + 'no OS_LOG_CONFIGURATIONS section found ' + 'in progress calculator.' + ) + else: + logging.debug( + 'OS_ADAPTER_CONFIGURATIONS is\n%s', + OS_ADAPTER_CONFIGURATIONS + ) + + global PACKAGE_ADAPTER_CONFIGURATIONS + if force or PACKAGE_ADAPTER_CONFIGURATIONS is None: + PACKAGE_ADAPTER_CONFIGURATIONS = [] + for progress_calculator_configuration in ( + PROGRESS_CALCULATOR_CONFIGURATIONS + ): + if 'ADAPTER_LOG_CONFIGURATIONS' in ( + progress_calculator_configuration + ): + package_installer_configurations = ( + progress_calculator_configuration[ + 'ADAPTER_LOG_CONFIGURATIONS' + ] + ) + for package_installer_configuration in ( + package_installer_configurations + ): + PACKAGE_ADAPTER_CONFIGURATIONS.append(PackageMatcher( + package_installer_name=( + package_installer_configuration[ + 'package_installer_name' + ] + ), + adapter_pattern=( + package_installer_configuration['adapter_pattern'] + ), + item_matcher=( + package_installer_configuration['item_matcher'] + ), + file_reader_factory=FileReaderFactory( + package_installer_configuration['logdir'] + ) + )) + if not PACKAGE_ADAPTER_CONFIGURATIONS: + logging.info( + 'no PACKAGE_LOG_CONFIGURATIONS section found ' + 'in progress calculator.' + ) + else: + logging.debug( + 'PACKAGE_ADAPTER_CONFIGURATIONS is\n%s', + PACKAGE_ADAPTER_CONFIGURATIONS + ) + + +def load_calculator_configurations(force_reload=False): + _load_calculator_configurations(force=force_reload) + + +def _get_os_matcher(os_installer_name, os_name): + """Get OS adapter matcher by os name and installer name.""" + _load_calculator_configurations() + for configuration in OS_ADAPTER_CONFIGURATIONS: + if configuration.match(os_installer_name, os_name): + return configuration + else: + logging.debug('configuration %s does not match %s and %s', + configuration, os_name, os_installer_name) + logging.error('No configuration found for os installer %s os %s', + os_installer_name, os_name) + return None + + +def _get_package_matcher( + package_installer_name, adapter_name +): + """Get package adapter matcher by adapter name and installer name.""" + _load_calculator_configurations() + for configuration in PACKAGE_ADAPTER_CONFIGURATIONS: + if configuration.match( + package_installer_name, + adapter_name + ): + return configuration + else: + logging.debug('configuration %s does not match %s and %s', + configuration, adapter_name, + package_installer_name) + logging.error('No configuration found for package installer %s adapter %s', + package_installer_name, adapter_name) + return None + + +def update_host_progress(host_mappping): + for host_id, (host, host_state, host_log_history_mapping) in ( + host_mappping.items() + ): + os_name = host['os_name'] + os_installer_name = host['os_installer']['name'] + os_matcher = _get_os_matcher( + os_installer_name, os_name + ) + if not os_matcher: + continue + name = host[setting.HOST_INSTALLATION_LOGDIR_NAME] + os_matcher.update_progress( + name, host_state, host_log_history_mapping + ) + + +def update_clusterhost_progress(clusterhost_mapping): + for ( + clusterhost_id, + (clusterhost, clusterhost_state, clusterhost_log_history_mapping) + ) in ( + clusterhost_mapping.items() + ): + adapter_name = clusterhost['adapter_name'] + package_installer_name = clusterhost['package_installer']['name'] + package_matcher = _get_package_matcher( + package_installer_name, + adapter_name + ) + if not package_matcher: + continue + name = clusterhost[setting.CLUSTERHOST_INATALLATION_LOGDIR_NAME] + package_matcher.update_progress( + name, clusterhost_state, + clusterhost_log_history_mapping + ) + + +def update_cluster_progress(cluster_mapping): + for cluster_id, (cluster, cluster_state) in cluster_mapping.items(): + pass |