Browse Source

Add support for vblade persistence

* Cherry-pick from upstream: Support for vblade persistence
* No longer recommend vblade-persist, include vblade-persist-convert to
  migrate vblade-persist configurations.
* Add extra documentation in README.Debian
Christoph Biedl 2 years ago
parent
commit
6d5b2699b6

+ 11 - 0
debian/README.Debian

@@ -5,3 +5,14 @@ Upstream provides a program `sparsefile` to create sparse files
 conveniently. It is not included in the Debian package. To create
 sparse files, use fallocate(1) provided by the essential package
 util-linux.
+
+
+Migrating from vblade-persist
+=============================
+
+Starting with version 24-2, the vblade provides persistence, see
+vblade-persistence(5) for details.
+
+For users of vblade-persist, there's a configuration conversion utility
+at /usr/share/vblade/vblade-persist-convert. For details, see
+vblade-persist-convert(8).

+ 3 - 2
debian/control

@@ -5,14 +5,15 @@ Standards-Version: 4.2.1
 Vcs-Browser: https://git.in-ulm.de/cbiedl/vblade
 Vcs-Git: https://git.in-ulm.de/cbiedl/vblade.git
 Build-Depends: debhelper (>= 11~),
+    asciidoctor,
 Priority: optional
 Section: admin
 
 Package: vblade
 Architecture: any
 Depends: ${misc:Depends}, ${shlibs:Depends},
-Recommends:
-    vblade-persist,
+    systemd | daemon,
+    systemd | lsb-base,
 Description: virtual AoE blade emulator
  The vblade is the virtual EtherDrive (R) blade, a program that makes a
  seekable file available over an ethernet local area network (LAN) via

+ 851 - 0
debian/patches/cherry-pick.vblade-24-1-g02afd36.support-for-vblade-persistence.patch

@@ -0,0 +1,851 @@
+Subject: RFC: Support for vblade persistence
+Origin: vblade-24-1-g02afd36
+Upstream-Author: Christoph Biedl <debian.axhn@manchmal.in-ulm.de>
+Date: Sat Sep 1 18:27:04 2018 +0200
+
+    Additionally, a typo fix
+
+--- /dev/null
++++ b/contrib/persistence/vblade-generator
+@@ -0,0 +1,37 @@
++#!/bin/sh
++
++set -eu
++
++SERVICEFILE="/lib/systemd/system/vblade@.service"
++WANTDIR="$1/vblade.service.wants"
++
++CONFIG_DIR=/etc/vblade.conf.d/
++
++if [ -d "$CONFIG_DIR" ] ; then
++    mkdir -p "$WANTDIR"
++    cd "$CONFIG_DIR"
++    for CONFIG in *.conf ; do
++        [ -f "$CONFIG" ] || continue
++        INSTANCE="$(systemd-escape "${CONFIG%%.conf}")"
++        LINK="$WANTDIR/vblade@$INSTANCE.service"
++
++        sh -n "$CONFIG_DIR$CONFIG" 2>/dev/null || continue
++
++        shelf=
++        slot=
++        netif=
++        filename=
++        options=
++
++        . "$CONFIG_DIR$CONFIG"
++
++        [ "$netif" ] || continue
++        [ "$shelf" ] || continue
++        [ "$slot" ] || continue
++        [ "$filename" ] || continue
++
++        ln -s "$SERVICEFILE" "$LINK"
++    done
++fi
++
++exit 0
+--- /dev/null
++++ b/contrib/persistence/vblade-persistence.txt
+@@ -0,0 +1,107 @@
++
++= VBLADE-PERSISTENCE(5)
++
++== NAME
++
++vblade-persistence - description of the vblade persistence
++
++== DESCRIPTION
++
++vblade-persistence uses the files in `/etc/vblade.conf.d/` to manage
++exports. File names must end in `.conf`. The "instance" name is the
++file name without `.conf`.
++
++The file format is a POSIX shell fragment.
++
++The following variables *must* be defined: `netif`, `shelf`, `slot`,
++and `filename`. See vblade(8) for their meaning. Incomplete
++configuration files are ignored, so are files that are not a valid
++shell syntax.
++
++Additionally, the following variables may be defined:
++
++* `options`
++
++Any options as provided by vblade(7).
++
++* `ionice`
++
++Use these to define an I/O scheduling class and level for that export.
++The value must be understood by ionice(1).
++
++
++== EXAMPLE
++
++----
++    shelf=14
++    slot=2
++    netif=ens3
++    filename=/dev/mapper/export
++    options='-r -m 11:22:33:44:55:66,22:33:44:55:66:77 -o 8'
++    ionice='--class best-effort --classdata 7'
++----
++
++
++== USAGE
++
++=== On systems using systemd
++
++Install `vblade-generator` in `/lib/systemd/system-generators/`, and
++both `vblade.service` and `vblade@.service` in `/lib/systemd/system/`.
++Enable the vblade service, reload systemd. Additional units for each
++export should appear, named `vblade@<instance>.service`.
++
++=== On systems using SysV init
++
++Individual instances may be controlled by providing their name as
++a second option, e.g.
++
++----
++    /etc/init.d/vblade status demo
++----
++
++Two different init scripts are available:
++
++==== `vblade.init.lsb-daemon`
++
++Uses LSB functions and daemon(1) program to control the instance.
++
++Pros: daemon(1) is a very fine tool for this, providing also respawning
++and output redirection.
++
++==== `vblade.init.daemon`
++
++As above, but without using LSB functions.
++
++Pros: Should be fairly portable, no thrills.
++
++==== Template
++
++The template for these scripts is `vblade.init.in`, the actual
++templating is done using tpage(1p), see `vblade.init.generate`.
++
++Support for using Debian's start-stop-daemon has been prepared but
++requires pid file supprt in vblade to be usable.
++
++
++== BUGS
++
++On SysV init systems, the configuration files are always sourced as
++shell scripts. On systemd systems, the configuration file is just
++a key/value store without shell expansion.
++
++It's a wise idea to run `sh -n` against a configuration file after any
++modification for basic format validation.
++
++
++== SEE ALSO
++
++daemon: <http://www.libslack.org/daemon/>
++
++tpage(1p)
++
++vblade(8)
++
++== AUTHOR
++
++Christoph Biedl <sourceforge.bnwi@manchmal.in-ulm.de>
+--- /dev/null
++++ b/contrib/persistence/vblade.init.daemon
+@@ -0,0 +1,191 @@
++#!/bin/sh
++
++PATH=/sbin:/usr/sbin:/bin:/usr/bin
++DESC="vblade export"
++NAME=vblade
++VBLADE="/usr/sbin/$NAME"
++DAEMON=/usr/bin/daemon
++IONICE=/usr/bin/ionice
++PIDDIR="/var/run/vblade/"
++
++[ -x "$VBLADE" ] || exit 0
++[ -x "$DAEMON" ] || exit 0
++
++mkdir -p "$PIDDIR"
++
++# Emulation of LSB functions
++VERBOSE=1
++log_daemon_msg () {
++    printf '%s ' "$@"
++}
++log_end_msg () {
++    local CODE="$1"
++    if [ "$CODE" -eq 0 ] ; then
++        echo '.'
++    else
++        echo 'failed!'
++    fi
++}
++
++# Start a vblade instance
++#
++# Return
++#   0 if daemon has been started
++#   1 if daemon was already running
++#   2 if daemon could not be started
++do_start () {
++    local INSTANCE="$1"
++    local CONFIG="$2"
++
++    sh -n "$CONFIG" 2>/dev/null || return 2
++
++    shelf=
++    slot=
++    filename=
++    netif=
++    options=
++    ionice=
++
++    . "$CONFIG"
++
++    [ "$netif" ] || return 2
++    [ "$shelf" ] || return 2
++    [ "$slot" ] || return 2
++    [ "$filename" ] || return 2
++
++    if [ "$ionice" ] ; then
++        if [ -x "$IONICE" ] ; then
++            ionice="$IONICE $ionice"
++        else
++            ionice=
++        fi
++    fi
++
++    "$DAEMON" \
++        --running \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        && return 1
++    $ionice "$DAEMON" \
++        --respawn \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        --output daemon.notice \
++        --stdout daemon.notice \
++        --stderr daemon.err -- \
++        $VBLADE $options $shelf $slot $netif $filename || return 2
++}
++
++# Stop a vblade instance
++#
++# Return
++#   0 if daemon has been stopped
++#   1 if daemon was already stopped
++#   2 if daemon could not be stopped
++#   other if a failure occurred
++do_stop () {
++    local INSTANCE="$1"
++
++    "$DAEMON" \
++        --running \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" || return 1
++    "$DAEMON" \
++        --stop \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        --stop || return 2
++    # Wait until the process is gone
++    for i in $(seq 1 10) ; do
++        "$DAEMON" \
++            --running \
++            --name "$INSTANCE" \
++            --pidfiles "$PIDDIR" || return 0
++    done
++    return 2
++}
++
++EXIT=0
++
++do_action () {
++    local CONFIG="$1"
++
++    INSTANCE="$(basename "${CONFIG%%.conf}")"
++
++    case "$ACTION" in
++        start)
++            [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$INSTANCE"
++            do_start "$INSTANCE" "$CONFIG"
++            case "$?" in
++                0|1)    [ "$VERBOSE" != no ] && log_end_msg 0 ;;
++                2)      [ "$VERBOSE" != no ] && log_end_msg 1 ;;
++            esac
++            ;;
++        stop)
++            [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$INSTANCE"
++            do_stop "$INSTANCE"
++            case "$?" in
++                0|1)    [ "$VERBOSE" != no ] && log_end_msg 0 ;;
++                2)      [ "$VERBOSE" != no ] && log_end_msg 1 ;;
++            esac
++            ;;
++        status)
++            if "$DAEMON" \
++                --running \
++                --name "$INSTANCE" \
++                --pidfiles "$PIDDIR"
++            then
++                echo "$DESC instance $INSTANCE is running"
++            else
++                echo "$DESC instance $INSTANCE is not running"
++                EXIT=1
++            fi
++            ;;
++        restart|force-reload)
++            log_daemon_msg "Restarting $DESC" "$INSTANCE"
++            do_stop "$INSTANCE"
++            case "$?" in
++                0|1)
++                    do_start "$INSTANCE" "$CONFIG"
++                    case "$?" in
++                        0)  log_end_msg 0 ;;
++                        *)
++                            # Old process is still running or
++                            # failed to start
++                            log_end_msg 1 ;;
++                    esac
++                    ;;
++                *)
++                    # Failed to stop
++                    log_end_msg 1
++                    ;;
++                esac
++            ;;
++        *)
++            echo "Usage: /etc/init.d/vblade {start|stop|status|restart|force-reload} [<export> ...]" >&2
++            exit 3
++            ;;
++    esac
++}
++
++
++ACTION="$1"
++shift
++
++if [ "$1" ] ; then
++    while [ "$1" ] ; do
++        CONFIG="/etc/vblade.conf.d/$1.conf"
++        if [ -f "$CONFIG" ] ; then
++            do_action "$CONFIG"
++        fi
++        shift
++    done
++else
++    for CONFIG in /etc/vblade.conf.d/*.conf ; do
++        if [ -f "$CONFIG" ] ; then
++            do_action "$CONFIG"
++        fi
++    done
++fi
++
++exit $EXIT
+--- /dev/null
++++ b/contrib/persistence/vblade.init.generate
+@@ -0,0 +1,24 @@
++#!/bin/sh
++
++set -e
++
++TEMPDIR="$(mktemp --directory --tmpdir "vblade.init.generate.$$.XXXXX")"
++trap "cd / ; rm -rf \"$TEMPDIR\"" EXIT
++
++run () {
++    local OUTPUT="$1"
++    echo "I: Processing $OUTPUT"
++    TEMP="$TEMPDIR/$OUTPUT"
++    shift
++    tpage "$@" vblade.init.in>"$TEMP"
++    sh -n "$TEMP"
++    if [ -f "$OUTPUT" ] && cmp -s "$TEMP" "$OUTPUT" ; then
++        echo "I: $OUTPUT is fresh"
++    else
++        cp "$TEMP" "$OUTPUT"
++    fi
++}
++
++# run 'vblade.init.debian'        --define lsb=1  --define control=ssd
++run 'vblade.init.lsb-daemon'    --define lsb=1  --define control=daemon
++run 'vblade.init.daemon'        --define lsb=   --define control=daemon
+--- /dev/null
++++ b/contrib/persistence/vblade.init.in
+@@ -0,0 +1,245 @@
++#!/bin/sh
++
++[% IF lsb -%]
++### BEGIN INIT INFO
++# Provides:          vblade
++# Required-Start:    $remote_fs $syslog $network
++# Required-Stop:     $remote_fs $syslog $network
++# Default-Start:     2 3 4 5
++# Default-Stop:      0 1 6
++# Short-Description: vblade exports
++# Description:       Manage all vlbade exports defined in
++#                    /etc/vblade.conf.d/
++### END INIT INFO
++
++[% END -%]
++PATH=/sbin:/usr/sbin:/bin:/usr/bin
++DESC="vblade export"
++NAME=vblade
++VBLADE="/usr/sbin/$NAME"
++[% IF control == 'ssd' -%]
++[% PERL -%]die ('control=ssd cannot be used as  long as vblade as no pidfile support');[% END -%]
++[% ELSIF control == 'daemon' -%]
++DAEMON=/usr/bin/daemon
++[% END -%]
++IONICE=/usr/bin/ionice
++PIDDIR="/var/run/vblade/"
++
++[ -x "$VBLADE" ] || exit 0
++[% IF control == 'daemon' -%]
++[ -x "$DAEMON" ] || exit 0
++[% END -%]
++
++mkdir -p "$PIDDIR"
++
++[% IF lsb -%]
++# Load the VERBOSE setting and other rcS variables
++. /lib/init/vars.sh
++
++# Define LSB functions
++. /lib/lsb/init-functions
++[% ELSE -%]
++# Emulation of LSB functions
++VERBOSE=1
++log_daemon_msg () {
++    printf '%s ' "$@"
++}
++log_end_msg () {
++    local CODE="$1"
++    if [ "$CODE" -eq 0 ] ; then
++        echo '.'
++    else
++        echo 'failed!'
++    fi
++}
++[% END -%]
++
++# Start a vblade instance
++#
++# Return
++#   0 if daemon has been started
++#   1 if daemon was already running
++#   2 if daemon could not be started
++do_start () {
++    local INSTANCE="$1"
++    local CONFIG="$2"
++
++    sh -n "$CONFIG" 2>/dev/null || return 2
++
++    shelf=
++    slot=
++    filename=
++    netif=
++    options=
++    ionice=
++
++    . "$CONFIG"
++
++    [ "$netif" ] || return 2
++    [ "$shelf" ] || return 2
++    [ "$slot" ] || return 2
++    [ "$filename" ] || return 2
++
++    if [ "$ionice" ] ; then
++        if [ -x "$IONICE" ] ; then
++            ionice="$IONICE $ionice"
++        else
++            ionice=
++        fi
++    fi
++
++[% IF control == 'ssd' -%]
++    local PIDFILE="$PIDDIR/$INSTANCE.pid"
++    start-stop-daemon --start --quiet \
++        --pidfile "$PIDFILE" --exec "$VBLADE" --test > /dev/null \
++        || return 1
++    start-stop-daemon --start --quiet \
++        --pidfile "$PIDFILE" \
++        --exec $ionice "$VBLADE" -- \
++        $shelf $slot $netif $filename $options \
++        || return 2
++[% ELSIF control == 'daemon' -%]
++    "$DAEMON" \
++        --running \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        && return 1
++    $ionice "$DAEMON" \
++        --respawn \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        --output daemon.notice \
++        --stdout daemon.notice \
++        --stderr daemon.err -- \
++        $VBLADE $options $shelf $slot $netif $filename || return 2
++[% END -%]
++}
++
++# Stop a vblade instance
++#
++# Return
++#   0 if daemon has been stopped
++#   1 if daemon was already stopped
++#   2 if daemon could not be stopped
++#   other if a failure occurred
++do_stop () {
++    local INSTANCE="$1"
++
++[% IF control == 'ssd' -%]
++    local PIDFILE="$PIDDIR/$INSTANCE.pid"
++    start-stop-daemon --stop --quiet \
++        --retry=TERM/30/KILL/5 --pidfile "$PIDFILE" --name "$NAME"
++    RETVAL="$?"
++    [ "$RETVAL" = 2 ] && return 2
++    # Many daemons don't delete their pidfiles when they exit.
++    rm -f "$PIDFILE"
++    return "$RETVAL"
++[% ELSIF control == 'daemon' -%]
++    "$DAEMON" \
++        --running \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" || return 1
++    "$DAEMON" \
++        --stop \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        --stop || return 2
++    # Wait until the process is gone
++    for i in $(seq 1 10) ; do
++        "$DAEMON" \
++            --running \
++            --name "$INSTANCE" \
++            --pidfiles "$PIDDIR" || return 0
++    done
++    return 2
++[% END -%]
++}
++
++EXIT=0
++
++do_action () {
++    local CONFIG="$1"
++
++    INSTANCE="$(basename "${CONFIG%%.conf}")"
++
++    case "$ACTION" in
++        start)
++            [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$INSTANCE"
++            do_start "$INSTANCE" "$CONFIG"
++            case "$?" in
++                0|1)    [ "$VERBOSE" != no ] && log_end_msg 0 ;;
++                2)      [ "$VERBOSE" != no ] && log_end_msg 1 ;;
++            esac
++            ;;
++        stop)
++            [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$INSTANCE"
++            do_stop "$INSTANCE"
++            case "$?" in
++                0|1)    [ "$VERBOSE" != no ] && log_end_msg 0 ;;
++                2)      [ "$VERBOSE" != no ] && log_end_msg 1 ;;
++            esac
++            ;;
++        status)
++[% IF lsb -%]
++            status_of_proc -p "$PIDDIR/$INSTANCE.pid" "$VBLADE" "vblade instance $INSTANCE" || EXIT=$?
++[% ELSE -%]
++            if "$DAEMON" \
++                --running \
++                --name "$INSTANCE" \
++                --pidfiles "$PIDDIR"
++            then
++                echo "$DESC instance $INSTANCE is running"
++            else
++                echo "$DESC instance $INSTANCE is not running"
++                EXIT=1
++            fi
++[% END -%]
++            ;;
++        restart|force-reload)
++            log_daemon_msg "Restarting $DESC" "$INSTANCE"
++            do_stop "$INSTANCE"
++            case "$?" in
++                0|1)
++                    do_start "$INSTANCE" "$CONFIG"
++                    case "$?" in
++                        0)  log_end_msg 0 ;;
++                        *)
++                            # Old process is still running or
++                            # failed to start
++                            log_end_msg 1 ;;
++                    esac
++                    ;;
++                *)
++                    # Failed to stop
++                    log_end_msg 1
++                    ;;
++                esac
++            ;;
++        *)
++            echo "Usage: /etc/init.d/vblade {start|stop|status|restart|force-reload} [<export> ...]" >&2
++            exit 3
++            ;;
++    esac
++}
++
++
++ACTION="$1"
++shift
++
++if [ "$1" ] ; then
++    while [ "$1" ] ; do
++        CONFIG="/etc/vblade.conf.d/$1.conf"
++        if [ -f "$CONFIG" ] ; then
++            do_action "$CONFIG"
++        fi
++        shift
++    done
++else
++    for CONFIG in /etc/vblade.conf.d/*.conf ; do
++        if [ -f "$CONFIG" ] ; then
++            do_action "$CONFIG"
++        fi
++    done
++fi
++
++exit $EXIT
+--- /dev/null
++++ b/contrib/persistence/vblade.init.lsb-daemon
+@@ -0,0 +1,185 @@
++#!/bin/sh
++
++### BEGIN INIT INFO
++# Provides:          vblade
++# Required-Start:    $remote_fs $syslog $network
++# Required-Stop:     $remote_fs $syslog $network
++# Default-Start:     2 3 4 5
++# Default-Stop:      0 1 6
++# Short-Description: vblade exports
++# Description:       Manage all vblade exports defined in
++#                    /etc/vblade.conf.d/
++### END INIT INFO
++
++PATH=/sbin:/usr/sbin:/bin:/usr/bin
++DESC="vblade export"
++NAME=vblade
++VBLADE="/usr/sbin/$NAME"
++DAEMON=/usr/bin/daemon
++IONICE=/usr/bin/ionice
++PIDDIR="/var/run/vblade/"
++
++[ -x "$VBLADE" ] || exit 0
++[ -x "$DAEMON" ] || exit 0
++
++mkdir -p "$PIDDIR"
++
++# Load the VERBOSE setting and other rcS variables
++. /lib/init/vars.sh
++
++# Define LSB functions
++. /lib/lsb/init-functions
++
++# Start a vblade instance
++#
++# Return
++#   0 if daemon has been started
++#   1 if daemon was already running
++#   2 if daemon could not be started
++do_start () {
++    local INSTANCE="$1"
++    local CONFIG="$2"
++
++    sh -n "$CONFIG" 2>/dev/null || return 2
++
++    shelf=
++    slot=
++    filename=
++    netif=
++    options=
++    ionice=
++
++    . "$CONFIG"
++
++    [ "$netif" ] || return 2
++    [ "$shelf" ] || return 2
++    [ "$slot" ] || return 2
++    [ "$filename" ] || return 2
++
++    if [ "$ionice" ] ; then
++        if [ -x "$IONICE" ] ; then
++            ionice="$IONICE $ionice"
++        else
++            ionice=
++        fi
++    fi
++
++    "$DAEMON" \
++        --running \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        && return 1
++    $ionice "$DAEMON" \
++        --respawn \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        --output daemon.notice \
++        --stdout daemon.notice \
++        --stderr daemon.err -- \
++        $VBLADE $options $shelf $slot $netif $filename || return 2
++}
++
++# Stop a vblade instance
++#
++# Return
++#   0 if daemon has been stopped
++#   1 if daemon was already stopped
++#   2 if daemon could not be stopped
++#   other if a failure occurred
++do_stop () {
++    local INSTANCE="$1"
++
++    "$DAEMON" \
++        --running \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" || return 1
++    "$DAEMON" \
++        --stop \
++        --name "$INSTANCE" \
++        --pidfiles "$PIDDIR" \
++        --stop || return 2
++    # Wait until the process is gone
++    for i in $(seq 1 10) ; do
++        "$DAEMON" \
++            --running \
++            --name "$INSTANCE" \
++            --pidfiles "$PIDDIR" || return 0
++    done
++    return 2
++}
++
++EXIT=0
++
++do_action () {
++    local CONFIG="$1"
++
++    INSTANCE="$(basename "${CONFIG%%.conf}")"
++
++    case "$ACTION" in
++        start)
++            [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$INSTANCE"
++            do_start "$INSTANCE" "$CONFIG"
++            case "$?" in
++                0|1)    [ "$VERBOSE" != no ] && log_end_msg 0 ;;
++                2)      [ "$VERBOSE" != no ] && log_end_msg 1 ;;
++            esac
++            ;;
++        stop)
++            [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$INSTANCE"
++            do_stop "$INSTANCE"
++            case "$?" in
++                0|1)    [ "$VERBOSE" != no ] && log_end_msg 0 ;;
++                2)      [ "$VERBOSE" != no ] && log_end_msg 1 ;;
++            esac
++            ;;
++        status)
++            status_of_proc -p "$PIDDIR/$INSTANCE.pid" "$VBLADE" "vblade instance $INSTANCE" || EXIT=$?
++            ;;
++        restart|force-reload)
++            log_daemon_msg "Restarting $DESC" "$INSTANCE"
++            do_stop "$INSTANCE"
++            case "$?" in
++                0|1)
++                    do_start "$INSTANCE" "$CONFIG"
++                    case "$?" in
++                        0)  log_end_msg 0 ;;
++                        *)
++                            # Old process is still running or
++                            # failed to start
++                            log_end_msg 1 ;;
++                    esac
++                    ;;
++                *)
++                    # Failed to stop
++                    log_end_msg 1
++                    ;;
++                esac
++            ;;
++        *)
++            echo "Usage: /etc/init.d/vblade {start|stop|status|restart|force-reload} [<export> ...]" >&2
++            exit 3
++            ;;
++    esac
++}
++
++
++ACTION="$1"
++shift
++
++if [ "$1" ] ; then
++    while [ "$1" ] ; do
++        CONFIG="/etc/vblade.conf.d/$1.conf"
++        if [ -f "$CONFIG" ] ; then
++            do_action "$CONFIG"
++        fi
++        shift
++    done
++else
++    for CONFIG in /etc/vblade.conf.d/*.conf ; do
++        if [ -f "$CONFIG" ] ; then
++            do_action "$CONFIG"
++        fi
++    done
++fi
++
++exit $EXIT
+--- /dev/null
++++ b/contrib/persistence/vblade.service
+@@ -0,0 +1,13 @@
++[Unit]
++Description=vblade exports
++Documentation=man:vblade-persistence(5)
++Documentation=man:vblade(8)
++
++[Service]
++Type=oneshot
++ExecStart=/bin/true
++ExecReload=/bin/true
++RemainAfterExit=on
++
++[Install]
++WantedBy=multi-user.target
+--- /dev/null
++++ b/contrib/persistence/vblade@.service
+@@ -0,0 +1,18 @@
++[Unit]
++Description=vblade instance %I
++SourcePath=/etc/vblade.conf.d/%I.conf
++Documentation=man:vblade(8)
++PartOf=vblade.service
++After=rc-local.service
++
++[Service]
++Type=simple
++Environment="ionice=-c2 -n7"
++EnvironmentFile=/etc/vblade.conf.d/%I.conf
++ExecStart=/usr/bin/ionice $ionice /usr/sbin/vblade $shelf $slot $netif $filename $options
++SyslogIdentifier=vblade
++Restart=always
++RestartSec=10
++
++[Install]
++WantedBy=multi-user.target

+ 3 - 0
debian/patches/series

@@ -1,4 +1,7 @@
 
+# cherry-picked from upstream
+cherry-pick.vblade-24-1-g02afd36.support-for-vblade-persistence.patch
+
 # local modification
 local.makefile-additional-commands.patch
 local.vbladed-check-params.patch

+ 16 - 0
debian/rules

@@ -12,6 +12,12 @@ endif
 %:
 	dh $@
 
+override_dh_clean:
+	-rm \
+		debian/vblade-persist-convert.8 \
+		contrib/persistence/vblade-persistence.5
+	dh_clean
+
 override_dh_auto_build:
 	$(MAKE) PLATFORM=$(PLATFORM)
 
@@ -20,3 +26,13 @@ override_dh_auto_install:
 
 override_dh_installchangelogs:
 	dh_installchangelogs NEWS
+
+override_dh_installman:
+	asciidoctor --attribute reproducible --backend=manpage debian/vblade-persist-convert.txt
+	asciidoctor --attribute reproducible --backend=manpage contrib/persistence/vblade-persistence.txt
+	dh_installman
+
+# needed as long as vblade-generator is provided by a patch
+override_dh_fixperms:
+	dh_fixperms
+	chmod 0755 debian/vblade/lib/systemd/system-generators/vblade-generator

+ 33 - 0
debian/skeleton.conf

@@ -0,0 +1,33 @@
+
+# This is a POSIX shell fragment
+
+# configuration of a single vblade instance
+
+# Supported variables:
+
+# shelf address. Mandatory
+# shelf=
+
+# slot address. Mandatory
+# slot=
+
+# Network interface name. Mandatory
+# netif=
+
+# The name of the regular file or block device to export. Mandatory
+# filename=
+
+# Other options, see vblade(8)
+# options=
+
+# ionice=
+# Set the I/O scheduling class and priority.
+# Must be understood by ionice(1)
+
+# Example:
+# shelf=10
+# slot=3
+# netif=em3
+# filename=/dev/mapper/export
+# options='-m 11:22:33:44:55:66 -o 8'
+# ionice='--class best-effort --classdata 7'

+ 1 - 0
debian/vblade-generator

@@ -0,0 +1 @@
+../contrib/persistence/debian/vblade-generator

+ 64 - 0
debian/vblade-persist-convert

@@ -0,0 +1,64 @@
+#!/bin/sh
+
+set -e
+
+NEW_DIR="$1"
+OLD_DIR="$2"
+
+[ "$OLD_DIR" ] || OLD_DIR='/var/lib/vblade-persist/vblades/'
+[ "$NEW_DIR" ] || NEW_DIR='/etc/vblade.conf.d/'
+
+[ -d "$OLD_DIR" ] || exit 0
+mkdir -p "$NEW_DIR"
+
+for d in $(find "$OLD_DIR" -mindepth 1 -maxdepth 1 -type d | sort) ; do
+    [ -d "$d" ] || continue
+    for f in NETIF SHELF SLOT SOURCE ; do
+        [ -f "$d/env/$f" ] && continue
+        echo "E: Incomplete vblade-persist configuration at '$d', 'env/$f' is missing"
+        continue 2
+    done
+    OLDNAME="$(basename "$d")"
+    INSTANCE="vblade.persist.$OLDNAME.conf"
+    echo "I: Processing $OLDNAME, will store as $INSTANCE"
+    if [ -e "$NEW_DIR/$INSTANCE" ] ; then
+        echo "E: A vblade configuration '$NEW_DIR/$INSTANCE' already exists, skipping"
+        continue
+    fi
+    TEMP="$(mktemp --tmpdir="$NEW_DIR" "$INSTANCE.XXXXX")"
+    trap "[ -f \"$TEMP\" ] && rm \"$TEMP\"" EXIT
+    (
+        cat <<__EOS__
+#
+# Created by $(basename "$0") on $(date)
+#
+Shelf=$(cat "$d/env/SHELF")
+Slot=$(cat "$d/env/SLOT")
+NetIf=$(cat "$d/env/NETIF")
+Filename=$(cat "$d/env/SOURCE")
+Options=$(
+    if [ -d "$d/macs" ] ; then
+        macs="$(
+            find "$d/macs" -type f -iname '[0-9a-f]*' -printf '%f,' |
+            sort |
+            sed -e 's/,$//'
+        )"
+        if [ "$macs" ] ; then
+            printf '"-m %s"' "$macs"
+        fi
+    fi
+)
+# IOSchedulingClass=
+# IOSchedulingPriority=
+__EOS__
+    ) >"$TEMP"
+    if ! sh -n "$TEMP" ; then
+        echo "F: Conversion of '$d' failed, checking the following script failed:"
+        cat "$TEMP" | sed -e 's/^/| /'
+        rm "$TEMP"
+        exit 1
+    fi
+    mv "$TEMP" "$NEW_DIR/$INSTANCE"
+done
+
+exit 0

+ 43 - 0
debian/vblade-persist-convert.txt

@@ -0,0 +1,43 @@
+
+VBLADE-PERSIST-CONVERT(8)
+=========================
+
+NAME
+----
+
+vblade-persist-convert - convert vblade-persist export configurations
+
+SYNOPSIS
+--------
+
+Usage:
+
+----
+    vblade-persist-convert [<vblade-directory> [ <runit-directory>]]
+----
+
+Beware: The order is "destination", "source", assuming the first is
+the one that's overridden more often, for e.g. a pre-flight check.
+
+OPTIONS
+-------
+
+The `<runit-directory>` defaults to `/var/lib/vblade-persist/vblades/`,
+the `<vblade-directory>` to `/etc/vblade.conf.d/`.
+
+
+DESCRIPTION
+-----------
+
+This program eases transition of vblade exports from the runit sniplets
+provided by vblade-persist(1) to the configuration files managed by
+vblade(8). The subdirectory names in `<runit-directory>`, consisting of
+shelf and slot name, are re-used as configuration file name, prefixed
+with "`vblade.persist.`". No configuration item should get lost.
+
+
+AUTHOR
+------
+
+This manpage was written for the Debian project by Christoph Biedl
+<debian.axhn@manchmal.in-ulm.de> but may be used by others.

+ 1 - 0
debian/vblade.init

@@ -0,0 +1 @@
+../contrib/persistence/vblade.init.lsb-daemon

+ 5 - 0
debian/vblade.install

@@ -1,2 +1,7 @@
+
 vblade  usr/sbin/
 vbladed usr/sbin/
+
+contrib/persistence/vblade-generator    lib/systemd/system-generators/
+debian/skeleton.conf                    etc/vblade.conf.d/
+debian/vblade-persist-convert           usr/share/vblade/

+ 3 - 0
debian/vblade.manpages

@@ -1 +1,4 @@
+
 vblade.8
+debian/vblade-persist-convert.8
+contrib/persistence/vblade-persistence.5

+ 1 - 0
debian/vblade.service

@@ -0,0 +1 @@
+../contrib/persistence/vblade.service

+ 1 - 0
debian/vblade@.service

@@ -0,0 +1 @@
+../contrib/persistence/vblade@.service