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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 from cmframework.apis.cmerror import CMError
19 from cmframework.apis.cmmanage import CMManage
20 from cmframework.utils.cmpluginloader import CMPluginLoader
21 from cmframework.utils.cmdependencysort import CMDependencySort
23 from cmdatahandlers.api.configmanager import ConfigManager
24 from cmdatahandlers.api import utils
27 class CMUpdateImpl(object):
28 def __init__(self, plugins_path, server_ip='config-manager', server_port=61100,
29 client_lib_impl_module='cmframework.lib.CMClientImpl', verbose_logger=None):
30 logging.info('CMUpdateImpl constructor, plugins_path is %s', plugins_path)
32 self._plugins_path = plugins_path
34 self._sorted_handlers = []
37 self._load_dependencies()
39 self.uuid_value = None
41 self.api = CMManage(server_ip, server_port, client_lib_impl_module, verbose_logger)
43 def _load_handlers(self):
44 loader = CMPluginLoader(self._plugins_path)
45 handler_modules, _ = loader.load()
46 logging.info('Handler module(s): %r', handler_modules)
48 for handler_class_name, module in handler_modules.iteritems():
49 handler_class = getattr(module, handler_class_name)
50 handler = handler_class()
51 self._handlers[handler_class_name] = handler
53 def update(self, confman=None):
54 logging.info('Taking snapshot of the original configuration just in-case')
55 now = int(round(time.time()*1000))
56 snapshot_name = 'cmupdate-' + str(now)
57 self.api.create_snapshot(snapshot_name)
59 properties = self.api.get_properties('.*')
60 propsjson = utils.unflatten_config_data(properties)
61 confman = ConfigManager(propsjson)
63 for handler in self._sorted_handlers:
65 logging.debug('Calling update for %s', handler)
66 self._handlers[handler].update(confman)
67 logging.debug('update for %s done', handler)
68 except Exception as ex: # pylint: disable=broad-except
69 logging.warning('Update handler %s failed: %s', handler, str(ex))
72 properties = confman.get_config()
73 flatprops = utils.flatten_config_data(properties)
76 self.uuid_value = self.api.set_properties(flatprops, True)
77 except Exception as exp: # pylint: disable=broad-except
78 for handler in self._sorted_handlers:
80 logging.debug('Calling validation_failed for %s', handler)
81 self._handlers[handler].validation_failed(confman)
82 except Exception as ex2: # pylint: disable=broad-except
83 logging.warning('Update handler %s validation_failed raised exception: %s',
87 def wait_activation(self):
89 self.api.wait_activation(self.uuid_value)
92 def _read_dependency_file(file_name):
97 with open(file_name, 'r') as deps_file:
99 line = deps_file.readline()
102 if line.startswith('Before:'):
103 before_list = line[7:].strip().replace(' ', '').split(',')
104 if line.startswith('After:'):
105 after_list = line[6:].strip().replace(' ', '').split(',')
107 logging.debug('Dependency file %s not found.', file_name)
109 return (before_list, after_list)
111 def _load_dependencies(self):
115 for handler in self._handlers.values():
116 deps_filename = '{}/{}.deps'.format(self._plugins_path, handler)
117 before_list, after_list = self._read_dependency_file(deps_filename)
119 for before_dep in before_list:
120 if not self._handlers.get(before_dep, None):
122 'Unexisting handler {} referred in handler {}\'s "Before" dependencies'
123 .format(before_dep, handler))
124 for after_dep in after_list:
125 if not self._handlers.get(after_dep, None):
127 'Unexisting handler {} referred in handler {}\'s "After" dependencies'
128 .format(after_dep, handler))
130 before_graph[str(handler)] = before_list
131 after_graph[str(handler)] = after_list
133 sorter = CMDependencySort(after_graph, before_graph)
134 self._sorted_handlers = sorter.sort()