File: stap-jupyter-container.in

package info (click to toggle)
systemtap 5.1-5
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 47,964 kB
  • sloc: cpp: 80,838; ansic: 54,757; xml: 49,725; exp: 43,665; sh: 11,527; python: 5,003; perl: 2,252; tcl: 1,312; makefile: 1,006; javascript: 149; lisp: 105; awk: 101; asm: 91; java: 70; sed: 16
file content (153 lines) | stat: -rwxr-xr-x 6,695 bytes parent folder | download
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
#!/bin/bash
# A launcher/builder/publisher for isystemtap containers
# Copyright (C) 2023 Red Hat Inc.
#
# This file is part of systemtap, and is free software.  You can
# redistribute it and/or modify it under the terms of the GNU General
# Public License (GPL); either version 2, or (at your option) any
# later version.
set -e

usage() { echo "Usage: stap-jupyter-container [--repo REPOSITORY] [--image IMAGE] [--tag TAG] [--keyname KEYNAME] --{run, pull, build, publish, remove}" 1>&2; exit 1; }

NOTEBOOK_DIR="@prefix@/share/systemtap/interactive-notebook"
declare -A options=( ["--repo"]="quay.io" ["--image"]="systemtap/isystemtap" ["--tag"]="latest" ["--keyname"]="id_rsa" )

while (( "$#" )); do
    # Parse the mode
    if [[ $1 == --*(run|pull|build|publish|remove) ]]; then
        if [ -z "$MODE" ]; then
            MODE=$1;
        else
            echo The mode may only be defined once; usage
        fi
    # Parse options
    elif [[ $1 == --*(repo|image|tag|keyname)* ]]; then
        flag=$1
        if [[ $flag == --*=* ]]; then
            arg=`echo $flag | awk -F "=" '{print $2}'`
            flag=`echo $flag | awk -F "=" '{print $1}'`
            if [ -z "$arg" ]; then echo "$flag cannot have an empty argument"; usage; fi
        else
            if [ $# -lt 2 ]; then echo "$flag cannot have an empty argument"; usage; fi
            arg="$2"
            shift
        fi
        options[$flag]=$arg
    else
        echo $1 is not a valid argument; usage
    fi
    shift
done


if [ "$MODE" = '--run' ]; then
    HOST_USER=`whoami`
    # The container user
    NB_USER="jovyan"

    HOST_SSH_DIR=$HOME/.ssh
    PRV_KEY_FILE=$HOST_SSH_DIR/${options[--keyname]}
    PUB_KEY_FILE=$HOST_SSH_DIR/${options[--keyname]}.pub
    if [ ! -f $PUB_KEY_FILE -o ! -f $PRV_KEY_FILE ]; then
        echo "A ssh public-private key pair is required! Create one with ssh-keygen";
        echo "If using --keyname ${options[--keyname]} they must be called ${options[--keyname]} and ${options[--keyname]}.pub"
        exit 1
    fi

    # Each run of the container will generate a tmpdir in /tmp
    CONTAINER_TMP_DIR=`mktemp -d "/tmp/systemtap_jupyter_container_XXXXXXXXXX"`
    chmod 777 $CONTAINER_TMP_DIR
    echo "Using tempdir $CONTAINER_TMP_DIR"
    CONTAINER_SSH_DIR=$CONTAINER_TMP_DIR/.ssh
    LOCALHOST=127.0.0.1

    # We store the private key & a config file in this .ssh dir which will be mounted
    echo "Setting up local .ssh directory $CONTAINER_SSH_DIR for ssh from container to localhost. Your ssh keys will never be saved in the container"
    mkdir -m 700 $CONTAINER_SSH_DIR/
    echo -e "Host $LOCALHOST\n\tStrictHostKeyChecking no\n\tUser $HOST_USER\n" > $CONTAINER_SSH_DIR/config
    chmod 600 $CONTAINER_SSH_DIR/config
    cp -pv $PRV_KEY_FILE $CONTAINER_SSH_DIR

    # If the public key is not in authorized_keys (on the host), add it
    if ! grep -Fxq "`cat $PUB_KEY_FILE`" $HOST_SSH_DIR/authorized_keys 2> /dev/null
    then
        # Since the keys exist in HOST_SSH_DIR its safe to assume the directory exists and is well formed
        cat $PUB_KEY_FILE >> $HOST_SSH_DIR/authorized_keys
        chmod 600 $HOST_SSH_DIR/authorized_keys
    fi

    # Extract the constants.py values, since the locally installed version of stap
    # is what the container needs (tr removes whitespace)
    STAP_VERSION_DEF=`grep VERSION $NOTEBOOK_DIR/isystemtap/constants.py | tr -d " \t\n\r"`
    STAP_PREFIX_DEF=`grep PREFIX $NOTEBOOK_DIR/isystemtap/constants.py | tr -d " \t\n\r"`
    STAP_PKGDATADIR_DEF=`grep PKGDATADIR $NOTEBOOK_DIR/isystemtap/constants.py | tr -d " \t\n\r"`
    # We also unpack the static dir containing the examples since
    # we need to mount that 
    STAP_PKGDATADIR=`echo "$STAP_PKGDATADIR_DEF" | tr -d "' " | awk -F "=" '{print $2}'`

    run_args=(
        # We need privileged network access to freely ssh/run websockets, etc.
        --privileged  \
        --net=host    \
        # MOUNTED VOLUMES ----------------------
        # Monitor mode interactions occur in /proc/systemtap/MODULE_NAME
        -v /proc:/proc:rw \
        # The directory where we will find the examples, tapsets, etc.
        # If installed correctly it is the parent of NOTEBOOK_DIR
        -v $STAP_PKGDATADIR:$STAP_PKGDATADIR \
        -v $CONTAINER_SSH_DIR:/home/$NB_USER/.ssh \
        # ENVIRONMENT VARIABLES ------------------
        -e $STAP_VERSION_DEF \
        -e $STAP_PREFIX_DEF \
        -e $STAP_PKGDATADIR_DEF
    )

    if [ $EUID -ne 0 ]; then
        # When running as a regular user we remap so that the container id 0 (which is the podman caller) maps
        # to the u/gid of jovyan the container user
        NB_UID=1000
        NB_GID=100
        SUBUID_SIZE=$(( $(podman info --format "{{ range .Host.IDMappings.UIDMap }}+{{.Size }}{{end }}" ) - 1 ))
        SUBGID_SIZE=$(( $(podman info --format "{{ range .Host.IDMappings.GIDMap }}+{{.Size }}{{end }}" ) - 1 ))

        run_args+=(
            --user $NB_UID:$NB_GID \
            --uidmap $NB_UID:0:1 --uidmap 0:1:$NB_UID --uidmap $(($NB_UID+1)):$(($NB_UID+1)):$(($SUBUID_SIZE-$NB_UID)) \
            --gidmap $NB_GID:0:1 --gidmap 0:1:$NB_GID --gidmap $(($NB_GID+1)):$(($NB_GID+1)):$(($SUBGID_SIZE-$NB_GID)) \
            # It's convinient to be able to access the host's home directory and working directory
            -v $PWD:/home/$NB_USER/working_dir \
            -v $HOME:/home/$NB_USER/${HOST_USER}_home_dir
        )
    else
        # When running as root we create a workdir so we can share data with the user (in the temp dir)
        echo Creating a shared host-container working directory
        WORKING_DIR=$CONTAINER_TMP_DIR/workdir
        mkdir -v $WORKING_DIR

        run_args+=(
            -v $WORKING_DIR:/home/$NB_USER/working_dir \
            --user root \
            -e CHOWN_EXTRA="/home/$NB_USER/.ssh",/home/$NB_USER/working_dir \
            -e CHOWN_EXTRA_OPTS="-R"
        )
    fi

    podman run -it --rm --name isystemtap "${run_args[@]}" "${options[--repo]}/${options[--image]}:${options[--tag]}"
elif [ "$MODE" = '--pull' ]; then
    podman pull "${options[--repo]}/${options[--image]}:${options[--tag]}"
elif [ "$MODE" = '--build' ]; then
    # Build the image 
    podman build \
        --file "$NOTEBOOK_DIR/container/Dockerfile" \
        --format="docker" \
        --tag="${options[--image]}:${options[--tag]}" \
        "$NOTEBOOK_DIR/.."
elif [ "$MODE" = '--publish' ]; then
    podman login $REPO
    podman push "${options[--image]}" "${options[--repo]}/${options[--image]}:${options[--tag]}"
elif [ "$MODE" = '--remove' ]; then
    podman image rm "${options[--repo]}/${options[--image]}:${options[--tag]}"
else
    usage;
fi