Help packaging Openfire with Nix (NGI0 Core)

Hello,

I’m a Summer of Nix participant working on packaging Openfire for Nix as part of the support effort for projects funded through NGI0 Core. Currently, I have three issues running the program.

First, Openfire looks for the logs relative to the OPENFIRE_HOME, but that directory is stored in the nix store, which is a read-only directory. As such, I’m met with the following error:

ERROR StatusConsoleListener Unable to create file /nix/store/z3h6gjarc8zl8qwm51np6ijkapxnbp8d-openfire-4.8.3/logs/openfire.log
 java.io.IOException: Could not create directory /nix/store/z3h6gjarc8zl8qwm51np6ijkapxnbp8d-openfire-4.8.3/logs

I tried using OPENFIRE_LOGDIR and OPENFIRE_LOG_DIR to point to writeable directories, but these variables don’t seem to have any effect.


Second, the program is unable to extract the search plugin:

An exception occurred while trying to extract plugin 'search':

Which I think is because it tries to unzip it in this read-only directory since the error message points to the unzipPlugin function.


Third, when opening http://localhost:9090/, I get the following message:

HTTP ERROR 503 Service Unavailable
URI:	/
STATUS:	503
MESSAGE:	Service Unavailable
SERVLET:	-

Which I don’t know if it’s related to the previous two issues or not.


In summary, is there any way to point Openfire to use a writeable directory for the logs and the plugin extraction or is there something that I missed to configure?

For more details, here is the full log:

openfire.log
$ ./result/bin/openfire.sh -debug start
Starting debug mode
Listening for transport dt_socket at address: 5005
ERROR StatusConsoleListener Unable to create file /nix/store/svp55vzxhgd0s7ykn2s026wi5diiqrs0-openfire-4.8.3/logs/openfire.log
 java.io.IOException: Could not create directory /nix/store/svp55vzxhgd0s7ykn2s026wi5diiqrs0-openfire-4.8.3/logs
        at org.apache.logging.log4j.core.util.FileUtils.mkdir(FileUtils.java:128)
        at org.apache.logging.log4j.core.util.FileUtils.makeParentDirs(FileUtils.java:141)
        at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:734)
        at org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory.createManager(RollingFileManager.java:718)
        at org.apache.logging.log4j.core.appender.AbstractManager.getManager(AbstractManager.java:144)
        at org.apache.logging.log4j.core.appender.OutputStreamManager.getManager(OutputStreamManager.java:100)
        at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.getFileManager(RollingFileManager.java:217)
        at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:135)
        at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:62)
        at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:124)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1138)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1063)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1055)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:664)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:258)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:304)
        at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:621)
        at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:694)
        at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:711)
        at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:253)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:47)
        at org.apache.logging.log4j.LogManager.getContext(LogManager.java:196)
        at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:137)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:61)
        at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:47)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:426)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:451)
        at org.jivesoftware.openfire.starter.ServerStarter.<clinit>(ServerStarter.java:48)
ERROR StatusConsoleListener Could not create plugin of type class org.apache.logging.log4j.core.appender.RollingFileAppender for element RollingFile: java.lang.IllegalStateException: ManagerFactory [org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory@478190fc] unable to create manager for [/nix/store/svp55vzxhgd0s7ykn2s026wi5diiqrs0-openfire-4.8.3/logs/openfire.log] with data [org.apache.logging.log4j.core.appender.rolling.RollingFileManager$FactoryData@79e2c065[pattern=/nix/store/svp55vzxhgd0s7ykn2s026wi5diiqrs0-openfire-4.8.3/logs/openfire.log-%i, append=true, bufferedIO=true, bufferSize=8192, policy=CompositeTriggeringPolicy(policies=[SizeBasedTriggeringPolicy(size=104857600)]), strategy=DefaultRolloverStrategy(min=1, max=7, useMax=true), advertiseURI=null, layout=%d{yyyy.MM.dd HH:mm:ss.SSS} %highlight{%-5p} [%t]: %c - %msg{nolookups}%n, filePermissions=null, fileOwner=null]]
 java.lang.IllegalStateException: ManagerFactory [org.apache.logging.log4j.core.appender.rolling.RollingFileManager$RollingFileManagerFactory@478190fc] unable to create manager for [/nix/store/svp55vzxhgd0s7ykn2s026wi5diiqrs0-openfire-4.8.3/logs/openfire.log] with data [org.apache.logging.log4j.core.appender.rolling.RollingFileManager$FactoryData@79e2c065[pattern=/nix/store/svp55vzxhgd0s7ykn2s026wi5diiqrs0-openfire-4.8.3/logs/openfire.log-%i, append=true, bufferedIO=true, bufferSize=8192, policy=CompositeTriggeringPolicy(policies=[SizeBasedTriggeringPolicy(size=104857600)]), strategy=DefaultRolloverStrategy(min=1, max=7, useMax=true), advertiseURI=null, layout=%d{yyyy.MM.dd HH:mm:ss.SSS} %highlight{%-5p} [%t]: %c - %msg{nolookups}%n, filePermissions=null, fileOwner=null]]
        at org.apache.logging.log4j.core.appender.AbstractManager.getManager(AbstractManager.java:146)
        at org.apache.logging.log4j.core.appender.OutputStreamManager.getManager(OutputStreamManager.java:100)
        at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.getFileManager(RollingFileManager.java:217)
        at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:135)
        at org.apache.logging.log4j.core.appender.RollingFileAppender$Builder.build(RollingFileAppender.java:62)
        at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:124)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1138)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1063)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1055)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:664)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:258)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:304)
        at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:621)
        at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:694)
        at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:711)
        at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:253)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:47)
        at org.apache.logging.log4j.LogManager.getContext(LogManager.java:196)
        at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:137)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:61)
        at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:47)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:426)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:451)
        at org.jivesoftware.openfire.starter.ServerStarter.<clinit>(ServerStarter.java:48)
ERROR StatusConsoleListener Unable to invoke factory method in class org.apache.logging.log4j.core.appender.RollingFileAppender for element RollingFile: java.lang.IllegalStateException: No factory method found for class org.apache.logging.log4j.core.appender.RollingFileAppender
 java.lang.IllegalStateException: No factory method found for class org.apache.logging.log4j.core.appender.RollingFileAppender
        at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.findFactoryMethod(PluginBuilder.java:260)
        at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:136)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1138)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1063)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1055)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:664)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:258)
        at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:304)
        at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:621)
        at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:694)
        at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:711)
        at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:253)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:155)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:47)
        at org.apache.logging.log4j.LogManager.getContext(LogManager.java:196)
        at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getContext(AbstractLoggerAdapter.java:137)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:61)
        at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:47)
        at org.apache.logging.slf4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:33)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:426)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:451)
        at org.jivesoftware.openfire.starter.ServerStarter.<clinit>(ServerStarter.java:48)
ERROR StatusConsoleListener Null object returned for RollingFile in Appenders.
ERROR StatusConsoleListener Unable to locate appender "openfire" for logger config "root"
Critical Error! The home directory has not been configured,
which will prevent the application from working correctly.


An exception occurred while trying to extract plugin 'search':
Openfire 4.8.3 [Sep 17, 2024, 11:51:00 AM]
Admin console listening at http://nixos:9090
Successfully loaded plugin 'admin'.
An exception occurred while trying to extract plugin 'search':
^CHalting server...
Server halted

Thanks for the help.

This is the link to the PR (new users have a limit of 2 links per post).

Ah, it’s exciting to see a new packaging effort. Thanks for taking this on!

Openfire’s packaging has always been a bit elusive to me. I have adopted a “don’t touch when it’s not broken” stance to it. That’s primarily due to a fear of introducing upgrading issues. As a result, it is not something that I’m very familiar with.

Generally speaking, Openfire requires read and write access to anything in and under OPENFIRE_HOME. The first two issues that you describe seem to be a direct result of the Openfire process not being able to. I don’t immediately recognize the third problem, but it’s likely that it’s a side-effect of the same.

Apart from the logging, this is where plugins get extracted (OPENFIRE_HOME/plugins/), where some (non-read-only) config is persisted (OPENFIRE_HOME/conf/, OPENFIRE_HOME/security/), the embedded database lives (OPENFIRE_HOME/embedded-db/) and where plugins can be expected to create directories where they persist their own data (e.g. the Monitoring Service plugin is known to create indices in (OPENFIRE_HOME/monitoring). I’m probably missing a couple of things that write to this directory.

You can quite easily control where log files are stored by modifying /lib/log4j2.xml. That file is a standard configuration file from Log4j.

I have no experience with Nix, so I can’t be of much practical help there. Maybe you can find some inspiration in the (largely outdated) distribution configuration that can be found in Openfire/build at main · igniterealtime/Openfire · GitHub but I suspect that, in the end, you’ll need to figure out a way for OPENFIRE_HOME to be writable to the Openfire process.

1 Like

Would it be possible to make a new env variable for these directories? Something like OPENFIRE_RUNTIME, perhaps? This would make packaging Openfire easier for Nix as we won’t have to patch these directories in the code. By default, this variable can point to OPENFIRE_HOME, which shouldn’t break compatibility with how Openfire handles things.

I’m not exactly sure if I understand what you mean. We could add a new environment variable, but all existing code, including lots of third-party plugins, would simply continue to use the old variable. That still would break everything, I think.

I meant anything writeable will use OPENFIRE_RUNTIME instead of OPENFIRE_HOME and the former will point to the latter, so things won’t break. Then, if we point OPENFIRE_RUNTIME to a writeable directory, the program will look there instead.

Updating all usages of OPENFIRE_HOME in the existing code is likely going to be a very difficult task. Not only is that used by Openfire itself, but also by many of our plugins. There will also be third-party plugins over which we have no control that depend on this.

Even if we would manage to pull this change off, I worry about backwards compatibility, by having older plugins installed on newer versions of Openfire.

I’m not saying that it cannot be done, but I suspect that it is a lot of work. If you are up for that, please give it a try. I would suggest finding a different approach to this problem though.

1 Like

Speaking about logs: we may use stdout or syslog instead and they will be processed by the systemd journald
I checked the deb packaging and sent some improvements:

The /var/log/openfire actually may be removed and logs by default should be printed to stdout or syslog where they can be collected by the systemd-journald and then available from the journalctl -u openfire -f command. This is not our business how to persist logs. The Prosody allows both: syslog and the append to a log file. This needs to be discussed separately.

IMO(not a developer, just an ordinary user), i would prefer to have the Openfire logs separated from the syslog(or at least some configurability for choosing to do so). I do like the convenience that those logs provide in many aspects.