summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-12-08 16:33:45 +0100
committerChristian Breunig <christian@breunig.cc>2024-12-16 22:24:50 +0100
commit779f311e7fe81e3c85de28f13e4e12e33b255483 (patch)
treea7edc34394439a03b019be94cadd1837bcb7f7e0
parent1666e3d99b8de700c880f09ce6ad5ea8bc7f4568 (diff)
downloadvyos-1x-779f311e7fe81e3c85de28f13e4e12e33b255483.tar.gz
vyos-1x-779f311e7fe81e3c85de28f13e4e12e33b255483.zip
frr: T6746: integrate FRRender class into vyos-configd
When running under vyos-configd only a single apply() is done as last step in the commit algorithm. FRRender class address is provided via an attribute from vyos-configd process.
-rw-r--r--python/vyos/configdict.py6
-rw-r--r--python/vyos/frrender.py2
-rwxr-xr-xsrc/conf_mode/interfaces_bonding.py11
-rwxr-xr-xsrc/conf_mode/interfaces_ethernet.py11
-rwxr-xr-xsrc/conf_mode/policy.py9
-rwxr-xr-xsrc/conf_mode/protocols_babel.py9
-rwxr-xr-xsrc/conf_mode/protocols_bfd.py8
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py9
-rwxr-xr-xsrc/conf_mode/protocols_eigrp.py8
-rwxr-xr-xsrc/conf_mode/protocols_isis.py9
-rwxr-xr-xsrc/conf_mode/protocols_mpls.py9
-rw-r--r--src/conf_mode/protocols_openfabric.py9
-rwxr-xr-xsrc/conf_mode/protocols_ospf.py8
-rwxr-xr-xsrc/conf_mode/protocols_ospfv3.py9
-rwxr-xr-xsrc/conf_mode/protocols_pim.py8
-rwxr-xr-xsrc/conf_mode/protocols_pim6.py9
-rwxr-xr-xsrc/conf_mode/protocols_rip.py13
-rwxr-xr-xsrc/conf_mode/protocols_ripng.py8
-rwxr-xr-xsrc/conf_mode/protocols_rpki.py7
-rwxr-xr-xsrc/conf_mode/protocols_segment-routing.py7
-rwxr-xr-xsrc/conf_mode/protocols_static.py8
-rwxr-xr-xsrc/conf_mode/vrf.py11
-rwxr-xr-xsrc/services/vyos-configd8
23 files changed, 114 insertions, 82 deletions
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index c7384f71d..baffd94dd 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -1125,6 +1125,12 @@ def get_frrender_dict(conf) -> dict:
dict.update({'vrf' : vrf})
+ # Use singleton instance of the FRR render class
+ if hasattr(conf, 'frrender_cls'):
+ frrender = getattr(conf, 'frrender_cls')
+ dict.update({'frrender_cls' : frrender})
+ frrender.generate(dict)
+
if os.path.exists(frr_debug_enable):
print('======== < BEGIN > ==========')
import pprint
diff --git a/python/vyos/frrender.py b/python/vyos/frrender.py
index 2069930a9..e02094bbb 100644
--- a/python/vyos/frrender.py
+++ b/python/vyos/frrender.py
@@ -136,7 +136,7 @@ class FRRender:
emsg = ''
while count < count_max:
count += 1
- print('FRR: Reloading configuration', count)
+ print('FRR: Reloading configuration - tries:', count, 'Python class ID:', id(self))
cmdline = '/usr/lib/frr/frr-reload.py --reload'
if DEBUG_ON:
diff --git a/src/conf_mode/interfaces_bonding.py b/src/conf_mode/interfaces_bonding.py
index adea8fc63..5f839b33c 100755
--- a/src/conf_mode/interfaces_bonding.py
+++ b/src/conf_mode/interfaces_bonding.py
@@ -45,7 +45,6 @@ from vyos.configdep import set_dependents, call_dependents
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
def get_bond_mode(mode):
if mode == 'round-robin':
@@ -94,7 +93,7 @@ def get_config(config=None):
if tmp: bond.update({'shutdown_required' : {}})
tmp = is_node_changed(conf, base + [ifname, 'evpn'])
- if tmp: bond.update({'frrender' : get_frrender_dict(conf)})
+ if tmp: bond.update({'frr_dict' : get_frrender_dict(conf)})
# determine which members have been removed
interfaces_removed = leaf_node_changed(conf, base + [ifname, 'member', 'interface'])
@@ -264,13 +263,13 @@ def verify(bond):
return None
def generate(bond):
- if 'frrender' in bond:
- frrender.generate(bond['frrender'])
+ if 'frr_dict' in bond and 'frrender_cls' not in bond['frr_dict']:
+ FRRender().generate(bond['frr_dict'])
return None
def apply(bond):
- if 'frrender' in bond:
- frrender.apply()
+ if 'frr_dict' in bond and 'frrender_cls' not in bond['frr_dict']:
+ FRRender().apply()
b = BondIf(bond['ifname'])
if 'deleted' in bond:
diff --git a/src/conf_mode/interfaces_ethernet.py b/src/conf_mode/interfaces_ethernet.py
index 6a035e9e9..accfb6b8e 100755
--- a/src/conf_mode/interfaces_ethernet.py
+++ b/src/conf_mode/interfaces_ethernet.py
@@ -44,7 +44,6 @@ from vyos.utils.dict import dict_delete
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
def update_bond_options(conf: Config, eth_conf: dict) -> list:
"""
@@ -166,7 +165,7 @@ def get_config(config=None):
if tmp: ethernet.update({'speed_duplex_changed': {}})
tmp = is_node_changed(conf, base + [ifname, 'evpn'])
- if tmp: ethernet.update({'frrender' : get_frrender_dict(conf)})
+ if tmp: ethernet.update({'frr_dict' : get_frrender_dict(conf)})
return ethernet
@@ -322,13 +321,13 @@ def verify_ethernet(ethernet):
return None
def generate(ethernet):
- if 'frrender' in ethernet:
- frrender.generate(ethernet['frrender'])
+ if 'frr_dict' in ethernet and 'frrender_cls' not in ethernet['frr_dict']:
+ FRRender().generate(ethernet['frr_dict'])
return None
def apply(ethernet):
- if 'frrender' in ethernet:
- frrender.apply()
+ if 'frr_dict' in ethernet and 'frrender_cls' not in ethernet['frr_dict']:
+ FRRender().apply()
e = EthernetIf(ethernet['ifname'])
if 'deleted' in ethernet:
diff --git a/src/conf_mode/policy.py b/src/conf_mode/policy.py
index e6b6d474a..2122cb032 100755
--- a/src/conf_mode/policy.py
+++ b/src/conf_mode/policy.py
@@ -26,8 +26,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
def community_action_compatibility(actions: dict) -> bool:
"""
Check compatibility of values in community and large community sections
@@ -264,10 +262,13 @@ def verify(config_dict):
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_babel.py b/src/conf_mode/protocols_babel.py
index f9d5e45a0..f458493c2 100755
--- a/src/conf_mode/protocols_babel.py
+++ b/src/conf_mode/protocols_babel.py
@@ -27,8 +27,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
def get_config(config=None):
if config:
conf = config
@@ -91,10 +89,13 @@ def verify(config_dict):
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py
index a0d7fdfb5..d8b19fa0e 100755
--- a/src/conf_mode/protocols_bfd.py
+++ b/src/conf_mode/protocols_bfd.py
@@ -25,8 +25,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
def get_config(config=None):
if config:
conf = config
@@ -79,10 +77,12 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index 989cf9b5c..2a4bcbadf 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -35,8 +35,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
vrf = None
if len(argv) > 1:
vrf = argv[1]
@@ -558,10 +556,13 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_eigrp.py b/src/conf_mode/protocols_eigrp.py
index 5d60e6bfd..4f56d2b94 100755
--- a/src/conf_mode/protocols_eigrp.py
+++ b/src/conf_mode/protocols_eigrp.py
@@ -25,7 +25,6 @@ from vyos.frrender import FRRender
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
vrf = None
if len(argv) > 1:
@@ -55,10 +54,13 @@ def verify(config_dict):
verify_vrf(eigrp)
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py
index e812770bc..9e494ecc8 100755
--- a/src/conf_mode/protocols_isis.py
+++ b/src/conf_mode/protocols_isis.py
@@ -30,8 +30,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
vrf = None
if len(argv) > 1:
vrf = argv[1]
@@ -281,10 +279,13 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_mpls.py b/src/conf_mode/protocols_mpls.py
index 2a691f4a4..12899f0b2 100755
--- a/src/conf_mode/protocols_mpls.py
+++ b/src/conf_mode/protocols_mpls.py
@@ -31,8 +31,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
def get_config(config=None):
if config:
conf = config
@@ -69,10 +67,13 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
if not has_frr_protocol_in_dict(config_dict, 'mpls'):
return None
diff --git a/src/conf_mode/protocols_openfabric.py b/src/conf_mode/protocols_openfabric.py
index 3dc06ee68..9fdcf4b50 100644
--- a/src/conf_mode/protocols_openfabric.py
+++ b/src/conf_mode/protocols_openfabric.py
@@ -24,9 +24,7 @@ from vyos.configverify import has_frr_protocol_in_dict
from vyos.frrender import FRRender
from vyos import ConfigError
from vyos import airbag
-
airbag.enable()
-frrender = FRRender()
def get_config(config=None):
if config:
@@ -91,10 +89,13 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py
index 32ad5e497..07e6a5860 100755
--- a/src/conf_mode/protocols_ospf.py
+++ b/src/conf_mode/protocols_ospf.py
@@ -30,7 +30,6 @@ from vyos.utils.network import get_interface_config
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
vrf = None
if len(argv) > 1:
@@ -178,10 +177,13 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py
index 038fcd2b4..9af85cabf 100755
--- a/src/conf_mode/protocols_ospfv3.py
+++ b/src/conf_mode/protocols_ospfv3.py
@@ -31,8 +31,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
vrf = None
if len(argv) > 1:
vrf = argv[1]
@@ -90,10 +88,13 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_pim.py b/src/conf_mode/protocols_pim.py
index 1ff7203b2..df0e82d69 100755
--- a/src/conf_mode/protocols_pim.py
+++ b/src/conf_mode/protocols_pim.py
@@ -32,7 +32,6 @@ from vyos.utils.process import call
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
def get_config(config=None):
if config:
@@ -87,7 +86,9 @@ def verify(config_dict):
unique.append(gr_addr)
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
if not has_frr_protocol_in_dict(config_dict, 'pim'):
@@ -102,7 +103,8 @@ def apply(config_dict):
if not pim_pid:
call('/usr/lib/frr/pimd -d -F traditional --daemon -A 127.0.0.1')
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_pim6.py b/src/conf_mode/protocols_pim6.py
index b3a4099d2..a5d612814 100755
--- a/src/conf_mode/protocols_pim6.py
+++ b/src/conf_mode/protocols_pim6.py
@@ -26,7 +26,6 @@ from vyos.frrender import FRRender
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
def get_config(config=None):
if config:
@@ -76,10 +75,14 @@ def verify(config_dict):
unique.append(gr_addr)
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
+ return None
if __name__ == '__main__':
try:
diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py
index 3862530a2..7eb060504 100755
--- a/src/conf_mode/protocols_rip.py
+++ b/src/conf_mode/protocols_rip.py
@@ -28,8 +28,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
def get_config(config=None):
if config:
conf = config
@@ -69,11 +67,14 @@ def verify(config_dict):
raise ConfigError(f'You can not have "split-horizon poison-reverse" enabled ' \
f'with "split-horizon disable" for "{interface}"!')
-def generate(frr_dict):
- frrender.generate(frr_dict)
+def generate(config_dict):
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
+ return None
-def apply(rip):
- frrender.apply()
+def apply(config_dict):
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py
index 327a0d239..5884e61f9 100755
--- a/src/conf_mode/protocols_ripng.py
+++ b/src/conf_mode/protocols_ripng.py
@@ -28,8 +28,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
-
def get_config(config=None):
if config:
conf = config
@@ -70,11 +68,13 @@ def verify(config_dict):
f'with "split-horizon disable" for "{interface}"!')
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py
index c75f95860..33696a742 100755
--- a/src/conf_mode/protocols_rpki.py
+++ b/src/conf_mode/protocols_rpki.py
@@ -30,7 +30,6 @@ from vyos.utils.file import write_file
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
rpki_ssh_key_base = '/run/frr/id_rpki'
@@ -95,11 +94,13 @@ def generate(config_dict):
write_file(cache_config['ssh']['public_key_file'], wrap_openssh_public_key(public_key_data, public_key_type))
write_file(cache_config['ssh']['private_key_file'], wrap_openssh_private_key(private_key_data))
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
return None
def apply(config_dict):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_segment-routing.py b/src/conf_mode/protocols_segment-routing.py
index 0fad968e1..a776d1038 100755
--- a/src/conf_mode/protocols_segment-routing.py
+++ b/src/conf_mode/protocols_segment-routing.py
@@ -27,7 +27,6 @@ from vyos.utils.system import sysctl_write
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
def get_config(config=None):
if config:
@@ -55,7 +54,8 @@ def verify(config_dict):
return None
def generate(config_dict):
- frrender.generate(config_dict)
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
return None
def apply(config_dict):
@@ -88,7 +88,8 @@ def apply(config_dict):
else:
sysctl_write(f'net.ipv6.conf.{interface}.seg6_enabled', '0')
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py
index 1e498b256..69500377c 100755
--- a/src/conf_mode/protocols_static.py
+++ b/src/conf_mode/protocols_static.py
@@ -28,7 +28,6 @@ from vyos.template import render
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
vrf = None
if len(argv) > 1:
@@ -92,11 +91,14 @@ def generate(config_dict):
# Put routing table names in /etc/iproute2/rt_tables
render(config_file, 'iproute2/static.conf.j2', static)
- frrender.generate(config_dict)
+
+ if 'frrender_cls' not in config_dict:
+ FRRender().generate(config_dict)
return None
def apply(static):
- frrender.apply()
+ if 'frrender_cls' not in config_dict:
+ FRRender().apply()
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index a13bb8b1e..6eea9af4d 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -38,7 +38,6 @@ from vyos.utils.system import sysctl_write
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-frrender = FRRender()
config_file = '/etc/iproute2/rt_tables.d/vyos-vrf.conf'
k_mod = ['vrf']
@@ -135,7 +134,7 @@ def get_config(config=None):
# We need to merge the FRR rendering dict into the VRF dict
# this is required to get the route-map information to FRR
- vrf.update({'frrender' : get_frrender_dict(conf)})
+ vrf.update({'frr_dict' : get_frrender_dict(conf)})
# We also need the route-map information from the config
#
@@ -210,8 +209,8 @@ def generate(vrf):
# Render iproute2 VR helper names
render(config_file, 'iproute2/vrf.conf.j2', vrf)
- if 'frrender' in vrf:
- frrender.generate(vrf['frrender'])
+ if 'frr_dict' in vrf and 'frrender_cls' not in vrf['frr_dict']:
+ FRRender().generate(vrf['frr_dict'])
return None
@@ -353,8 +352,8 @@ def apply(vrf):
if has_rule(afi, 2000, 'l3mdev'):
call(f'ip {afi} rule del pref 2000 l3mdev unreachable')
- if 'frrender' in vrf:
- frrender.apply()
+ if 'frr_dict' in vrf and 'frrender_cls' not in vrf['frr_dict']:
+ FRRender().apply()
return None
diff --git a/src/services/vyos-configd b/src/services/vyos-configd
index d977ba2cb..21d91005a 100755
--- a/src/services/vyos-configd
+++ b/src/services/vyos-configd
@@ -37,6 +37,7 @@ from vyos.configsource import ConfigSourceString
from vyos.configsource import ConfigSourceError
from vyos.configdiff import get_commit_scripts
from vyos.config import Config
+from vyos.frrender import FRRender
from vyos import ConfigError
CFG_GROUP = 'vyattacfg'
@@ -209,6 +210,9 @@ def initialization(socket):
scripts_called = []
setattr(config, 'scripts_called', scripts_called)
+ if not hasattr(config, 'frrender_cls'):
+ setattr(config, 'frrender_cls', FRRender())
+
return config
@@ -326,5 +330,9 @@ if __name__ == '__main__':
if message['last'] and config:
scripts_called = getattr(config, 'scripts_called', [])
logger.debug(f'scripts_called: {scripts_called}')
+
+ if hasattr(config, 'frrender_cls'):
+ frrender_cls = getattr(config, 'frrender_cls')
+ frrender_cls.apply()
else:
logger.critical(f'Unexpected message: {message}')