I have a web app that at a certain point the user can restart another web app, both running on apache-tomcat servers, both running under the same user.
Web app 1, let's call it manager, is used to stop and start web app 2, let's call it app-server.
Both tomcat servers are running as a user service, with the unit files located in /etc/systemd/user/
.
While installing these two tomcat servers, through some bash scripts, I made sure to run loginctl enable-linger user
. In those scripts, I'm able to run systemctl --user
but only after setting the following variables on a here document and running everything inside it:
#!/bin/bash
(...)
su user << 'EOF'
export XDG_RUNTIME_DIR=/run/user/$(id -u user)
export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u user)/bus
systemctl --user ...
EOF
(...)
You can check how I dealt with this on another question of mine, here: https://superuser.com/q/1730397/1708440
Now, the problem that I'm facing is when trying to stop or start the app-server service with systemctl --user stop app-server
.
Both web apps are Java applications, so to stop and start the services I'm doing:
Process p = Runtime.getRuntime().exec("systemctl --user start app-server");
I've also tried:
String[] commands = {"bin/sh","-c","export XDG_RUNTIME_DIR=/run/user/$(id -u user)",
"export DBUS_SESSION_BUS_ADDRESS=/run/user/$(id -u user)/bus","systemctl --user start app-server"}
Process p = Runtime.getRuntime().exec(commands);
In both cases, it outputs:
Failed to connect to bus: No such file or directory
I've also noticed that if I run the start command after su user
, the output is the same but only if I do not set the environment variables.
I can see that linger is enabled for the user after running loginctl user-status
and I can also see the /lib/systemd/systemd --user
process running for that user.
So, my question is: How can I achieve the start and stop of a user service within a Java web app that is running on a Tomcat server?
CodePudding user response:
After a lot of trial and error I finally found the solution:
I am now able to achieve my goal with:
String[] commands = {"/bin/sh","-c","export XDG_RUNTIME_DIR=/run/user/$(id -u user)
&& systemctl --user start app-server"}
Process p = Runtime.getRuntime().exec(commands);
Turns out I was on the right track, just missing a linking point.
The difference from my initial approach is the "&&" (and operator) on the command, to make sure that the systemctl --user
is only executed after the variable has been set.
In the meantime I also found out that I only need to set XDG_RUNTIME_DIR
.