github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/extras/rootless/containerd-rootless-setuptool.sh (about)

     1  #!/bin/sh
     2  
     3  #   Copyright The containerd Authors.
     4  
     5  #   Licensed under the Apache License, Version 2.0 (the "License");
     6  #   you may not use this file except in compliance with the License.
     7  #   You may obtain a copy of the License at
     8  
     9  #       http://www.apache.org/licenses/LICENSE-2.0
    10  
    11  #   Unless required by applicable law or agreed to in writing, software
    12  #   distributed under the License is distributed on an "AS IS" BASIS,
    13  #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  #   See the License for the specific language governing permissions and
    15  #   limitations under the License.
    16  
    17  # -----------------------------------------------------------------------------
    18  # Forked from https://github.com/moby/moby/blob/v20.10.3/contrib/dockerd-rootless-setuptool.sh
    19  # Copyright The Moby Authors.
    20  # Licensed under the Apache License, Version 2.0
    21  # NOTICE: https://github.com/moby/moby/blob/v20.10.3/NOTICE
    22  # -----------------------------------------------------------------------------
    23  
    24  # containerd-rootless-setuptool.sh: setup tool for containerd-rootless.sh
    25  # Needs to be executed as a non-root user.
    26  #
    27  # Typical usage: containerd-rootless-setuptool.sh install
    28  set -eu
    29  
    30  # utility functions
    31  INFO() {
    32  	# https://github.com/koalaman/shellcheck/issues/1593
    33  	# shellcheck disable=SC2039
    34  	/bin/echo -e "\e[104m\e[97m[INFO]\e[49m\e[39m ${*}"
    35  }
    36  
    37  WARNING() {
    38  	# shellcheck disable=SC2039
    39  	/bin/echo >&2 -e "\e[101m\e[97m[WARNING]\e[49m\e[39m ${*}"
    40  }
    41  
    42  ERROR() {
    43  	# shellcheck disable=SC2039
    44  	/bin/echo >&2 -e "\e[101m\e[97m[ERROR]\e[49m\e[39m ${*}"
    45  }
    46  
    47  # constants
    48  CONTAINERD_ROOTLESS_SH="containerd-rootless.sh"
    49  SYSTEMD_CONTAINERD_UNIT="containerd.service"
    50  SYSTEMD_BUILDKIT_UNIT="buildkit.service"
    51  SYSTEMD_FUSE_OVERLAYFS_UNIT="containerd-fuse-overlayfs.service"
    52  SYSTEMD_STARGZ_UNIT="stargz-snapshotter.service"
    53  SYSTEMD_IPFS_UNIT="ipfs-daemon.service"
    54  SYSTEMD_BYPASS4NETNSD_UNIT="bypass4netnsd.service"
    55  
    56  # global vars
    57  ARG0="$0"
    58  REALPATH0="$(realpath "$ARG0")"
    59  BIN=""
    60  XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
    61  XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
    62  
    63  # run checks and also initialize global vars (BIN)
    64  init() {
    65  	id="$(id -u)"
    66  	# User verification: deny running as root
    67  	if [ "$id" = "0" ]; then
    68  		ERROR "Refusing to install rootless containerd as the root user"
    69  		exit 1
    70  	fi
    71  
    72  	# set BIN
    73  	if ! BIN="$(command -v "$CONTAINERD_ROOTLESS_SH" 2>/dev/null)"; then
    74  		ERROR "$CONTAINERD_ROOTLESS_SH needs to be present under \$PATH"
    75  		exit 1
    76  	fi
    77  	BIN=$(dirname "$BIN")
    78  
    79  	# detect systemd
    80  	if ! systemctl --user show-environment >/dev/null 2>&1; then
    81  		ERROR "Needs systemd (systemctl --user)"
    82  		exit 1
    83  	fi
    84  
    85  	# HOME verification
    86  	if [ -z "${HOME:-}" ] || [ ! -d "$HOME" ]; then
    87  		ERROR "HOME needs to be set"
    88  		exit 1
    89  	fi
    90  	if [ ! -w "$HOME" ]; then
    91  		ERROR "HOME needs to be writable"
    92  		exit 1
    93  	fi
    94  
    95  	# Validate XDG_RUNTIME_DIR
    96  	if [ -z "${XDG_RUNTIME_DIR:-}" ] || [ ! -w "$XDG_RUNTIME_DIR" ]; then
    97  		ERROR "Aborting because but XDG_RUNTIME_DIR (\"$XDG_RUNTIME_DIR\") is not set, does not exist, or is not writable"
    98  		ERROR "Hint: this could happen if you changed users with 'su' or 'sudo'. To work around this:"
    99  		ERROR "- try again by first running with root privileges 'loginctl enable-linger <user>' where <user> is the unprivileged user and export XDG_RUNTIME_DIR to the value of RuntimePath as shown by 'loginctl show-user <user>'"
   100  		ERROR "- or simply log back in as the desired unprivileged user (ssh works for remote machines, machinectl shell works for local machines)"
   101  		ERROR "See also https://rootlesscontaine.rs/getting-started/common/login/ ."
   102  		exit 1
   103  	fi
   104  }
   105  
   106  # CLI subcommand: "check"
   107  cmd_entrypoint_check() {
   108  	init
   109  	INFO "Checking RootlessKit functionality"
   110  	if ! rootlesskit \
   111  		--net=slirp4netns \
   112  		--disable-host-loopback \
   113  		--copy-up=/etc --copy-up=/run --copy-up=/var/lib \
   114  		true; then
   115  		ERROR "RootlessKit failed, see the error messages and https://rootlesscontaine.rs/getting-started/common/ ."
   116  		exit 1
   117  	fi
   118  
   119  	INFO "Checking cgroup v2"
   120  	controllers="/sys/fs/cgroup/user.slice/user-${id}.slice/user@${id}.service/cgroup.controllers"
   121  	if [ ! -f "${controllers}" ]; then
   122  		WARNING "Enabling cgroup v2 is highly recommended, see https://rootlesscontaine.rs/getting-started/common/cgroup2/ "
   123  	else
   124  		for f in cpu memory pids; do
   125  			if ! grep -qw "$f" "$controllers"; then
   126  				WARNING "The cgroup v2 controller \"$f\" is not delegated for the current user (\"$controllers\"), see https://rootlesscontaine.rs/getting-started/common/cgroup2/"
   127  			fi
   128  		done
   129  	fi
   130  
   131  	INFO "Checking overlayfs"
   132  	tmp=$(mktemp -d)
   133  	mkdir -p "${tmp}/l" "${tmp}/u" "${tmp}/w" "${tmp}/m"
   134  	if ! rootlesskit mount -t overlay -o lowerdir="${tmp}/l,upperdir=${tmp}/u,workdir=${tmp}/w" overlay "${tmp}/m"; then
   135  		WARNING "Overlayfs is not enabled, consider installing fuse-overlayfs snapshotter (\`$0 install-fuse-overlayfs\`), " \
   136  			"or see https://rootlesscontaine.rs/how-it-works/overlayfs/ to enable overlayfs."
   137  	fi
   138  	rm -rf "${tmp}"
   139  	INFO "Requirements are satisfied"
   140  }
   141  
   142  propagate_env_from() {
   143  	pid="$1"
   144  	env="$(sed -e "s/\x0/'\n/g" <"/proc/${pid}/environ" | sed -Ee "s/^[^=]*=/export \0'/g")"
   145  	shift
   146  	for key in $@; do
   147  		eval $(echo "$env" | grep "^export ${key=}")
   148  	done
   149  }
   150  
   151  # CLI subcommand: "nsenter"
   152  cmd_entrypoint_nsenter() {
   153  	# No need to call init()
   154  	pid=$(cat "$XDG_RUNTIME_DIR/containerd-rootless/child_pid")
   155  	n=""
   156  	# If RootlessKit is running with `--detach-netns` mode, we do NOT enter the detached netns here
   157  	if [ ! -e "$XDG_RUNTIME_DIR/containerd-rootless/netns" ]; then
   158  		n="-n"
   159  	fi
   160  	propagate_env_from "$pid" ROOTLESSKIT_STATE_DIR ROOTLESSKIT_PARENT_EUID ROOTLESSKIT_PARENT_EGID
   161  	exec nsenter --no-fork --wd="$(pwd)" --preserve-credentials -m $n -U -t "$pid" -- "$@"
   162  }
   163  
   164  show_systemd_error() {
   165  	unit="$1"
   166  	n="20"
   167  	ERROR "Failed to start ${unit}. Run \`journalctl -n ${n} --no-pager --user --unit ${unit}\` to show the error log."
   168  	ERROR "Before retrying installation, you might need to uninstall the current setup: \`$0 uninstall; ${BIN}/rootlesskit rm -rf ${HOME}/.local/share/containerd\`"
   169  }
   170  
   171  install_systemd_unit() {
   172  	unit="$1"
   173  	unit_file="${XDG_CONFIG_HOME}/systemd/user/${unit}"
   174  	if [ -f "${unit_file}" ]; then
   175  		WARNING "File already exists, skipping: ${unit_file}"
   176  	else
   177  		INFO "Creating \"${unit_file}\""
   178  		mkdir -p "${XDG_CONFIG_HOME}/systemd/user"
   179  		cat >"${unit_file}"
   180  		systemctl --user daemon-reload
   181  	fi
   182  	if ! systemctl --user --no-pager status "${unit}" >/dev/null 2>&1; then
   183  		INFO "Starting systemd unit \"${unit}\""
   184  		(
   185  			set -x
   186  			if ! systemctl --user start "${unit}"; then
   187  				set +x
   188  				show_systemd_error "${unit}"
   189  				exit 1
   190  			fi
   191  			sleep 3
   192  		)
   193  	fi
   194  	(
   195  		set -x
   196  		if ! systemctl --user --no-pager --full status "${unit}"; then
   197  			set +x
   198  			show_systemd_error "${unit}"
   199  			exit 1
   200  		fi
   201  		systemctl --user enable "${unit}"
   202  	)
   203  	INFO "Installed \"${unit}\" successfully."
   204  	INFO "To control \"${unit}\", run: \`systemctl --user (start|stop|restart) ${unit}\`"
   205  }
   206  
   207  uninstall_systemd_unit() {
   208  	unit="$1"
   209  	unit_file="${XDG_CONFIG_HOME}/systemd/user/${unit}"
   210  	if [ ! -f "${unit_file}" ]; then
   211  		INFO "Unit ${unit} is not installed"
   212  		return
   213  	fi
   214  	(
   215  		set -x
   216  		systemctl --user stop "${unit}"
   217  	) || :
   218  	(
   219  		set -x
   220  		systemctl --user disable "${unit}"
   221  	) || :
   222  	rm -f "${unit_file}"
   223  	INFO "Uninstalled \"${unit}\""
   224  }
   225  
   226  # CLI subcommand: "install"
   227  cmd_entrypoint_install() {
   228  	init
   229  	cmd_entrypoint_check
   230  	cat <<-EOT | install_systemd_unit "${SYSTEMD_CONTAINERD_UNIT}"
   231  		[Unit]
   232  		Description=containerd (Rootless)
   233  
   234  		[Service]
   235  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   236  		Environment=CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS=${CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS:-}
   237  		ExecStart=$BIN/${CONTAINERD_ROOTLESS_SH}
   238  		ExecReload=/bin/kill -s HUP \$MAINPID
   239  		TimeoutSec=0
   240  		RestartSec=2
   241  		Restart=always
   242  		StartLimitBurst=3
   243  		StartLimitInterval=60s
   244  		LimitNOFILE=infinity
   245  		LimitNPROC=infinity
   246  		LimitCORE=infinity
   247  		TasksMax=infinity
   248  		Delegate=yes
   249  		Type=simple
   250  		KillMode=mixed
   251  
   252  		[Install]
   253  		WantedBy=default.target
   254  	EOT
   255  	systemctl --user daemon-reload
   256  	INFO "To run \"${SYSTEMD_CONTAINERD_UNIT}\" on system startup automatically, run: \`sudo loginctl enable-linger $(id -un)\`"
   257  	INFO "------------------------------------------------------------------------------------------"
   258  	INFO "Use \`nerdctl\` to connect to the rootless containerd."
   259  	INFO "You do NOT need to specify \$CONTAINERD_ADDRESS explicitly."
   260  }
   261  
   262  # CLI subcommand: "install-buildkit"
   263  cmd_entrypoint_install_buildkit() {
   264  	init
   265  	if ! command -v "buildkitd" >/dev/null 2>&1; then
   266  		ERROR "buildkitd (https://github.com/moby/buildkit) needs to be present under \$PATH"
   267  		exit 1
   268  	fi
   269  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   270  		ERROR "Install containerd first (\`$ARG0 install\`)"
   271  		exit 1
   272  	fi
   273  	BUILDKITD_FLAG="--oci-worker=true --oci-worker-rootless=true --containerd-worker=false"
   274  	if buildkitd --help | grep -q bridge; then
   275  		# Available since BuildKit v0.13
   276  		BUILDKITD_FLAG="${BUILDKITD_FLAG} --oci-worker-net=bridge"
   277  	fi
   278  	cat <<-EOT | install_systemd_unit "${SYSTEMD_BUILDKIT_UNIT}"
   279  		[Unit]
   280  		Description=BuildKit (Rootless)
   281  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   282  
   283  		[Service]
   284  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   285  		ExecStart="$REALPATH0" nsenter -- buildkitd ${BUILDKITD_FLAG}
   286  		ExecReload=/bin/kill -s HUP \$MAINPID
   287  		RestartSec=2
   288  		Restart=always
   289  		Type=simple
   290  		KillMode=mixed
   291  
   292  		[Install]
   293  		WantedBy=default.target
   294  	EOT
   295  }
   296  
   297  # CLI subcommand: "install-buildkit-containerd"
   298  cmd_entrypoint_install_buildkit_containerd() {
   299  	init
   300  	if ! command -v "buildkitd" >/dev/null 2>&1; then
   301  		ERROR "buildkitd (https://github.com/moby/buildkit) needs to be present under \$PATH"
   302  		exit 1
   303  	fi
   304  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   305  		ERROR "Install containerd first (\`$ARG0 install\`)"
   306  		exit 1
   307  	fi
   308  	UNIT_NAME=${SYSTEMD_BUILDKIT_UNIT}
   309  	BUILDKITD_FLAG="--oci-worker=false --containerd-worker=true --containerd-worker-rootless=true"
   310  	if [ -n "${CONTAINERD_NAMESPACE:-}" ]; then
   311  		UNIT_NAME="${CONTAINERD_NAMESPACE}-${SYSTEMD_BUILDKIT_UNIT}"
   312  		BUILDKITD_FLAG="${BUILDKITD_FLAG} --addr=unix://${XDG_RUNTIME_DIR}/buildkit-${CONTAINERD_NAMESPACE}/buildkitd.sock --root=${XDG_DATA_HOME}/buildkit-${CONTAINERD_NAMESPACE} --containerd-worker-namespace=${CONTAINERD_NAMESPACE}"
   313  	else
   314  		WARNING "buildkitd has access to images in \"buildkit\" namespace by default. If you want to give buildkitd access to the images in \"default\" namespace, run this command with CONTAINERD_NAMESPACE=default"
   315  	fi
   316  	if [ -n "${CONTAINERD_SNAPSHOTTER:-}" ]; then
   317  		BUILDKITD_FLAG="${BUILDKITD_FLAG} --containerd-worker-snapshotter=${CONTAINERD_SNAPSHOTTER}"
   318  	fi
   319  	if buildkitd --help | grep -q bridge; then
   320  		# Available since BuildKit v0.13
   321  		BUILDKITD_FLAG="${BUILDKITD_FLAG} --containerd-worker-net=bridge"
   322  	fi
   323  	cat <<-EOT | install_systemd_unit "${UNIT_NAME}"
   324  		[Unit]
   325  		Description=BuildKit (Rootless)
   326  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   327  
   328  		[Service]
   329  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   330  		ExecStart="$REALPATH0" nsenter -- buildkitd ${BUILDKITD_FLAG}
   331  		ExecReload=/bin/kill -s HUP \$MAINPID
   332  		RestartSec=2
   333  		Restart=always
   334  		Type=simple
   335  		KillMode=mixed
   336  
   337  		[Install]
   338  		WantedBy=default.target
   339  	EOT
   340  }
   341  
   342  # CLI subcommand: "install-bypass4netnsd"
   343  cmd_entrypoint_install_bypass4netnsd() {
   344  	init
   345  	if ! command -v "bypass4netnsd" >/dev/null 2>&1; then
   346  		ERROR "bypass4netnsd (https://github.com/rootless-containers/bypass4netns) needs to be present under \$PATH"
   347  		exit 1
   348  	fi
   349  	command_v_bypass4netnsd="$(command -v bypass4netnsd)"
   350  	# FIXME: bail if bypass4netnsd is an alias
   351  	cat <<-EOT | install_systemd_unit "${SYSTEMD_BYPASS4NETNSD_UNIT}"
   352  		[Unit]
   353  		Description=bypass4netnsd (daemon for bypass4netns, accelerator for rootless containers)
   354  		# Not PartOf=${SYSTEMD_CONTAINERD_UNIT}
   355  
   356  		[Service]
   357  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   358  		ExecStart="${command_v_bypass4netnsd}"
   359  		ExecReload=/bin/kill -s HUP \$MAINPID
   360  		RestartSec=2
   361  		Restart=always
   362  		Type=simple
   363  		KillMode=mixed
   364  
   365  		[Install]
   366  		WantedBy=default.target
   367  	EOT
   368  	INFO "To use bypass4netnsd, set the \"nerdctl/bypass4netns=true\" annotation on containers, e.g., \`nerdctl run --annotation nerdctl/bypass4netns=true\`"
   369  }
   370  
   371  # CLI subcommand: "install-fuse-overlayfs"
   372  cmd_entrypoint_install_fuse_overlayfs() {
   373  	init
   374  	if ! command -v "containerd-fuse-overlayfs-grpc" >/dev/null 2>&1; then
   375  		ERROR "containerd-fuse-overlayfs-grpc (https://github.com/containerd/fuse-overlayfs-snapshotter) needs to be present under \$PATH"
   376  		exit 1
   377  	fi
   378  	if ! command -v "fuse-overlayfs" >/dev/null 2>&1; then
   379  		ERROR "fuse-overlayfs (https://github.com/containers/fuse-overlayfs) needs to be present under \$PATH"
   380  		exit 1
   381  	fi
   382  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   383  		ERROR "Install containerd first (\`$ARG0 install\`)"
   384  		exit 1
   385  	fi
   386  	cat <<-EOT | install_systemd_unit "${SYSTEMD_FUSE_OVERLAYFS_UNIT}"
   387  		[Unit]
   388  		Description=containerd-fuse-overlayfs (Rootless)
   389  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   390  
   391  		[Service]
   392  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   393  		ExecStart="$REALPATH0" nsenter containerd-fuse-overlayfs-grpc "${XDG_RUNTIME_DIR}/containerd-fuse-overlayfs.sock" "${XDG_DATA_HOME}/containerd-fuse-overlayfs"
   394  		ExecReload=/bin/kill -s HUP \$MAINPID
   395  		RestartSec=2
   396  		Restart=always
   397  		Type=simple
   398  		KillMode=mixed
   399  
   400  		[Install]
   401  		WantedBy=default.target
   402  	EOT
   403  	INFO "Add the following lines to \"${XDG_CONFIG_HOME}/containerd/config.toml\" manually, and then run \`systemctl --user restart ${SYSTEMD_CONTAINERD_UNIT}\`:"
   404  	cat <<-EOT
   405  		### BEGIN ###
   406  		[proxy_plugins]
   407  		  [proxy_plugins."fuse-overlayfs"]
   408  		    type = "snapshot"
   409  		    address = "${XDG_RUNTIME_DIR}/containerd-fuse-overlayfs.sock"
   410  		###  END  ###
   411  	EOT
   412  	INFO "Set \`export CONTAINERD_SNAPSHOTTER=\"fuse-overlayfs\"\` to use the fuse-overlayfs snapshotter."
   413  }
   414  
   415  # CLI subcommand: "install-stargz"
   416  cmd_entrypoint_install_stargz() {
   417  	init
   418  	if ! command -v "containerd-stargz-grpc" >/dev/null 2>&1; then
   419  		ERROR "containerd-stargz-grpc (https://github.com/containerd/stargz-snapshotter) needs to be present under \$PATH"
   420  		exit 1
   421  	fi
   422  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   423  		ERROR "Install containerd first (\`$ARG0 install\`)"
   424  		exit 1
   425  	fi
   426  	if [ ! -f "${XDG_CONFIG_HOME}/containerd-stargz-grpc/config.toml" ]; then
   427  		mkdir -p "${XDG_CONFIG_HOME}/containerd-stargz-grpc"
   428  		touch "${XDG_CONFIG_HOME}/containerd-stargz-grpc/config.toml"
   429  	fi
   430  	cat <<-EOT | install_systemd_unit "${SYSTEMD_STARGZ_UNIT}"
   431  		[Unit]
   432  		Description=stargz snapshotter (Rootless)
   433  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   434  
   435  		[Service]
   436  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   437  		Environment=IPFS_PATH=${XDG_DATA_HOME}/ipfs
   438  		ExecStart="$REALPATH0" nsenter -- containerd-stargz-grpc -address "${XDG_RUNTIME_DIR}/containerd-stargz-grpc/containerd-stargz-grpc.sock" -root "${XDG_DATA_HOME}/containerd-stargz-grpc" -config "${XDG_CONFIG_HOME}/containerd-stargz-grpc/config.toml"
   439  		ExecReload=/bin/kill -s HUP \$MAINPID
   440  		RestartSec=2
   441  		Restart=always
   442  		Type=simple
   443  		KillMode=mixed
   444  
   445  		[Install]
   446  		WantedBy=default.target
   447  	EOT
   448  	INFO "Add the following lines to \"${XDG_CONFIG_HOME}/containerd/config.toml\" manually, and then run \`systemctl --user restart ${SYSTEMD_CONTAINERD_UNIT}\`:"
   449  	cat <<-EOT
   450  		### BEGIN ###
   451  		[proxy_plugins]
   452  		  [proxy_plugins."stargz"]
   453  		    type = "snapshot"
   454  		    address = "${XDG_RUNTIME_DIR}/containerd-stargz-grpc/containerd-stargz-grpc.sock"
   455  		###  END  ###
   456  	EOT
   457  	INFO "Set \`export CONTAINERD_SNAPSHOTTER=\"stargz\"\` to use the stargz snapshotter."
   458  }
   459  
   460  # CLI subcommand: "install-ipfs"
   461  cmd_entrypoint_install_ipfs() {
   462  	init
   463  	if ! command -v "ipfs" >/dev/null 2>&1; then
   464  		ERROR "ipfs needs to be present under \$PATH"
   465  		exit 1
   466  	fi
   467  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   468  		ERROR "Install containerd first (\`$ARG0 install\`)"
   469  		exit 1
   470  	fi
   471  	IPFS_PATH="${XDG_DATA_HOME}/ipfs"
   472  	mkdir -p "${IPFS_PATH}"
   473  	cat <<-EOT | install_systemd_unit "${SYSTEMD_IPFS_UNIT}"
   474  		[Unit]
   475  		Description=ipfs daemon for rootless nerdctl
   476  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   477  
   478  		[Service]
   479  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   480  		Environment=IPFS_PATH=${IPFS_PATH}
   481  		ExecStart="$REALPATH0" nsenter -- ipfs daemon $@
   482  		ExecReload=/bin/kill -s HUP \$MAINPID
   483  		RestartSec=2
   484  		Restart=always
   485  		Type=simple
   486  		KillMode=mixed
   487  
   488  		[Install]
   489  		WantedBy=default.target
   490  	EOT
   491  
   492  	# Avoid using 5001(api)/8080(gateway) which are reserved by tests.
   493  	# TODO: support unix socket
   494  	systemctl --user stop "${SYSTEMD_IPFS_UNIT}"
   495  	sleep 3
   496  	IPFS_PATH=${IPFS_PATH} ipfs config Addresses.API "/ip4/127.0.0.1/tcp/5888"
   497  	IPFS_PATH=${IPFS_PATH} ipfs config Addresses.Gateway "/ip4/127.0.0.1/tcp/5889"
   498  	systemctl --user restart "${SYSTEMD_IPFS_UNIT}"
   499  	sleep 3
   500  
   501  	INFO "If you use stargz-snapshotter, add the following line to \"${XDG_CONFIG_HOME}/containerd-stargz-grpc/config.toml\" manually, and then run \`systemctl --user restart ${SYSTEMD_STARGZ_UNIT}\`:"
   502  	cat <<-EOT
   503  		### BEGIN ###
   504  		ipfs = true
   505  		###  END  ###
   506  	EOT
   507  	INFO "If you want to expose the port 4001 of ipfs daemon, re-install rootless containerd with CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS=\"--publish=0.0.0.0:4001:4001/tcp\" environment variable."
   508  	INFO "Set \`export IPFS_PATH=\"${IPFS_PATH}\"\` to use ipfs."
   509  }
   510  
   511  # CLI subcommand: "uninstall"
   512  cmd_entrypoint_uninstall() {
   513  	init
   514  	uninstall_systemd_unit "${SYSTEMD_BUILDKIT_UNIT}"
   515  	if [ -n "${CONTAINERD_NAMESPACE:-}" ]; then
   516  		uninstall_systemd_unit "${CONTAINERD_NAMESPACE}-${SYSTEMD_BUILDKIT_UNIT}"
   517  	fi
   518  	uninstall_systemd_unit "${SYSTEMD_FUSE_OVERLAYFS_UNIT}"
   519  	uninstall_systemd_unit "${SYSTEMD_CONTAINERD_UNIT}"
   520  	uninstall_systemd_unit "${SYSTEMD_STARGZ_UNIT}"
   521  	uninstall_systemd_unit "${SYSTEMD_IPFS_UNIT}"
   522  	uninstall_systemd_unit "${SYSTEMD_BYPASS4NETNSD_UNIT}"
   523  
   524  	INFO "This uninstallation tool does NOT remove containerd binaries and data."
   525  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/containerd\`"
   526  }
   527  
   528  # CLI subcommand: "uninstall-buildkit"
   529  cmd_entrypoint_uninstall_buildkit() {
   530  	init
   531  	uninstall_systemd_unit "${SYSTEMD_BUILDKIT_UNIT}"
   532  	INFO "This uninstallation tool does NOT remove data."
   533  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/buildkit\`"
   534  	if [ -e "${XDG_CONFIG_HOME}/buildkit/buildkitd.toml" ]; then
   535  		INFO "You may also want to remove the daemon config: \`rm -f ${XDG_CONFIG_HOME}/buildkit/buildkitd.toml\`"
   536  	fi
   537  }
   538  
   539  # CLI subcommand: "uninstall-buildkit-containerd"
   540  cmd_entrypoint_uninstall_buildkit_containerd() {
   541  	init
   542  	UNIT_NAME=${SYSTEMD_BUILDKIT_UNIT}
   543  	BUILDKIT_ROOT="${XDG_DATA_HOME}/buildkit"
   544  	if [ -n "${CONTAINERD_NAMESPACE:-}" ]; then
   545  		UNIT_NAME="${CONTAINERD_NAMESPACE}-${SYSTEMD_BUILDKIT_UNIT}"
   546  		BUILDKIT_ROOT="${XDG_DATA_HOME}/buildkit-${CONTAINERD_NAMESPACE}"
   547  	fi
   548  	uninstall_systemd_unit "${UNIT_NAME}"
   549  	INFO "This uninstallation tool does NOT remove data."
   550  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${BUILDKIT_ROOT}\`"
   551  }
   552  
   553  # CLI subcommand: "uninstall-bypass4netnsd"
   554  cmd_entrypoint_uninstall_bypass4netnsd() {
   555  	init
   556  	uninstall_systemd_unit "${SYSTEMD_BYPASS4NETNSD_UNIT}"
   557  }
   558  
   559  # CLI subcommand: "uninstall-fuse-overlayfs"
   560  cmd_entrypoint_uninstall_fuse_overlayfs() {
   561  	init
   562  	uninstall_systemd_unit "${SYSTEMD_FUSE_OVERLAYFS_UNIT}"
   563  	INFO "This uninstallation tool does NOT remove data."
   564  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/containerd-fuse-overlayfs"
   565  }
   566  
   567  # CLI subcommand: "uninstall-stargz"
   568  cmd_entrypoint_uninstall_stargz() {
   569  	init
   570  	uninstall_systemd_unit "${SYSTEMD_STARGZ_UNIT}"
   571  	INFO "This uninstallation tool does NOT remove data."
   572  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/containerd-stargz-grpc"
   573  }
   574  
   575  # CLI subcommand: "uninstall-ipfs"
   576  cmd_entrypoint_uninstall_ipfs() {
   577  	init
   578  	uninstall_systemd_unit "${SYSTEMD_IPFS_UNIT}"
   579  	INFO "This uninstallation tool does NOT remove data."
   580  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/ipfs"
   581  }
   582  
   583  # text for --help
   584  usage() {
   585  	echo "Usage: ${ARG0} [OPTIONS] COMMAND"
   586  	echo
   587  	echo "A setup tool for Rootless containerd (${CONTAINERD_ROOTLESS_SH})."
   588  	echo
   589  	echo "Commands:"
   590  	echo "  check        Check prerequisites"
   591  	echo "  nsenter      Enter into RootlessKit namespaces (mostly for debugging)"
   592  	echo "  install      Install systemd unit and show how to manage the service"
   593  	echo "  uninstall    Uninstall systemd unit"
   594  	echo
   595  	echo "Add-on commands (BuildKit):"
   596  	echo "  install-buildkit            Install the systemd unit for BuildKit"
   597  	echo "  uninstall-buildkit          Uninstall the systemd unit for BuildKit"
   598  	echo
   599  	echo "Add-on commands (bypass4netnsd):"
   600  	echo "  install-bypass4netnsd       Install the systemd unit for bypass4netnsd"
   601  	echo "  uninstall-bypass4netnsd     Uninstall the systemd unit for bypass4netnsd"
   602  	echo
   603  	echo "Add-on commands (fuse-overlayfs):"
   604  	echo "  install-fuse-overlayfs      Install the systemd unit for fuse-overlayfs snapshotter"
   605  	echo "  uninstall-fuse-overlayfs    Uninstall the systemd unit for fuse-overlayfs snapshotter"
   606  	echo
   607  	echo "Add-on commands (stargz):"
   608  	echo "  install-stargz              Install the systemd unit for stargz snapshotter"
   609  	echo "  uninstall-stargz            Uninstall the systemd unit for stargz snapshotter"
   610  	echo
   611  	echo "Add-on commands (ipfs):"
   612  	echo "  install-ipfs [ipfs-daemon-flags...]  Install the systemd unit for ipfs daemon. Specify \"--offline\" if run the daemon in offline mode. Specify \"--init\" to initialize IPFS repository as well."
   613  	echo "  uninstall-ipfs                       Uninstall the systemd unit for ipfs daemon"
   614  	echo
   615  	echo "Add-on commands (BuildKit containerd worker):"
   616  	echo "  install-buildkit-containerd   Install the systemd unit for BuildKit with CONTAINERD_NAMESPACE=${CONTAINERD_NAMESPACE:-} and CONTAINERD_SNAPSHOTTER=${CONTAINERD_SNAPSHOTTER:-}"
   617  	echo "  uninstall-buildkit-containerd Uninstall the systemd unit for BuildKit with CONTAINERD_NAMESPACE=${CONTAINERD_NAMESPACE:-} and CONTAINERD_SNAPSHOTTER=${CONTAINERD_SNAPSHOTTER:-}"
   618  }
   619  
   620  # parse CLI args
   621  if ! args="$(getopt -o h --long help -n "$ARG0" -- "$@")"; then
   622  	usage
   623  	exit 1
   624  fi
   625  eval set -- "$args"
   626  while [ "$#" -gt 0 ]; do
   627  	arg="$1"
   628  	shift
   629  	case "$arg" in
   630  	-h | --help)
   631  		usage
   632  		exit 0
   633  		;;
   634  	--)
   635  		break
   636  		;;
   637  	*)
   638  		# XXX this means we missed something in our "getopt" arguments above!
   639  		ERROR "Scripting error, unknown argument '$arg' when parsing script arguments."
   640  		exit 1
   641  		;;
   642  	esac
   643  done
   644  
   645  command=$(echo "${1:-}" | sed -e "s/-/_/g")
   646  if [ -z "$command" ]; then
   647  	ERROR "No command was specified. Run with --help to see the usage. Maybe you want to run \`$ARG0 install\`?"
   648  	exit 1
   649  fi
   650  
   651  if ! command -v "cmd_entrypoint_${command}" >/dev/null 2>&1; then
   652  	ERROR "Unknown command: ${command}. Run with --help to see the usage."
   653  	exit 1
   654  fi
   655  
   656  # main
   657  shift
   658  "cmd_entrypoint_${command}" "$@"