Skip to content

Commit 9dbd2bb

Browse files
committed
Use DOOD stategy to keep supporting ubuntu18.04
See NVIDIA/cccl#1779 Signed-off-by: Jordan Jacobelli <[email protected]>
1 parent 51fabee commit 9dbd2bb

File tree

15 files changed

+381
-57
lines changed

15 files changed

+381
-57
lines changed

.devcontainer/cuda11.1-gcc7/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"shutdownAction": "stopContainer",
3-
"image": "rapidsai/devcontainers:24.12-cpp-gcc7-cuda11.1-ubuntu20.04",
3+
"image": "rapidsai/devcontainers:24.12-cpp-gcc7-cuda11.1-ubuntu18.04",
44
"hostRequirements": {
55
"gpu": "optional"
66
},

.devcontainer/cuda11.1-gcc8/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"shutdownAction": "stopContainer",
3-
"image": "rapidsai/devcontainers:24.12-cpp-gcc8-cuda11.1-ubuntu20.04",
3+
"image": "rapidsai/devcontainers:24.12-cpp-gcc8-cuda11.1-ubuntu18.04",
44
"hostRequirements": {
55
"gpu": "optional"
66
},

.devcontainer/cuda11.1-gcc9/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"shutdownAction": "stopContainer",
3-
"image": "rapidsai/devcontainers:24.12-cpp-gcc9-cuda11.1-ubuntu20.04",
3+
"image": "rapidsai/devcontainers:24.12-cpp-gcc9-cuda11.1-ubuntu18.04",
44
"hostRequirements": {
55
"gpu": "optional"
66
},

.devcontainer/cuda11.1-llvm9/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"shutdownAction": "stopContainer",
3-
"image": "rapidsai/devcontainers:24.12-cpp-llvm9-cuda11.1-ubuntu20.04",
3+
"image": "rapidsai/devcontainers:24.12-cpp-llvm9-cuda11.1-ubuntu18.04",
44
"hostRequirements": {
55
"gpu": "optional"
66
},

.devcontainer/docker-entrypoint.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env bash
2+
3+
# Maybe change the UID/GID of the container's non-root user to match the host's UID/GID
4+
5+
: "${REMOTE_USER:="coder"}";
6+
: "${OLD_UID:=}";
7+
: "${OLD_GID:=}";
8+
: "${NEW_UID:=}";
9+
: "${NEW_GID:=}";
10+
11+
eval "$(sed -n "s/${REMOTE_USER}:[^:]*:\([^:]*\):\([^:]*\):[^:]*:\([^:]*\).*/OLD_UID=\1;OLD_GID=\2;HOME_FOLDER=\3/p" /etc/passwd)";
12+
eval "$(sed -n "s/\([^:]*\):[^:]*:${NEW_UID}:.*/EXISTING_USER=\1/p" /etc/passwd)";
13+
eval "$(sed -n "s/\([^:]*\):[^:]*:${NEW_GID}:.*/EXISTING_GROUP=\1/p" /etc/group)";
14+
15+
if [ -z "$OLD_UID" ]; then
16+
echo "Remote user not found in /etc/passwd ($REMOTE_USER).";
17+
exec "$(pwd)/.devcontainer/nvbench-entrypoint.sh" "$@";
18+
elif [ "$OLD_UID" = "$NEW_UID" ] && [ "$OLD_GID" = "$NEW_GID" ]; then
19+
echo "UIDs and GIDs are the same ($NEW_UID:$NEW_GID).";
20+
exec "$(pwd)/.devcontainer/nvbench-entrypoint.sh" "$@";
21+
elif [ "$OLD_UID" != "$NEW_UID" ] && [ -n "$EXISTING_USER" ]; then
22+
echo "User with UID exists ($EXISTING_USER=$NEW_UID).";
23+
exec "$(pwd)/.devcontainer/nvbench-entrypoint.sh" "$@";
24+
else
25+
if [ "$OLD_GID" != "$NEW_GID" ] && [ -n "$EXISTING_GROUP" ]; then
26+
echo "Group with GID exists ($EXISTING_GROUP=$NEW_GID).";
27+
NEW_GID="$OLD_GID";
28+
fi
29+
echo "Updating UID:GID from $OLD_UID:$OLD_GID to $NEW_UID:$NEW_GID.";
30+
sed -i -e "s/\(${REMOTE_USER}:[^:]*:\)[^:]*:[^:]*/\1${NEW_UID}:${NEW_GID}/" /etc/passwd;
31+
if [ "$OLD_GID" != "$NEW_GID" ]; then
32+
sed -i -e "s/\([^:]*:[^:]*:\)${OLD_GID}:/\1${NEW_GID}:/" /etc/group;
33+
fi
34+
35+
# Fast parallel `chown -R`
36+
find "$HOME_FOLDER/" -not -user "$REMOTE_USER" -print0 \
37+
| xargs -0 -r -n1 -P"$(nproc --all)" chown "$NEW_UID:$NEW_GID"
38+
39+
# Run the container command as $REMOTE_USER, preserving the container startup environment.
40+
#
41+
# We cannot use `su -w` because that's not supported by the `su` in Ubuntu18.04, so we reset the following
42+
# environment variables to the expected values, then pass through everything else from the startup environment.
43+
export HOME="$HOME_FOLDER";
44+
export XDG_CACHE_HOME="$HOME_FOLDER/.cache";
45+
export XDG_CONFIG_HOME="$HOME_FOLDER/.config";
46+
export XDG_STATE_HOME="$HOME_FOLDER/.local/state";
47+
export PYTHONHISTFILE="$HOME_FOLDER/.local/state/.python_history";
48+
exec su -p "$REMOTE_USER" -- "$(pwd)/.devcontainer/nvbench-entrypoint.sh" "$@";
49+
fi

.devcontainer/launch.sh

Lines changed: 196 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,46 @@ print_help() {
1111
echo "the top-level devcontainer in .devcontainer/devcontainer.json will be used."
1212
echo ""
1313
echo "Options:"
14-
echo " -c, --cuda Specify the CUDA version. E.g., 12.2"
15-
echo " -H, --host Specify the host compiler. E.g., gcc12"
16-
echo " -d, --docker Launch the development environment in Docker directly without using VSCode."
17-
echo " -h, --help Display this help message and exit."
14+
echo " -c, --cuda Specify the CUDA version. E.g., 12.2"
15+
echo " -H, --host Specify the host compiler. E.g., gcc12"
16+
echo " -d, --docker Launch the development environment in Docker directly without using VSCode."
17+
echo " --gpus gpu-request GPU devices to add to the container ('all' to pass all GPUs)."
18+
echo " -e, --env list Set additional container environment variables."
19+
echo " -v, --volume list Bind mount a volume."
20+
echo " -h, --help Display this help message and exit."
21+
}
22+
23+
# Assign variable one scope above the caller
24+
# Usage: local "$1" && _upvar $1 "value(s)"
25+
# Param: $1 Variable name to assign value to
26+
# Param: $* Value(s) to assign. If multiple values, an array is
27+
# assigned, otherwise a single value is assigned.
28+
# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference
29+
_upvar() {
30+
if unset -v "$1"; then
31+
if (( $# == 2 )); then
32+
eval $1=\"\$2\";
33+
else
34+
eval $1=\(\"\${@:2}\"\);
35+
fi;
36+
fi
1837
}
1938

2039
parse_options() {
21-
local OPTIONS=c:H:dh
22-
local LONG_OPTIONS=cuda:,host:,docker,help
40+
local -;
41+
set -euo pipefail;
42+
43+
# Read the name of the variable in which to return unparsed arguments
44+
local UNPARSED="${!#}";
45+
# Splice the unparsed arguments variable name from the arguments list
46+
set -- "${@:1:$#-1}";
47+
48+
local OPTIONS=c:e:H:dhv
49+
local LONG_OPTIONS=cuda:,env:,host:,gpus:,volume:,docker,help
50+
# shellcheck disable=SC2155
2351
local PARSED_OPTIONS=$(getopt -n "$0" -o "${OPTIONS}" --long "${LONG_OPTIONS}" -- "$@")
2452

53+
# shellcheck disable=SC2181
2554
if [[ $? -ne 0 ]]; then
2655
exit 1
2756
fi
@@ -34,10 +63,18 @@ parse_options() {
3463
cuda_version="$2"
3564
shift 2
3665
;;
66+
-e|--env)
67+
env_vars+=("$1" "$2")
68+
shift 2
69+
;;
3770
-H|--host)
3871
host_compiler="$2"
3972
shift 2
4073
;;
74+
--gpus)
75+
gpu_request="$2"
76+
shift 2
77+
;;
4178
-d|--docker)
4279
docker_mode=true
4380
shift
@@ -46,8 +83,13 @@ parse_options() {
4683
print_help
4784
exit 0
4885
;;
86+
-v|--volume)
87+
volumes+=("$1" "$2")
88+
shift 2
89+
;;
4990
--)
5091
shift
92+
_upvar "${UNPARSED}" "${@}"
5193
break
5294
;;
5395
*)
@@ -59,20 +101,153 @@ parse_options() {
59101
done
60102
}
61103

104+
# shellcheck disable=SC2155
62105
launch_docker() {
63-
DOCKER_IMAGE=$(grep "image" "${path}/devcontainer.json" | sed 's/.*: "\(.*\)",/\1/')
64-
echo "Found image: ${DOCKER_IMAGE}"
65-
docker pull ${DOCKER_IMAGE}
66-
docker run \
67-
-it --rm \
68-
--user coder \
69-
--workdir /home/coder/cccl \
70-
--mount type=bind,src="$(pwd)",dst='/home/coder/cccl' \
71-
${DOCKER_IMAGE} \
72-
/bin/bash
106+
local -;
107+
set -euo pipefail
108+
109+
inline_vars() {
110+
cat - \
111+
`# inline local workspace folder` \
112+
| sed "s@\${localWorkspaceFolder}@$(pwd)@g" \
113+
`# inline local workspace folder basename` \
114+
| sed "s@\${localWorkspaceFolderBasename}@$(basename "$(pwd)")@g" \
115+
`# inline container workspace folder` \
116+
| sed "s@\${containerWorkspaceFolder}@${WORKSPACE_FOLDER:-}@g" \
117+
`# inline container workspace folder basename` \
118+
| sed "s@\${containerWorkspaceFolderBasename}@$(basename "${WORKSPACE_FOLDER:-}")@g" \
119+
`# translate local envvars to shell syntax` \
120+
| sed -r 's/\$\{localEnv:([^\:]*):?(.*)\}/${\1:-\2}/g'
121+
}
122+
123+
args_to_path() {
124+
local -a keys=("${@}")
125+
keys=("${keys[@]/#/[}")
126+
keys=("${keys[@]/%/]}")
127+
echo "$(IFS=; echo "${keys[*]}")"
128+
}
129+
130+
json_string() {
131+
python3 -c "import json,sys; print(json.load(sys.stdin)$(args_to_path "${@}"))" 2>/dev/null | inline_vars
132+
}
133+
134+
json_array() {
135+
python3 -c "import json,sys; [print(f'\"{x}\"') for x in json.load(sys.stdin)$(args_to_path "${@}")]" 2>/dev/null | inline_vars
136+
}
137+
138+
json_map() {
139+
python3 -c "import json,sys; [print(f'{k}=\"{v}\"') for k,v in json.load(sys.stdin)$(args_to_path "${@}").items()]" 2>/dev/null | inline_vars
140+
}
141+
142+
devcontainer_metadata_json() {
143+
docker inspect --type image --format '{{json .Config.Labels}}' "$DOCKER_IMAGE" \
144+
| json_string '"devcontainer.metadata"'
145+
}
146+
147+
###
148+
# Read relevant values from devcontainer.json
149+
###
150+
151+
local devcontainer_json="${path}/devcontainer.json";
152+
153+
# Read image
154+
local DOCKER_IMAGE="$(json_string '"image"' < "${devcontainer_json}")"
155+
# Always pull the latest copy of the image
156+
docker pull "$DOCKER_IMAGE"
157+
158+
# Read workspaceFolder
159+
local WORKSPACE_FOLDER="$(json_string '"workspaceFolder"' < "${devcontainer_json}")"
160+
# Read remoteUser
161+
local REMOTE_USER="$(json_string '"remoteUser"' < "${devcontainer_json}")"
162+
# If remoteUser isn't in our devcontainer.json, read it from the image's "devcontainer.metadata" label
163+
if test -z "${REMOTE_USER:-}"; then
164+
REMOTE_USER="$(devcontainer_metadata_json | json_string "-1" '"remoteUser"')"
165+
fi
166+
# Read runArgs
167+
local -a RUN_ARGS="($(json_array '"runArgs"' < "${devcontainer_json}"))"
168+
# Read initializeCommand
169+
local -a INITIALIZE_COMMAND="($(json_array '"initializeCommand"' < "${devcontainer_json}"))"
170+
# Read containerEnv
171+
local -a ENV_VARS="($(json_map '"containerEnv"' < "${devcontainer_json}" | sed -r 's/(.*)=(.*)/--env \1=\2/'))"
172+
# Read mounts
173+
local -a MOUNTS="($(
174+
tee < "${devcontainer_json}" \
175+
1>/dev/null \
176+
>(json_array '"mounts"') \
177+
>(json_string '"workspaceMount"') \
178+
| xargs -r -I% echo --mount '%'
179+
))"
180+
181+
###
182+
# Update run arguments and container environment variables
183+
###
184+
185+
# Only pass `-it` if the shell is a tty
186+
if ! ${CI:-'false'} && tty >/dev/null 2>&1 && (exec </dev/tty); then
187+
RUN_ARGS+=("-it")
188+
fi
189+
190+
for flag in rm init; do
191+
if [[ " ${RUN_ARGS[*]} " != *" --${flag} "* ]]; then
192+
RUN_ARGS+=("--${flag}")
193+
fi
194+
done
195+
196+
# Prefer the user-provided --gpus argument
197+
if test -n "${gpu_request:-}"; then
198+
RUN_ARGS+=(--gpus "${gpu_request}")
199+
else
200+
# Otherwise read and infer from hostRequirements.gpu
201+
local GPU_REQUEST="$(json_string '"hostRequirements"' '"gpu"' < "${devcontainer_json}")"
202+
if test "${GPU_REQUEST:-false}" = true; then
203+
RUN_ARGS+=(--gpus all)
204+
elif test "${GPU_REQUEST:-false}" = optional && \
205+
command -v nvidia-container-runtime >/dev/null 2>&1; then
206+
RUN_ARGS+=(--gpus all)
207+
fi
208+
fi
209+
210+
RUN_ARGS+=(--workdir "${WORKSPACE_FOLDER:-/home/coder/cccl}")
211+
212+
if test -n "${REMOTE_USER:-}"; then
213+
ENV_VARS+=(--env NEW_UID="$(id -u)")
214+
ENV_VARS+=(--env NEW_GID="$(id -g)")
215+
ENV_VARS+=(--env REMOTE_USER="$REMOTE_USER")
216+
RUN_ARGS+=(-u root:root)
217+
RUN_ARGS+=(--entrypoint "${WORKSPACE_FOLDER:-/home/coder/cccl}/.devcontainer/docker-entrypoint.sh")
218+
fi
219+
220+
if test -n "${SSH_AUTH_SOCK:-}"; then
221+
ENV_VARS+=(--env "SSH_AUTH_SOCK=/tmp/ssh-auth-sock")
222+
MOUNTS+=(--mount "source=${SSH_AUTH_SOCK},target=/tmp/ssh-auth-sock,type=bind")
223+
fi
224+
225+
# Append user-provided volumes
226+
if test -v volumes && test ${#volumes[@]} -gt 0; then
227+
MOUNTS+=("${volumes[@]}")
228+
fi
229+
230+
# Append user-provided envvars
231+
if test -v env_vars && test ${#env_vars[@]} -gt 0; then
232+
ENV_VARS+=("${env_vars[@]}")
233+
fi
234+
235+
# Run the initialize command before starting the container
236+
if test "${#INITIALIZE_COMMAND[@]}" -gt 0; then
237+
eval "${INITIALIZE_COMMAND[*]@Q}"
238+
fi
239+
240+
exec docker run \
241+
"${RUN_ARGS[@]}" \
242+
"${ENV_VARS[@]}" \
243+
"${MOUNTS[@]}" \
244+
"${DOCKER_IMAGE}" \
245+
"$@"
73246
}
74247

75248
launch_vscode() {
249+
local -;
250+
set -euo pipefail;
76251
# Since Visual Studio Code allows only one instance per `devcontainer.json`,
77252
# this code prepares a unique temporary directory structure for each launch of a devcontainer.
78253
# By doing so, it ensures that multiple instances of the same environment can be run
@@ -85,7 +260,7 @@ launch_vscode() {
85260
mkdir -p "${tmpdir}"
86261
mkdir -p "${tmpdir}/.devcontainer"
87262
cp -arL "${path}/devcontainer.json" "${tmpdir}/.devcontainer"
88-
sed -i 's@\\${localWorkspaceFolder}@$(pwd)@g' "${tmpdir}/.devcontainer/devcontainer.json"
263+
sed -i "s@\\${localWorkspaceFolder}@$(pwd)@g" "${tmpdir}/.devcontainer/devcontainer.json"
89264
local path="${tmpdir}"
90265
local hash="$(echo -n "${path}" | xxd -pu - | tr -d '[:space:]')"
91266
local url="vscode://vscode-remote/dev-container+${hash}/home/coder/cccl"
@@ -105,7 +280,9 @@ launch_vscode() {
105280
}
106281

107282
main() {
108-
parse_options "$@"
283+
local -a unparsed;
284+
parse_options "$@" unparsed;
285+
set -- "${unparsed[@]}";
109286

110287
# If no CTK/Host compiler are provided, just use the default environment
111288
if [[ -z ${cuda_version:-} ]] && [[ -z ${host_compiler:-} ]]; then
@@ -120,7 +297,7 @@ main() {
120297
fi
121298

122299
if ${docker_mode:-'false'}; then
123-
launch_docker
300+
launch_docker "$@"
124301
else
125302
launch_vscode
126303
fi
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
3+
# shellcheck disable=SC1091
4+
5+
set -e;
6+
7+
devcontainer-utils-post-create-command;
8+
devcontainer-utils-init-git;
9+
devcontainer-utils-post-attach-command;
10+
11+
cd /home/coder/cccl/
12+
13+
if test $# -gt 0; then
14+
exec "$@";
15+
else
16+
exec /bin/bash -li;
17+
fi

.github/actions/configure_cccl_sccache/action.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ description: "Set up AWS credentials and environment variables for sccache"
33
runs:
44
using: "composite"
55
steps:
6-
- name: Get AWS credentials for sccache bucket
7-
uses: aws-actions/configure-aws-credentials@v2
8-
with:
9-
role-to-assume: arn:aws:iam::279114543810:role/gha-oidc-NVIDIA
10-
aws-region: us-east-2
11-
role-duration-seconds: 43200 # 12 hours)
126
- name: Set environment variables
137
run: |
148
echo "SCCACHE_BUCKET=rapids-sccache-devs" >> $GITHUB_ENV

0 commit comments

Comments
 (0)