Functions and dialplan global variables

I had an issue where I was using

[globals]
HOST=${SHELL(uname -n | cut -d. -f1):0:-1}

and it seemed to be working on some boxes, but not on others. ${HOST} was set correctly on most boxes, but not all. There were no obviously relevant differences between the boxes. RedHat and Asterisk versions were the same.

Further investigation showed that a core reload seemed to set the variable.

Digging in the logs I found some occurrences of
[Nov 4 09:29:12] ERROR[11916] pbx_functions.c: Function SHELL not registered

This error suggested that there was an issue with the SHELL function, but it was used OK elsewhere in the dialplan. I looked for documentation and guidance about the use of functions within the [globals] section, but I didn’t find anything.

Changing to use
HOST=${CUT(SYSTEMNAME,.,1)}
also seemed to work on some systems, but not others, sometimes producing the error
[Nov 4 09:50:48] ERROR[15503] pbx_functions.c: Function CUT not registered
so it seemed likely that the globals were being evaluated before those functions were loaded.

There is nothing I can see in the documentation or the book to warn that functions may not be available when evaluating [globals]

I think adding a preload for the required function to modules.conf will get it to work reliably, e.g.
preload=func_cut.so

It woudl be nice if this could be clearly documented and even better if it could be made deterministic, so that all functions would be available to the dialplan.

I was surprised that functions were expanded at all in this context. Most people wouldn’t try, which is probably why there is no load order dependency for this.

Doing a preload is the way to handle this situation.

This is documented in modules.conf.sample:

; Any modules that need to be loaded before the Asterisk core has been
; initialized (just after the logger has been initialized) can be loaded
; using 'preload'. This will frequently be needed if you wish to map all
; module configuration files into Realtime storage, since the Realtime
; driver will need to be loaded before the modules using those configuration
; files are initialized.

I’ll grant that it mostly talks about Realtime here, but the implication that you need to use preload to load a module used by the core (which the PBX dialplan most certainly is part of) is pretty explicit.

If you think there could be further documentation improvements, by all means, please contribute a patch to the documentation via Gerrit or find the appropriate wiki page on the Asterisk wiki and leave a comment on it with the suggested changes.

1 Like

That’s not somewhere most people will find it, IMHO.

Thinking about that, it seems to me that there is no guarantee that functions are available in running extensions either? In practice I imagine that it would be vanishingly rare for a running extension to find that it relies on a function that hasn’t been loaded, but it could be a source of obscure, hard to trace issues.

It’s not obvious where in the current documentation it would go. I had a dig through the wiki and there doesn’t seem to be a topic for dialplan variables or the [globals] section. It might be useful as a note on dialplan functions?

When you’re running an extension, you have an active channel. If you have an active channel, you’re past the loading of modules.

Generally, you need to preload when something is evaluated prior to that point. Global variables, hints, and - in some cases - queue members are the most likely candidates. Part of the problem with providing a ‘listing’ is that sometimes these things don’t require preload, and sometimes people find creative mechanisms that we can’t anticipate.

I wouldn’t be against that.