X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=cmframework%2Fsrc%2Fcmframework%2Fserver%2Fcmprocessor.py;fp=cmframework%2Fsrc%2Fcmframework%2Fserver%2Fcmprocessor.py;h=d5e7ea9e23dee658abe41f2297d8e47b50c79219;hb=c389bdee7b3845b55f443dbf04c0ce4083a55886;hp=0000000000000000000000000000000000000000;hpb=5030f0c004701dd422c78c71c014ef60f48139fc;p=ta%2Fconfig-manager.git diff --git a/cmframework/src/cmframework/server/cmprocessor.py b/cmframework/src/cmframework/server/cmprocessor.py new file mode 100644 index 0000000..d5e7ea9 --- /dev/null +++ b/cmframework/src/cmframework/server/cmprocessor.py @@ -0,0 +1,316 @@ +# Copyright 2019 Nokia + +# 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. +import logging + +from cmframework.utils import cmactivationwork +from cmframework.server import cmeventletrwlock +from cmframework.server import cmcsn +from cmframework.server import cmsnapshot +from cmframework.utils.cmflagfile import CMFlagFile +from cmframework.utils import cmalarm + + +class CMProcessor(object): + SERVICE_GROUP_NAME = 'config-manager' + + def __init__(self, + backend_handler, + validator, + activator, + changemonitor, + activationstate_handler, + snapshot_handler): + logging.debug('CMProcessor constructed') + + self.backend_handler = backend_handler + self.lock = cmeventletrwlock.CMEventletRWLock() + self.csn = cmcsn.CMCSN(self.backend_handler) + self.validator = validator + self.activator = activator + self.reboot_requests = set() + self.automatic_activation_disabled = CMFlagFile('automatic_activation_disabled') + self.changemonitor = changemonitor + self.activationstate_handler = activationstate_handler + self.snapshot = cmsnapshot.CMSnapshot(snapshot_handler) + + def reboot_request(self, node_name): + logging.debug('reboot_request called for %s', node_name) + + self.reboot_requests.add(node_name) + + def _clear_reboot_requests(self): + logging.debug('_clear_reboot_requests called') + + self.reboot_requests.clear() + + def _raise_reboot_alarms(self): + logging.debug('_raise_reboot_alarms called') + + reboot_request_alarm = cmalarm.CMRebootRequestAlarm() + + for node_name in self.reboot_requests: + reboot_request_alarm.raise_alarm_for_node(node_name) + + def get_property(self, prop_name, snapshot_name=None): + logging.debug('get_property called for %s', prop_name) + + with self.lock.reader(): + if snapshot_name: + self.snapshot.load(snapshot_name) + + return self.snapshot.get_property(prop_name) + + return self.backend_handler.get_property(prop_name) + + def get_properties(self, prop_filter, snapshot_name=None): + logging.debug('get_properties called with filter %s', prop_filter) + + with self.lock.reader(): + if snapshot_name: + self.snapshot.load(snapshot_name) + + return self.snapshot.get_properties(prop_filter) + + return self.backend_handler.get_properties(prop_filter) + + def set_property(self, prop_name, prop_value): + logging.debug('set_property called %s=%s', prop_name, prop_value) + + props = {} + props[prop_name] = prop_value + return self.set_properties(props) + + def set_properties(self, props, overwrite=False): + logging.debug('set_properties called for %s', str(props)) + + with self.lock.writer(): + self._validate_set(props) + if overwrite: + logging.debug('Deleting old configuration data as requested') + orig_props = self.backend_handler.get_properties('.*') + self.backend_handler.delete_properties(orig_props.keys()) + self.backend_handler.set_properties(props) + self.csn.increment() + + if not self.automatic_activation_disabled: + return self._activate_set(props) + + return "0" + + def delete_property(self, prop_name): + logging.debug('delete_property called for %s', prop_name) + + props = [] + props.append(prop_name) + return self._delete_properties(props, None) + + def delete_properties(self, arg): + logging.debug('delete_properties called with arg %r', arg) + + keys = [] + prop_filter = None + if isinstance(arg, str): + prop_filter = arg + props = self.get_properties(prop_filter) + keys = props.keys() + else: + keys = arg + return self._delete_properties(keys, prop_filter) + + def _delete_properties(self, props, props_filter): + logging.debug('_delete_properties called with props %s filter %s', props, props_filter) + + with self.lock.writer(): + self._validate_delete(props) + if props_filter: + self.backend_handler.delete_properties(props_filter) + else: + if len(props) == 1: + self.backend_handler.delete_property(props[0]) + else: + self.backend_handler.delete_properties(props) + self.csn.increment() + + if not self.automatic_activation_disabled: + return self._activate_delete(props) + + return "0" + + def _validate_set(self, props): + logging.debug('_validate_set called for %s', str(props)) + + self.validator.validate_set(props) + + def _activate_set_no_lock(self, props): + logging.debug('_activate_set_no_lock called for %s', str(props)) + + uuid_value = self.changemonitor.start_change() + + work = cmactivationwork.CMActivationWork(cmactivationwork.CMActivationWork.OPER_SET, + self.csn.get(), props) + work.uuid_value = uuid_value + self.activator.add_work(work) + return uuid_value + + def _activate_set(self, props): + logging.debug('_activate_set called') + + with self.lock.reader(): + return self._activate_set_no_lock(props) + + def _validate_delete(self, props): + logging.debug('_validate_delete called for %s', str(props)) + + self.validator.validate_delete(props) + + def _activate_delete(self, props): + logging.debug('_activate_delete called for %s', str(props)) + + with self.lock.reader(): + uuid_value = self.changemonitor.start_change() + work = cmactivationwork.CMActivationWork(cmactivationwork.CMActivationWork.OPER_DELETE, + self.csn.get(), props) + work.uuid_value = uuid_value + self.activator.add_work(work) + return uuid_value + + def create_snapshot(self, snapshot_name): + logging.debug('create_snapshot called, snapshot name is %s', snapshot_name) + + with self.lock.writer(): + self.snapshot.create(snapshot_name, self.backend_handler) + + def restore_snapshot(self, snapshot_name): + logging.debug('restore_snapshot called, snapshot name is %s', snapshot_name) + + with self.lock.writer(): + self.snapshot.load(snapshot_name) + + self._validate_set(self.snapshot.get_properties()) + + self.snapshot.restore(self.backend_handler) + + self.csn = cmcsn.CMCSN(self.backend_handler) + + self._activate_set_no_lock(self.snapshot.get_properties()) + + def list_snapshots(self): + logging.debug('list_snapshots called') + + snapshots = [] + with self.lock.writer(): + snapshots = self.snapshot.list() + + return snapshots + + def delete_snapshot(self, snapshot_name): + logging.debug('delete_snapshot called, snapshot name is %s', snapshot_name) + + with self.lock.writer(): + self.snapshot.delete(snapshot_name) + + def activate(self, node_name=None, startup_activation=False): + logging.debug('activate called, node is %s', node_name) + + activation_alarm = cmalarm.CMActivationFailedAlarm() + if node_name: + activation_alarm.cancel_alarm_for_node(node_name) + else: + activation_alarm.cancel_alarm_for_sg(CMProcessor.SERVICE_GROUP_NAME) + + with self.lock.reader(): + uuid_value = self.changemonitor.start_change() + if not node_name: + work = cmactivationwork.CMActivationWork( + cmactivationwork.CMActivationWork.OPER_FULL, + self.csn.get(), {}, None, startup_activation) + else: + work = cmactivationwork.CMActivationWork( + cmactivationwork.CMActivationWork.OPER_FULL, + self.csn.get(), {}, node_name) + work.uuid_value = uuid_value + self.activator.add_work(work) + + logging.debug('activation work added, going to wait for result') + failures = work.get_result() + logging.debug('got activation result') + + if self.reboot_requests: + self._raise_reboot_alarms() + + if not node_name: + self.activationstate_handler.clear_full_failed() + + if failures: + logging.warning('Activation failed: %s', failures) + + failed_activators = [activator for handler in failures.keys() + for activator in failures[handler]] + + supplementary_info = {'failed activators': failed_activators} + + if node_name: + activation_alarm.raise_alarm_for_node(node_name, supplementary_info) + else: + self.activationstate_handler.set_full_failed(failed_activators) + + activation_alarm.raise_alarm_for_sg(CMProcessor.SERVICE_GROUP_NAME, + supplementary_info) + return uuid_value + + def activate_node(self, node_name): + logging.debug('activate_node called, node name is %s', node_name) + + if self.automatic_activation_disabled: + return False + + with self.lock.reader(): + node_csn = self.csn.get_node_csn(node_name) + + if self.csn.get() == node_csn: + logging.info('No change in data since last translation, last csn %d', + self.csn.get()) + return False + + self._clear_reboot_requests() + work = cmactivationwork.CMActivationWork(cmactivationwork.CMActivationWork.OPER_NODE, + self.csn.get(), {}, node_name) + self.activator.add_work(work) + + activation_alarm = cmalarm.CMActivationFailedAlarm() + activation_alarm.cancel_alarm_for_node(node_name) + + failures = work.get_result() + if failures: + logging.warning('Activation failed: %s', failures) + + failed_activators = [activator for handler in failures.keys() + for activator in failures[handler]] + supplementary_info = {'failed activators': failed_activators} + activation_alarm.raise_alarm_for_node(node_name, supplementary_info) + + else: + with self.lock.writer(): + self.csn.sync_node_csn(node_name) + + return node_name in self.reboot_requests + + def set_automatic_activation_state(self, state): + logging.debug('set_automatic_activation_state called, state is %s', state) + + with self.lock.writer(): + if state: + self.automatic_activation_disabled.unset() + else: + self.automatic_activation_disabled.set()