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 5 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
 conveniently. It is not included in the Debian package. To create
 sparse files, use fallocate(1) provided by the essential package
 sparse files, use fallocate(1) provided by the essential package
 util-linux.
 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-Browser: https://git.in-ulm.de/cbiedl/vblade
 Vcs-Git: https://git.in-ulm.de/cbiedl/vblade.git
 Vcs-Git: https://git.in-ulm.de/cbiedl/vblade.git
 Build-Depends: debhelper (>= 11~),
 Build-Depends: debhelper (>= 11~),
+    asciidoctor,
 Priority: optional
 Priority: optional
 Section: admin
 Section: admin
 
 
 Package: vblade
 Package: vblade
 Architecture: any
 Architecture: any
 Depends: ${misc:Depends}, ${shlibs:Depends},
 Depends: ${misc:Depends}, ${shlibs:Depends},
-Recommends:
-    vblade-persist,
+    systemd | daemon,
+    systemd | lsb-base,
 Description: virtual AoE blade emulator
 Description: virtual AoE blade emulator
  The vblade is the virtual EtherDrive (R) blade, a program that makes a
  The vblade is the virtual EtherDrive (R) blade, a program that makes a
  seekable file available over an ethernet local area network (LAN) via
  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 modification
 local.makefile-additional-commands.patch
 local.makefile-additional-commands.patch
 local.vbladed-check-params.patch
 local.vbladed-check-params.patch

+ 16 - 0
debian/rules

@@ -12,6 +12,12 @@ endif
 %:
 %:
 	dh $@
 	dh $@
 
 
+override_dh_clean:
+	-rm \
+		debian/vblade-persist-convert.8 \
+		contrib/persistence/vblade-persistence.5
+	dh_clean
+
 override_dh_auto_build:
 override_dh_auto_build:
 	$(MAKE) PLATFORM=$(PLATFORM)
 	$(MAKE) PLATFORM=$(PLATFORM)
 
 
@@ -20,3 +26,13 @@ override_dh_auto_install:
 
 
 override_dh_installchangelogs:
 override_dh_installchangelogs:
 	dh_installchangelogs NEWS
 	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/
 vblade  usr/sbin/
 vbladed 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
 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