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.
On Sun, Apr 17, 2016 at 3:56 PM, Denis Serov <intrudo at outlook.com> wrote:> 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 :)Here are a few more :)> 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.How critical is 32-bit x86 these days? (Especially if we were to support a minimum of something later than XP)> 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.).Not sure if there is a solution for building MSIs already, but it would be nice to have the option to cross-compile from Linux.> 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.It might not be hard to do in git-space, but I do not want the duplicated history from our failed attempts to merge the original windows_port branch (that Windows-v2.6.7 is derived from). As I mentioned earlier, we do not know how many regressions were introduced in the windows_port branch due to the use of inexact SVN revisions ('HEAD') when merging. Given some of your recommendations about refactoring for platform abstraction, I think the extra history from the old branches will be a distraction. TL;DR: I do not want this branch merged as-is. Rebasing or reconstructing is fine, though.> 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.You might want to check with @zykh on Github: https://github.com/networkupstools/nut/issues/211 It is slightly tangential to the problems you are trying to solve, but the NUT logging code could use some cleanup, and I wouldn't want someone to have to do this twice. I personally like the idea of more descriptive log levels, but have not had a chance to map this out myself.> 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.I certainly can't speak for all of the NUT users, but I suspect that most would care more about the server side of NUT. They might dive into client-side logs if something goes wrong, but I don't see many users trying to continuously aggregate the logs from NUT Windows clients.> 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.I am not an expert in Windows file handling, but I suspect that there will need to be coordination between the daemons for things like log rotation. One log file per component might work better in that case.> 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.It would be good to get feedback from others on this, since it sounds like there are at least two options here (service for a single upsdrvctl/watchdog, or let upsdrvctl create service entries for drivers dynamically).> 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).Is there any way to use Netscape's NSS? There are licensing issues with distributing OpenSSL with software built from GPL'd source code.> 3. upsmon depends on libgcc_s_dw2-1.dll file, but it missed in sbin directory and should be added to setup too.Is there a way to automatically check the installation for dependencies? Something like running 'ldd upsmon' on Linux, then verifying that the needed libraries are either part of the OS (goes back to the previous question about minimum supported version) or are included with the install. On a related note, if it's not too hard, I would like to be able to cross-compile this from Linux, at least for continuous integration (if it is too hard to cross-compile WIX for packages, assuming that even makes any sense). Debian has some mingw-* packages that could be used for this, but at the moment, I think there are still a few assumptions that the build and target platforms are the same.> 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.Either way, NUT will need to ensure that updates for any dependencies are tracked closely. Linking statically will make it harder for a sysadmin to scan for old libraries during audits.> 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.Agreed. I do not think the Windows branches automatically update the version string from Git the way the master branch does, but that should not be too hard. Let me (and the list) know if you have questions about that code.> 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 am not opposed to stripping debug information if it is available somewhere, but what will be debug procedure? Ideally, a developer without access to a Windows system should be able to look at a crash log and pinpoint the source code for the error location.> 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.I am not a fan of nut-scanner, but I think that it does "lazy linking" against some of the libraries to simplify things on *nix systems. Your static linking proposal might run into trouble here.> 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.Thanks for taking the time to write this up. Hopefully, we can get some other users and developers to chime in, too. -- - Charles Lepple
Thanks for your answers, Charles! Please, find my replies below.> > 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 :)> Here are a few more :)> > 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.> How critical is 32-bit x86 these days? (Especially if we were to > support a minimum of something later than XP)Indeed, if we are talking about Windows Server versions, 32-bit support looks at least strange. But there are a lot of desktop systems like Windows 7-10, which are still installed as 32-bit. I think that 32-bit version of NUT can be good alternative to different vendors' software. Anyway, it is easy to write x86/x64 compiled code at once if remember about it, is not it? :)> > 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.).> Not sure if there is a solution for building MSIs already, but it > would be nice to have the option to cross-compile from Linux.As I understood, MSI setups of all Windows releases have been built in Windows environment. This way will always require Windows builder and I agree that this is very inconveniently. I have googled some products which can create MSI from Linux, but they are very expensive. Another way is using of msitools, but it does not support all features of WiX and it should be checked. I have sent a manual how to build NUT Windows port in Windows environment before this thread. Now I think to repeat the same steps in Linux environment to see what will be in result. Maybe it will resolve the situation with setup and msitools.> > 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.> It might not be hard to do in git-space, but I do not want the > duplicated history from our failed attempts to merge the original > windows_port branch (that Windows-v2.6.7 is derived from). As I > mentioned earlier, we do not know how many regressions were introduced > in the windows_port branch due to the use of inexact SVN revisions > ('HEAD') when merging.> Given some of your recommendations about refactoring for platform > abstraction, I think the extra history from the old branches will be a > distraction.> TL;DR: I do not want this branch merged as-is. Rebasing or > reconstructing is fine, though.Hmm... It looks like Windows-v2.6.7 branch is dead-end...> > 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.> You might want to check with @zykh on Github: > https://github.com/networkupstools/nut/issues/211> It is slightly tangential to the problems you are trying to solve, but > the NUT logging code could use some cleanup, and I wouldn't want > someone to have to do this twice. I personally like the idea of more > descriptive log levels, but have not had a chance to map this out > myself.I have seen the same nuance in source code that is described in #211 issue. Really, it is quite similar to what I said before, but is more related to log interface. I think that upslog and upsdebug functions mix two different conception: log severity and log level. As result, it is not possible to specify log level for upslog function; upsdebug one is very neutral, where is no way to log message with warning or error indication. Maybe it would be better to union upslog and upsdebug functions into one. For example: upslog(level, severity, ...); Severity: LOG_ERR, LOG_INFO, LOG_DEBUG, LOG_NOTICE, LOG_ALERT, LOG_WARNING, LOG_CRIT, LOG_EMERG Level: SEVERITY_MANDATORY = 1, SEVERITY_NORMAL = 2, SEVERITY_MEDIUM = 3, SEVERITY_HIGH = 4, SEVERITY_DETAILED = 5, SEVERITY_EXTRA = 6, SEVERITY_FULL = 7 (I has not found the level that is more than 7 in source code). Anyway, I agree that the work should not be done twice. If you would not mind, I will move this discussion to #211 issue.> > 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.> I certainly can't speak for all of the NUT users, but I suspect that > most would care more about the server side of NUT. They might dive > into client-side logs if something goes wrong, but I don't see many > users trying to continuously aggregate the logs from NUT Windows > clients.> > 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.> I am not an expert in Windows file handling, but I suspect that there > will need to be coordination between the daemons for things like log > rotation. One log file per component might work better in that case.I used such kind of logging system. To coordinate clients' calls between different processes and threads a named mutex should be used. As result, any combinations are possible: every process writes to its owned log, all processes writes to one single log and so on. For log rotation, a special thread is required in every process. This thread is mostly sleeping, but periodically becomes alive and check sizes of owned log files. If rotation is required, the thread creates another named mutex to protect rotation algorithm from other clients. The algorithm rotates the log files by scheme like file(N-1) -> file(N). This is very fast operation and it will not stop the process(es) extremely. After rotation, the thread checks if compression is required or not. If yes, the thread compresses just rotated log files to gzip (for example). Rotation and compression algorithm can be tuned via config file like logrotate.conf.> > 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.> It would be good to get feedback from others on this, since it sounds > like there are at least two options here (service for a single > upsdrvctl/watchdog, or let upsdrvctl create service entries for > drivers dynamically).Well, let's wait the community reaction. It would be very nice to discuss all the questions, make plan and release Windows version of NUT at last :) (I would be glad to help with development, even completing Windows version by myself, if there is a lack of resources).> > 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).> Is there any way to use Netscape's NSS? There are licensing issues > with distributing OpenSSL with software built from GPL'd source code.Unfortunately, I can say nothing about Netscape NSS, I used OpenSSL only. Research is required to say something definite (I do not see potential problems with it).> > 3. upsmon depends on libgcc_s_dw2-1.dll file, but it missed in sbin directory and should be added to setup too.> Is there a way to automatically check the installation for > dependencies? Something like running 'ldd upsmon' on Linux, then > verifying that the needed libraries are either part of the OS (goes > back to the previous question about minimum supported version) or are > included with the install.I have never seen such tools, but they probably exist. ldd looks like interesting idea, the main problem I am seeing is how to detect which files are included to OS by default and which are not.>From the other side, the dependencies are not changed very frequently, so, they can be checked manually (I have spent about 5 minutes to check Windows setup).> On a related note, if it's not too hard, I would like to be able to > cross-compile this from Linux, at least for continuous integration (if > it is too hard to cross-compile WIX for packages, assuming that even > makes any sense). Debian has some mingw-* packages that could be used > for this, but at the moment, I think there are still a few assumptions > that the build and target platforms are the same.I agree that cross-compile from Linux is final goal. I will try to build Windows port from Linux...> > 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.> Either way, NUT will need to ensure that updates for any dependencies > are tracked closely. Linking statically will make it harder for a > sysadmin to scan for old libraries during audits.This is good point! I see at least one problem: net-snmp library. It does not support dynamic library by default. I have built it using some tricks.> > 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.> Agreed. I do not think the Windows branches automatically update the > version string from Git the way the master branch does, but that > should not be too hard. Let me (and the list) know if you have > questions about that code.OK, thanks!> > 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 am not opposed to stripping debug information if it is available > somewhere, but what will be debug procedure? Ideally, a developer > without access to a Windows system should be able to look at a crash > log and pinpoint the source code for the error location.I think that logging via upslogx/upsdebugx function should be enough to understand what is going on. Stripping debug information does not affect to __FILE__/__FUNC__ macros. If you are talking about Windows crash dump, I am not sure that debug information generated by GCC will help, because PDB format is required for such scenario. Anyways, if debug information is so important, may be it would be better to separate it from binaries into single .debug files? They can be published with NUT releases together and the developers can download them if necessary...> > 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.> I am not a fan of nut-scanner, but I think that it does "lazy linking" > against some of the libraries to simplify things on *nix systems. Your > static linking proposal might run into trouble here.All setup related issues are the tasks for a brighter future :) I would prefer to have mature NUT Windows version without brilliant installer.> > 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.> Thanks for taking the time to write this up. Hopefully, we can get > some other users and developers to chime in, too.I hope so much!> -- > - Charles LeppleThanks for your answers! Denis