Skip to content

Use target for drivers in Linux systemd (updated) and SMF instances for drivers in new Solaris-like systems (and bring AIX initscript into better shape)#330

Merged
aquette merged 168 commits intonetworkupstools:masterfrom
jimklimov:systemd-target
Aug 14, 2018

Conversation

@jimklimov
Copy link
Copy Markdown
Member

Includes #229 by @miska and some subsequent improvements.

@jimklimov
Copy link
Copy Markdown
Member Author

jimklimov commented Oct 10, 2016

@aquette pointed out a user-experience problem with this approach, which can be solved technically:

the main point why I'm still not ack'ing that PR is that there are additional user actions required, compared to the historic approach of enabling/starting all drivers in one shot: user now has to spawn all sub units, which can be done through some helper script that iterates over ups.conf and does the spawning / enabling.

So indeed such an action might be done as an ExecStartPre= handler for example, or even as another unit to depend on (which might be more easily disabled or masked by the end-user, if not desired).

@peterhoeg
Copy link
Copy Markdown

@jimklimov , you probably want to look into generators at least for systemd instead of your ExecStartPre hook.

man 7 systemd.generator

Also, the recommended way to deal with the network-online.target issue is not to make a copy, but instead a drop-in configuration fragment which can be done without changing the unit file you are providing:

So in /etc/systemd/system/nut-driver.target.d/network.conf you would put:

[Unit]
Requires=network-online.target
After=network-online.target

@jimklimov
Copy link
Copy Markdown
Member Author

@peterhoeg : Thanks for the hints, especially about https://www.freedesktop.org/software/systemd/man/systemd.generator.html

However I am not sure it is a good match for this use-case, due to this:

Units written by generators are removed when the configuration is reloaded. That means the lifetime of the generated units is closely bound to the reload cycles of systemd itself.

One application of NUT in an internal project of ours is for embedded systems, and this regular re-generation and removal of files will cause needless wear on the flash storage. Also if systemctl may not be called (per doc) at this stage, the generator script write should apparently resort to creating the /etc/systemd/...wants... explicitly which is an architectural flaw of systemd I believe - if there's an API and contract, consumers like us should not crawl under the hood (it is not future-proof in particular).

But the script is already mostly there in this PR, I just expect to wrap it into a separate unit that may be enabled or disabled as the end-user would desire :)

@peterhoeg
Copy link
Copy Markdown

@jimklimov, the generators should not dump data under /etc/systemd/system but instead /run/systemd/system which is mounted on tmpfs. This is how mount points are set from /etc/fstab as an example.

You can of course achieve the same with the Pre hook although the generators are run much earlier. Besides, you already have the script for the Pre hook and written code always wins over "should probably write it this way". ;-)

@jimklimov
Copy link
Copy Markdown
Member Author

jimklimov commented Oct 28, 2016

@aquette : I revised the newly added script, adding a standard copyright header in particular - can you please review if it is OK this way?

@jimklimov
Copy link
Copy Markdown
Member Author

Rebased over today's master to take advantage of new Travis CI integration.

Comment thread scripts/systemd/nut-server.service.in Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requires

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, fixed

@jimklimov jimklimov changed the title Use target for drivers in systemd (updated) Use target for drivers in Linux systemd (updated) and SMF instances for drivers in new Solaris-like systems Mar 5, 2017
@jimklimov jimklimov force-pushed the systemd-target branch 4 times, most recently from 6f7a4ea to 9c9530c Compare March 5, 2017 20:28
@jimklimov jimklimov changed the title Use target for drivers in Linux systemd (updated) and SMF instances for drivers in new Solaris-like systems Use target for drivers in Linux systemd (updated) and SMF instances for drivers in new Solaris-like systems (and bring AIX initscript into better shape) Mar 5, 2017
@jimklimov
Copy link
Copy Markdown
Member Author

jimklimov commented Mar 5, 2017

This had to step beyond original system scope to ensure the solution core can reasonably adapt to different service frameworks. Then to ensure I can install it in those other systems :)

Now this codebase should be at least testable, so please give it a go to check if it does what's intended, in the end :)

@jimklimov
Copy link
Copy Markdown
Member Author

jimklimov commented Mar 6, 2017

Currently found caveats that might be solved later but require considerable effort:

  • Solaris SMF constrains the syntax valid strings for instance names (e.g. not starting with a digit, no period chars) which blocks creation of some UPS driver instances. This might be worked around by hashing the device name e.g. to base64 (and un-hashing instance name when calling upsdrvctl), but is not quite user-friendly. Also can store device name in a service attribute while mangling the instance name to a valid subset. Comparisons (if devices are already wrapped) becomes more complicated in the script in either case, as well as in the service startup method.
    ** The + / = characters from base64 are also invalid for SMF instance name, but the first two can be sed'ed to - _ and back, for example (http://stackoverflow.com/questions/13195143/range-of-valid-character-for-a-base-64-encoding, Filesystem-safe mode from http://www.rfc-editor.org/rfc/rfc4648.txt). Some prefix word is also needed (avoid starting with a digit). The trailing padding = can be dropped, and added until we get a non-empty decode. Conversions can be done by echo "$string" | openssl base64 -e|-d
  • Dummy-UPS services that "proxy" another locally defined section are essentially a circular dependency for upsd. While the system might start-up lacking a driver, there should be some timer to re-enable failed not-disabled drivers (would be useful in any case though).

@jimklimov
Copy link
Copy Markdown
Member Author

Adding to my previous comment, it currently seems reasonable to provide the section-name conversion routines in NUT common code (e.g. config parser) so tools like upsdrvctl can be called to generate the base64 string, as well as all tools can interpret it as identification of a config section, local or remote monitored NUT device, etc.

Also, service instances created and tracked by the enumeration script should include somewhere the copy or hash of configuration variables used when the service instance was created - e.g. if the driver or even port value was changed for the same-named section, we may have new dependencies to track for service management (destroy and recreate the nut-driver unit instance).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apcsmart is serial only

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed

@jimklimov
Copy link
Copy Markdown
Member Author

Rebased over current master branch state today

@jimklimov
Copy link
Copy Markdown
Member Author

I've played with several package (re-)installation scenarios, finding ways to make the procedure robust. Hopefully struck the balance at least for Solaris-like systems (OpenIndiana actually).

@jimklimov jimklimov added the ready / code review Author (and CI) consider the PR worthy of human rewievers' time label May 23, 2018
Copy link
Copy Markdown
Member

@aquette aquette left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to go for 2.7.5, with the minor fix on configure.ac/in

Comment thread Makefile.am Outdated
@@ -139,21 +139,28 @@ setver:
@echo "Error: 'make setver' no longer exists."
@echo "Edit configure.in to set version number."
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's configure.ac now ;)

@aquette aquette merged commit 8b75b03 into networkupstools:master Aug 14, 2018
jimklimov added a commit to jimklimov/nut that referenced this pull request Aug 14, 2018
…or drivers in new Solaris-like systems (and bring AIX initscript into better shape) (networkupstools#330)

* Use target for drivers in systemd

This allows much better granularity and better monitoring in case of
multiple UPSes.

* nut-driver.target improvements suggested by @peterhoeg in PR#229

* systemd units dependencies revised and commented

* nut-driver-enumerator.sh initial commit

* nut-driver@.service.in : integrate comments from @peterhoeg about extending unit requirements

* WIP : initial integration of nut-driver-enumerator.sh/service into makefiles etc.

* nut-driver-enumerator.sh renamed into nut-driver-enumerator.sh.in as it has processable templates in code

* nut-driver-enumerator.sh.in : add its own config-file support to set the variables used inside (if not via command-line env)

* nut-driver-enumerator.sh.in : fix up the copyright header

* Subject: Fix systemd service file for Debian
From: Laurent Bigonville <bigon@debian.org>
Forwarded: not-needed

* nut-driver-enumerator.sh.in : complete the Solaris SMF support in the helper script

* EXTRA_DIST the scripts/systemd/nut-driver.target (non-templated) file

* nut-driver-enumerator.sh.in : updated comments (esp. about usage and exit-codes) and runtime messages

* nut-driver-enumerator.service.in : define an actual service payload

* nut-driver-enumerator.sh.in : refactor the logic of MAIN PROGRAM into smaller routines for readability

* nut-driver-enumerator.sh.in : introduce routines to help define custom dependencies of particular drivers on other services

* nut-driver-enumerator.sh.in : allow custom NUT_CONF_DIR from envvar, to facilitate testing

* nut-server.service.in : typo fix in comments

* nut-driver-enumerator.sh.in : support the concept of localhost networking dependencies, and define vars with lists of services to depend on

* nut-driver-enumerator.sh.in : use proper FMRI:instance separator for SMF

* nut-driver-enumerator.sh.in : added variables for dependency type on third-party service units

* nut-driver-enumerator.sh.in : change upsconf_getDriverMedia() output from tab-separated to multiline; add upsconf_getMedia() and upsconf_debug() and upslist_debug()

* nut-driver-enumerator.sh.in : refactor with upsconf_getValue() and cached pre-cooked ups.conf data; infrastructure to configure service dependencies when adding the service instance

* Remove hardcoded dependencies on udev and network from provided systemd units; add comments about extending via drop-in files and that nut-driver-enumerator will do this for nut-drivers

* nutshutdown.in : mark executable

* nut-driver-enumerator.sh.in : complete the systemd drop-in support for custom dependencies for a driver

* nut-driver-enumerator.sh.in : complete the SMF drop-in support for custom dependencies for a driver

* nut-driver-enumerator.sh.in : comment-away upslist_debug() in default runs

* WIP Adding Solaris SMF manifests for NUT

* Sanitize Solaris SVR4 packaging rules

* Sanitize Solaris packaging scripts some more

* Add configure options for Solaris packaging variants

* Sanitize Solaris packaging scripts some more - consider DESTDIR for installation root

* Turn solaris preproto.pl into a template so it uses proper (configured) user/group strings

* Makefile.am : ensure there is a DESTDIR set before packaging

* Makefile.am : use $(MAKE) $(AM_MAKEFLAGS) instead of explicit "make" (mostly in packaging recipe)

* makelocal.sh : commented and revised

* Solaris/Makefile.am : put generated SVR4 package into builddir (not srcdir that may be readonly) to match other OS recipes

* Makefile.am : ensure the DESTDIR is used for packaging purposes (when calling sub-makes)

* Solaris/pkginfo.in : ARCH is CPU_TYPE, not OS_NAME

* GitIgnore built Solaris/NUT*.local.gz product

* GitIgnore built systemd files

* GitIgnore _install_pkgprotodir

* Makefile.am : ensure only the custom DESTDIR is used for packaging purposes

* Makefile.am : convert the big packaging "if" into "case"; link steps with "&&"; retain DESTDIR if Solaris packaging fails; ensure the correct custom DESTDIR is absent before packaging (and after Solaris packaging)

* Solaris/Makefile.am : Revise recipe-names and comments for Solaris packaging variants

* Solaris/Makefile.am and *.xml.in : relocate SMF methods and manifests under NUT DATADIR to package compactly

* Solaris-SMF : svc-nut.in svc-nut-client.in : use @RUN_AS_*@ and @PIDPATH@ vars instead of hardcoding

* Solaris/Makefile.am : list helper scripts and installation scripts and data in variables and depend on them in packaging; chmod +x the scripts after copying over to proto area

* GitIgnore config.cache

* Remove Solaris/prepackage.py (unreferenced duplicate of precheck.py)

* Solaris/nut.in : sanitize the default init-script

* Solaris/Makefile.am : put init-scripts under NUT share (DATADIR) to package it compactly; copy to OS dirs in postinstall

* Makefile.am .gitignore etc. relocate successfully built package files to abs_top_builddir

* Change Aix/nut.init to a .in template

* svc-nut.in svc-nut-client.in : consider nut.conf if available

* Solaris/Makefile.am and SVR4 scripts : install augeas lenses as part of NUT package (in DATADIR at least)

* configure.ac : comment about sysconfdir for NUT

* Sanitize Aix/nut.init.in

* More standardization of Solaris initscripts and SMF methods; use LD_LIBRARY_PATH to prefer NUT provided libs in case of conflicts (facilitate bundling with third-party packages)

* Solaris/Makefile.am : add ability to "make check" something here, e.g. validate manifest XMLs

* Solaris SMF XML manifests : fix "dependent" definitions, and add dependencies on required config files

* configure.ac : fix a manually crafted "Checking for" into using AC_MSG routines

* Solaris SVR4 packaging should now take care of SMF service registration/teardown

* Solaris preremove.in postinstall.in : Usage of @datadir@ caused "${prefix}" strings to pop up - define the vars

* Solaris scripts : use lower-cased @datadir@ in templates processed by configure

* Solaris/preremove.in : fix FMRI pattern when removing package

* Solaris/postinstall.in : fix SMF manifest dir

* Solaris/postremove.in : fix verbose RM; wipe the /var/run/nut dir too

* Solaris/preremove.in : fix commands when removing package

* Solaris/postinstall.in : enable SMF services if configs are already available (esp. create nut-driver instances)

* Solaris/preremove.in : fix commands when removing package

* Solaris/postinstall.in : enable SMF services if configs are already available (esp. create nut-driver instances) - verbosity

* Solaris/nut-driver-enumerator.xml.in : use a unique dependency name (avoid conflict in nut-driver instances chain of deps)

* systemd and Solaris : fix up embedded ${prefix} in service files and SMF manifests after generation

* systemd/README : add recent authors

* Define a NUT_DATADIR and NUT_LIBEXECDIR with expanded path values to use in service manifests

* Solaris : packaged service addition/removal more verbose

* nut-driver-enumerator.xml.in nut-driver.xml.in : do not block startup of nut server

* nut.xml.in : do not block startup of nut server due to failed nut-driver-enumerator

* nut-driver-enumerator.sh.in : improve portability by using TAB char as is (not regex \t which gets misinterpreted by some tools)

* nut-driver-enumerator.sh.in : comment the caveats

* nut-driver-enumerator.sh.in : apcsmart is serial only

* nut-driver-enumerator.sh.in : By default, update wrapping of devices into services... but keep the door open to other uses of the script

* nut-driver-enumerator.sh.in : refactor a bit and add externally callable actions

* Introduce upsdrvsvcctl with semantics similar to upsdrvctl, but managing stop/start of SMF or systemd unit instances

* nut-driver-enumerator.sh.in : consider possible difference of device and service instance names

* nut-driver-enumerator.sh.in : refactor md5

* nut-driver-enumerator.xml.in : add REFRESH action and do not die on RESTART

* Mention nut-driver-enumerator and upsdrvsvcctl in (systemd/|Solaris/)README

* upsdrvsvcctl.in : updated comments

* upsdrvsvcctl.in : added a resync option

* Rename Solaris SMF services to match systemd patterns and ease life for sysadmins

* Add systemd nut.target to manage the bundle of NUT services

* config-notes.txt : document the systemd and SMF support in NUT

* nut.dict : update spellchecker

* Solaris/Makefile.am : support copying where attrs can not be preserved

* Solaris postinstall : report if services were not instantly enabled due to missing config files

* upsdrvsvcctl.in : reformat prettily

* nut-driver-enumerator.sh.in : wrap usage()

* nut-driver-enumerator.sh.in : added --list-services-for-devices

* nut-driver@.service.in : comment about aligning timeouts with ups.conf maxstartdelay

* nut.xml.in : Revise comments

* nut-driver-enumerator.sh.in : when amending service unit instance config for systemd, update the Description to state the NUT device section name

* nut-driver-enumerator.sh.in : support common NUT_CONFPATH envvar

* Add upsdrvsvcctl.txt manpage and references to upsdrvsvcctl in other docs

* upsdrvsvcctl.txt manpage : refer to service management system logs

* upsdrvsvcctl : support "list upsname" CLI action to help troubleshooting

* upsdrvsvcctl : add handling for "shutdown" command

* Docs about upsdrvsvcctl - clarify that it may not be preinstalled with non-SMF/non-systemd OS packages

* Pass spellcheck for upsdrvsvcctl doc updates

* Solaris packaging of nut-driver-enumerator.sh : deliver into libexecdir same as in Linux

* Move nut-driver-enumerator.sh.in and upsdrvsvcctl.in into scripts/upsdrvsvcctl to share on par between Linux and Solaris (for starters)

* Use @NUT_LIBEXECDIR@ for nut-driver-enumerator.sh

* Introduce nut-driver-enumerator.path.in for systemd

* nut-driver-enumerator.service.in : be part of nut.target, not common multi-user

* Systemd services : be PartOf=nut.target to propagate service stops

* postinstall.in : use NUT_DATADIR

* nut-monitor.xml.in : depend on nut-server (if locally running)

* nut.xml.in : fix path (use pre-eval-ed version)

* nut-driver-enumerator.sh.in : add a way to print out just an instance suffix name

* nut-driver-enumerator.sh.in : when printing full instance name, do not add stuff if the argument is already a full name

* nut-driver-enumerator.sh.in : implement --get-device-for-service

* nut-driver (systemd/SMF) : use "nut-driver-enumerator.sh --get-device-for-service" for current service instance name

* nut.xml.in : this service is transient

* upsdrvsvcctl.in : fix parameter passing

* upsdrvsvcctl.in : "clear" the SMF service state when stopping/starting, just in case it was failed

* nut-driver-enumerator.sh.in : restart upsd IFF the set of known-device mappings was changed

* Revise and relax some dependencies for Solaris SMF services

* nut-driver-enumerator.sh.in : info messages go to stderr; reply for request only goes to stdout

* nut-driver-enumerator.sh.in : complete the upslist_equals() method

* nut.xml.in : never fail on stop (if component services did not stop, it is their problem)

* Solaris preremove.in SMF : clear sevices before stopping them, just in case

* upsdrvsvcctl.in : post-process clearing of SMF service instances if any have failed

* nut.xml.in : never fail on stop (if component services did not stop, it is their problem)

* Solaris preremove.in SMF : remove nut before services it depends on

* main.c upsdrvctl.c : make debug messages a bit more useful

* Solaris preremove.in SMF : do not block stopping NUT driver services, but follow up with upsdrv(svc)ctl stop of everything

* Solaris preremove.in SMF : sleep after stopping drivers before removing their services

* Solaris preremove.in SMF : force-remove services of drivers

* nut-driver.xml.in : rename a dependency to avoid conflicts

* Solaris nut.xml.in : add a refresh action handler

* Solaris postinstall.in SMF : first use nut-driver-enumerator.sh.in to just register the mappings, no autostarts

* Solaris preremove.in SMF : stop drivers with common method (and use NUT_SBINDIR) before going one by one

* Solaris postinstall.in SMF : start the drivers via upsdrvsvcctl after registering (so the mapping is stable)

* Solaris postinstall.in preremove.in : NUT_SBINDIR => SBINDIR

* Add manpage for nut-driver-enumerator[8]

* Handle EXTRA_DIST of scripts/upsdrvsvcctl/ with their own Makefile

* nut-driver-enumerator.txt : change to be more like other page sources

* Spellcheck nut-driver-enumerator.txt

* Add scripts/upsdrvsvcctl/README

* Update gitignores

* List new manpages upsdrvsvcctl nut-driver-enumerator in index

* Add upsdrvsvcctl do scripts/Makefile.am SUBDIRS

* upsdrvsvcctl.in nut-driver-enumerator.sh.in : Add a way to show configs per device

* nut-driver-enumerator.sh.in : fix upsconf_getValue() to return success if key was found, or report an error if not

* nut-driver-enumerator.sh.in : expose upsconf_getValue() as --show-device-config-value

* nut-driver-enumerator.sh.in : NOTE on top about the choice of simplified shell

* nut-driver-enumerator.sh.in : in upsconf_getSection() stop after printing out the section contents

* nut-driver-enumerator.sh.in : refactor upsconf_getValue() to use upsconf_getSection()

* nut-driver-enumerator.sh.in : update comment in header

* nut-driver-enumerator.service.in : do not fail the systemd unit, it cannot restart

* Fix references for configure.in to point to configure.ac nowadays

* nut-driver-enumerator.sh.in : use fully-pathed SMF svccfg in all parts of code consistently

* nut-driver-enumerator.sh.in : comment about not-detecting reconfigurations of existing sections currently
@jimklimov jimklimov added the nut-driver-enumerator (NDE) nut-driver-enumerator (NDE) automates service management integration for NUT driver instances etc. label Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

nut-driver-enumerator (NDE) nut-driver-enumerator (NDE) automates service management integration for NUT driver instances etc. ready / code review Author (and CI) consider the PR worthy of human rewievers' time systemd

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants