aboutsummaryrefslogtreecommitdiff
path: root/guix-container.sh
blob: afede7354792074275ac4b2126dfada72df4f21b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/bin/sh

# SPDX-License-Identifier: CC0-1.0

# Copyright (C) 2022 Wojtek Kosior <koszko@koszko.org>
#
# Available under the terms of Creative Commons Zero v1.0 Universal.

### BEGIN INIT INFO
# Provides:          guix-container
# Required-Start:    $local_fs $remote_fs $syslog
# Required-Stop:     $local_fs $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start Wojtek's Guix container with various services
### END INIT INFO

set -e

. /lib/lsb/init-functions

if [ 0 != $(id -u) ]; then
    log_action_msg "Script '$0' must be run as root"
    exit 1
fi

PIDFILE=/run/guix-container.pid
EXECUTABLE=/usr/local/bin/guix-container
HOST_SYSTEM_ROOT=
MAX_CONTAINER_SPINUP_WAIT=60

ACTION="$1"
shift

OPTIND=1
while getopts p:e:r:s: OPTION_LETTER ; do
    case "$OPTION_LETTER" in
        p)  PIDFILE="$OPTARG"    ;;
        e)  EXECUTABLE="$OPTARG" ;;
        r)  HOST_SYSTEM_ROOT="$OPTARG" ;;
        s)  MAX_CONTAINER_SPINUP_WAIT="$OPTARG" ;;
    esac
done

GUILE_PID=
SUCCESS=
QUIET_EXIT=

is_running() {
    test -e "$PIDFILE" && test -n "$(ps -o pid= --pid $(cat "$PIDFILE"))"
    return $?
}

network_rip() {
    ip link delete veth-guix-out 2>/dev/null || true
}

stop() {
    network_rip
    /sbin/start-stop-daemon                                                 \
        --stop --signal TERM --pidfile "$PIDFILE"  --remove-pidfile --quiet \
        --retry 60  2>/dev/null || true
}

onexit() {
    if [ -z "$SUCCESS" ]; then
        if [ "x$ACTION" = "xstart" -a -n "$GUILE_PID" ]; then
            stop
            kill $GUILE_PID >/dev/null || true
        fi
        if [ -z "$QUIET_EXIT" ]; then
            log_failure_msg
        fi
    else
        if [ -z "$QUIET_EXIT" ]; then
            log_success_msg
        fi
    fi
}

start() {
    LOG_DIR="$HOST_SYSTEM_ROOT"/var/log/guix-container

    KOSZKO_SIDELOAD_REAL="$HOST_SYSTEM_ROOT"/var/www/koszko.org/html
    LOG_REAL="$LOG_DIR"/container
    ETC_REAL="$HOST_SYSTEM_ROOT"/etc/guix-container

    HTTP_DIR_SHARE_OPT=--share="$KOSZKO_SIDELOAD_REAL"=/srv/http/koszko.org
    LOG_DIR_SHARE_OPT=--share="$LOG_REAL"=/var/log
    ETC_DIR_SHARE_OPT=--share="$ETC_REAL"=/etc

    mkdir --mode=700 -p "$LOG_DIR"
    mkdir --mode=700 -p "$LOG_DIR"/container

    "$EXECUTABLE" "$HTTP_DIR_SHARE_OPT"                                \
                  "$LOG_DIR_SHARE_OPT"                                 \
                  "$ETC_DIR_SHARE_OPT"                                 \
                  >> "$LOG_DIR"/stdout.log 2>> "$LOG_DIR"/stderr.log &

    GUILE_PID=$!
    WAIT_TIME=0
    SHEPHERD_PID=

    while [ $WAIT_TIME -lt "$MAX_CONTAINER_SPINUP_WAIT" ]; do
        sleep 1
        WAIT_TIME=$((WAIT_TIME + 1))
        SHEPHERD_PID=$(ps -o pid= --ppid $GUILE_PID || true)
        if [ -n "$SHEPHERD_PID" ]; then
            mkdir -p "$(dirname "$PIDFILE")"
            printf '%s' $SHEPHERD_PID > "$PIDFILE"
            break
        fi
    done

    if [ -z "$SHEPHERD_PID" ]; then
        exit 1
    fi

    network_rip

    ip link add veth-guix-out type veth peer name veth-guix-in
    ip link set veth-guix-in netns "$SHEPHERD_PID"

    ip link set veth-guix-out up
    ip addr add 10.207.87.1/24 dev veth-guix-out

    nsenter -t "$SHEPHERD_PID" --net ip link set lo up
    nsenter -t "$SHEPHERD_PID" --net ip link set veth-guix-in up
    nsenter -t "$SHEPHERD_PID" --net ip addr add 10.207.87.2/24 dev veth-guix-in
}

trap onexit EXIT

case "$ACTION" in
    start)
        if is_running; then
            log_daemon_msg "Guix container" "already running"
            log_warning_msg
            QUIET_EXIT=1
        else
            log_daemon_msg "Guix container" "starting"
            start
        fi
        ;;
    stop)
        log_daemon_msg "Guix container" "stopping"
        stop
        ;;
    restart)
        QUIET_EXIT=1
        "$0" stop "$@"
        "$0" start "$@"
        ;;
    reload|force-reload)
        QUIET_EXIT=1
        "$0" stop "$@"
        "$0" start "$@"
        ;;
    status)
        status_of_proc -p "$PIDFILE" "$EXECUTABLE" "Guix container"
        QUIET_EXIT=1
        ;;
    *)
        log_action_msg "Usage: $0 {start|stop|status|restart|reload|force-reload}"
        QUIET_EXIT=1
        exit 2
        ;;
esac

SUCCESS=1

exit 0