net/haproxy: Template generation fails when model serializes list fields as dict instead of string
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 55/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- python
- Ambito
- backend, networking
Direzione di ricerca
Iniziate dal comando che fallisce configctl template reload OPNsense/HAProxy ed esaminate net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf e sslCerts.yaml, insieme a template_helpers.py. Tracciate i campi elencati sia nella forma string sia nella forma dict, quindi verificate che il rendering di frontend, certificato, ACL/action e backend abbia esito positivo e che HAProxy si avvii senza errori di sintassi.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
[HAProxy] Template generation crashes when model serializes list fields as dict instead of string
Important notices
- I have read the contributing guide lines at https://github.com/opnsense/plugins/blob/master/CONTRIBUTING.md
- I have searched the existing issues, open and closed, and I'm convinced that mine is new.
- The title contains the plugin to which this issue belongs
Describe the bug
Applying any HAProxy frontend configuration fails with
Configuration exception — Template generation failed for internal service "haproxy". See backend log for details.
(and a red "HAProxy configtest found critical errors" banner in the GUI).
Root cause: the HAProxy Jinja2 templates (haproxy.conf, sslCerts.yaml)
assume several model fields are CSV strings, but on os-haproxy 5.1 /
OPNsense 26.7.3_8 the model serializes those same fields as dicts
(OrderedDict). The template then calls .split(",") / .name on a dict
and aborts rendering — so HAProxy can never be (re)started from the
plugin-generated config.
Last known working version: unknown — the trigger depends on how the
model serializes list-typed fields; on setups where it still emits
strings the bug stays hidden.
To Reproduce
- OPNsense 26.7.3_8, install os-haproxy 5.1, enable the plugin.
- Go to Services → HAProxy → Frontend (
https://<firewall>/ui/haproxy/frontend). - Click Add, set
bindto0.0.0.0:443, enable SSL, select a certificate, set a default backend, and add an action (use_backendon an ACL) plus the matching ACL. - Click Apply (or trigger it via
configctl template reload OPNsense/HAProxy). - See error: red banner +
configd.logshows a chain of Jinja
UndefinedError/TypeErrorwhile rendering
OPNsense/HAProxy/haproxy.confandOPNsense/HAProxy/sslCerts.yaml.
Expected behavior
Apply should render a valid haproxy.conf and (re)start HAProxy
without manual template patching, regardless of whether the model
serializes list fields as string or dict.
Screenshots
n/a
Relevant log files
configd.log (excerpt, plugin version 5.1 / OPNsense 26.7.3_8):
error generating template OPNsense/HAProxy : ...
File ".../OPNsense/HAProxy/haproxy.conf", line 2468, in top-level template code
{% for bind in frontend.bind.split(",") %}
jinja2.exceptions.UndefinedError: 'collections.OrderedDict object' has no attribute 'split'
error generating template OPNsense/HAProxy : ...
File ".../OPNsense/HAProxy/sslCerts.yaml", line 37, in top-level template code
{% for cert in frontend.get('ssl_certificates', '').split(',') + ... %}
TypeError: can only concatenate list (not "odict_keys") to list
Confirmed failing spots (all in
/usr/local/opnsense/service/templates/OPNsense/HAProxy/):
haproxy.conf~2468:frontend.bind.split(",")—bindis
{"0.0.0.0:443": {"value": "0.0.0.0:443", "selected": 1}}haproxy.confAclsAndActionsmacro (~88, ~96, ~1757):
linkedData.split(","),action_data.linkedAcls.split(","),
action_data.name— dicts, not strings/objectshaproxy.conf~2517:option {{frontend.connectionBehaviour}}—
renders a bareoption(empty) when the field is empty → hard
HAProxy syntax errorhaproxy.conf~2811:backend.linkedServers.split(",")— dict →
noserverlines emitted → HTTP 502 on every routesslCerts.yaml~37:frontend.get('ssl_certificates','').split(',')
— dict → no certlist generated → frontend has no listener
Upstream confirmation
The exact same patterns are present in current master of the plugin:
net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf
({% for action in linkedData.split(",") %},
action_data.linkedAcls.split(","),
backend.linkedServers.split(","))net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/sslCerts.yaml
(frontend.get('ssl_certificates', '').split(','))
So the templates assume string-typed list fields. The bug only surfaces
when the model serializes those fields as dict (os-haproxy 5.1 /
OPNsense 26.7.3_8). On setups where the model still emits strings the
failure is invisible — which is likely why prior reports were
auto-triaged as low-priority.
Workaround (tested locally — not a PR)
template_helpers.py— makegetUUID()return a dict subclass that
supports bothobj['key']andobj.key:
andclass _DotDict(dict): def __getattr__(self, name): if name in self: return self[name] raise AttributeError(name) def __getitem__(self, key): v = dict.__getitem__(self, key) if isinstance(v, dict) and not isinstance(v, _DotDict): return _DotDict(v) return vreturn _DotDict(self._template_in_data['__uuid__'].get(uuid, {}))
insidegetUUID().haproxy.conf— guard the.split(",")calls so they accept a dict:
{% for x in (field.keys() if field is mapping else field.split(",")) %}
(applied tofrontend.bind,backend.linkedServers,
action_data.linkedAcls,frontend_data.bind).haproxy.conf— guardconnectionBehaviour:
{% if frontend.connectionBehaviour|default("") != "" %} option {{frontend.connectionBehaviour}}{% endif %}sslCerts.yaml— replace the.split(',')onssl_certificates/
ssl_default_certificatewith a for-loop that iterates dict keys when
the value is a mapping.
After these, configctl template reload OPNsense/HAProxy returns OK
and HAProxy starts from the plugin-generated config with all backends up.
Suggested proper fix
Add a small Jinja filter (e.g. tolist) in the template engine /
helpers that normalizes both shapes — string CSV and dict — into a list,
and use it wherever the templates currently call .split(",") on a model
field. That makes the templates robust regardless of how the model
serializes list-typed fields.
Additional context
This report was drafted with assistance from an AI tool (Hermes / Nous
Research, model tencent/hy3) based on direct inspection of the failing
template render and a comparison with the plugin master branch, as
required by CONTRIBUTING.md.
Environment
- OPNsense 26.7.3_8 (amd64)
- os-haproxy plugin: 5.1
- haproxy: 3.2.22
- Python: 3.13.15
- Jinja2: 3.1.6
- FreeBSD: 15.1-RELEASE-p3
- Lingua principale
- PHP
- Stelle
- 1.2k
- Fork
- 896
- Merge medio
- 3g 15h
- PR unite (30g)
- 11
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di opnsense/plugins
-
security/tailscale: add description to restart serviceForse già presa @drpsyko101 l’ha presa oggi. Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
security/acme-client: missing accounts directory causes DNS-01 validation failureForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Apertasupport
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
opnsense/plugins#5770 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
security/tor: Advanced mode / help toggles are brokenForse già presa @txr13 l’ha presa 43 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
os-opnproxy 1.0.5_5Apertaincomplete
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
opnsense/plugins#5710 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
net/vnstat: use OPNsense interface names in dashboard widgetForse già presa @joeroback l’ha presa 106 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di opnsense/plugins
Issue simili
-
enhancement
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
Text to Speech fails on Windows: the temp file path loses its backslashes when stored in post metaForse già presa @azizulhasan l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
Bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
GravityPDF/gravity-pdf#1991 ·
I maintainer di solito rispondono entro 1 giorno
-
Advanced search: created_at:!= combined with another term returns entries that do not match itAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
I maintainer di solito rispondono entro 1 giorno
-
[Finder] Glob::toRegex() produces an invalid regex for bracket expressions containing a slashApertaFinder
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno