github.com/containerd/nerdctl@v1.7.7/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  	propagate_env_from "$pid" ROOTLESSKIT_STATE_DIR ROOTLESSKIT_PARENT_EUID ROOTLESSKIT_PARENT_EGID
   156  	exec nsenter --no-fork --wd="$(pwd)" --preserve-credentials -m -n -U -t "$pid" -- "$@"
   157  }
   158  
   159  show_systemd_error() {
   160  	unit="$1"
   161  	n="20"
   162  	ERROR "Failed to start ${unit}. Run \`journalctl -n ${n} --no-pager --user --unit ${unit}\` to show the error log."
   163  	ERROR "Before retrying installation, you might need to uninstall the current setup: \`$0 uninstall; ${BIN}/rootlesskit rm -rf ${HOME}/.local/share/containerd\`"
   164  }
   165  
   166  install_systemd_unit() {
   167  	unit="$1"
   168  	unit_file="${XDG_CONFIG_HOME}/systemd/user/${unit}"
   169  	if [ -f "${unit_file}" ]; then
   170  		WARNING "File already exists, skipping: ${unit_file}"
   171  	else
   172  		INFO "Creating \"${unit_file}\""
   173  		mkdir -p "${XDG_CONFIG_HOME}/systemd/user"
   174  		cat >"${unit_file}"
   175  		systemctl --user daemon-reload
   176  	fi
   177  	if ! systemctl --user --no-pager status "${unit}" >/dev/null 2>&1; then
   178  		INFO "Starting systemd unit \"${unit}\""
   179  		(
   180  			set -x
   181  			if ! systemctl --user start "${unit}"; then
   182  				set +x
   183  				show_systemd_error "${unit}"
   184  				exit 1
   185  			fi
   186  			sleep 3
   187  		)
   188  	fi
   189  	(
   190  		set -x
   191  		if ! systemctl --user --no-pager --full status "${unit}"; then
   192  			set +x
   193  			show_systemd_error "${unit}"
   194  			exit 1
   195  		fi
   196  		systemctl --user enable "${unit}"
   197  	)
   198  	INFO "Installed \"${unit}\" successfully."
   199  	INFO "To control \"${unit}\", run: \`systemctl --user (start|stop|restart) ${unit}\`"
   200  }
   201  
   202  uninstall_systemd_unit() {
   203  	unit="$1"
   204  	unit_file="${XDG_CONFIG_HOME}/systemd/user/${unit}"
   205  	if [ ! -f "${unit_file}" ]; then
   206  		INFO "Unit ${unit} is not installed"
   207  		return
   208  	fi
   209  	(
   210  		set -x
   211  		systemctl --user stop "${unit}"
   212  	) || :
   213  	(
   214  		set -x
   215  		systemctl --user disable "${unit}"
   216  	) || :
   217  	rm -f "${unit_file}"
   218  	INFO "Uninstalled \"${unit}\""
   219  }
   220  
   221  # CLI subcommand: "install"
   222  cmd_entrypoint_install() {
   223  	init
   224  	cmd_entrypoint_check
   225  	cat <<-EOT | install_systemd_unit "${SYSTEMD_CONTAINERD_UNIT}"
   226  		[Unit]
   227  		Description=containerd (Rootless)
   228  
   229  		[Service]
   230  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   231  		Environment=CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS=${CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS:-}
   232  		ExecStart=$BIN/${CONTAINERD_ROOTLESS_SH}
   233  		ExecReload=/bin/kill -s HUP \$MAINPID
   234  		TimeoutSec=0
   235  		RestartSec=2
   236  		Restart=always
   237  		StartLimitBurst=3
   238  		StartLimitInterval=60s
   239  		LimitNOFILE=infinity
   240  		LimitNPROC=infinity
   241  		LimitCORE=infinity
   242  		TasksMax=infinity
   243  		Delegate=yes
   244  		Type=simple
   245  		KillMode=mixed
   246  
   247  		[Install]
   248  		WantedBy=default.target
   249  	EOT
   250  	systemctl --user daemon-reload
   251  	INFO "To run \"${SYSTEMD_CONTAINERD_UNIT}\" on system startup automatically, run: \`sudo loginctl enable-linger $(id -un)\`"
   252  	INFO "------------------------------------------------------------------------------------------"
   253  	INFO "Use \`nerdctl\` to connect to the rootless containerd."
   254  	INFO "You do NOT need to specify \$CONTAINERD_ADDRESS explicitly."
   255  }
   256  
   257  # CLI subcommand: "install-buildkit"
   258  cmd_entrypoint_install_buildkit() {
   259  	init
   260  	if ! command -v "buildkitd" >/dev/null 2>&1; then
   261  		ERROR "buildkitd (https://github.com/moby/buildkit) needs to be present under \$PATH"
   262  		exit 1
   263  	fi
   264  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   265  		ERROR "Install containerd first (\`$ARG0 install\`)"
   266  		exit 1
   267  	fi
   268  	cat <<-EOT | install_systemd_unit "${SYSTEMD_BUILDKIT_UNIT}"
   269  		[Unit]
   270  		Description=BuildKit (Rootless)
   271  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   272  
   273  		[Service]
   274  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   275  		ExecStart="$REALPATH0" nsenter buildkitd
   276  		ExecReload=/bin/kill -s HUP \$MAINPID
   277  		RestartSec=2
   278  		Restart=always
   279  		Type=simple
   280  		KillMode=mixed
   281  
   282  		[Install]
   283  		WantedBy=default.target
   284  	EOT
   285  }
   286  
   287  # CLI subcommand: "install-buildkit-containerd"
   288  cmd_entrypoint_install_buildkit_containerd() {
   289  	init
   290  	if ! command -v "buildkitd" >/dev/null 2>&1; then
   291  		ERROR "buildkitd (https://github.com/moby/buildkit) needs to be present under \$PATH"
   292  		exit 1
   293  	fi
   294  	if [ ! -f "${XDG_CONFIG_HOME}/buildkit/buildkitd.toml" ]; then
   295  		mkdir -p "${XDG_CONFIG_HOME}/buildkit"
   296  		cat <<-EOF >"${XDG_CONFIG_HOME}/buildkit/buildkitd.toml"
   297  			[worker.oci]
   298  			enabled = false
   299  
   300  			[worker.containerd]
   301  			enabled = true
   302  			rootless = true
   303  		EOF
   304  	fi
   305  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   306  		ERROR "Install containerd first (\`$ARG0 install\`)"
   307  		exit 1
   308  	fi
   309  	UNIT_NAME=${SYSTEMD_BUILDKIT_UNIT}
   310  	BUILDKITD_FLAG=
   311  	if [ -n "${CONTAINERD_NAMESPACE:-}" ]; then
   312  		UNIT_NAME="${CONTAINERD_NAMESPACE}-${SYSTEMD_BUILDKIT_UNIT}"
   313  		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}"
   314  	else
   315  		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"
   316  	fi
   317  	if [ -n "${CONTAINERD_SNAPSHOTTER:-}" ]; then
   318  		BUILDKITD_FLAG="${BUILDKITD_FLAG} --containerd-worker-snapshotter=${CONTAINERD_SNAPSHOTTER}"
   319  	fi
   320  	cat <<-EOT | install_systemd_unit "${UNIT_NAME}"
   321  		[Unit]
   322  		Description=BuildKit (Rootless)
   323  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   324  
   325  		[Service]
   326  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   327  		ExecStart="$REALPATH0" nsenter -- buildkitd ${BUILDKITD_FLAG}
   328  		ExecReload=/bin/kill -s HUP \$MAINPID
   329  		RestartSec=2
   330  		Restart=always
   331  		Type=simple
   332  		KillMode=mixed
   333  
   334  		[Install]
   335  		WantedBy=default.target
   336  	EOT
   337  }
   338  
   339  # CLI subcommand: "install-bypass4netnsd"
   340  cmd_entrypoint_install_bypass4netnsd() {
   341  	init
   342  	if ! command -v "bypass4netnsd" >/dev/null 2>&1; then
   343  		ERROR "bypass4netnsd (https://github.com/rootless-containers/bypass4netns) needs to be present under \$PATH"
   344  		exit 1
   345  	fi
   346  	command_v_bypass4netnsd="$(command -v bypass4netnsd)"
   347  	# FIXME: bail if bypass4netnsd is an alias
   348  	cat <<-EOT | install_systemd_unit "${SYSTEMD_BYPASS4NETNSD_UNIT}"
   349  		[Unit]
   350  		Description=bypass4netnsd (daemon for bypass4netns, accelerator for rootless containers)
   351  		# Not PartOf=${SYSTEMD_CONTAINERD_UNIT}
   352  
   353  		[Service]
   354  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   355  		ExecStart="${command_v_bypass4netnsd}"
   356  		ExecReload=/bin/kill -s HUP \$MAINPID
   357  		RestartSec=2
   358  		Restart=always
   359  		Type=simple
   360  		KillMode=mixed
   361  
   362  		[Install]
   363  		WantedBy=default.target
   364  	EOT
   365  	INFO "To use bypass4netnsd, set the \"nerdctl/bypass4netns=true\" label on containers, e.g., \`nerdctl run --label nerdctl/bypass4netns=true\`"
   366  }
   367  
   368  # CLI subcommand: "install-fuse-overlayfs"
   369  cmd_entrypoint_install_fuse_overlayfs() {
   370  	init
   371  	if ! command -v "containerd-fuse-overlayfs-grpc" >/dev/null 2>&1; then
   372  		ERROR "containerd-fuse-overlayfs-grpc (https://github.com/containerd/fuse-overlayfs-snapshotter) needs to be present under \$PATH"
   373  		exit 1
   374  	fi
   375  	if ! command -v "fuse-overlayfs" >/dev/null 2>&1; then
   376  		ERROR "fuse-overlayfs (https://github.com/containers/fuse-overlayfs) needs to be present under \$PATH"
   377  		exit 1
   378  	fi
   379  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   380  		ERROR "Install containerd first (\`$ARG0 install\`)"
   381  		exit 1
   382  	fi
   383  	cat <<-EOT | install_systemd_unit "${SYSTEMD_FUSE_OVERLAYFS_UNIT}"
   384  		[Unit]
   385  		Description=containerd-fuse-overlayfs (Rootless)
   386  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   387  
   388  		[Service]
   389  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   390  		ExecStart="$REALPATH0" nsenter containerd-fuse-overlayfs-grpc "${XDG_RUNTIME_DIR}/containerd-fuse-overlayfs.sock" "${XDG_DATA_HOME}/containerd-fuse-overlayfs"
   391  		ExecReload=/bin/kill -s HUP \$MAINPID
   392  		RestartSec=2
   393  		Restart=always
   394  		Type=simple
   395  		KillMode=mixed
   396  
   397  		[Install]
   398  		WantedBy=default.target
   399  	EOT
   400  	INFO "Add the following lines to \"${XDG_CONFIG_HOME}/containerd/config.toml\" manually, and then run \`systemctl --user restart ${SYSTEMD_CONTAINERD_UNIT}\`:"
   401  	cat <<-EOT
   402  		### BEGIN ###
   403  		[proxy_plugins]
   404  		  [proxy_plugins."fuse-overlayfs"]
   405  		    type = "snapshot"
   406  		    address = "${XDG_RUNTIME_DIR}/containerd-fuse-overlayfs.sock"
   407  		###  END  ###
   408  	EOT
   409  	INFO "Set \`export CONTAINERD_SNAPSHOTTER=\"fuse-overlayfs\"\` to use the fuse-overlayfs snapshotter."
   410  }
   411  
   412  # CLI subcommand: "install-stargz"
   413  cmd_entrypoint_install_stargz() {
   414  	init
   415  	if ! command -v "containerd-stargz-grpc" >/dev/null 2>&1; then
   416  		ERROR "containerd-stargz-grpc (https://github.com/containerd/stargz-snapshotter) needs to be present under \$PATH"
   417  		exit 1
   418  	fi
   419  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   420  		ERROR "Install containerd first (\`$ARG0 install\`)"
   421  		exit 1
   422  	fi
   423  	if [ ! -f "${XDG_CONFIG_HOME}/containerd-stargz-grpc/config.toml" ]; then
   424  		mkdir -p "${XDG_CONFIG_HOME}/containerd-stargz-grpc"
   425  		touch "${XDG_CONFIG_HOME}/containerd-stargz-grpc/config.toml"
   426  	fi
   427  	cat <<-EOT | install_systemd_unit "${SYSTEMD_STARGZ_UNIT}"
   428  		[Unit]
   429  		Description=stargz snapshotter (Rootless)
   430  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   431  
   432  		[Service]
   433  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   434  		Environment=IPFS_PATH=${XDG_DATA_HOME}/ipfs
   435  		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"
   436  		ExecReload=/bin/kill -s HUP \$MAINPID
   437  		RestartSec=2
   438  		Restart=always
   439  		Type=simple
   440  		KillMode=mixed
   441  
   442  		[Install]
   443  		WantedBy=default.target
   444  	EOT
   445  	INFO "Add the following lines to \"${XDG_CONFIG_HOME}/containerd/config.toml\" manually, and then run \`systemctl --user restart ${SYSTEMD_CONTAINERD_UNIT}\`:"
   446  	cat <<-EOT
   447  		### BEGIN ###
   448  		[proxy_plugins]
   449  		  [proxy_plugins."stargz"]
   450  		    type = "snapshot"
   451  		    address = "${XDG_RUNTIME_DIR}/containerd-stargz-grpc/containerd-stargz-grpc.sock"
   452  		###  END  ###
   453  	EOT
   454  	INFO "Set \`export CONTAINERD_SNAPSHOTTER=\"stargz\"\` to use the stargz snapshotter."
   455  }
   456  
   457  # CLI subcommand: "install-ipfs"
   458  cmd_entrypoint_install_ipfs() {
   459  	init
   460  	if ! command -v "ipfs" >/dev/null 2>&1; then
   461  		ERROR "ipfs needs to be present under \$PATH"
   462  		exit 1
   463  	fi
   464  	if ! systemctl --user --no-pager status "${SYSTEMD_CONTAINERD_UNIT}" >/dev/null 2>&1; then
   465  		ERROR "Install containerd first (\`$ARG0 install\`)"
   466  		exit 1
   467  	fi
   468  	IPFS_PATH="${XDG_DATA_HOME}/ipfs"
   469  	mkdir -p "${IPFS_PATH}"
   470  	cat <<-EOT | install_systemd_unit "${SYSTEMD_IPFS_UNIT}"
   471  		[Unit]
   472  		Description=ipfs daemon for rootless nerdctl
   473  		PartOf=${SYSTEMD_CONTAINERD_UNIT}
   474  
   475  		[Service]
   476  		Environment=PATH=$BIN:/sbin:/usr/sbin:$PATH
   477  		Environment=IPFS_PATH=${IPFS_PATH}
   478  		ExecStart="$REALPATH0" nsenter -- ipfs daemon $@
   479  		ExecReload=/bin/kill -s HUP \$MAINPID
   480  		RestartSec=2
   481  		Restart=always
   482  		Type=simple
   483  		KillMode=mixed
   484  
   485  		[Install]
   486  		WantedBy=default.target
   487  	EOT
   488  
   489  	# Avoid using 5001(api)/8080(gateway) which are reserved by tests.
   490  	# TODO: support unix socket
   491  	systemctl --user stop "${SYSTEMD_IPFS_UNIT}"
   492  	sleep 3
   493  	IPFS_PATH=${IPFS_PATH} ipfs config Addresses.API "/ip4/127.0.0.1/tcp/5888"
   494  	IPFS_PATH=${IPFS_PATH} ipfs config Addresses.Gateway "/ip4/127.0.0.1/tcp/5889"
   495  	systemctl --user restart "${SYSTEMD_IPFS_UNIT}"
   496  	sleep 3
   497  
   498  	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}\`:"
   499  	cat <<-EOT
   500  		### BEGIN ###
   501  		ipfs = true
   502  		###  END  ###
   503  	EOT
   504  	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."
   505  	INFO "Set \`export IPFS_PATH=\"${IPFS_PATH}\"\` to use ipfs."
   506  }
   507  
   508  # CLI subcommand: "uninstall"
   509  cmd_entrypoint_uninstall() {
   510  	init
   511  	uninstall_systemd_unit "${SYSTEMD_BUILDKIT_UNIT}"
   512  	uninstall_systemd_unit "${SYSTEMD_FUSE_OVERLAYFS_UNIT}"
   513  	uninstall_systemd_unit "${SYSTEMD_CONTAINERD_UNIT}"
   514  
   515  	INFO "This uninstallation tool does NOT remove containerd binaries and data."
   516  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/containerd\`"
   517  }
   518  
   519  # CLI subcommand: "uninstall-buildkit"
   520  cmd_entrypoint_uninstall_buildkit() {
   521  	init
   522  	uninstall_systemd_unit "${SYSTEMD_BUILDKIT_UNIT}"
   523  	INFO "This uninstallation tool does NOT remove data."
   524  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/buildkit"
   525  }
   526  
   527  # CLI subcommand: "uninstall-buildkit-containerd"
   528  cmd_entrypoint_uninstall_buildkit_containerd() {
   529  	init
   530  	UNIT_NAME=${SYSTEMD_BUILDKIT_UNIT}
   531  	BUILDKIT_ROOT="${XDG_DATA_HOME}/buildkit"
   532  	if [ -n "${CONTAINERD_NAMESPACE:-}" ]; then
   533  		UNIT_NAME="${CONTAINERD_NAMESPACE}-${SYSTEMD_BUILDKIT_UNIT}"
   534  		BUILDKIT_ROOT="${XDG_DATA_HOME}/buildkit-${CONTAINERD_NAMESPACE}"
   535  	fi
   536  	uninstall_systemd_unit "${UNIT_NAME}"
   537  	INFO "This uninstallation tool does NOT remove data."
   538  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${BUILDKIT_ROOT}\`"
   539  }
   540  
   541  # CLI subcommand: "uninstall-bypass4netnsd"
   542  cmd_entrypoint_uninstall_bypass4netnsd() {
   543  	init
   544  	uninstall_systemd_unit "${SYSTEMD_BYPASS4NETNSD_UNIT}"
   545  }
   546  
   547  # CLI subcommand: "uninstall-fuse-overlayfs"
   548  cmd_entrypoint_uninstall_fuse_overlayfs() {
   549  	init
   550  	uninstall_systemd_unit "${SYSTEMD_FUSE_OVERLAYFS_UNIT}"
   551  	INFO "This uninstallation tool does NOT remove data."
   552  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/containerd-fuse-overlayfs"
   553  }
   554  
   555  # CLI subcommand: "uninstall-stargz"
   556  cmd_entrypoint_uninstall_stargz() {
   557  	init
   558  	uninstall_systemd_unit "${SYSTEMD_STARGZ_UNIT}"
   559  	INFO "This uninstallation tool does NOT remove data."
   560  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/containerd-stargz-grpc"
   561  }
   562  
   563  # CLI subcommand: "uninstall-ipfs"
   564  cmd_entrypoint_uninstall_ipfs() {
   565  	init
   566  	uninstall_systemd_unit "${SYSTEMD_IPFS_UNIT}"
   567  	INFO "This uninstallation tool does NOT remove data."
   568  	INFO "To remove data, run: \`$BIN/rootlesskit rm -rf ${XDG_DATA_HOME}/ipfs"
   569  }
   570  
   571  # text for --help
   572  usage() {
   573  	echo "Usage: ${ARG0} [OPTIONS] COMMAND"
   574  	echo
   575  	echo "A setup tool for Rootless containerd (${CONTAINERD_ROOTLESS_SH})."
   576  	echo
   577  	echo "Commands:"
   578  	echo "  check        Check prerequisites"
   579  	echo "  nsenter      Enter into RootlessKit namespaces (mostly for debugging)"
   580  	echo "  install      Install systemd unit and show how to manage the service"
   581  	echo "  uninstall    Uninstall systemd unit"
   582  	echo
   583  	echo "Add-on commands (BuildKit):"
   584  	echo "  install-buildkit            Install the systemd unit for BuildKit"
   585  	echo "  uninstall-buildkit          Uninstall the systemd unit for BuildKit"
   586  	echo
   587  	echo "Add-on commands (bypass4netnsd):"
   588  	echo "  install-bypass4netnsd       Install the systemd unit for bypass4netnsd"
   589  	echo "  uninstall-bypass4netnsd     Uninstall the systemd unit for bypass4netnsd"
   590  	echo
   591  	echo "Add-on commands (fuse-overlayfs):"
   592  	echo "  install-fuse-overlayfs      Install the systemd unit for fuse-overlayfs snapshotter"
   593  	echo "  uninstall-fuse-overlayfs    Uninstall the systemd unit for fuse-overlayfs snapshotter"
   594  	echo
   595  	echo "Add-on commands (stargz):"
   596  	echo "  install-stargz              Install the systemd unit for stargz snapshotter"
   597  	echo "  uninstall-stargz            Uninstall the systemd unit for stargz snapshotter"
   598  	echo
   599  	echo "Add-on commands (ipfs):"
   600  	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."
   601  	echo "  uninstall-ipfs                       Uninstall the systemd unit for ipfs daemon"
   602  	echo
   603  	echo "Add-on commands (BuildKit containerd worker):"
   604  	echo "  install-buildkit-containerd   Install the systemd unit for BuildKit with CONTAINERD_NAMESPACE=${CONTAINERD_NAMESPACE:-} and CONTAINERD_SNAPSHOTTER=${CONTAINERD_SNAPSHOTTER:-}"
   605  	echo "  uninstall-buildkit-containerd Uninstall the systemd unit for BuildKit with CONTAINERD_NAMESPACE=${CONTAINERD_NAMESPACE:-} and CONTAINERD_SNAPSHOTTER=${CONTAINERD_SNAPSHOTTER:-}"
   606  }
   607  
   608  # parse CLI args
   609  if ! args="$(getopt -o h --long help -n "$ARG0" -- "$@")"; then
   610  	usage
   611  	exit 1
   612  fi
   613  eval set -- "$args"
   614  while [ "$#" -gt 0 ]; do
   615  	arg="$1"
   616  	shift
   617  	case "$arg" in
   618  	-h | --help)
   619  		usage
   620  		exit 0
   621  		;;
   622  	--)
   623  		break
   624  		;;
   625  	*)
   626  		# XXX this means we missed something in our "getopt" arguments above!
   627  		ERROR "Scripting error, unknown argument '$arg' when parsing script arguments."
   628  		exit 1
   629  		;;
   630  	esac
   631  done
   632  
   633  command=$(echo "${1:-}" | sed -e "s/-/_/g")
   634  if [ -z "$command" ]; then
   635  	ERROR "No command was specified. Run with --help to see the usage. Maybe you want to run \`$ARG0 install\`?"
   636  	exit 1
   637  fi
   638  
   639  if ! command -v "cmd_entrypoint_${command}" >/dev/null 2>&1; then
   640  	ERROR "Unknown command: ${command}. Run with --help to see the usage."
   641  	exit 1
   642  fi
   643  
   644  # main
   645  shift
   646  "cmd_entrypoint_${command}" "$@"