| # |
| # Copyright 2017 the original author or authors. |
| # |
| # 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. |
| # |
| |
| """ |
| A config rev object that persists itself |
| """ |
| from bz2 import compress, decompress |
| |
| import structlog |
| from simplejson import dumps, loads |
| |
| from pyvoltha.common.config.config_rev import ConfigRevision, children_fields |
| |
| log = structlog.get_logger() |
| |
| |
| class PersistedConfigRevision(ConfigRevision): |
| |
| compress = False |
| |
| __slots__ = ('_kv_store',) |
| |
| def __init__(self, branch, data, children=None): |
| self._kv_store = branch._node._root._kv_store |
| super(PersistedConfigRevision, self).__init__(branch, data, children) |
| |
| def _finalize(self): |
| super(PersistedConfigRevision, self)._finalize() |
| self.store() |
| |
| def __del__(self): |
| try: |
| if self._hash: |
| if self._config.__weakref__ is None: |
| if self._config._hash in self._kv_store: |
| del self._kv_store[self._config._hash] |
| assert self.__weakref__ is None |
| if self._hash in self._kv_store: |
| del self._kv_store[self._hash] |
| except Exception, e: |
| # this should never happen |
| log.exception('del-error', hash=self.hash, e=e) |
| |
| def store(self): |
| |
| try: |
| # crude serialization of children hash and config data hash |
| if self._hash in self._kv_store: |
| return |
| |
| self.store_config() |
| |
| children_lists = {} |
| for field_name, children in self._children.iteritems(): |
| hashes = [rev.hash for rev in children] |
| children_lists[field_name] = hashes |
| |
| data = dict( |
| children=children_lists, |
| config=self._config._hash |
| ) |
| blob = dumps(data) |
| if self.compress: |
| blob = compress(blob) |
| |
| self._kv_store[self._hash] = blob |
| |
| except Exception, e: |
| log.exception('store-error', e=e) |
| |
| @classmethod |
| def load(cls, branch, kv_store, msg_cls, hash): |
| # Update the branch's config store |
| blob = kv_store[hash] |
| if cls.compress: |
| blob = decompress(blob) |
| data = loads(blob) |
| |
| config_hash = data['config'] |
| config_data = cls.load_config(kv_store, msg_cls, config_hash) |
| |
| children_list = data['children'] |
| assembled_children = {} |
| node = branch._node |
| for field_name, meta in children_fields(msg_cls).iteritems(): |
| child_msg_cls = tmp_cls_loader(meta.module, meta.type) |
| children = [] |
| for child_hash in children_list[field_name]: |
| child_node = node._mknode(child_msg_cls) |
| child_node.load_latest(child_hash) |
| child_rev = child_node.latest |
| children.append(child_rev) |
| assembled_children[field_name] = children |
| rev = cls(branch, config_data, assembled_children) |
| return rev |
| |
| def store_config(self): |
| if self._config._hash in self._kv_store: |
| return |
| |
| # crude serialization of config data |
| blob = self._config._data.SerializeToString() |
| if self.compress: |
| blob = compress(blob) |
| |
| self._kv_store[self._config._hash] = blob |
| |
| @classmethod |
| def load_config(cls, kv_store, msg_cls, config_hash): |
| blob = kv_store[config_hash] |
| if cls.compress: |
| blob = decompress(blob) |
| |
| # TODO use a loader later on |
| data = msg_cls() |
| data.ParseFromString(blob) |
| return data |
| |
| |
| def tmp_cls_loader(module_name, cls_name): |
| # TODO this shall be generalized |
| from voltha.protos import voltha_pb2, health_pb2, adapter_pb2, \ |
| logical_device_pb2, device_pb2, openflow_13_pb2, bbf_fiber_base_pb2, \ |
| bbf_fiber_traffic_descriptor_profile_body_pb2, \ |
| bbf_fiber_tcont_body_pb2, bbf_fiber_gemport_body_pb2, \ |
| bbf_fiber_multicast_gemport_body_pb2, \ |
| bbf_fiber_multicast_distribution_set_body_pb2, \ |
| omci_mib_db_pb2, \ |
| omci_alarm_db_pb2 |
| return getattr(locals()[module_name], cls_name) |