action managed upgrade fails with "jinja2.exceptions.UndefinedError: 'storage_ceph' is undefined"
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Gnocchi Charm |
Fix Released
|
Undecided
|
Unassigned | ||
OpenStack Principle Layer |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
The action managed upgrade fails as the interfaces don't get added to the context for the Jinja2 renderer:
Traceback (most recent call last):
File "/var/lib/
File "/var/lib/
File "/var/lib/
File "/var/lib/
File "/var/lib/
File "/var/lib/
File "/var/lib/
File "/var/lib/
content = template.
File "/var/lib/
return original_
File "/var/lib/
return self.environmen
File "/var/lib/
File "/var/lib/
raise value.with_
File "templates/
{% if options.
File "/var/lib/
return getattr(obj, attribute)
jinja2.
The reason is related to this code in charms.openstack: (charms_
def render_
"""Render the configuration files identified in the list passed as
configs.
Configs may not only be loaded via OpenStack loaders but also via
string templates passed via config options or from relation data.
This must be explicitly declared via string_templates dict of a given
derived charm class by using a relation name that identifies a relation
adapter or config option adapter and a property to be used from that
adapter instance.
:param configs: list of strings, the names of the configuration files.
:param adapters_instance: [optional] the adapters_instance to use.
"""
if adapters_instance is None:
for f in flags.get_flags():
if ep_from_f:
try:
except TypeError:
During an action, the adapters_interface passed to the function is None AND the flags.get_flags() doesn't result in any interfaces. Therefore, no context gets passed to the charm-helpers renderer and thus the rendering fails.
A workaround is to NOT use the action managed 'openstack-upgrade' function, and instead, use the config option with "action-
Temporary fix is to remove the action-
no longer affects: | charms.openstack |
Changed in layer-openstack-principle: | |
status: | New → In Progress |
Changed in charm-gnocchi: | |
status: | New → In Progress |
Changed in charm-gnocchi: | |
milestone: | none → 21.01 |
Changed in layer-openstack-principle: | |
milestone: | none → 21.01 |
Changed in charm-gnocchi: | |
status: | In Progress → Fix Committed |
Changed in layer-openstack-principle: | |
status: | In Progress → Fix Committed |
Changed in layer-openstack-principle: | |
assignee: | Alex Kavanagh (ajkavanagh) → nobody |
Changed in charm-gnocchi: | |
assignee: | Alex Kavanagh (ajkavanagh) → nobody |
Changed in charm-gnocchi: | |
status: | Fix Committed → Fix Released |
Changed in layer-openstack-principle: | |
status: | Fix Committed → Fix Released |
Part of the problem is in charms.openstack in the run_upgrade() function in core.py which tries to do the rendering (which is good), but fails completely if the rendering fails. This would mean that an upgrade can't proceed if, say, the charm is not related to the components that the config files require rendering; remember this is being called from an action and that means that it may not have the full context; c.f. with normally rendering, where the handlers will not run if the interfaces are not available, avoiding the whole "rendering" issue.
I think the right thing to do is to wrap the rendering and the upgrade in a try-except. This would allow the action to complete, but may result in the configs not being rendered and the db migration not happening. I think this should be gated on the interfaces_list being empty. i.e. don't worry about a failing render or db migration if the interfaces_list is empty as the unit may not actually be related to anything. If it is, then it's up to the charm to provide the interfaces list (and thus probably override "run_upgrade()" to provide the minimal list of interfaces if they are configured.