diff --git a/.bash_completion.d/google-cloud-sdk b/.bash_completion.d/google-cloud-sdk deleted file mode 100644 index bdf232a9cbbea59ea87c2af3932c9a7b54e7d43c..0000000000000000000000000000000000000000 --- a/.bash_completion.d/google-cloud-sdk +++ /dev/null @@ -1,82 +0,0 @@ -_python_argcomplete() { - local IFS='' - local prefix= - typeset -i n - (( lastw=${#COMP_WORDS[@]} -1)) - if [[ ${COMP_WORDS[lastw]} == --*=* ]]; then - # for bash version 3.2 - flag=${COMP_WORDS[lastw]%%=*} - set -- "$1" "$2" '=' - elif [[ $3 == '=' ]]; then - flag=${COMP_WORDS[-3]} - fi - if [[ $3 == ssh && $2 == *@* ]] ;then - # handle ssh user@instance specially - prefix=${2%@*}@ - COMP_LINE=${COMP_LINE%$2}"${2#*@}" - elif [[ $3 == '=' ]] ; then - # handle --flag=value - prefix=$flag=$2 - line=${COMP_LINE%$prefix}; - COMP_LINE=$line${prefix/=/ }; - prefix= - fi - if [[ $2 == *,* ]]; then - # handle , separated list - prefix=${2%,*}, - set -- "$1" "${2#$prefix}" "$3" - COMP_LINE==${COMP_LINE%$prefix*}$2 - fi - # Treat --flag=<TAB> as --flag <TAB> to work around bash 4.x bug - if [[ ${COMP_LINE} == *= && ${COMP_WORDS[-2]} == --* ]]; then - COMP_LINE=${COMP_LINE%=}' ' - fi - COMPREPLY=( $(IFS="$IFS" COMP_LINE="$COMP_LINE" COMP_POINT="$COMP_POINT" _ARGCOMPLETE_COMP_WORDBREAKS="$COMP_WORDBREAKS" _ARGCOMPLETE=1 "$1" 8>&1 9>&2 1>/dev/null 2>/dev/null) ) - if [[ $? != 0 ]]; then - unset COMPREPLY - return - fi - if [[ $prefix != '' ]]; then - for ((n=0; n < ${#COMPREPLY[@]}; n++)); do - COMPREPLY[$n]=$prefix${COMPREPLY[$n]} - done - fi - for ((n=0; n < ${#COMPREPLY[@]}; n++)); do - match=${COMPREPLY[$n]%' '} - if [[ $match != '' ]]; then - COMPREPLY[$n]=${match//? /' '}' ' - fi - done - # if flags argument has a single completion and ends in '= ', delete ' ' - if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} == -* && - ${COMPREPLY[0]} == *'= ' ]]; then - COMPREPLY[0]=${COMPREPLY[0]%' '} - fi -} -complete -o nospace -F _python_argcomplete "gcloud" - -_completer() { - command=$1 - name=$2 - eval '[[ "$'"${name}"'_COMMANDS" ]] || '"${name}"'_COMMANDS="$('"${command}"')"' - set -- $COMP_LINE - shift - while [[ $1 == -* ]]; do - shift - done - [[ $2 ]] && return - grep -q "${name}\s*$" <<< $COMP_LINE && - eval 'COMPREPLY=($'"${name}"'_COMMANDS)' && - return - [[ "$COMP_LINE" == *" " ]] && return - [[ $1 ]] && - eval 'COMPREPLY=($(echo "$'"${name}"'_COMMANDS" | grep ^'"$1"'))' -} - -unset bq_COMMANDS -_bq_completer() { - _completer "CLOUDSDK_COMPONENT_MANAGER_DISABLE_UPDATE_CHECK=1 bq help | grep '^[^ ][^ ]* ' | sed 's/ .*//'" bq -} - -complete -F _bq_completer bq -complete -o nospace -F _python_argcomplete gsutil diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index df261f7150044e9fbb4d8d82fef956c4a9b250ef..2977bdcb9dd2426798c07b784618f4bf05439511 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -87,3 +87,4 @@ repos: rev: v0.13.0 hooks: - id: detect-secrets + exclude: rabbitmqadmin diff --git a/Documents/bin/rabbitmqadmin b/Documents/bin/rabbitmqadmin index f5553f7a526283de467d5755ad8f1d7db438c8ba..55173cb69c7c9aec6712e86f341872bc6e4c5ff2 100755 --- a/Documents/bin/rabbitmqadmin +++ b/Documents/bin/rabbitmqadmin @@ -531,6 +531,12 @@ class Management: def delete(self, path): return self.http("DELETE", "%s/api%s" % (self.options.path_prefix, path), "") + def __initialize_connection(self, hostname, port): + if self.options.ssl: + return self.__initialize_https_connection(hostname, port) + else: + return httplib.HTTPConnection(hostname, port, timeout=self.options.request_timeout) + def __initialize_https_connection(self, hostname, port): # Python 2.7.9+ if hasattr(ssl, 'create_default_context'): @@ -564,13 +570,7 @@ class Management: return ssl_ctx def http(self, method, path, body): - if self.options.ssl: - conn = self.__initialize_https_connection(self.options.hostname, - self.options.port) - else: - conn = httplib.HTTPConnection(self.options.hostname, - self.options.port, - timeout=self.options.request_timeout) + conn = self.__initialize_connection(self.options.hostname, self.options.port) auth = (self.options.username + ":" + self.options.password) headers = {"Authorization": "Basic " + b64(auth)} @@ -605,8 +605,8 @@ class Management: self.options.hostname = host self.options.port = int(port) return self.http(method, url.path + '?' + url.query, body) - if resp.status < 200 or resp.status > 400: - raise Exception("Received %d %s for path %s\n%s" + if resp.status > 400: + raise Exception("Received response %d %s for path %s\n%s" % (resp.status, resp.reason, path, resp.read())) return resp.read().decode('utf-8') @@ -686,7 +686,7 @@ class Management: if self.options.vhost: uri += "/%s" % quote_plus(self.options.vhost) self.post(uri, definitions) - self.verbose("Imported definitions for %s from \"%s\"" + self.verbose("Uploaded definitions from \"%s\" to %s. The import process may take some time. Consult server logs to track progress." % (self.options.hostname, path)) def invoke_list(self): diff --git a/Documents/bin/toolbox b/Documents/bin/toolbox new file mode 100755 index 0000000000000000000000000000000000000000..16a4483dda05a98ab227c8d5d82b23a7d4a3703e --- /dev/null +++ b/Documents/bin/toolbox @@ -0,0 +1,2498 @@ +#!/bin/sh +# +# Copyright © 2018 – 2019 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +exec 3>/dev/null + +arguments="" +assume_yes=false +base_toolbox_command=$(basename "$0" 2>&3) +base_toolbox_image="" +cgroups_version="" + +# Based on the nameRegex value in: +# https://github.com/containers/libpod/blob/master/libpod/options.go +container_name_regexp="[a-zA-Z0-9][a-zA-Z0-9_.-]*" + +environment=$(set) +environment_variables="COLORTERM \ + COLUMNS \ + DBUS_SESSION_BUS_ADDRESS \ + DBUS_SYSTEM_BUS_ADDRESS \ + DESKTOP_SESSION \ + DISPLAY \ + LANG \ + LINES \ + SHELL \ + SSH_AUTH_SOCK \ + TERM \ + TOOLBOX_PATH \ + VTE_VERSION \ + WAYLAND_DISPLAY \ + XDG_CURRENT_DESKTOP \ + XDG_DATA_DIRS \ + XDG_MENU_PREFIX \ + XDG_RUNTIME_DIR \ + XDG_SEAT \ + XDG_SESSION_DESKTOP \ + XDG_SESSION_ID \ + XDG_SESSION_TYPE \ + XDG_VTNR" +fgc="" + +registry="registry.fedoraproject.org" +registry_candidate="candidate-registry.fedoraproject.org" +release="" +release_default="" +spinner_animation="[>----] [=>---] [==>--] [===>-] [====>] [----<] [---<=] [--<==] [-<===] [<====]" +spinner_template="toolbox-spinner-XXXXXXXXXX" +tab="$(printf '\t')" +toolbox_command_path="" +toolbox_container="" +toolbox_container_default="" +toolbox_container_old_v1="" +toolbox_container_old_v2="" +toolbox_container_prefix_default="" +toolbox_image="" +toolbox_runtime_directory="$XDG_RUNTIME_DIR"/toolbox +user_id_real=$(id -ru 2>&3) +verbose=false + + +LGC='\033[1;32m' # Light Green Color +NC='\033[0m' # No Color + + +has_prefix() +( + str="$1" + prefix="$2" + + ret_val=1 + + case "$str" in + "$prefix"* ) + ret_val=0 + ;; + * ) + ret_val=1 + ;; + esac + + return "$ret_val" +) + + +has_substring() +( + haystack="$1" + needle="$2" + + ret_val=1 + + case "$haystack" in + *"$needle"* ) + ret_val=0 + ;; + * ) + ret_val=1 + ;; + esac + + return "$ret_val" +) + + +is_integer() +{ + [ "$1" != "" ] && [ "$1" -eq "$1" ] 2>&3 + return "$?" +} + + +save_positional_parameters() +{ + for i; do + printf "%s\\n" "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" 2>&3 + done + echo " " +} + + +spinner_start() +( + directory="$1" + message="$2" + + if $verbose; then + rm --force --recursive "$directory" 2>&3 + return 0 + fi + + if ! touch "$directory/spinner-start" 2>&3; then + echo "$base_toolbox_command: unable to start spinner: spinner start file couldn't be created" >&2 + return 1 + fi + + printf "%s" "$message" + tput civis 2>&3 + + exec 4>"$directory/spinner-start" + if ! flock 4 2>&3; then + echo "$base_toolbox_command: unable to start spinner: spinner lock couldn't be acquired" >&2 + return 1 + fi + + ( + while [ -f "$directory/spinner-start" ]; do + echo "$spinner_animation" | sed "s/ /\n/g" 2>&3 | while read -r frame; do + if ! [ -f "$directory/spinner-start" ] 2>&3; then + break + fi + + printf "%s" "$frame" + + frame_len=${#frame} + i=0 + while [ "$i" -lt "$frame_len" ]; do + printf "\b" + i=$((i + 1)) + done + + sleep 1 + done + done + + printf "\033[2K" # delete entire line regardless of cursor position + printf "\r" + tput cnorm 2>&3 + ) & + + return 0 +) + + +spinner_stop() +( + $verbose && return + directory="$1" + + exec 4>"$directory/spinner-start" + + if ! rm "$directory/spinner-start" 2>&3; then + echo "$base_toolbox_command: unable to stop spinner: spinner start file couldn't be removed" >&2 + return + fi + + if ! flock 4 2>&3; then + echo "$base_toolbox_command: unable to stop spinner: spinner lock couldn't be acquired" >&2 + return + fi + + rm --force --recursive "$directory" 2>&3 +) + + +ask_for_confirmation() +( + default_response="$1" + prompt="$2" + ret_val=0 + + while :; do + printf "%s " "$prompt" + read -r user_response + + if [ "$user_response" = "" ] 2>&3; then + user_response="$default_response" + else + user_response=$(echo "$user_response" | tr "[:upper:]" "[:lower:]" 2>&3) + fi + + if [ "$user_response" = "no" ] 2>&3 || [ "$user_response" = "n" ] 2>&3; then + ret_val=1 + break + elif [ "$user_response" = "yes" ] 2>&3 || [ "$user_response" = "y" ] 2>&3; then + ret_val=0 + break + fi + done + + return "$ret_val" +) + + +container_name_is_valid() +( + name="$1" + + echo "$name" | grep "^$container_name_regexp$" >/dev/null 2>&3 + return "$?" +) + + +container_start() +( + container="$1" + + error_message=$( (podman start "$container" >/dev/null) 2>&1) + ret_val="$?" + [ "$error_message" != "" ] 2>&3 && echo "$error_message" >&3 + + if [ "$ret_val" -ne 0 ] 2>&3; then + if echo "$error_message" | grep "use system migrate to mitigate" >/dev/null 2>&3; then + echo "$base_toolbox_command: checking if 'podman system migrate' supports --new-runtime" >&3 + + if ! (podman system migrate --help 2>&3 | grep "new-runtime" >/dev/null 2>&3); then + echo "$base_toolbox_command: container $container doesn't support cgroups v$cgroups_version" >&2 + echo "Update Podman to version 1.6.2 or newer." >&2 + return 1 + else + echo "$base_toolbox_command: 'podman system migrate' supports --new-runtime" >&3 + + oci_runtime_required="runc" + [ "$cgroups_version" -eq 2 ] 2>&3 && oci_runtime_required="crun" + + echo "$base_toolbox_command: migrating containers to OCI runtime $oci_runtime_required" >&3 + + if ! podman system migrate --new-runtime "$oci_runtime_required" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to migrate containers to OCI runtime $oci_runtime_required" >&2 + echo "Factory reset with: toolbox reset" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + return 1 + fi + + if ! podman start "$container" >/dev/null 2>&3; then + echo "$base_toolbox_command: container $container doesn't support cgroups v$cgroups_version" >&2 + echo "Factory reset with: toolbox reset" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + return 1 + fi + fi + else + echo "$base_toolbox_command: failed to start container $container" >&2 + return 1 + fi + fi + + return 0 +) + + +copy_etc_profile_d_toolbox_to_container() +( + container="$1" + + profile_d_lock="$toolbox_runtime_directory"/profile.d-toolbox.lock + + # shellcheck disable=SC2174 + if ! mkdir --mode 700 --parents "$toolbox_runtime_directory" 2>&3; then + echo "$base_toolbox_command: unable to copy $toolbox_runtime_directory/toolbox.sh: runtime directory not created" >&2 + return 1 + fi + + exec 5>"$profile_d_lock" + if ! flock 5 2>&3; then + echo "$base_toolbox_command: unable to copy $toolbox_runtime_directory/toolbox.sh: copy lock not acquired" >&2 + return 1 + fi + + if ! [ -f "$toolbox_runtime_directory"/toolbox.sh ] 2>&3; then + echo "$base_toolbox_command: $toolbox_runtime_directory/toolbox.sh not found" >&2 + return 0 + fi + + echo "$base_toolbox_command: copying $toolbox_runtime_directory/toolbox.sh to container $container" >&3 + + if ! podman exec \ + --user root:root \ + "$container" \ + sh -c "cp $toolbox_runtime_directory/toolbox.sh /etc/profile.d" sh 2>&3; then + echo "$base_toolbox_command: unable to copy $toolbox_runtime_directory/toolbox.sh to container $container" >&2 + return 1 + fi + + return 0 +) + + +copy_etc_profile_d_toolbox_to_runtime_directory() +( + profile_d_lock="$toolbox_runtime_directory"/profile.d-toolbox.lock + + if ! [ -f /etc/profile.d/toolbox.sh ] 2>&3; then + echo "$base_toolbox_command: /etc/profile.d/toolbox.sh not found" >&2 + return 0 + fi + + # shellcheck disable=SC2174 + if ! mkdir --mode 700 --parents "$toolbox_runtime_directory" 2>&3; then + echo "$base_toolbox_command: unable to copy /etc/profile.d/toolbox.sh: runtime directory not created" >&2 + return 1 + fi + + exec 5>"$profile_d_lock" + if ! flock 5 2>&3; then + echo "$base_toolbox_command: unable to copy /etc/profile.d/toolbox.sh: copy lock not acquired" >&2 + return 1 + fi + + echo "$base_toolbox_command: copying /etc/profile.d/toolbox.sh to $toolbox_runtime_directory" >&3 + + if ! cp /etc/profile.d/toolbox.sh "$toolbox_runtime_directory" 2>&3; then + echo "$base_toolbox_command: unable to copy /etc/profile.d/toolbox.sh to $toolbox_runtime_directory" >&2 + return 1 + fi + + return 0 +) + + +create_enter_command() +( + container="$1" + + if [ "$container" = "$toolbox_container_default" ] 2>&3; then + echo "$base_toolbox_command enter" + elif [ "$container" = "$toolbox_container_prefix_default-$release" ] 2>&3; then + echo "$base_toolbox_command enter --release $release" + else + echo "$base_toolbox_command enter --container $container" + fi +) + + +create_environment_options() +( + columns="" + lines="" + + if terminal_size=$(stty size 2>&3); then + columns=$(echo "$terminal_size" | cut --delimiter " " --fields 2 2>&3) + if ! is_integer "$columns"; then + echo "$base_toolbox_command: failed to parse the number of columns from the terminal size" >&3 + columns="" + fi + + lines=$(echo "$terminal_size" | cut --delimiter " " --fields 1 2>&3) + if ! is_integer "$lines"; then + echo "$base_toolbox_command: failed to parse the number of lines from the terminal size" >&3 + lines="" + fi + else + echo "$base_toolbox_command: failed to read terminal size" >&3 + fi + + echo "$environment_variables" \ + | sed "s/ \+/\n/g" 2>&3 \ + | { + environment_options="" + echo "$base_toolbox_command: creating list of environment variables to forward" >&3 + value="" + while read -r variable; do + if echo "$environment" | grep "^$variable" >/dev/null 2>&3; then + eval value="$""$variable" + echo "$base_toolbox_command: $variable=$value" >&3 + environment_options="$environment_options --env=$variable=$value" + else + echo "$base_toolbox_command: $variable is unset" >&3 + fi + done + + if ! (echo "$environment_options" | grep COLUMNS >/dev/null 2>&3) && [ "$columns" != "" ] 2>&3; then + environment_options="$environment_options --env=COLUMNS=$columns" + fi + + if ! (echo "$environment_options" | grep LINES >/dev/null 2>&3) && [ "$lines" != "" ] 2>&3; then + environment_options="$environment_options --env=LINES=$lines" + fi + + environment_options=${environment_options#" "} + echo "$base_toolbox_command: created options for environment variables to forward" >&3 + echo "$environment_options" >&3 + echo "$environment_options" + } +) + + +create_toolbox_container_name() +( + image="$1" + + basename=$(image_reference_get_basename "$image") + if [ "$basename" = "" ] 2>&3; then + return 100 + fi + + tag=$(image_reference_get_tag "$image") + if [ "$tag" = "" ] 2>&3; then + return 101 + fi + + echo "$basename-$tag" + return 0 +) + + +create_toolbox_image_name() +( + # Based on the ResolveName function implemented in: + # https://github.com/containers/buildah/blob/master/util/util.go + + if image_reference_can_be_id "$base_toolbox_image"; then + if base_toolbox_image_id=$(podman inspect \ + --format "{{.Id}}" \ + --type image \ + "$base_toolbox_image" 2>&3); then + if has_prefix "$base_toolbox_image_id" "$base_toolbox_image"; then + echo "$base_toolbox_image-$USER:latest" + return 0 + fi + fi + fi + + basename=$(image_reference_get_basename "$base_toolbox_image") + if [ "$basename" = "" ] 2>&3; then + return 100 + fi + + tag=$(image_reference_get_tag "$base_toolbox_image") + if [ "$tag" = "" ] 2>&3; then + echo "$basename-$USER:latest" + else + echo "$basename-$USER:$tag" + fi + + return 0 +) + + +enter_print_container_not_found() +( + container="$1" + + echo "$base_toolbox_command: container $container not found" >&2 + echo "Use the 'create' command to create a toolbox." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 +) + + +get_cgroups_version() +( + version=1 + + if ! mounts=$(mount 2>&3); then + echo "$base_toolbox_command: failed to detect cgroups version: couldn't list mount points" >&2 + return 1 + fi + + if ! (echo "$mounts" | grep "^cgroup " >/dev/null 2>&3) && (echo "$mounts" | grep "^cgroup2 " >/dev/null 2>&3); then + version=2 + fi + + echo "$version" + return 0 +) + + +get_group_for_sudo() +( + group="" + if getent group sudo >/dev/null 2>&3; then + group="sudo" + elif getent group wheel >/dev/null 2>&3; then + group="wheel" + else + return 1 + fi + + echo "$group" + return 0 +) + + +get_host_id() +( + # shellcheck disable=SC1091 + . /usr/lib/os-release + echo "$ID" +) + + +get_host_variant_id() +( + # shellcheck disable=SC1091 + . /usr/lib/os-release + echo "$VARIANT_ID" +) + + +get_host_version_id() +( + # shellcheck disable=SC1091 + . /usr/lib/os-release + echo "$VERSION_ID" +) + + +image_reference_can_be_id() +( + image="$1" + + echo "$image" | grep "^[a-f0-9]\{6,64\}$" >/dev/null 2>&3 + return "$?" +) + + +image_reference_get_basename() +( + image="$1" + + domain=$(image_reference_get_domain "$image") + remainder=${image#$domain} + path=${remainder%:*} + basename=${path##*/} + echo "$basename" +) + + +image_reference_get_domain() +( + image="$1" + + image_reference_has_domain "$image" && domain=${image%%/*} + echo "$domain" +) + + +image_reference_get_tag() +( + image="$1" + + domain=$(image_reference_get_domain "$image") + remainder=${image#$domain} + + tag="" + if (echo "$remainder" | grep ":" >/dev/null 2>&3); then + tag=${remainder#*:} + fi + + echo "$tag" +) + + +image_reference_has_domain() +( + # Based on the splitDockerDomain function implemented in: + # https://github.com/docker/distribution/blob/master/reference/normalize.go + + image="$1" + + if ! (echo "$image" | grep "/" >/dev/null 2>&3); then + return 1 + fi + + prefix=${image%%/*} + if ! (echo "$prefix" | grep "[.:]" >/dev/null 2>&3) && [ "$prefix" != "localhost" ] 2>&3; then + return 1 + fi + + return 0 +) + + +images_get_details() +( + images="$1" + + if ! echo "$images" | while read -r image; do + [ "$image" = "" ] 2>&3 && continue + + if ! podman images \ + --format "{{.ID}} {{.Repository}}:{{.Tag}} {{.Created}}" \ + --noheading \ + "$image" 2>&3; then + echo "$base_toolbox_command: failed to get details for image $image" >&2 + return 1 + fi + echo + done; then + return 1 + fi + + return 0 +) + + +is_etc_profile_d_toolbox_a_bind_mount() +{ + container="$1" + + podman inspect --format "[{{range .Mounts}}{{.Dst}} {{end}}]" --type container "$container" 2>&3 \ + | grep /etc/profile.d/toolbox.sh >/dev/null 2>/dev/null 2>&3 + + return "$?" +} + + +list_container_names() +( + if ! containers_old=$(podman ps \ + --all \ + --filter "label=com.redhat.component=fedora-toolbox" \ + --format "{{.Names}}" 2>&3); then + echo "$base_toolbox_command: failed to list containers with com.redhat.component=fedora-toolbox" >&2 + return 1 + fi + + if ! containers=$(podman ps \ + --all \ + --filter "label=com.github.debarshiray.toolbox=true" \ + --format "{{.Names}}" 2>&3); then + echo "$base_toolbox_command: failed to list containers with com.github.debarshiray.toolbox=true" >&2 + return 1 + fi + + printf "%s\n%s\n" "$containers_old" "$containers" | sort 2>&3 | uniq 2>&3 + return 0 +) + + +pull_base_toolbox_image() +( + domain="" + has_domain=false + prompt_for_download=true + pull_image=false + + if image_reference_can_be_id "$base_toolbox_image"; then + echo "$base_toolbox_command: looking for image $base_toolbox_image" >&3 + + if podman image exists "$base_toolbox_image" >/dev/null 2>&3; then + return 0 + fi + fi + + image_reference_has_domain "$base_toolbox_image" && has_domain=true + + if ! $has_domain; then + echo "$base_toolbox_command: looking for image localhost/$base_toolbox_image" >&3 + + if podman image exists localhost/$base_toolbox_image >/dev/null 2>&3; then + return 0 + fi + fi + + if $has_domain; then + base_toolbox_image_full="$base_toolbox_image" + else + base_toolbox_image_full="$registry/$fgc/$base_toolbox_image" + fi + + echo "$base_toolbox_command: looking for image $base_toolbox_image_full" >&3 + + if podman image exists "$base_toolbox_image_full" >/dev/null 2>&3; then + return 0 + fi + + domain=$(image_reference_get_domain "$base_toolbox_image_full") + if $assume_yes || [ "$domain" = "localhost" ] 2>&3; then + prompt_for_download=false + pull_image=true + fi + + if $prompt_for_download; then + echo "Image required to create toolbox container." + + prompt=$(printf "Download %s (500MB)? [y/N]:" "$base_toolbox_image_full") + if ask_for_confirmation "n" "$prompt"; then + pull_image=true + else + pull_image=false + fi + fi + + if ! $pull_image; then + return 1 + fi + + echo "$base_toolbox_command: pulling image $base_toolbox_image_full" >&3 + + if spinner_directory=$(mktemp --directory --tmpdir $spinner_template 2>&3); then + spinner_message="Pulling $base_toolbox_image_full: " + if ! spinner_start "$spinner_directory" "$spinner_message"; then + spinner_directory="" + fi + else + echo "$base_toolbox_command: unable to start spinner: spinner directory not created" >&2 + spinner_directory="" + fi + + podman pull $base_toolbox_image_full >/dev/null 2>&3 + ret_val=$? + + if [ "$spinner_directory" != "" ]; then + spinner_stop "$spinner_directory" + fi + + if [ "$ret_val" -ne 0 ] 2>&3; then + echo "$base_toolbox_command: failed to pull base image $base_toolbox_image" >&2 + fi + + return $ret_val +) + + +unshare_userns_rm() +( + path="$1" + + if ! unshare_directory=$(mktemp --directory --tmpdir "toolbox-unshare-userns-rm-XXXXXXXXXX" 2>&3); then + echo "$base_toolbox_command: failed to enter user namespace: directory couldn't be created" >&2 + return 1 + fi + + if ! touch "$unshare_directory/map" 2>&3; then + echo "$base_toolbox_command: failed to enter user namespace: file couldn't be created" >&2 + return 1 + fi + + exec 4>"$unshare_directory/map" + if ! flock 4 2>&3; then + echo "$base_toolbox_command: failed to enter user namespace: lock couldn't be acquired" >&2 + return 1 + fi + + echo "$base_toolbox_command: parsing /etc/subgid" >&3 + + if ! subgid_entry=$(grep "^$USER:" /etc/subgid 2>&3); then + echo "$base_toolbox_command: failed to enter user namespace: no entry in /etc/subgid" >&2 + return 1 + fi + + userns_gid_start=$(echo "$subgid_entry" | cut --delimiter ":" --fields 2 2>&3) + if ! is_integer "$userns_gid_start"; then + echo "$base_toolbox_command: failed to enter user namespace: cannot parse the first sub-GID" >&2 + return 1 + fi + + userns_gid_len=$(echo "$subgid_entry" | cut --delimiter ":" --fields 3 2>&3) + if ! is_integer "$userns_gid_len"; then + echo "$base_toolbox_command: failed to enter user namespace: cannot parse the sub-GID count" >&2 + return 1 + fi + + echo "$base_toolbox_command: parsing /etc/subuid" >&3 + + if ! subuid_entry=$(grep "^$USER:" /etc/subuid 2>&3); then + echo "$base_toolbox_command: failed to enter user namespace: no entry in /etc/subuid" >&2 + return 1 + fi + + userns_uid_start=$(echo "$subuid_entry" | cut --delimiter ":" --fields 2 2>&3) + if ! is_integer "$userns_uid_start"; then + echo "$base_toolbox_command: failed to enter user namespace: cannot parse the first sub-UID" >&2 + return 1 + fi + + userns_uid_len=$(echo "$subuid_entry" | cut --delimiter ":" --fields 3 2>&3) + if ! is_integer "$userns_uid_len"; then + echo "$base_toolbox_command: failed to enter user namespace: cannot parse the sub-UID count" >&2 + return 1 + fi + + echo "$base_toolbox_command: unsharing user namespace" >&3 + + unshare --user sh -c "flock $unshare_directory/map rm --force --recursive $path" 2>&3 & + unshare_pid="$!" + + echo "$base_toolbox_command: setting GID and UID map of user namespace" >&3 + + if ! newgidmap "$unshare_pid" 0 "$user_id_real" 1 1 "$userns_gid_start" "$userns_gid_len" 2>&3; then + echo "$base_toolbox_command: failed to set GID mapping of user namespace" >&2 + kill -9 "$unshare_pid" 2>&3 + return 1 + fi + + if ! newuidmap "$unshare_pid" 0 "$user_id_real" 1 1 "$userns_uid_start" "$userns_uid_len" 2>&3; then + echo "$base_toolbox_command: failed to set UID mapping of user namespace" >&2 + kill -9 "$unshare_pid" 2>&3 + return 1 + fi + + echo "$base_toolbox_command: GID map of user namespace:" >&3 + cat /proc/"$unshare_pid"/gid_map 1>&3 2>&3 + + echo "$base_toolbox_command: UID map of user namespace:" >&3 + cat /proc/"$unshare_pid"/uid_map 1>&3 2>&3 + + if ! flock --unlock 4 2>&3; then + echo "$base_toolbox_command: failed to remove $path: lock couldn't be unlocked" >&2 + kill -9 "$unshare_pid" 2>&3 + return 1 + fi + + if ! wait "$unshare_pid" 2>&3; then + echo "$base_toolbox_command: failed to remove $path" >&2 + return 1 + fi + + rm --force --recursive "$unshare_directory" 2>&3 + + return 0 +) + + +create() +( + enter_command_skip="$1" + + dbus_system_bus_address="unix:path=/var/run/dbus/system_bus_socket" + home_link="" + flatpak_system_directory_bind="" + kcm_socket="" + kcm_socket_bind="" + libvirt_system_directory_bind="" + run_media_path_bind="" + toolbox_profile_bind="" + ulimit_host="" + usr_mount_destination_flags="ro" + + # shellcheck disable=SC2153 + if [ "$DBUS_SYSTEM_BUS_ADDRESS" != "" ]; then + dbus_system_bus_address=$DBUS_SYSTEM_BUS_ADDRESS + fi + dbus_system_bus_path=$(echo "$dbus_system_bus_address" | cut --delimiter = --fields 2 2>&3) + dbus_system_bus_path=$(readlink --canonicalize "$dbus_system_bus_path" 2>&3) + + if [ -d /var/lib/flatpak ] 2>&3; then + flatpak_system_directory_bind="--volume /var/lib/flatpak:/var/lib/flatpak:ro" + fi + + # Note that 'systemctl show ...' doesn't terminate with a non-zero exit + # code when used with an unknown unit. eg.: + # $ systemctl show --value --property Listen foo + # $ echo $? + # 0 + if ! kcm_socket_listen=$(systemctl show --value --property Listen sssd-kcm.socket 2>&3); then + echo "$base_toolbox_command: failed to use 'systemctl show'" >&3 + kcm_socket_listen="" + elif [ "$kcm_socket_listen" = "" ] 2>&3; then + echo "$base_toolbox_command: failed to read property Listen from sssd-kcm.socket" >&3 + else + echo "$base_toolbox_command: checking value $kcm_socket_listen of property Listen in sssd-kcm.socket" >&3 + + if ! (echo "$kcm_socket_listen" | grep " (Stream)$" >/dev/null 2>&3); then + echo "$base_toolbox_command: unknown socket in sssd-kcm.socket" >&2 + echo "$base_toolbox_command: expected SOCK_STREAM" >&2 + kcm_socket_listen="" + elif ! (echo "$kcm_socket_listen" | grep "^/" >/dev/null 2>&3); then + echo "$base_toolbox_command: unknown socket in sssd-kcm.socket" >&2 + echo "$base_toolbox_command: expected file system socket in the AF_UNIX family" >&2 + kcm_socket_listen="" + fi + fi + + echo "$base_toolbox_command: parsing value $kcm_socket_listen of property Listen in sssd-kcm.socket" >&3 + + if [ "$kcm_socket_listen" != "" ] 2>&3; then + kcm_socket=${kcm_socket_listen%" (Stream)"} + kcm_socket_bind="--volume $kcm_socket:$kcm_socket" + fi + + if [ -d /run/libvirt ] 2>&3; then + libvirt_system_directory_bind="--volume /run/libvirt:/run/libvirt" + fi + + echo "$base_toolbox_command: checking if 'podman create' supports --ulimit host" >&3 + + if man podman-create 2>&3 | grep "You can pass host" >/dev/null 2>&3; then + echo "$base_toolbox_command: 'podman create' supports --ulimit host" >&3 + + ulimit_host="--ulimit host" + fi + + if ! pull_base_toolbox_image; then + return 1 + fi + + if image_reference_has_domain "$base_toolbox_image"; then + base_toolbox_image_full="$base_toolbox_image" + else + if ! base_toolbox_image_full=$(podman inspect \ + --format "{{index .RepoTags 0}}" \ + --type image \ + "$base_toolbox_image" 2>&3); then + echo "$base_toolbox_command: failed to get RepoTag for base image $base_toolbox_image" >&2 + return 1 + fi + + echo "$base_toolbox_command: base image $base_toolbox_image resolved to $base_toolbox_image_full" >&3 + fi + + echo "$base_toolbox_command: checking if container $toolbox_container already exists" >&3 + + enter_command=$(create_enter_command "$toolbox_container") + if podman container exists $toolbox_container >/dev/null 2>&3; then + echo "$base_toolbox_command: container $toolbox_container already exists" >&2 + echo "Enter with: $enter_command" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + return 1 + fi + + if ! group_for_sudo=$(get_group_for_sudo); then + echo "$base_toolbox_command: failed to create container $toolbox_container: group for sudo not found" >&2 + return 1 + fi + + if [ -f /etc/profile.d/toolbox.sh ] 2>&3; then + toolbox_profile_bind="--volume /etc/profile.d/toolbox.sh:/etc/profile.d/toolbox.sh:ro" + fi + + if [ -d /run/media ] 2>&3; then + run_media_path_bind="--volume /run/media:/run/media:rslave" + fi + + echo "$base_toolbox_command: checking if /usr is mounted read-only or read-write" >&3 + + if ! usr_mount_point=$(df --output=target /usr | tail --lines 1 2>&3); then + echo "$base_toolbox_command: failed to get the mount-point of /usr" >&2 + else + echo "$base_toolbox_command: mount-point of /usr is $usr_mount_point" >&3 + + if ! usr_mount_source_flags=$(findmnt --noheadings --output OPTIONS "$usr_mount_point" 2>&3); then + echo "$base_toolbox_command: failed to get the mount options of $usr_mount_point" >&2 + else + echo "$base_toolbox_command: mount flags of /usr on the host are $usr_mount_source_flags" >&3 + + if echo "$usr_mount_source_flags" | grep --invert-match "ro" >/dev/null 2>&3; then + usr_mount_destination_flags="rw" + fi + fi + fi + + if ! home_canonical=$(readlink --canonicalize "$HOME" 2>&3); then + echo "$base_toolbox_command: failed to canonicalize $HOME" >&2 + return 1 + fi + + echo "$base_toolbox_command: $HOME canonicalized to $home_canonical" >&3 + + echo "$base_toolbox_command: checking if /home is a symbolic link to /var/home" >&3 + + if [ "$(readlink /home)" = var/home ] 2>&3; then + echo "$base_toolbox_command: /home is a symbolic link to /var/home" >&3 + home_link="--home-link" + fi + + echo "$base_toolbox_command: calling org.freedesktop.Flatpak.SessionHelper.RequestSession" >&3 + + if ! gdbus call \ + --session \ + --dest org.freedesktop.Flatpak \ + --object-path /org/freedesktop/Flatpak/SessionHelper \ + --method org.freedesktop.Flatpak.SessionHelper.RequestSession >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to call org.freedesktop.Flatpak.SessionHelper.RequestSession" >&2 + exit 1 + fi + + echo "$base_toolbox_command: creating container $toolbox_container" >&3 + + if spinner_directory=$(mktemp --directory --tmpdir $spinner_template 2>&3); then + spinner_message="Creating container $toolbox_container: " + if ! spinner_start "$spinner_directory" "$spinner_message"; then + spinner_directory="" + fi + else + echo "$base_toolbox_command: unable to start spinner: spinner directory not created" >&2 + spinner_directory="" + fi + + # shellcheck disable=SC2086 + podman create \ + --dns none \ + --env TOOLBOX_PATH="$TOOLBOX_PATH" \ + --group-add "$group_for_sudo" \ + --hostname toolbox \ + --ipc host \ + --label "com.github.containers.toolbox=true" \ + --label "com.github.debarshiray.toolbox=true" \ + --name $toolbox_container \ + --network host \ + --no-hosts \ + --pid host \ + --privileged \ + --security-opt label=disable \ + $ulimit_host \ + --userns=keep-id \ + --user root:root \ + $flatpak_system_directory_bind \ + $kcm_socket_bind \ + $libvirt_system_directory_bind \ + $run_media_path_bind \ + $toolbox_profile_bind \ + --volume "$TOOLBOX_PATH":/usr/bin/toolbox:ro \ + --volume "$XDG_RUNTIME_DIR":"$XDG_RUNTIME_DIR" \ + --volume "$XDG_RUNTIME_DIR"/.flatpak-helper/monitor:/run/host/monitor \ + --volume "$dbus_system_bus_path":"$dbus_system_bus_path" \ + --volume "$home_canonical":"$home_canonical":rslave \ + --volume /etc:/run/host/etc \ + --volume /dev:/dev:rslave \ + --volume /media:/media:rslave \ + --volume /mnt:/mnt:rslave \ + --volume /run:/run/host/run:rslave \ + --volume /tmp:/run/host/tmp:rslave \ + --volume /usr:/run/host/usr:"$usr_mount_destination_flags",rslave \ + --volume /var:/run/host/var:rslave \ + "$base_toolbox_image_full" \ + toolbox --verbose init-container \ + --home "$HOME" \ + $home_link \ + --monitor-host \ + --shell "$SHELL" \ + --uid "$user_id_real" \ + --user "$USER" >/dev/null 2>&3 + ret_val=$? + + if [ "$spinner_directory" != "" ]; then + spinner_stop "$spinner_directory" + fi + + if [ $ret_val -ne 0 ]; then + echo "$base_toolbox_command: failed to create container $toolbox_container" >&2 + return 1 + fi + + if ! $enter_command_skip; then + echo "Created container: $toolbox_container" + echo "Enter with: $enter_command" + fi + + return 0 +) + + +enter() +( + emit_escape_sequence=false + host_id=$(get_host_id) + host_variant_id=$(get_host_variant_id) + + if [ "$host_id" = "fedora" ] 2>&3 \ + && { [ "$host_variant_id" = "silverblue" ] 2>&3 || [ "$host_variant_id" = "workstation" ] 2>&3; }; then + emit_escape_sequence=true + fi + + run "$emit_escape_sequence" true false "$SHELL" -l +) + + +init_container() +{ + init_container_home="$1" + init_container_home_link="$2" + init_container_monitor_host="$3" + init_container_shell="$4" + init_container_uid="$5" + init_container_user="$6" + + if [ "$XDG_RUNTIME_DIR" = "" ] 2>&3; then + echo "$base_toolbox_command: XDG_RUNTIME_DIR is unset" >&3 + + XDG_RUNTIME_DIR=/run/user/"$init_container_uid" + echo "$base_toolbox_command: XDG_RUNTIME_DIR set to $XDG_RUNTIME_DIR" >&3 + + toolbox_runtime_directory="$XDG_RUNTIME_DIR"/toolbox + fi + + init_container_initialized_stamp="$toolbox_runtime_directory"/container-initialized-"$$" + + echo "$base_toolbox_command: creating /run/.toolboxenv" >&3 + + if ! touch /run/.toolboxenv 2>&3; then + echo "$base_toolbox_command: failed to create /run/.toolboxenv" >&2 + return 1 + fi + + if $init_container_monitor_host; then + working_directory="$PWD" + + if [ -d /run/host/etc ] 2>&3; then + if ! readlink /etc/host.conf >/dev/null 2>&3; then + echo "$base_toolbox_command: redirecting /etc/host.conf to /run/host/etc/host.conf" >&3 + + if ! (cd /etc 2>&3 \ + && rm --force host.conf 2>&3 \ + && ln --symbolic /run/host/etc/host.conf host.conf 2>&3); then + echo "$base_toolbox_command: failed to redirect /etc/host.conf to /run/host/etc/host.conf" >&2 + return 1 + fi + fi + + if ! readlink /etc/hosts >/dev/null 2>&3; then + echo "$base_toolbox_command: redirecting /etc/hosts to /run/host/etc/hosts" >&3 + + if ! (cd /etc 2>&3 \ + && rm --force hosts 2>&3 \ + && ln --symbolic /run/host/etc/hosts hosts 2>&3); then + echo "$base_toolbox_command: failed to redirect /etc/hosts to /run/host/etc/hosts" >&2 + return 1 + fi + fi + + if ! readlink /etc/resolv.conf >/dev/null 2>&3; then + echo "$base_toolbox_command: redirecting /etc/resolv.conf to /run/host/etc/resolv.conf" >&3 + + if ! (cd /etc 2>&3 \ + && rm --force resolv.conf 2>&3 \ + && ln --symbolic /run/host/etc/resolv.conf resolv.conf 2>&3); then + echo "$base_toolbox_command: failed to redirect /etc/resolv.conf to /run/host/etc/resolv.conf" \ + >&2 + return 1 + fi + fi + fi + + if [ -d /run/host/monitor ] 2>&3; then + if ! localtime_target=$(readlink /etc/localtime >/dev/null 2>&3) \ + || [ "$localtime_target" != "/run/host/monitor/localtime" ] 2>&3; then + echo "$base_toolbox_command: redirecting /etc/localtime to /run/host/monitor/localtime" >&3 + + if ! (cd /etc 2>&3 \ + && rm --force localtime 2>&3 \ + && ln --symbolic /run/host/monitor/localtime localtime 2>&3); then + echo "$base_toolbox_command: failed to redirect /etc/localtime to /run/host/monitor/localtime" \ + >&2 + return 1 + fi + fi + + if ! readlink /etc/timezone >/dev/null 2>&3; then + echo "$base_toolbox_command: redirecting /etc/timezone to /run/host/monitor/timezone" >&3 + + if ! (cd /etc 2>&3 \ + && rm --force timezone 2>&3 \ + && ln --symbolic /run/host/monitor/timezone timezone 2>&3); then + echo "$base_toolbox_command: failed to redirect /etc/timezone to /run/host/monitor/timezone" >&2 + return 1 + fi + fi + fi + + if ! cd "$working_directory" 2>&3; then + echo "$base_toolbox_command: failed to restore working directory" >&2 + fi + fi + + if ! id -u "$init_container_user" >/dev/null 2>&3; then + if $init_container_home_link ; then + echo "$base_toolbox_command: making /home a symlink" >&3 + + # shellcheck disable=SC2174 + if ! (rmdir /home 2>&3 \ + && mkdir --mode 0755 --parents /var/home 2>&3 \ + && ln --symbolic var/home /home 2>&3); then + echo "$base_toolbox_command: failed to make /home a symlink" >&2 + return 1 + fi + fi + + if ! groups=$(get_group_for_sudo); then + echo "$base_toolbox_command: failed to add user $init_container_user: group for sudo not found" >&2 + return 1 + fi + + echo "$base_toolbox_command: adding user $init_container_user with UID $init_container_uid" >&3 + + if ! useradd \ + --home-dir "$init_container_home" \ + --no-create-home \ + --shell "$init_container_shell" \ + --uid "$init_container_uid" \ + --groups "$groups" \ + "$init_container_user" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to add user $init_container_user with UID $init_container_uid" >&2 + return 1 + fi + + echo "$base_toolbox_command: removing password for user $init_container_user" >&3 + + if ! passwd --delete "$init_container_user" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove password for user $init_container_user" >&2 + return 1 + fi + + echo "$base_toolbox_command: removing password for user root" >&3 + + if ! passwd --delete root >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove password for user root" >&2 + return 1 + fi + + fi + + if [ -d /etc/krb5.conf.d ] 2>&3 && ! [ -f /etc/krb5.conf.d/kcm_default_ccache ] 2>&3; then + echo "$base_toolbox_command: setting KCM as the default Kerberos credential cache" >&3 + + cat <<EOF >/etc/krb5.conf.d/kcm_default_ccache 2>&3 +# Written by Toolbox +# https://github.com/debarshiray/toolbox +# +# # To disable the KCM credential cache, comment out the following lines. + +[libdefaults] + default_ccache_name = KCM: +EOF + ret_val=$? + + if [ "$ret_val" -ne 0 ] 2>&3; then + echo "$base_toolbox_command: failed to set KCM as the default Kerberos credential cache" >&2 + return 1 + fi + fi + + echo "$base_toolbox_command: finished initializing container" >&3 + + if ! touch "$init_container_initialized_stamp" 2>&3; then + echo "$base_toolbox_command: failed to create initialization stamp" >&2 + return 1 + fi + + echo "$base_toolbox_command: going to sleep" >&3 + + exec sleep +Inf +} + + +run() +( + emit_escape_sequence="$1" + fallback_to_bash="$2" + pedantic="$3" + program="$4" + shift 4 + + create_toolbox_container=false + prompt_for_create=true + + echo "$base_toolbox_command: checking if container $toolbox_container exists" >&3 + + if ! podman container exists "$toolbox_container" 2>&3; then + echo "$base_toolbox_command: container $toolbox_container not found" >&3 + + if podman container exists "$toolbox_container_old_v1" 2>&3; then + echo "$base_toolbox_command: container $toolbox_container_old_v1 found" >&3 + + # shellcheck disable=SC2030 + toolbox_container="$toolbox_container_old_v1" + elif podman container exists "$toolbox_container_old_v2" 2>&3; then + echo "$base_toolbox_command: container $toolbox_container_old_v2 found" >&3 + + # shellcheck disable=SC2030 + toolbox_container="$toolbox_container_old_v2" + else + if $pedantic; then + enter_print_container_not_found "$toolbox_container" + exit 1 + fi + + if ! containers=$(list_container_names); then + enter_print_container_not_found "$toolbox_container" + exit 1 + fi + + containers_count=$(echo "$containers" | grep --count . 2>&3) + if ! is_integer "$containers_count"; then + enter_print_container_not_found "$toolbox_container" + exit 1 + fi + + echo "$base_toolbox_command: found $containers_count containers" >&3 + + if [ "$containers_count" -eq 0 ] 2>&3; then + if $assume_yes; then + create_toolbox_container=true + prompt_for_create=false + fi + + if $prompt_for_create; then + prompt="No toolbox containers found. Create now? [y/N]" + if ask_for_confirmation "n" "$prompt"; then + create_toolbox_container=true + else + create_toolbox_container=false + fi + fi + + if ! $create_toolbox_container; then + echo "A container can be created later with the 'create' command." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + fi + + if ! update_container_and_image_names; then + exit 1 + fi + + if ! create true; then + exit 1 + fi + elif [ "$containers_count" -eq 1 ] 2>&3 \ + && [ "$toolbox_container" = "$toolbox_container_default" ] 2>&3; then + echo "$base_toolbox_command: container $toolbox_container not found" >&2 + + toolbox_container=$(echo "$containers" | grep . 2>&3 | head --lines 1 2>&3) + echo "Entering container $toolbox_container instead." >&2 + echo "Use the 'create' command to create a different toolbox." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + else + echo "$base_toolbox_command: container $toolbox_container not found" >&2 + echo "Use the '--container' option to select a toolbox." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + fi + fi + fi + + echo "$base_toolbox_command: calling org.freedesktop.Flatpak.SessionHelper.RequestSession" >&3 + + if ! gdbus call \ + --session \ + --dest org.freedesktop.Flatpak \ + --object-path /org/freedesktop/Flatpak/SessionHelper \ + --method org.freedesktop.Flatpak.SessionHelper.RequestSession >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to call org.freedesktop.Flatpak.SessionHelper.RequestSession" >&2 + exit 1 + fi + + echo "$base_toolbox_command: starting container $toolbox_container" >&3 + + if is_etc_profile_d_toolbox_a_bind_mount "$toolbox_container"; then + echo "$base_toolbox_command: /etc/profile.d/toolbox.sh already mounted in container $toolbox_container" >&3 + + if ! container_start "$toolbox_container"; then + exit 1 + fi + else + echo "$base_toolbox_command: /etc/profile.d/toolbox.sh not mounted in container $toolbox_container" >&3 + + if ! copy_etc_profile_d_toolbox_to_runtime_directory; then + exit 1 + fi + + if ! container_start "$toolbox_container"; then + exit 1 + fi + + if ! copy_etc_profile_d_toolbox_to_container "$toolbox_container"; then + exit 1 + fi + fi + + echo "$base_toolbox_command: inspecting entry point of container $toolbox_container" >&3 + + if ! entry_point=$(podman inspect --format "{{index .Config.Cmd 0}}" --type container "$toolbox_container" 2>&3); then + echo "$base_toolbox_command: failed to inspect entry point of container $toolbox_container" >&2 + exit 1 + fi + + echo "$base_toolbox_command: entry point of container $toolbox_container is $entry_point" >&3 + + if [ "$entry_point" = "toolbox" ] 2>&3; then + echo "$base_toolbox_command: waiting for container $toolbox_container to finish initializing" >&3 + + if ! entry_point_pid=$(podman inspect --format "{{.State.Pid}}" --type container "$toolbox_container" 2>&3); then + echo "$base_toolbox_command: failed to inspect entry point PID of container $toolbox_container" >&2 + exit 1 + fi + + if ! is_integer "$entry_point_pid"; then + echo "$base_toolbox_command: failed to parse entry point PID of container $toolbox_container" >&2 + exit 1 + fi + + if [ "$entry_point_pid" -le 0 ] 2>&3; then + echo "$base_toolbox_command: invalid entry point PID of container $toolbox_container" >&2 + exit 1 + fi + + container_initialized_stamp="$toolbox_runtime_directory/container-initialized-$entry_point_pid" + container_initialized_timeout=25 #s + + i=0 + while ! [ -f "$container_initialized_stamp" ] 2>&3; do + sleep 1 2>&3 + + i=$((i + 1)) + if [ "$i" -eq "$container_initialized_timeout" ] 2>&3; then + echo "$base_toolbox_command: failed to initialize container $toolbox_container" >&2 + exit 1 + fi + done + fi + + if ! podman exec --user root:root "$toolbox_container" touch /run/.toolboxenv 2>&3; then + echo "$base_toolbox_command: failed to create /run/.toolboxenv in container $toolbox_container" >&2 + exit 1 + fi + + set_environment=$(create_environment_options) + + echo "$base_toolbox_command: looking for $program in container $toolbox_container" >&3 + + # shellcheck disable=SC2016 + if ! podman exec \ + --user "$USER" \ + "$toolbox_container" \ + sh -c 'command -v "$1"' sh "$program" >/dev/null 2>&3; then + if $fallback_to_bash; then + echo "$base_toolbox_command: $program not found in $toolbox_container; using /bin/bash instead" >&3 + program=/bin/bash + else + echo "$base_toolbox_command: command '$program' not found in container $toolbox_container" >&2 + exit 127 + fi + fi + + echo "$base_toolbox_command: running in container $toolbox_container:" >&3 + echo "$base_toolbox_command: $program" >&3 + for i in "$@"; do + echo "$base_toolbox_command: $i" >&3 + done + + $emit_escape_sequence && printf "\033]777;container;push;%s;toolbox\033\\" "$toolbox_container" + + # shellcheck disable=SC2016 + # for the command passed to capsh + # shellcheck disable=SC2086 + podman exec \ + --interactive \ + --tty \ + --user "$USER" \ + --workdir "$PWD" \ + $set_environment \ + "$toolbox_container" \ + capsh --caps="" -- -c 'exec "$@"' /bin/sh "$program" "$@" 2>&3 + ret_val="$?" + + $emit_escape_sequence && printf "\033]777;container;pop;;\033\\" + + exit "$ret_val" +) + + +help() +( + to_help_command="$1" + + if [ "$to_help_command" = "" ] 2>&3 || [ "$to_help_command" = "$base_toolbox_command" ] 2>&3; then + exec man toolbox 2>&1 + fi + + exec man toolbox-"$to_help_command" 2>&1 +) + + +list_images() +( + output="" + + if ! images_old=$(podman images \ + --filter "label=com.redhat.component=fedora-toolbox" \ + --format "{{.Repository}}:{{.Tag}}" 2>&3); then + echo "$base_toolbox_command: failed to list images with com.redhat.component=fedora-toolbox" >&2 + return 1 + fi + + if ! images=$(podman images \ + --filter "label=com.github.debarshiray.toolbox=true" \ + --format "{{.Repository}}:{{.Tag}}" 2>&3); then + echo "$base_toolbox_command: failed to list images with com.github.debarshiray.toolbox=true" >&2 + return 1 + fi + + images=$(printf "%s\n%s\n" "$images_old" "$images" | sort 2>&3 | uniq 2>&3) + if ! details=$(images_get_details "$images"); then + return 1 + fi + + if [ "$details" != "" ] 2>&3; then + table_data=$(printf "%s\t%s\t%s\n" "IMAGE ID" "IMAGE NAME" "CREATED"; echo "$details") + if ! output=$(echo "$table_data" | sed "s/ \{2,\}/\t/g" 2>&3 | column -s "$tab" -t 2>&3); then + echo "$base_toolbox_command: failed to parse list of images" >&2 + return 1 + fi + fi + + if [ "$output" != "" ]; then + echo "$output" + fi + + return 0 +) + + +containers_get_details() +( + containers="$1" + + if ! echo "$containers" | while read -r container; do + [ "$container" = "" ] 2>&3 && continue + + if ! podman ps --all \ + --filter "name=$container" \ + --format "{{.ID}} {{.Names}} {{.Created}} {{.Status}} {{.Image}}" 2>&3; then + echo "$base_toolbox_command: failed to get details for container $container" >&2 + return 1 + fi + done; then + return 1 + fi + + return 0 +) + + +list_containers() +( + output="" + + if ! containers=$(list_container_names); then + return 1 + fi + + if ! details=$(containers_get_details "$containers"); then + return 1 + fi + + if [ "$details" != "" ] 2>&3; then + table_data=$(printf "%s\t%s\t%s\t%s\t%s\n" "CONTAINER ID" "CONTAINER NAME" "CREATED" "STATUS" "IMAGE NAME" + echo "$details") + if ! output=$(echo "$table_data" | sed "s/ \{2,\}/\t/g" 2>&3 | column -s "$tab" -t 2>&3); then + echo "$base_toolbox_command: failed to parse list of containers" >&2 + return 1 + fi + fi + + if [ "$output" != "" ]; then + echo "$output" | head --lines 1 2>&3 + + echo "$output" | tail --lines +2 2>&3 \ + | ( + while read -r container; do + id=$(echo "$container" | cut --delimiter " " --fields 1 2>&3) + is_running=$(podman inspect "$id" --format "{{.State.Running}}" 2>&3) + if $is_running; then + # shellcheck disable=SC2059 + printf "${LGC}$container${NC}\n" + else + echo "$container" + fi + done + ) + fi + + return 0 +) + + +migrate() +( + configuration_directory="$HOME/.config/toolbox" + migrate_stamp="$configuration_directory/podman-system-migrate" + + migrate_lock="$toolbox_runtime_directory"/migrate.lock + + if ! version=$(podman version --format "{{.Version}}" 2>&3); then + echo "$base_toolbox_command: unable to migrate containers: Podman version couldn't be read" >&2 + return 1 + fi + + echo "$base_toolbox_command: current Podman version is $version" >&3 + + if ! mkdir --parents "$configuration_directory" 2>&3; then + echo "$base_toolbox_command: unable to migrate containers: configuration directory not created" >&2 + return 1 + fi + + # shellcheck disable=SC2174 + if ! mkdir --mode 700 --parents "$toolbox_runtime_directory" 2>&3; then + echo "$base_toolbox_command: unable to migrate containers: runtime directory not created" >&2 + return 1 + fi + + exec 5>"$migrate_lock" + if ! flock 5 2>&3; then + echo "$base_toolbox_command: unable to migrate containers: migration lock not acquired" >&3 + return 1 + fi + + if [ -f "$migrate_stamp" ] 2>&3; then + if grep "$version" "$migrate_stamp" >/dev/null 2>&3; then + echo "$base_toolbox_command: migration not needed: Podman version $version is unchanged" >&3 + return 0 + fi + + if ! version_old=$(printf "%s\n" "$version" \ + | cat "$migrate_stamp" - 2>&3 \ + | sort --version-sort 2>&3 \ + | head --lines 1 2>&3); then + echo "$base_toolbox_command: unable to migrate containers: Podman versions couldn't be sorted" >&2 + return 1 + fi + + if [ "$version" = "$version_old" ] 2>&3; then + echo "$base_toolbox_command: migration not needed: Podman version $version is old" >&3 + return 0 + fi + fi + + if ! podman system migrate >/dev/null 2>&3; then + echo "$base_toolbox_command: unable to migrate containers" >&2 + return 1 + fi + + echo "$version" >"$migrate_stamp" + return 0 +) + + +remove_containers() +( + ids=$1 + all=$2 + force=$3 + + ret_val=0 + + $force && force_option="--force" + + if $all; then + if ! ids_old=$(podman ps \ + --all \ + --filter "label=com.redhat.component=fedora-toolbox" \ + --format "{{.ID}}" 2>&3); then + echo "$base_toolbox_command: failed to list containers with com.redhat.component=fedora-toolbox" >&2 + return 1 + fi + + if ! ids=$(podman ps \ + --all \ + --filter "label=com.github.debarshiray.toolbox=true" \ + --format "{{.ID}}" 2>&3); then + echo "$base_toolbox_command: failed to list containers with com.github.debarshiray.toolbox=true" >&2 + return 1 + fi + + ids=$(printf "%s\n%s\n" "$ids_old" "$ids" | sort 2>&3 | uniq 2>&3) + if [ "$ids" != "" ]; then + ret_val=$(echo "$ids" \ + | ( + while read -r id; do + if ! podman rm $force_option "$id" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove container $id" >&2 + ret_val=1 + fi + done + + echo "$ret_val" + ) + ) + fi + else + ret_val=$(echo "$ids" \ + | sed "s/ \+/\n/g" 2>&3 \ + | ( + while read -r id; do + if ! labels=$(podman inspect \ + --format "{{.Config.Labels}}" \ + --type container \ + "$id" 2>&3); then + echo "$base_toolbox_command: failed to inspect $id" >&2 + ret_val=1 + continue + fi + + if ! has_substring "$labels" "com.github.debarshiray.toolbox" \ + && ! has_substring "$labels" "com.redhat.component:fedora-toolbox"; then + echo "$base_toolbox_command: $id is not a toolbox container" >&2 + ret_val=1 + continue + fi + + if ! podman rm $force_option "$id" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove container $id" >&2 + ret_val=1 + fi + done + + echo "$ret_val" + ) + ) + fi + + return "$ret_val" +) + + +remove_images() +( + ids=$1 + all=$2 + force=$3 + + ret_val=0 + + $force && force_option="--force" + + if $all; then + if ! ids_old=$(podman images \ + --filter "label=com.redhat.component=fedora-toolbox" \ + --format "{{.ID}}" 2>&3); then + echo "$0: failed to list images with com.redhat.component=fedora-toolbox" >&2 + return 1 + fi + + if ! ids=$(podman images \ + --all \ + --filter "label=com.github.debarshiray.toolbox=true" \ + --format "{{.ID}}" 2>&3); then + echo "$0: failed to list images with com.github.debarshiray.toolbox=true" >&2 + return 1 + fi + + ids=$(printf "%s\n%s\n" "$ids_old" "$ids" | sort 2>&3 | uniq 2>&3) + if [ "$ids" != "" ]; then + ret_val=$(echo "$ids" \ + | ( + while read -r id; do + if ! podman rmi $force_option "$id" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove image $id" >&2 + ret_val=1 + fi + done + + echo "$ret_val" + ) + ) + fi + else + ret_val=$(echo "$ids" \ + | sed "s/ \+/\n/g" 2>&3 \ + | ( + while read -r id; do + if ! labels=$(podman inspect \ + --format "{{.Labels}}" \ + --type image \ + "$id" 2>&3); then + echo "$base_toolbox_command: failed to inspect $id" >&2 + ret_val=1 + continue + fi + + if ! has_substring "$labels" "com.github.debarshiray.toolbox" \ + && ! has_substring "$labels" "com.redhat.component:fedora-toolbox"; then + echo "$base_toolbox_command: $id is not a toolbox image" >&2 + ret_val=1 + continue + fi + + if ! podman rmi $force_option "$id" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove image $id" >&2 + ret_val=1 + fi + done + + echo "$ret_val" + ) + ) + fi + + return "$ret_val" +) + + +reset() +( + do_reset=false + prompt_for_reset=true + ret_val=0 + + if [ "$user_id_real" -eq 0 ] 2>&3; then + if [ -d /run/containers ] 2>&3; then + echo "$base_toolbox_command: The 'reset' command cannot be used after other commands" >&2 + echo "Reboot the system before using it again." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + return 1 + fi + else + if [ -d "$XDG_RUNTIME_DIR"/overlay-containers ] 2>&3 \ + || [ -d "$XDG_RUNTIME_DIR"/overlay-layers ] 2>&3 \ + || [ -d "$XDG_RUNTIME_DIR"/overlay-locks ] 2>&3; then + echo "$base_toolbox_command: The 'reset' command cannot be used after other commands" >&2 + echo "Reboot the system before using it again." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + return 1 + fi + fi + + if $assume_yes; then + do_reset=true + prompt_for_reset=false + fi + + if $prompt_for_reset; then + echo "All existing podman (and toolbox) containers and images will be removed." + + prompt=$(printf "Continue? [y/N]:") + if ask_for_confirmation "n" "$prompt"; then + do_reset=true + else + do_reset=false + fi + fi + + if ! $do_reset; then + return 1 + fi + + echo "$base_toolbox_command: resetting local state" >&3 + + if [ "$user_id_real" -eq 0 ] 2>&3; then + if ! rm --force --recursive /var/lib/containers/cache >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove /var/lib/containers/cache" >&2 + ret_val=1 + fi + + if ! rm --force --recursive /var/lib/containers/sigstore/* >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove the contents of /var/lib/containers/sigstore" >&2 + ret_val=1 + fi + + if ! rm --force --recursive /var/lib/containers/storage >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove /var/lib/containers/storage" >&2 + ret_val=1 + fi + else + if ! unshare_userns_rm "$HOME/.local/share/containers"; then + ret_val=1 + fi + + if ! rm --force --recursive "$HOME/.config/containers" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove $HOME/.config/containers" >&2 + ret_val=1 + fi + fi + + if ! rm --force --recursive "$HOME/.config/toolbox" >/dev/null 2>&3; then + echo "$base_toolbox_command: failed to remove $HOME/.config/toolbox" >&2 + ret_val=1 + fi + + return "$ret_val" +) + + +exit_if_extra_operand() +{ + if [ "$1" != "" ]; then + echo "$base_toolbox_command: extra operand '$1'" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + fi +} + + +exit_if_missing_argument() +{ + if [ "$2" = "" ]; then + echo "$base_toolbox_command: missing argument for '$1'" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + fi +} + + +exit_if_non_positive_argument() +{ + if ! is_integer "$2"; then + echo "$base_toolbox_command: invalid argument for '$1'" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + fi + if [ "$2" -le 0 ] 2>&3; then + echo "$base_toolbox_command: invalid argument for '$1'" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + fi +} + + +exit_if_unrecognized_option() +{ + echo "$base_toolbox_command: unrecognized option '$1'" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 +} + + +# shellcheck disable=SC2120 +forward_to_host() +( + if ! command -v flatpak-spawn >/dev/null 2>&3; then + echo "$base_toolbox_command: flatpak-spawn not found" >&2 + return 1 + fi + + eval "set -- $arguments" + + set_environment=$(create_environment_options) + + echo "$base_toolbox_command: forwarding to host:" >&3 + echo "$base_toolbox_command: $TOOLBOX_PATH" >&3 + for i in "$@"; do + echo "$base_toolbox_command: $i" >&3 + done + + # shellcheck disable=SC2086 + flatpak-spawn $set_environment --host "$TOOLBOX_PATH" "$@" 2>&3 + ret_val="$?" + + return "$ret_val" +) + + +update_container_and_image_names() +{ + [ "$release" = "" ] 2>&3 && release="$release_default" + + if [ "$base_toolbox_image" = "" ] 2>&3; then + base_toolbox_image="fedora-toolbox:$release" + else + release=$(image_reference_get_tag "$base_toolbox_image") + [ "$release" = "" ] 2>&3 && release="$release_default" + fi + + fgc="f$release" + echo "$base_toolbox_command: Fedora generational core is $fgc" >&3 + + echo "$base_toolbox_command: base image is $base_toolbox_image" >&3 + + toolbox_image=$(create_toolbox_image_name) + if ! ( + ret_val=$? + if [ "$ret_val" -ne 0 ] 2>&3; then + if [ "$ret_val" -eq 100 ] 2>&3; then + echo "$base_toolbox_command: failed to get the basename of base image $base_toolbox_image" >&2 + else + echo "$base_toolbox_command: failed to create an ID for the customized user-specific image" >&2 + fi + + exit 1 + fi + + exit 0 + ); then + return 1 + fi + + # shellcheck disable=SC2031 + if [ "$toolbox_container" = "" ]; then + toolbox_container=$(create_toolbox_container_name "$base_toolbox_image") + if ! ( + ret_val=$? + if [ "$ret_val" -ne 0 ] 2>&3; then + if [ "$ret_val" -eq 100 ] 2>&3; then + echo "$base_toolbox_command: failed to get the basename of image $base_toolbox_image" >&2 + elif [ "$ret_val" -eq 101 ] 2>&3; then + echo "$base_toolbox_command: failed to get the tag of image $base_toolbox_image" >&2 + else + echo "$base_toolbox_command: failed to create a name for the toolbox container" >&2 + fi + + exit 1 + fi + + exit 0 + ); then + return 1 + fi + + if ! container_name_is_valid "$toolbox_container"; then + echo "$base_toolbox_command: generated container name $toolbox_container is invalid" >&2 + echo "Container names must match '$container_name_regexp'." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + return 1 + fi + + toolbox_container_old_v1=$(create_toolbox_container_name "$toolbox_image") + if ! ( + ret_val=$? + if [ "$ret_val" -ne 0 ] 2>&3; then + if [ "$ret_val" -eq 100 ] 2>&3; then + echo "$base_toolbox_command: failed to get the basename of image $toolbox_image" >&2 + elif [ "$ret_val" -eq 101 ] 2>&3; then + echo "$base_toolbox_command: failed to get the tag of image $toolbox_image" >&2 + else + echo "$base_toolbox_command: failed to create a name for the toolbox container" >&2 + fi + + exit 1 + fi + + exit 0 + ); then + return 1 + fi + + toolbox_container_old_v2="$toolbox_image" + fi + + echo "$base_toolbox_command: container is $toolbox_container" >&3 + return 0 +} + + +arguments=$(save_positional_parameters "$@") + +host_id=$(get_host_id) +if [ "$host_id" = "fedora" ] 2>&3; then + release_default=$(get_host_version_id) +else + release_default="30" +fi +toolbox_container_prefix_default="fedora-toolbox" +toolbox_container_default="$toolbox_container_prefix_default-$release_default" + +while has_prefix "$1" -; do + case $1 in + --assumeyes | -y ) + assume_yes=true + ;; + -h | --help ) + if [ -f /run/.containerenv ] 2>&3; then + if ! [ -f /run/.toolboxenv ] 2>&3; then + echo "$base_toolbox_command: this is not a toolbox container" >&2 + exit 1 + fi + + # shellcheck disable=SC2119 + forward_to_host + exit + fi + + help "$2" + exit + ;; + -v | --verbose ) + exec 3>&2 + verbose=true + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift +done + +echo "$base_toolbox_command: running as real user ID $user_id_real" >&3 + +if ! toolbox_command_path=$(realpath "$0" 2>&3); then + echo "$base_toolbox_command: failed to resolve absolute path to $0" >&2 + exit 1 +fi + +echo "$base_toolbox_command: resolved absolute path for $0 to $toolbox_command_path" >&3 + +if [ -f /run/.containerenv ] 2>&3; then + if [ "$TOOLBOX_PATH" = "" ] 2>&3; then + echo "$base_toolbox_command: TOOLBOX_PATH not set" >&2 + exit 1 + fi +else + if [ "$user_id_real" -ne 0 ] 2>&3; then + echo "$base_toolbox_command: checking if /etc/subgid and /etc/subuid have entries for user $USER" >&3 + + if ! grep "^$USER:" /etc/subgid >/dev/null 2>&3 || ! grep "^$USER:" /etc/subuid >/dev/null 2>&3; then + echo "$base_toolbox_command: /etc/subgid and /etc/subuid don't have entries for user $USER" >&2 + echo "See the podman(1), subgid(5), subuid(5) and usermod(8) manuals for more" >&2 + echo "information." >&2 + exit 1 + fi + fi + + if [ "$TOOLBOX_PATH" = "" ] 2>&3; then + TOOLBOX_PATH="$toolbox_command_path" + fi +fi + +echo "$base_toolbox_command: TOOLBOX_PATH is $TOOLBOX_PATH" >&3 + +if [ "$1" = "" ]; then + echo "$base_toolbox_command: missing command" >&2 + echo >&2 + echo "These are some common commands:" >&2 + echo "create Create a new toolbox container" >&2 + echo "enter Enter an existing toolbox container" >&2 + echo "list List all existing toolbox containers and images" >&2 + echo >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 +fi + +op=$1 +shift + +if [ -f /run/.containerenv ] 2>&3; then + case $op in + create | enter | list | rm | rmi | run | help ) + if ! [ -f /run/.toolboxenv ] 2>&3; then + echo "$base_toolbox_command: this is not a toolbox container" >&2 + exit 1 + fi + + # shellcheck disable=SC2119 + forward_to_host + exit "$?" + ;; + init-container ) + init_container_home_link=false + init_container_monitor_host=false + while has_prefix "$1" -; do + case $1 in + -h | --help ) + # shellcheck disable=SC2119 + forward_to_host + exit + ;; + --home ) + shift + exit_if_missing_argument --home "$1" + init_container_home="$1" + ;; + --home-link ) + init_container_home_link=true + ;; + --monitor-host ) + init_container_monitor_host=true + ;; + --shell ) + shift + exit_if_missing_argument --shell "$1" + init_container_shell="$1" + ;; + --uid ) + shift + exit_if_missing_argument --uid "$1" + init_container_uid="$1" + ;; + --user ) + shift + exit_if_missing_argument --user "$1" + init_container_user="$1" + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + init_container \ + "$init_container_home" \ + "$init_container_home_link" \ + "$init_container_monitor_host" \ + "$init_container_shell" \ + "$init_container_uid" \ + "$init_container_user" + exit "$?" + ;; + reset ) + echo "$base_toolbox_command: The 'reset' command cannot be used inside containers" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + ;; + * ) + echo "$base_toolbox_command: unrecognized command '$op'" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + ;; + esac +fi + +if ! cgroups_version=$(get_cgroups_version); then + exit 1 +fi + +echo "$base_toolbox_command: running on a cgroups v$cgroups_version host" >&3 + +if [ "$op" != "reset" ] 2>&3; then + if ! migrate; then + exit 1 + fi +fi + +case $op in + create ) + while has_prefix "$1" -; do + case $1 in + --candidate-registry ) + registry=$registry_candidate + ;; + -c | --container ) + shift + exit_if_missing_argument --container "$1" + arg=$1 + if ! container_name_is_valid "$arg"; then + echo "$base_toolbox_command: invalid argument for '--container'" >&2 + echo "Container names must match '$container_name_regexp'." >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + fi + toolbox_container="$arg" + ;; + -h | --help ) + help "$op" + exit + ;; + -i | --image ) + shift + exit_if_missing_argument --image "$1" + base_toolbox_image=$1 + ;; + -r | --release ) + shift + exit_if_missing_argument --release "$1" + arg=$(echo "$1" | sed "s/^F\|^f//" 2>&3) + exit_if_non_positive_argument --release "$arg" + release=$arg + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + exit_if_extra_operand "$1" + if ! update_container_and_image_names; then + exit 1 + fi + if ! create false; then + exit 1 + fi + exit + ;; + enter ) + while has_prefix "$1" -; do + case $1 in + -c | --container ) + shift + exit_if_missing_argument --container "$1" + toolbox_container=$1 + ;; + -h | --help ) + help "$op" + exit + ;; + -r | --release ) + shift + exit_if_missing_argument --release "$1" + arg=$(echo "$1" | sed "s/^F\|^f//" 2>&3) + exit_if_non_positive_argument --release "$arg" + release=$arg + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + exit_if_extra_operand "$1" + if ! update_container_and_image_names; then + exit 1 + fi + enter + exit + ;; + help ) + while has_prefix "$1" -; do + case $1 in + -h | --help ) + help "$op" + exit + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + help "$1" + exit + ;; + init-container ) + while has_prefix "$1" -; do + case $1 in + -h | --help ) + help "$op" + exit + esac + shift + done + echo "$base_toolbox_command: The 'init-container' command can only be used inside containers" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 + ;; + list ) + ls_add_empty_line=false + ls_images=false + ls_containers=false + while has_prefix "$1" -; do + case $1 in + -c | --containers ) + ls_containers=true + ;; + -h | --help ) + help "$op" + exit + ;; + -i | --images ) + ls_images=true + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + exit_if_extra_operand "$1" + + if ! $ls_containers && ! $ls_images; then + ls_containers=true + ls_images=true + fi + + if $ls_images; then + if ! images=$(list_images); then + exit 1 + fi + fi + + if $ls_containers; then + if ! containers=$(list_containers); then + exit 1 + fi + fi + + if $ls_images && [ "$images" != "" ] 2>&3; then + echo "$images" + ls_add_empty_line=true + fi + + if $ls_containers && [ "$containers" != "" ] 2>&3; then + $ls_add_empty_line && echo "" + echo "$containers" + fi + + exit + ;; + reset ) + while has_prefix "$1" -; do + case $1 in + -h | --help ) + help "$op" + exit + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + exit_if_extra_operand "$1" + + reset + exit "$?" + ;; + rm | rmi ) + rm_all=false + rm_force=false + while has_prefix "$1" -; do + case $1 in + -a | --all ) + rm_all=true + ;; + -f | --force ) + rm_force=true + ;; + -h | --help ) + help "$op" + exit + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + + rm_ids="" + if $rm_all; then + exit_if_extra_operand "$1" + else + exit_if_missing_argument "$op" "$1" + while [ "$1" != "" ]; do + rm_ids="$rm_ids $1" + shift + done + fi + + rm_ids=$(echo "$rm_ids" | sed "s/^ \+//" 2>&3) + + if [ "$op" = "rm" ]; then + remove_containers "$rm_ids" "$rm_all" "$rm_force" + else + remove_images "$rm_ids" "$rm_all" "$rm_force" + fi + exit + ;; + run ) + while has_prefix "$1" -; do + case $1 in + -c | --container ) + shift + exit_if_missing_argument --container "$1" + toolbox_container=$1 + ;; + -h | --help ) + help "$op" + exit + ;; + -r | --release ) + shift + exit_if_missing_argument --release "$1" + arg=$(echo "$1" | sed "s/^F\|^f//" 2>&3) + exit_if_non_positive_argument --release "$arg" + release=$arg + ;; + * ) + exit_if_unrecognized_option "$1" + esac + shift + done + if ! update_container_and_image_names; then + exit 1 + fi + run false false true "$@" + exit + ;; + * ) + echo "$base_toolbox_command: unrecognized command '$op'" >&2 + echo "Try '$base_toolbox_command --help' for more information." >&2 + exit 1 +esac diff --git a/Makefile b/Makefile index d7fa3311d245023ff1c30d56ef27395c015c5e6f..4a0f6065a0a356134cae239fd447bf3329b56c37 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,10 @@ goarch != go env GOARCH ssh_configs != find ".ssh/config.d/" -type f \! -name '.*' | sort curl = curl --location --silent --fail download = $(curl) --output $@ +ansible-local = ansible localhost -c local -i localhost, -e "ansible_python_interpreter=$$(which python3)" all: binaries vendored generated -vendored: .config/pythonrc.py .bash_completion.d/aws .bash_completion.d/docker-compose .bash_completion.d/docker-machine.bash .bash_completion.d/docker-machine.bash .travis/travis.sh .bash_completion.d/molecule Documents/bin/rabbitmqadmin .bash_completion.d/google-cloud-sdk +vendored: .config/pythonrc.py .bash_completion.d/aws .bash_completion.d/docker-compose .bash_completion.d/docker-machine.bash .bash_completion.d/docker-machine.bash .travis/travis.sh .bash_completion.d/molecule Documents/bin/rabbitmqadmin Documents/bin/toolbox .bash_completion.d/toolbox generated: .ssh/config .bash_completion.d/helm .bash_completion.d/kops .bash_completion.d/kubectl .bash_completion.d/kompose .bash_completion.d/minikube .bash_completion.d/pipenv .bash_completion.d/pandoc .bash_completion.d/skaffold .bash_completion.d/rabbitmqadmin .ssh/localhost .ssh/localhost.pub .ssh/authorized_keys .bash_completion.d/minishift .bash_completion.d/oc .bash_completion.d/poetry binaries: $(DESTDIR)/share/bfg/bfg.jar $(DESTDIR)/bin/rke $(DESTDIR)/bin/docker-machine $(DESTDIR)/bin/packer $(DESTDIR)/bin/terraform $(DESTDIR)/bin/vault $(DESTDIR)/bin/kubectl $(DESTDIR)/bin/kops $(DESTDIR)/bin/kompose $(DESTDIR)/bin/minikube $(DESTDIR)/bin/docker-machine-driver-kvm2 $(DESTDIR)/bin/kustomize $(DESTDIR)/bin/pack $(DESTDIR)/bin/skaffold $(DESTDIR)/bin/minishift $(DESTDIR)/bin/oc $(DESTDIR)/bin/docker-machine-driver-kvm $(HELM_HOME)/plugins/helm-diff/bin/diff $(DESTDIR)/bin/gomplate $(DESTDIR)/bin/envconsul @@ -23,17 +24,17 @@ $(DESTDIR)/share/bfg/bfg.jar: $(DESTDIR)/bin/rke: mkdir -p $$(dirname $@) - -$(download) https://github.com/rancher/rke/releases/download/v0.2.2/rke_$(os)-$(goarch) + -$(download) https://github.com/rancher/rke/releases/download/v0.3.2/rke_$(os)-$(goarch) -chmod +x $@ $(DESTDIR)/bin/docker-machine: mkdir -p $$(dirname $@) - -$(download) "https://github.com/docker/machine/releases/download/v0.16.1/docker-machine-$(os)-$(arch)" + -$(download) "https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-$(os)-$(arch)" -chmod +x $@ $(DESTDIR)/bin/packer: mkdir -p $$(dirname $@) - $(curl) https://releases.hashicorp.com/packer/1.4.1/packer_1.4.1_$(os)_$(goarch).zip --output $(tempdir)/packer.zip + $(curl) https://releases.hashicorp.com/packer/1.4.5/packer_1.4.5_$(os)_$(goarch).zip --output $(tempdir)/packer.zip unzip -d $(tempdir) $(tempdir)/packer.zip install -m 755 $(tempdir)/packer $@ rm $(tempdir)/packer* @@ -47,24 +48,24 @@ $(DESTDIR)/bin/terraform: $(DESTDIR)/bin/vault: mkdir -p $$(dirname $@) - $(curl) https://releases.hashicorp.com/vault/1.1.1/vault_1.1.1_$(os)_$(goarch).zip --output $(tempdir)/vault.zip + $(curl) https://releases.hashicorp.com/vault/1.2.3/vault_1.2.3_$(os)_$(goarch).zip --output $(tempdir)/vault.zip unzip -d $(tempdir) $(tempdir)/vault.zip install -m 755 $(tempdir)/vault $@ rm $(tempdir)/vault* $(DESTDIR)/bin/kubectl: mkdir -p $$(dirname $@) - -$(download) "https://storage.googleapis.com/kubernetes-release/release/v1.14.2/bin/$(os)/$(goarch)/kubectl" + -$(download) "https://storage.googleapis.com/kubernetes-release/release/v1.16.2/bin/$(os)/$(goarch)/kubectl" -chmod +x $@ $(DESTDIR)/bin/kops: mkdir -p $$(dirname $@) - -$(download) "https://github.com/kubernetes/kops/releases/download/1.12.1/kops-$(os)-$(goarch)" + -$(download) "https://github.com/kubernetes/kops/releases/download/1.14.1/kops-$(os)-$(goarch)" -chmod +x $@ $(DESTDIR)/bin/kompose: mkdir -p $$(dirname $@) - -$(download) https://github.com/kubernetes/kompose/releases/download/v1.18.0/kompose-$(os)-$(goarch) + -$(download) https://github.com/kubernetes/kompose/releases/download/v1.19.0/kompose-$(os)-$(goarch) -chmod +x $@ $(DESTDIR)/bin/minikube: @@ -74,7 +75,7 @@ $(DESTDIR)/bin/minikube: $(DESTDIR)/bin/kustomize: mkdir -p $$(dirname $@) - -$(download) https://github.com/kubernetes-sigs/kustomize/releases/download/v2.0.3/kustomize_2.0.3_$(os)_$(goarch) + -$(download) https://github.com/kubernetes-sigs/kustomize/releases/download/v3.3.0/kustomize_3.3.0_$(os)_$(goarch) -chmod +x $@ $(DESTDIR)/bin/docker-machine-driver-kvm2: @@ -85,22 +86,22 @@ $(DESTDIR)/bin/docker-machine-driver-kvm2: $(DESTDIR)/bin/helm: mkdir -p $$(dirname $@) mkdir -p $(tempdir)/helm - -$(curl) https://storage.googleapis.com/kubernetes-helm/helm-v2.14.0-$(os)-$(goarch).tar.gz | tar -zxf - -C $(tempdir)/helm/ + -$(curl) https://storage.googleapis.com/kubernetes-helm/helm-v2.16.0-$(os)-$(goarch).tar.gz | tar -zxf - -C $(tempdir)/helm/ -install -m 755 $(tempdir)/helm/$(os)-$(goarch)/helm $@ rm -r $(tempdir)/helm $(DESTDIR)/bin/pack: mkdir -p $$(dirname $@) - -$(curl) https://github.com/buildpack/pack/releases/download/v0.2.0/pack-v0.s.0-$(os).tgz | tar -xzC $(DESTDIR)/bin/ + -$(curl) https://github.com/buildpack/pack/releases/download/v0.5.0/pack-v0.5.0-$(os).tgz | tar -xzC $(DESTDIR)/bin/ $(DESTDIR)/bin/skaffold: mkdir -p $$(dirname $@) - -$(download) https://storage.googleapis.com/skaffold/releases/v0.29.0/skaffold-$(os)-$(goarch) + -$(download) https://storage.googleapis.com/skaffold/releases/v0.41.0/skaffold-$(os)-$(goarch) -chmod +x $@ $(DESTDIR)/bin/minishift: mkdir -p $$(dirname $@) - -$(curl) https://github.com/minishift/minishift/releases/download/v1.33.0/minishift-1.33.0-$(goos)-$(goarch).tgz | tar -xzC $(tempdir) + -$(curl) https://github.com/minishift/minishift/releases/download/v1.34.1/minishift-1.34.1-$(goos)-$(goarch).tgz | tar -xzC $(tempdir) -install -m 755 $(tempdir)/minishift-*/minishift $@ -rm -r $(tempdir)/minishift-* @@ -122,23 +123,23 @@ $(HELM_HOME)/plugins/helm-diff/bin/diff: $(DESTDIR)/bin/helm $(DESTDIR)/bin/gomplate: mkdir -p $$(dirname $@) - -$(download) https://github.com/hairyhenderson/gomplate/releases/download/v3.4.1/gomplate_$(goos)-$(goarch) + -$(download) https://github.com/hairyhenderson/gomplate/releases/download/v3.5.0/gomplate_$(goos)-$(goarch) -chmod +x $@ $(DESTDIR)/bin/envconsul: mkdir -p $$(dirname $@) - -$(curl) https://releases.hashicorp.com/envconsul/0.8.0/envconsul_0.8.0_$(goos)_$(goarch).tgz | tar -xzC $$(dirname $@) -f - + -$(curl) https://releases.hashicorp.com/envconsul/0.9.0/envconsul_0.9.0_$(goos)_$(goarch).tgz | tar -xzC $$(dirname $@) -f - ## Vendored files .bash_completion.d/docker-compose: mkdir -p $$(dirname $@) - $(download) https://raw.githubusercontent.com/docker/compose/1.24.0/contrib/completion/bash/docker-compose + $(download) https://raw.githubusercontent.com/docker/compose/1.24.1/contrib/completion/bash/docker-compose .bash_completion.d/docker-machine.bash: mkdir -p $$(dirname $@) - $(download) https://raw.githubusercontent.com/docker/machine/v0.16.1/contrib/completion/bash/docker-machine.bash + $(download) https://raw.githubusercontent.com/docker/machine/v0.16.2/contrib/completion/bash/docker-machine.bash .bash_completion.d/fabric-completion.bash: mkdir -p $$(dirname $@) @@ -161,12 +162,13 @@ Documents/bin/rabbitmqadmin: $(download) https://raw.githubusercontent.com/rabbitmq/rabbitmq-management/master/bin/rabbitmqadmin chmod +x $@ -.bash_completion.d/google-cloud-sdk: - mkdir -p $$(dirname $@) - $(download) https://raw.githubusercontent.com/google-cloud-sdk/google-cloud-sdk/master/completion.bash.inc +.bash_completion.d/toolbox: + $(download) https://raw.githubusercontent.com/containers/toolbox/0.0.16/completion/bash/toolbox -.bash_completion.d/poetry: - poetry completions bash > $@ +Documents/bin/toolbox: + mkdir -p $$(dirname $@) + $(download) https://raw.githubusercontent.com/containers/toolbox/0.0.16/toolbox + chmod +x $@ ## Generated files @@ -218,7 +220,7 @@ Documents/bin/rabbitmqadmin: ssh-keygen -y -f $< > $@ .ssh/authorized_keys: .ssh/localhost.pub - ansible localhost -c local -i localhost, -m authorized_key -a "user=$$(whoami) key='$$(cat .ssh/localhost.pub)' key_options='from=\"127.0.0.1/8\"'" + $(ansible-local) -m authorized_key -a "user=$$(whoami) key='$$(cat .ssh/localhost.pub)' key_options='from=\"127.0.0.1/8\"'" .bash_completion.d/minishift: $(DESTDIR)/bin/minishift mkdir -p $$(dirname $@) @@ -227,3 +229,6 @@ Documents/bin/rabbitmqadmin: .bash_completion.d/oc: $(DESTDIR)/bin/oc mkdir -p $$(dirname $@) -$$(basename $@) completion bash > $@ + +.bash_completion.d/poetry: + poetry completions bash > $@