Avatar Error
Deployment Type
Docker
Version
2.0.4
Steps to Reproduce
define 'avatar' in devices.yaml
Expected Behavior
Create a logo for a router.
Observed Behavior
Error in: /opt/hyperglass/hyperglass/models/config/devices.py, line 201 device=values["name"]
Configuration
No response
Devices
---
devices:
- name: r1
group: Cape Town
avatar: /etc/hyperglass/router.png
Logs
error: hyperglass_1 | File "/opt/hyperglass/hyperglass/models/config/devices.py", line 201, in validate_avatar
hyperglass_1 | device=values["name"]
@thatmattlove I seem to be having possibly a similar issue trying to get avatars working. Using the following device config (just some testing values):
devices:
- name: UKSE1 (London)
address: 127.0.0.1
avatar: /etc/hyperglass/flags/gb.png
credential:
username: test
password: test
platform: frr
attrs:
source4: 127.0.0.1
source6: 2001:db8::1
directives:
- builtins: false
- frr-bgp-route
I end up with the following traceback when restarting hyperglass
Jun 03 21:27:18 lg1 python3[39548]: [DEBUG] 20250603 21:27:18 |66 | load_dsl <E2><86><92> Loaded configuration {'path': PosixPath('/etc/hyperglass/config.yaml')}
Jun 03 21:27:18 lg1 python3[39548]: [DEBUG] 20250603 21:27:18 |66 | load_dsl <E2><86><92> Loaded configuration {'path': PosixPath('/etc/hyperglass/directives.yaml')}
Jun 03 21:27:18 lg1 python3[39548]: [DEBUG] 20250603 21:27:18 |66 | load_dsl <E2><86><92> Loaded configuration {'path': PosixPath('/etc/hyperglass/directives.yaml')}
Jun 03 21:27:18 lg1 python3[39548]: [DEBUG] 20250603 21:27:18 |66 | load_dsl <E2><86><92> Loaded configuration {'path': PosixPath('/etc/hyperglass/devices.yaml')}
Jun 03 21:27:18 lg1 python3[39548]: [CRITICAL] 20250603 21:27:18 |176 | run <E2><86><92> 'pydantic_core._pydantic_core.ValidationInfo' object is not subscriptable {}
Jun 03 21:27:18 lg1 python3[39548]: [DEBUG] 20250603 21:27:18 |181 | run <E2><86><92> Cleared hyperglass state {}
Jun 03 21:27:18 lg1 python3[39548]: Error in sys.excepthook:
Jun 03 21:27:18 lg1 python3[39548]: Traceback (most recent call last):
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/typer/main.py", line 72, in except_hook
Jun 03 21:27:18 lg1 python3[39548]: rich_tb = Traceback.from_exception(
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/rich/traceback.py", line 343, in from_exception
Jun 03 21:27:18 lg1 python3[39548]: rich_traceback = cls.extract(
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/rich/traceback.py", line 489, in extract
Jun 03 21:27:18 lg1 python3[39548]: key: pretty.traverse(
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/rich/pretty.py", line 874, in traverse
Jun 03 21:27:18 lg1 python3[39548]: node = _traverse(_object, root=True)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/rich/pretty.py", line 667, in _traverse
Jun 03 21:27:18 lg1 python3[39548]: args = list(iter_rich_args(rich_repr_result))
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/rich/pretty.py", line 634, in iter_rich_args
Jun 03 21:27:18 lg1 python3[39548]: for arg in rich_args:
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/pydantic/_internal/_repr.py", line 80, in __rich_repr__
Jun 03 21:27:18 lg1 python3[39548]: for name, field_repr in self.__repr_args__():
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/pydantic/root_model.py", line 157, in __repr_args__
Jun 03 21:27:18 lg1 python3[39548]: yield 'root', self.root
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/pydantic/main.py", line 991, in __getattr__
Jun 03 21:27:18 lg1 python3[39548]: raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')
Jun 03 21:27:18 lg1 python3[39548]: AttributeError: 'Devices' object has no attribute 'root'
Jun 03 21:27:18 lg1 python3[39548]: Original exception was:
Jun 03 21:27:18 lg1 python3[39548]: Traceback (most recent call last):
Jun 03 21:27:18 lg1 python3[39548]: File "<frozen runpy>", line 198, in _run_module_as_main
Jun 03 21:27:18 lg1 python3[39548]: File "<frozen runpy>", line 88, in _run_code
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/console.py", line 8, in <module>
Jun 03 21:27:18 lg1 python3[39548]: run()
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/cli/main.py", line 29, in run
Jun 03 21:27:18 lg1 python3[39548]: return typer.run(cli())
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/typer/main.py", line 328, in __call__
Jun 03 21:27:18 lg1 python3[39548]: raise e
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/typer/main.py", line 311, in __call__
Jun 03 21:27:18 lg1 python3[39548]: return get_command(self)(*args, **kwargs)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/click/core.py", line 1442, in __call__
Jun 03 21:27:18 lg1 python3[39548]: return self.main(*args, **kwargs)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/typer/core.py", line 783, in main
Jun 03 21:27:18 lg1 python3[39548]: return _main(
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/typer/core.py", line 225, in _main
Jun 03 21:27:18 lg1 python3[39548]: rv = self.invoke(ctx)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/click/core.py", line 1830, in invoke
Jun 03 21:27:18 lg1 python3[39548]: return _process_result(sub_ctx.command.invoke(sub_ctx))
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/click/core.py", line 1226, in invoke
Jun 03 21:27:18 lg1 python3[39548]: return ctx.invoke(self.callback, **ctx.params)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/click/core.py", line 794, in invoke
Jun 03 21:27:18 lg1 python3[39548]: return callback(*args, **kwargs)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/typer/main.py", line 683, in wrapper
Jun 03 21:27:18 lg1 python3[39548]: return callback(**use_params) # type: ignore
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/cli/main.py", line 61, in _start
Jun 03 21:27:18 lg1 python3[39548]: run(workers)
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/main.py", line 183, in run
Jun 03 21:27:18 lg1 python3[39548]: raise error
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/main.py", line 140, in run
Jun 03 21:27:18 lg1 python3[39548]: init_user_config()
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/configuration/__init__.py", line 41, in init_user_config
Jun 03 21:27:18 lg1 python3[39548]: _devices = devices or init_devices()
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/configuration/validate.py", line 105, in init_devices
Jun 03 21:27:18 lg1 python3[39548]: devices = Devices(*items)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/models/config/devices.py", line 315, in __init__
Jun 03 21:27:18 lg1 python3[39548]: super().__init__(*with_id)
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/models/main.py", line 203, in __init__
Jun 03 21:27:18 lg1 python3[39548]: valid = self._valid_items(*items)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/models/main.py", line 305, in _valid_items
Jun 03 21:27:18 lg1 python3[39548]: items[index] = self.model(**item)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/models/config/devices.py", line 78, in __init__
Jun 03 21:27:18 lg1 python3[39548]: super().__init__(**kw)
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/venv/lib/python3.12/site-packages/pydantic/main.py", line 253, in __init__
Jun 03 21:27:18 lg1 python3[39548]: validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
Jun 03 21:27:18 lg1 python3[39548]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: File "/opt/hyperglass/hyperglass/models/config/devices.py", line 201, in validate_avatar
Jun 03 21:27:18 lg1 python3[39548]: device=values["name"],
Jun 03 21:27:18 lg1 python3[39548]: ~~~~~~^^^^^^^^
Jun 03 21:27:18 lg1 python3[39548]: TypeError: 'pydantic_core._pydantic_core.ValidationInfo' object is not subscriptable
gb.png gets copied successfully to static/images
I can also reproduce this issue for the address field when it is set to a hostname that is unresolvable. The issue stems from the attempt to use https://docs.pydantic.dev/latest/concepts/validators/#validation-info like a dictionary when writing to the logs.
https://github.com/thatmattlove/hyperglass/blob/15491f904b1522b639b3dc2a4b051e37b4c87bb7/hyperglass/models/config/devices.py#L171-L184
The troublesome line is 181. I am not particularly familiar with pydantic but the use of values looks like it might be a left over from v1? (current pydantic version is v2).
I will try fix this then open a PR