podmanRunWrapper 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #!/usr/bin/env bash
  2. # shellcheck disable=SC1090,SC2004
  3. podmanRunWrapper() {
  4. ########################
  5. ###### FUNCTIONS #######
  6. ########################
  7. _printHelpAndExit() {
  8. if [[ -z $_debug ]]; then
  9. cat <<-'EOF'
  10. USAGE
  11. Argument mode:
  12. podmanRunWrapper -m MODE -o OPTIONS -i IMAGE [-n CONTAINER_NAME] [--help]
  13. [--debug] [COMMANDS [ARGS...]]
  14. Array mode (bash >= 4.3):
  15. podmanRunWrapper -a ARRAY
  16. EXAMPLE
  17. podmanRunWrapper -m ephemeral -o "-it -v $PWD:$PWD -w $PWD" -i "php:latest" -c "php ./script.php"
  18. ARRAY=( "-m" "ephemeral" "-o" "--rm -it -v $PWD:$PWD -w $PWD" "-i" "php:latest" "-c" "php ./script.php")
  19. podmanRunWrapper -a ARRAY
  20. COMMANDS
  21. COMMANDS to run in the container (e.g. the current active file, an external build script, a
  22. program residing in the container, etc.)
  23. Can be empty (run default container entrypoint)
  24. OPTIONS
  25. --mode, -m MODE
  26. MODE can be any of the following:
  27. 1. ephemeral
  28. 2. persistent
  29. 3. recreate-persistent
  30. --options, -o OPTIONS
  31. OPTIONS to pass directly to `podman run` or `podman exec` depending on the mode or
  32. container state
  33. --image, -i IMAGE
  34. IMAGE used to create the container
  35. --array, -a ARRAY
  36. Read arguments array named ARRAY (bash >= 4.3)
  37. This is useful to reduce parsing errors and recommended for build-wrapper plugins
  38. --optionsarray OPTIONS_ARRAY
  39. Read podman options from array named OPTIONS_ARRAY (bash >= 4.3)
  40. This is useful to reduce parsing errors and recommended for build-wrapper plugins
  41. --commandsarray COMMANDS_ARRAY
  42. Read container commands from array named COMMANDS_ARRAY (bash >= 4.3)
  43. This is useful to reduce parsing errors and recommended for build-wrapper plugins
  44. --name, -n CONTAINER_NAME
  45. Use the CONTAINER_NAME base to name containers (should be unique to each project)
  46. Default: Container name will be set based on a concatenation of the image and commands
  47. --selinuxfix
  48. A temporary hack to grant SELinux write access on $PWD until a better fix is found
  49. --debug, -d
  50. Print debugging
  51. --help, -h
  52. Print this help message and exit
  53. EOF
  54. fi
  55. # Exit using passed exit code
  56. [[ -z $1 ]] && exit 0 || exit "$1"
  57. }
  58. # Parse input
  59. _parseInput() {
  60. unset _mode _cmds_arr _opts_arr _options _prw_opts_arr _image _name _array _selinux_fix
  61. # Use getopt to print help
  62. if INPUT=$(getopt -o +m:o:i:x:n:a:dh -l mode:,options:,image:,name:,array:,optionsarray:,commandsarray:,selinuxfix,debug,help -- "$@"); then
  63. eval set -- "$INPUT"
  64. while true; do
  65. case "$1" in
  66. --mode|-m)
  67. shift
  68. _mode="$1"
  69. ;;
  70. --options|-o)
  71. shift
  72. _options+=("$1")
  73. ;;
  74. --image|-i)
  75. shift
  76. _image="$1"
  77. ;;
  78. --name|-n)
  79. shift
  80. _name="$1"
  81. ;;
  82. --array|-a)
  83. shift
  84. _array="$1"
  85. ;;
  86. --optionsarray)
  87. shift
  88. _opts_arr="$1"
  89. ;;
  90. --commandsarray)
  91. shift
  92. _cmds_arr="$1"
  93. ;;
  94. --selinuxfix)
  95. _selinux_fix="1"
  96. ;;
  97. --help|-h)
  98. _printHelpAndExit 0
  99. ;;
  100. --debug|-d)
  101. export _debug="1"
  102. echo "Debugging on!"
  103. ;;
  104. --)
  105. shift
  106. break
  107. ;;
  108. esac
  109. shift
  110. done
  111. else
  112. echo "Incorrect options provided!"
  113. _printHelpAndExit 1
  114. fi
  115. # If array mode, load and parse input array
  116. if [[ -n $_array ]]; then
  117. checkBashVersion
  118. local _n_array
  119. declare -n _n_array="$_array"
  120. _parseInput "${_n_array[@]}"
  121. return
  122. fi
  123. # Parse podman options from --optionsarray
  124. if [[ -n $_opts_arr ]]; then
  125. # namerefs are awesome
  126. declare -gn _prw_opts_arr="$_opts_arr"
  127. # If no array given, parse input from options
  128. elif [[ ${#_options[@]} -ge 1 ]]; then
  129. declare -ga _prw_opts_arr=("${_options[@]}")
  130. else
  131. echo "Must provide --options or the name of an existing --optionsarray"
  132. _printHelpAndExit 1
  133. fi
  134. # Parse commands
  135. if [[ -n $_cmds_arr ]]; then
  136. declare -gn _prw_cmds_arr="$_cmds_arr"
  137. else
  138. # Create COMMANDS array from remaining arguments
  139. # shift getopt parameters away
  140. shift $((OPTIND - 1))
  141. # create array
  142. declare -ga _prw_cmds_arr
  143. _prw_cmds_arr=("$@")
  144. if [[ ${#_prw_cmds_arr[@]} -lt 1 ]]; then
  145. debug "Running container without any commands"
  146. fi
  147. fi
  148. debug "_prw_opts_arr:" "${_prw_opts_arr[@]}"
  149. debug "_prw_cmds_arr:" "${_prw_cmds_arr[@]}"
  150. }
  151. _addCName() {
  152. # autogenerate _name if missing
  153. [[ -z $_name ]] && _name="${_image}${_prw_cmds_arr[*]}"
  154. # sanitize container name
  155. _name="${_name//_/}" && _name="${_name// /}" && \
  156. _name="${_name//[^a-zA-Z0-9_]/}" && _name="${_name,,}"
  157. # append flag
  158. if [[ "$_mode" == "ephemeral" ]]; then
  159. _cname="prw-e-$_name"
  160. else
  161. _cname="prw-p-$_name"
  162. fi
  163. _prw_opts_arr+=("--name" "$_cname")
  164. }
  165. _removeContainer() {
  166. if podman container exists "$1"; then
  167. debug "podman rm -v -f $1"
  168. podman rm -v -f "$1"
  169. fi
  170. }
  171. _runContainer() {
  172. # Run _remove_container first to not run in existing container
  173. if podman container exists "$1"; then
  174. debug podman exec "$1" sh -c "${_prw_cmds_arr[@]}"
  175. podman exec "$1" sh -c "${_prw_cmds_arr[@]}"
  176. exit $?
  177. else
  178. debug "Command: podman run" "${_prw_opts_arr[@]}" "$_image" sh -c "${_prw_cmds_arr[@]}"
  179. podman run "${_prw_opts_arr[@]}" "$_image" "${_prw_cmds_arr[@]}"
  180. exit $?
  181. fi
  182. }
  183. #########################
  184. ####### EXECUTE #########
  185. #########################
  186. __main() {
  187. # Get input
  188. _parseInput "$@"
  189. # Set container name
  190. _addCName
  191. # SELinux fix
  192. [[ -n $_selinux_fix ]] && fixPermissions "$PWD"
  193. # Execute podman
  194. if [[ "$_mode" =~ ^(ephemeral|recreate-persistent)$ ]]; then
  195. _removeContainer "$_cname"
  196. fi
  197. _runContainer "$_cname"
  198. }
  199. # Allow this function to be executed directly
  200. __main "$@"
  201. exit $?
  202. }
  203. # Allow script to be called directly
  204. if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
  205. _getBaseDir () {
  206. # Get base directory name of where this script resides
  207. # https://stackoverflow.com/questions/59895/how-to-get-the-source-directory-of-a-bash-script-from-within-the-script-itself#comment54598418_246128
  208. _basedir=$(dirname "$(readlink -f "$0")")
  209. }
  210. _sourceFunctions () {
  211. # Get the location of this file
  212. _getBaseDir
  213. # Go up two directories
  214. ff="${_basedir%/*/*}/functions"
  215. # Source functions file
  216. if [[ -f "$ff" ]]; then
  217. source "$ff"
  218. else
  219. echo "Cannot find functions file: ${ff}"
  220. fi
  221. }
  222. _sourceFunctions
  223. podmanRunWrapper "$@"
  224. fi