sysutils/nut [os-nut]: upsdrvctl shutdown does not get triggered
Important notices Before you add a new report, we ask you kindly to acknowledge the following:
- [x] I have read the contributing guide lines at https://github.com/opnsense/plugins/blob/master/CONTRIBUTING.md
- [x] I have searched the existing issues, open and closed, and I'm convinced that mine is new.
- [x] The title contains the plugin to which this issue belongs
Describe the bug
upsdrvctl shutdown does not get triggered. This could lead to a state in which the UPS remains on but OPNsense is powered down with no way to recover.
To Reproduce Steps to reproduce the behavior:
- Go to 'NUT --> Configuration --> General Settings'
- Check 'Enable Nut'
- Switch 'Service Mode' to 'standalone'
- Set 'Name' to 'ups'
- Click on 'Apply'
- Go to 'NUT --> Configuration --> UPS Type --> USBHID-Driver'
- Check 'enable'
- Click on 'Apply'
- Execute a forced shutdown via
upsmon -c fsd - OPNsense powers off, but the UPS remains running
Expected behavior
upsdrvctl shutdown should be triggered during a upsmon forced shutdown event. Executing upsdrvctl shutdown during an event will start the UPS shutdown timer, which will turn the UPS off and wait for power to return. If power returns during a shutdown, the UPS will power cycle (turn off for about a second, and turn back on) and force the server to startup (if set in the BIOS).
Additional context I believe there is actually 2 problems here:
-
The
upsmon -Ktest does not work. It is always exits withEXIT_FAILUREregardless if/etc/killpoweris present or not. Replacing this withtest -f /etc/killpowerdoes work. -
nut_upsshut="YES"is never set in/etc/rc.conf.d/nut. Because this is never set, the test in/usr/local/etc/rc.d/nutfails.
I haven't investigated why upsmon -K does not work, however test -f /etc/killpower does. Perhaps permissions?
I believe adding a checkbox in the UI to enable UPS Shutdown, which updates the template to add nut_upsshut="YES" would correct this. By default, in /usr/local/etc/rc.d/nut, it is set to NO.
Reference /usr/local/etc/rc.d/nut:
This is where the UPS power off test are. Im not sure where this is in the plugin source code.
Top of file. Notice default is set to NO: nut_upsshut=${nut_upsshut:-"NO"}
#!/bin/sh
# PROVIDE: nut
# REQUIRE: NETWORKING devfs
# BEFORE: LOGIN
# KEYWORD: shutdown
# Define these nut_* variables in one of these files:
# /etc/rc.conf
# /etc/rc.conf.local
# /etc/rc.conf.d/nut
#
# DO NOT CHANGE THESE DEFAULT VALUES HERE
#
nut_enable=${nut_enable:-"NO"}
nut_prefix=${nut_prefix:-"/usr/local"}
nut_upsshut=${nut_upsshut:-"NO"}
The stop function:
nut_poststop() {
if ${nut_prefix}/sbin/upsdrvctl stop && checkyesno nut_upsshut; then
if ${nut_prefix}/sbin/upsmon -K; then
${nut_prefix}/sbin/upsdrvctl shutdown
fi
fi
}
Template for /etc/rc.conf.d/nut:
https://github.com/opnsense/plugins/blob/285dcd88c3a99f1d38c4f7ad1d8a4546daa08170/sysutils/nut/src/opnsense/service/templates/OPNsense/Nut/nut#L1-L6
Temporary Workaround / Proof of Concept
I created a file called 99-nut in /usr/local/etc/rc.syshook.d/stop and made it executable. I added some beeps so I could hear what mode was detected and executed.
#!/bin/sh
# This does NOT work:
# (/usr/local/sbin/upsmon -K)
# This does work:
# (test -f /etc/killpower)
if (test -f /etc/killpower); then
echo "UPS: Power Failure Shutdown - UPS Shutdown Activated"
opnsense-beep high
opnsense-beep high
opnsense-beep low
opnsense-beep high
opnsense-beep high
/usr/local/sbin/upsdrvctl shutdown
else
echo "UPS: Standard Shutdown - No UPS shutdown"
opnsense-beep low
opnsense-beep low
opnsense-beep high
opnsense-beep low
opnsense-beep low
fi
Helpful Links
- This was helpful in understanding FreeBSD / NUT during a Low Battery Shutdown Procedure: https://blog.tyk.nu/blog/going-nuts-using-a-ups-on-freebsd/
- Similar Issue: NUT: no restart of UPS https://forum.opnsense.org/index.php?topic=23164.0
Environment OPNsense 22.1.8_1 (amd64) os-nut 1.8.1