diff --git a/docs/source/conf.py b/docs/source/conf.py index dc75f60eb2..10c31ff659 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -90,9 +90,9 @@ def __getattr__(cls, name): author = 'The VOLTTRON Community' # The short X.Y version -version = '9.0' +version = '9.0.1' # The full version, including alpha/beta/rc tags -release = '9.0' +release = '9.0.1' # -- General configuration --------------------------------------------------- diff --git a/services/core/PlatformDriverAgent/platform_driver/driver.py b/services/core/PlatformDriverAgent/platform_driver/driver.py index b86688f465..40b20fa887 100644 --- a/services/core/PlatformDriverAgent/platform_driver/driver.py +++ b/services/core/PlatformDriverAgent/platform_driver/driver.py @@ -167,7 +167,17 @@ def setup_device(self): self.heart_beat_point = config.get("heart_beat_point") - + # Warn if there is no registry: + if registry_config is None: + _log.warning(f'No registry was found for device: devices/{self.device_path}') + else: + # Check for duplicate names in registry entries and warn if this will cause rows to be skipped. + point_names = [r['Volttron Point Name'] for r in registry_config] + seen = set(point_names) + duplicates = [n for n in point_names if n not in seen or seen.remove(n)] + if duplicates: + _log.warning(f'Duplicate point names detected in registry file for devices/{self.device_path}. ' + f'Only the last registry row will be used for points with names: {set(duplicates)}') self.interface = self.get_interface(driver_type, driver_config, registry_config) self.meta_data = {} diff --git a/volttron/platform/__init__.py b/volttron/platform/__init__.py index d6ce14cdd2..5a7525b81e 100644 --- a/volttron/platform/__init__.py +++ b/volttron/platform/__init__.py @@ -35,7 +35,7 @@ from urllib.parse import urlparse from ..utils.frozendict import FrozenDict -__version__ = '9.0rc0' +__version__ = '9.0.1' _log = logging.getLogger(__name__) diff --git a/volttron/platform/vip/agent/subsystems/auth.py b/volttron/platform/vip/agent/subsystems/auth.py index 8ba4e2dcba..9337d0e513 100644 --- a/volttron/platform/vip/agent/subsystems/auth.py +++ b/volttron/platform/vip/agent/subsystems/auth.py @@ -265,6 +265,7 @@ def update_rpc_method_capabilities(self): """ rpc_method_authorizations = {} rpc_methods = self.get_rpc_exports() + updated_rpc_authorizations = None for method in rpc_methods: if len(method.split(".")) > 1: pass @@ -295,9 +296,7 @@ def update_rpc_method_capabilities(self): _log.info( f"Skipping updating rpc auth capabilities for agent " f"{self._core().identity} connecting to remote address: {self._core().address} ") - updated_rpc_authorizations = None except gevent.timeout.Timeout: - updated_rpc_authorizations = None _log.warning(f"update_id_rpc_authorization rpc call timed out for {self._core().identity} {rpc_method_authorizations}") except MethodNotFound: _log.warning("update_id_rpc_authorization method is missing from " @@ -306,7 +305,6 @@ def update_rpc_method_capabilities(self): "dynamic RPC authorizations.") return except Exception as e: - updated_rpc_authorizations = None _log.exception(f"Exception when calling rpc method update_id_rpc_authorizations for identity: " f"{self._core().identity} Exception:{e}") if updated_rpc_authorizations is None: @@ -318,7 +316,7 @@ def update_rpc_method_capabilities(self): f"the identity of the agent" ) return - if rpc_method_authorizations != updated_rpc_authorizations: + if rpc_method_authorizations != updated_rpc_authorizations and updated_rpc_authorizations is not None: for method in updated_rpc_authorizations: self.set_rpc_authorizations( method, updated_rpc_authorizations[method] diff --git a/volttron/platform/web/admin_endpoints.py b/volttron/platform/web/admin_endpoints.py index 9de8d05a5c..d307b2f353 100644 --- a/volttron/platform/web/admin_endpoints.py +++ b/volttron/platform/web/admin_endpoints.py @@ -46,7 +46,6 @@ from volttron.platform import get_home from volttron.platform import jsonapi from volttron.utils import VolttronHomeFileReloader -from volttron.utils.persistance import PersistentDict _log = logging.getLogger(__name__) @@ -84,7 +83,7 @@ def __init__(self, rmq_mgmt=None, ssl_public_key: bytes = None, rpc_caller=None) else: self._ssl_public_key = None - self._userdict = None + self._userdict = {} self.reload_userdict() self._observer = Observer() @@ -96,7 +95,14 @@ def __init__(self, rmq_mgmt=None, ssl_public_key: bytes = None, rpc_caller=None) def reload_userdict(self): webuserpath = os.path.join(get_home(), 'web-users.json') - self._userdict = PersistentDict(webuserpath, format="json") + if os.path.exists(webuserpath): + with open(webuserpath) as fp: + try: + self._userdict = jsonapi.loads(fp.read()) + except json.decoder.JSONDecodeError: + self._userdict = {} + # Keep same behavior as with PersistentDict + raise ValueError("File not in a supported format") def get_routes(self): """ @@ -339,4 +345,5 @@ def add_user(self, username, unencrypted_pw, groups=None, overwrite=False): groups=groups ) - self._userdict.sync() + with open(os.path.join(get_home(), 'web-users.json'), 'w') as fp: + fp.write(jsonapi.dumps(self._userdict, indent=2)) diff --git a/volttron/platform/web/topic_tree.py b/volttron/platform/web/topic_tree.py index fedc0e6820..d029298520 100644 --- a/volttron/platform/web/topic_tree.py +++ b/volttron/platform/web/topic_tree.py @@ -166,6 +166,9 @@ def from_store(cls, platform, rpc_caller): registry_config = registry_config if kwargs else registry_config.get(timeout=5) for pnt in registry_config: point_name = pnt.pop('Volttron Point Name') - n = device_tree.create_node(point_name, f"{d}/{point_name}", parent=d, data=pnt) - n.segment_type = 'POINT' + try: + n = device_tree.create_node(point_name, f"{d}/{point_name}", parent=d, data=pnt) + n.segment_type = 'POINT' + except DuplicatedNodeIdError: + _log.warning(f'Duplicate Voltron Point Name ({point_name}) found in registry: {reg_cfg_name}.') return device_tree