|
@@ -0,0 +1,223 @@
|
|
|
+#!/usr/bin/env bash
|
|
|
+# shellcheck disable=SC1090,SC2004
|
|
|
+#
|
|
|
+# This script/function is a wrapper for podman run/exec that will automatically handle container
|
|
|
+# creation, removal, and reuse
|
|
|
+#
|
|
|
+# MIT License
|
|
|
+# Copyright (c) 2020 Bryan Roessler
|
|
|
+# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
+# of this software and associated documentation files (the "Software"), to deal
|
|
|
+# in the Software without restriction, including without limitation the rights
|
|
|
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
+# copies of the Software, and to permit persons to whom the Software is
|
|
|
+# furnished to do so, subject to the following conditions:
|
|
|
+#
|
|
|
+# The above copyright notice and this permission notice shall be included in all
|
|
|
+# copies or substantial portions of the Software.
|
|
|
+#
|
|
|
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
+# SOFTWARE.
|
|
|
+
|
|
|
+podmanRun() {
|
|
|
+
|
|
|
+ _printHelpAndExit() {
|
|
|
+
|
|
|
+ if [[ -z $_debug ]]; then
|
|
|
+ cat <<-'EOF'
|
|
|
+USAGE
|
|
|
+ podmanRun [-m MODE] [-o OPTIONS] [COMMANDS [ARGS]...] [--help] [--debug]
|
|
|
+
|
|
|
+COMMANDS
|
|
|
+ COMMANDS to run in the container
|
|
|
+
|
|
|
+OPTIONS
|
|
|
+ --mode, -m MODE
|
|
|
+ 1. recreate (remove container if it already exists and create a new one)
|
|
|
+ 2. persistent (reuse existing container if it exists)
|
|
|
+ --options, -o OPTIONS
|
|
|
+ OPTIONS to pass to podman run/exec
|
|
|
+ Can be passed multiple times to concatenate
|
|
|
+ Will be split on whitespace
|
|
|
+ Final option should be the name of the container image
|
|
|
+ --debug, -d
|
|
|
+ Print debugging
|
|
|
+ --help, -h
|
|
|
+ Print this help message and exit
|
|
|
+
|
|
|
+EXAMPLES
|
|
|
+ Note: IDE examples are using Atom Build package placeholders.
|
|
|
+
|
|
|
+ Run an ephemeral PHP webserver container using the current directory as webroot:
|
|
|
+ podmanRun -o "-p=8000:80 --name=php_script -v=$PWD:/var/www/html:z php:7.3-apache"
|
|
|
+
|
|
|
+ Run an ephemeral PHP webserver container using the current directory as webroot using IDE:
|
|
|
+ podmanRun -o "-p=8000:80 --name=php_{FILE_ACTIVE_NAME_BASE} \
|
|
|
+ -v={FILE_ACTIVE_PATH}:/var/www/html:z php:7.3-apache"
|
|
|
+
|
|
|
+ Run an ephemeral bash script:
|
|
|
+ podmanRun -o "--name=bash_script -v=$PWD:$PWD:z -w=$PWD debian:testing" ./script.sh
|
|
|
+
|
|
|
+ Run an ephemeral bash script using IDE:
|
|
|
+ podmanRun -o "--name=bash_{FILE_ACTIVE_NAME_BASE}" \
|
|
|
+ -o "-v={FILE_ACTIVE_PATH}:{FILE_ACTIVE_PATH}:z"
|
|
|
+ -o "-w={FILE_ACTIVE_PATH}" \
|
|
|
+ -o "debian:testing" \
|
|
|
+ {FILE_ACTIVE} arg1 arg2
|
|
|
+EOF
|
|
|
+ fi
|
|
|
+
|
|
|
+ # Exit using passed exit code
|
|
|
+ [[ -z $1 ]] && exit 0 || exit "$1"
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ # Parse input
|
|
|
+ _parseInput() {
|
|
|
+
|
|
|
+ declare -g _mode _debug
|
|
|
+ declare -ga _opts_arr _cmds_arr
|
|
|
+ local INPUT
|
|
|
+
|
|
|
+ # Use getopt to print help
|
|
|
+ if INPUT=$(getopt -o +m:o:dh -l mode:,options:,debug,help -- "$@"); then
|
|
|
+ eval set -- "$INPUT"
|
|
|
+ while true; do
|
|
|
+ case "$1" in
|
|
|
+ --mode|-m)
|
|
|
+ shift
|
|
|
+ _mode="$1"
|
|
|
+ ;;
|
|
|
+ --options|-o)
|
|
|
+ shift
|
|
|
+ #
|
|
|
+ _opts_arr+=("$1")
|
|
|
+ ;;
|
|
|
+ --help|-h)
|
|
|
+ _printHelpAndExit 0
|
|
|
+ ;;
|
|
|
+ --debug|-d)
|
|
|
+ _debug="1"
|
|
|
+ echo "Debugging on!"
|
|
|
+ ;;
|
|
|
+ --)
|
|
|
+ shift
|
|
|
+ break
|
|
|
+ ;;
|
|
|
+ esac
|
|
|
+ shift
|
|
|
+ done
|
|
|
+ else
|
|
|
+ err "Incorrect options provided!"
|
|
|
+ _printHelpAndExit 1
|
|
|
+ fi
|
|
|
+
|
|
|
+ # Load remaining arguments into the commands array
|
|
|
+ shift $((OPTIND - 1))
|
|
|
+ _cmds_arr=("$@")
|
|
|
+
|
|
|
+ # Set default mode
|
|
|
+ [[ -z $_mode ]] && _mode="recreate"
|
|
|
+ # Allow mode numbers
|
|
|
+ [[ "$_mode" == "1" ]] && _mode="recreate"
|
|
|
+ [[ "$_mode" == "2" ]] && _mode="persistent"
|
|
|
+ # Sanity check
|
|
|
+ [[ ! "$_mode" =~ ^(recreate|persistent)$ ]] && err "Bad --mode" && _printHelpAndExit 1
|
|
|
+
|
|
|
+ # Split options on whitespace
|
|
|
+ # This assumes that podman options are properly formatted
|
|
|
+ # https://unix.stackexchange.com/a/519917/382539
|
|
|
+ readarray -td' ' _opts_arr < <(printf '%s' "${_opts_arr[*]}")
|
|
|
+
|
|
|
+ debug "_opts_arr:" "${_opts_arr[@]}"
|
|
|
+ debug "_cmds_arr:" "${_cmds_arr[@]}"
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ debug() { [[ -n $_debug ]] && echo "debug: " "$@"; }
|
|
|
+ err() { echo "error: $*" >&2; }
|
|
|
+
|
|
|
+
|
|
|
+ _setContainerName() {
|
|
|
+
|
|
|
+ debug "${FUNCNAME[0]}"
|
|
|
+
|
|
|
+ export _cname
|
|
|
+ local index _name
|
|
|
+
|
|
|
+ # Get user-specified container name by parsing the options array for --name
|
|
|
+ for ((index=0; index <= ${#_opts_arr[@]}; index++)); do
|
|
|
+ if [[ "${_opts_arr[index]}" == "--name" ]]; then
|
|
|
+ _name="${_opts_arr[index+1]}"
|
|
|
+ elif [[ "${_opts_arr[index]}" =~ ^--name ]]; then
|
|
|
+ _name="${_opts_arr[index]}"
|
|
|
+ _name="${_name#--name=}"
|
|
|
+ fi
|
|
|
+ done
|
|
|
+
|
|
|
+ _sanitize() {
|
|
|
+ local i="$*"; i="${i// /}" && i="${i//[^a-zA-Z0-9_]/}" && i="${i,,}"; echo "$i" ;
|
|
|
+ }
|
|
|
+
|
|
|
+ # If no --name is specified, then generate one using the opts and cmds arrays
|
|
|
+ if [[ -z $_name ]]; then
|
|
|
+ _cname="$(_sanitize "${_opts_arr[*]}${_cmds_arr[*]}")"
|
|
|
+ else
|
|
|
+ _cname="$(_sanitize "$_name")"
|
|
|
+ [[ "$_name" != "$_cname" ]] && err "You must provide a valid --name" && exit 1
|
|
|
+ fi
|
|
|
+
|
|
|
+ debug "_cname: $_cname"
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ _containerExists() { debug "${FUNCNAME[0]} $1"; podman container exists "$1"; }
|
|
|
+
|
|
|
+ _removeContainer() { debug "${FUNCNAME[0]} $1"; _containerExists "$1" && podman rm -vf "$1"; }
|
|
|
+
|
|
|
+ _runContainer() {
|
|
|
+
|
|
|
+ debug "${FUNCNAME[0]} $1"
|
|
|
+
|
|
|
+ if _containerExists "$1"; then
|
|
|
+ debug "podman exec $1 sh -c" "${_cmds_arr[@]}"
|
|
|
+ podman exec "$1" "${_cmds_arr[@]}"
|
|
|
+ else
|
|
|
+ debug "podman run" "${_opts_arr[@]}" "${_cmds_arr[@]}"
|
|
|
+ podman run "${_opts_arr[@]}" "${_cmds_arr[@]}"
|
|
|
+ fi
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ __main() {
|
|
|
+
|
|
|
+ # Get input
|
|
|
+ _parseInput "$@"
|
|
|
+
|
|
|
+ # Set _cname (container name)
|
|
|
+ _setContainerName
|
|
|
+
|
|
|
+ # Remove container if necessary
|
|
|
+ [[ "$_mode" == "recreate" ]] && _containerExists "$_cname" && _removeContainer "$_cname"
|
|
|
+
|
|
|
+ # Run or execute container
|
|
|
+ _runContainer "$_cname"
|
|
|
+
|
|
|
+ # Cleanup more reliably
|
|
|
+ [[ "$_mode" == "recreate" ]] && _containerExists "$_cname" && _removeContainer "$_cname"
|
|
|
+ }
|
|
|
+
|
|
|
+ # Allow this function to be executed directly
|
|
|
+ __main "$@"
|
|
|
+ exit $?
|
|
|
+}
|
|
|
+
|
|
|
+# Allow script to be called directly
|
|
|
+if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
|
+ podmanRun "$@"
|
|
|
+fi
|