Hello!
I performed lightweight review of Windows port source code (Windows-v2.6.5-7
branch). I have some ideas I would like to share with NUT community.
First of all, Frederic did great job to port NUT sources to Windows platform
and we have the path in dark forest. Unfortunately, the port looks like
experimental. I think that the next major iteration is required.
Here are many words, sorry about it :)
Denis
REQUIREMENTS
------------
I could not find any requirements for Windows port version of NUT. I have
arranged some items, which I see currently:
1. Windows port must be reliable and stable. It should provide enough level of
logging and debugging to have good technical support.
2. Windows port must support all devices and programs, which Linux version does.
3. Windows port must be done for x86 and x64 platforms. The source code
supports both platforms. To get the binaries, it is enough to configure and
compile the sources, nothing more.
4. Windows port must support installation via Windows Installer. There should
be two MSI setups for both platforms or single one with automatic platform
detection. The setup system should provide selecting the features (programs,
drivers, etc.).
5. Windows port components (x86, x64) must be compatible with Linux versions in
any combinations. For example, Windows version of upsmon should be compatible
with Linux version of upsd and so on. It allows to have mixed environment
without any problem.
It seems there are no system requirements for minimal supported Windows
version. As result, no one checks the version of operating system: neither NUT
programs nor MSI setup. For example, Windows port uses OpenSCManager function,
but it is available from Windows XP/Windows 2003 only. As result, the programs
will crash in environment of older operating systems.
I think that minimal supported Windows version must be Windows XP/Windows 2003
or even more modern one. Setup and source code should check operating system at
startup.
GIT BRANCHES
------------
As I understand, master and Windows-v2.6.5-7 branches separated in last years
and they contain different commits. In the end of Windows port implementation
there should be one single branch for Windows port and Linux version (master).
After it, Windows and Linux versions will be released simultaneously under
equal versions.
That is the big question what branch should be used for next development
iteration of Windows port.
I think Windows port must be stabilized in Windows-v2.6.5-7 branch and then
merged to master one. Sure, the merge will 100% affect Linux version and may be
bring some regression. On the other hand, it is single operation and it does
not look very hard.
PLATFORM ABSTRACTION
--------------------
Current Windows port sources contain mixed Linux and Windows code in form of
compiler predefines like #ifdef WIN32. It makes the sources unreadable and not
maintainable.
I think the solution is implementation of abstraction layer that hides platform
specific from algorithms and business logic. Saying the truth, something like
abstraction layer already exists in wincompat.c file, but it is not full.
It would be great to have the abstraction layer not for Windows port only but
for Linux version too. For example, the algorithms call the functions from
interface like C-header. There are different implementations of this interface
in static linked libraries. The libraries are building from different source
code for specified target platform.
------------- ---------------
Linux version Windows version
----------------------------------------------
Common algorithms and business logic
----------------------------------------------
Software abstraction layer
----------------------------------------------
Linux implementation Windows implementation
-------------------- ----------------------
LOGGING AND DEBUGGING
---------------------
When I tried to install Windows port in my environment, I had some problems to
understand what is going on and what is wrong: it is quite hard to increase
logging level and it is uncomfortable to work with Windows Event Log. I think
that logging architecture should be improved.
Linux version contains several logging function like upslogx,
upslog_with_errno, upsdebugx, etc. All of them call vupslog function inside.
This function can write messages into STDERR stream and send them into syslog
(writing to a log file is not required because Linux has syslogd, logrotation,
etc.).
Windows port contains the same function. It can write messages into STDERR
stream too, but as there is no native syslog support in Windows, Windows port
provides special implementation of syslog function. It sends message via named
pipe into a service called nut.exe (NUT service). The service writes them into
Windows Event Log. In other words, NUT service provides simple "syslogd"
feature.
This solution has different issues.
1. Sure, it is common recommendation to use Windows Event Log in Windows world
as replacement of Linux syslog. I think it is not proper equivalent: Windows
Event Log is more complex to use; it designed to log periodical significant
events, not heavy debugging output; it is not useful for direct logs analysis,
quite slow and problematic with support of users.
2. If NUT service is not available (stopped or crashed), logging is stopped
automatically. I think that important software like NUT has to provide more
reliable logging.
3. Unfortunately, "syslogd" implementation is unstable in Windows port. It eats
syslog messages periodically and they do not appear in Windows Event Log (I did
not find the bug yet, but something is wrong with new pipe connections).
4. Design of Windows Event Log bases on event identifiers and message table
resources. Different notifications should have different Event ID and message
body. Now, Windows port supports one predefined Event ID for formatted message
"%1". It means that all messages have equal Event ID. This is not a big
problem, but removes charm of Windows Event Log: no way to filter Windows port
events and it is not transparent to external software analyzers. Moreover,
Windows Event Log locks binaries with message table resources, so, nut.exe file
becomes locked if somebody is viewing NUT messages in Event Viewer.
5. Currently, mixed NUT environment (Linux version and current Windows port)
provides mixed logging: syslog and Windows Event Log. The people who use such
environments will try to have single mechanism (just imagine). They will have
to install additional software converters from syslog to Windows Event Log or
vice versa and it looks at least strange.
It seems that "syslogd" feature is elimination candidate and it should be
removed from NUT service.
I think that Windows port may provide file-based logging instead of "syslogd"
implementation. Every program may write to their own file or in the common one.
File logging is more stable; the programs do not depend from "central point"
availability. Thereby, the users can simply send log files to developers during
support cases and nothing more.
It would be nice to provide classic implementation of syslog function in
Windows port (for example, RFC 5424). This is not hard and such support resolve
mixed NUT environment issue.
On the other hand, Windows administrators are used to looking into Windows
Event Log for important notifications. It would be great if Windows port can
additionally write the significant messages to Windows Event Log. Every program
may write them directly in special points of the source code. The messages can
be located in resource DLL module to avoid "lock" problem.
I suggests the following logging architecture:
Linux version Windows version
------------------- ----------------------------
STDERR (no changes) STDERR (no changes)
syslog (no changes) syslog (new implementation)
filelog (new implementation)
Windows Event Log (redesign)
WINDOWS PORT ARCHITECTURE
-------------------------
NUT drivers are daemons in Linux version. They are starting and are stopping
via controller called upsdrvctl (it is not daemon). Network server (upsd) and
monitoring client (upsmon) are daemons too. Special "init.d" scripts start and
stop all the programs in required order.
Linux architecture is following:
---------------------------------
upsmon (daemon)
---------------------------------
upsd (daemon)
---------------------------------
Drivers (daemons)
apcsmart blazer ... usbhid-ups
-------- ------ --- ----------
In contrast to Linux version, Windows port contains NUT service that is
"central point". The main idea of NUT service is providing functions like
"syslogd" (I described it above) and "init.d", because their equivalents are
absent in Windows world.
Drivers, network server and monitoring client are implemented as console
applications. The service just starts and stops them as hidden processes in
required order.
Windows port architecture is following:
---------------------------------
nut (service)
---------------------------------
upsmon (console application)
---------------------------------
upsd (console application)
---------------------------------
Drivers (console applications)
apcsmart blazer ... usbhid-ups
-------- ------ --- ----------
This design has some issues.
1. NUT service does not control the programs it has started. It is just a kind
of starter. In the case of any failure (for example, upsd has crashed or
terminated unexpectedly), the service does not restart failed program and
thinks that everything is OK, but the system becomes unavailable. I have seen
such behavior several times and I think that Windows port has to provide the
mechanisms making the whole system more stable (watchdogs, etc.) because
functionality of NUT is very important. For example, NUT service can be
watchdog for all programs it has started.
2. Then upsmon executing shutdown procedure, it sends stop signal to NUT
service and the service will stop everything it has started before, including
upsmon. Therefore, it looks like a scheme where no main component is but
chaotic calls are. It cannot be stable by default. What will be if NUT service
is stopped? It seems nothing good.
This is common recommendation to port Linux daemons to Windows services. I
think that upsd and upsmon should be implemented as Windows services (sure,
they can be started as usual applications manually). As result, NUT service is
not required anymore and it can be discarded.
Such scheme has many advantages:
1. It moves the responsibility of starting and stopping upsd and upsmon from
NUT service to operating system.
2. Windows provides service recovery feature: in the case of failure, system
will restart the service automatically. Service recovery function is a kind of
watchdog I have told before. It will raise product stability and availability.
3. Additionally, the users will get standard system notifications and easy way
to control and check what is running or not (via Control Panel).
As there are many drivers, there is no reason to implement them as services.
They can stay as the simple console applications.
To control the drivers, the following function are required:
1. Start and stop the drivers at the operating system startup/shutdown (as
upsdrvctl controller does).
2. Provide watchdog function for started driver. If driver process is finished
by unknown reasons, it will be restarted automatically.
I think a new service should be implemented for these functions or it is
possible to extend upsdrvctl source code to be as service. Another way is
integrate the functions into upsd service, but it is quite different from Linux
version.
The setup can register all the services in operating system. Moreover, it may
create the dependencies between services and the system will start and stop
them in required order. As result, there is no necessity to "init.d" function
in NUT service.
New Windows port architecture can look like:
---------------------------------
upsmon (service)
---------------------------------
upsd (service)
---------------------------------
Drivers controller (service)
---------------------------------
Drivers (console applications)
apcsmart blazer ... usbhid-ups
-------- ------ --- ----------
CONFIG FILES
------------
Some parameters in configuration files must contain double backslashes. For
example, "\\\\.\\COM1" should be used instead of "\\.\COM1". I am not sure, but
configuration files parsing looks like a candidate to improve in Windows
version. It can be moved to abstraction layer I have described above.
SETUP AND BINARIES
------------------
I think that currently used solution based on WIX is the best. I have found
some issues, they are not critical, but should be fixed in future.
1. It seems that Windows port releases have been built under MinGW in Windows
environment. Probably, the first versions were based at MSYS (not MINGW32),
because setup contains files like msys-*.dll. Now, they can be removed from
setup (bin/sbin directories), because no one uses them.
2. Windows port has been built with SSL support, because some binaries require
libeay32.dll and ssleay32.dll. These files should be added to setup (bin/sbin
directories).
3. upsmon depends on libgcc_s_dw2-1.dll file, but it missed in sbin directory
and should be added to setup too.
4. bin directory contains upssched-cmd file without extension. It is WIN32
executable file and there is its duplicate in sbin directory called
upssched.exe. As result, upssched-cmd file should be removed. Unfortunately, I
didn’t check what is the right place of upssched.exe file, may be it should be
relocated too.
5. The setup contains lib directory with libupsclient.a and libupsclient.la
files. I think they are not interesting for most of users and can be removed.
6. When I tried to build Windows port branch, I have found that neon and
net-snmp libraries can be linked statically. Currently, they represent as
dynamic libraries with quite big size and they are exporting many useless
functions. I could reduce the setup size using static linking during my
experiments.
7. The installed executable files should have VERSIONINFO resource by Windows
Installer rules. I think it is easy to add proper version and description to
every executable file.
8. I am not sure that StartService.bat/ StopService.bat files are necessary.
They just start and stop NUT service. These actions can be performed via
Control Panel.
9. Binary files contain debug information that can be stripped. It will
significantly decrease setup file.
I told before about one single setup with automatic Windows platform detection
(x86 or x64). Current setup installs all files at once without any
customization. The main idea is to group the files to drivers, client files and
server ones. After platform detection, the setup will ask the user about
working mode (standalone, netserver, netclient).
If netclient mode is selected, the setup will install the client files only
(upsmon, etc.).
For netserver mode, the setup will install the server files (upsd, etc.). The
client files can be optionally installed by additional user select.
For standalone mode, the setup will install both client and server files.
The most important thing is that netserver and standalone modes require driver
installation. For these modes, the user can select which drivers he needs or
install all. Also, the setup can provide automatic detection of available
devices via nut-scanner.
In the end of installation, the setup writes selected configuration into *.conf
files, registers all necessary services and starts them. As result, the product
is ready to use.
_______________________________________________
Nut-upsdev mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/nut-upsdev