lxc.sh 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #!/usr/bin/env bash
  2. # -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
  3. # SPDX-License-Identifier: AGPL-3.0-or-later
  4. # shellcheck source=utils/lib.sh
  5. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  6. source_dot_config
  7. # ----------------------------------------------------------------------------
  8. # config
  9. # ----------------------------------------------------------------------------
  10. #
  11. # read also:
  12. # - https://lxd.readthedocs.io/en/latest/
  13. # name of https://images.linuxcontainers.org
  14. LINUXCONTAINERS_ORG_NAME="${LINUXCONTAINERS_ORG_NAME:-images}"
  15. HOST_PREFIX="${HOST_PREFIX:-searx}"
  16. TEST_IMAGES=(
  17. "$LINUXCONTAINERS_ORG_NAME:ubuntu/18.04" "ubu1804"
  18. "$LINUXCONTAINERS_ORG_NAME:ubuntu/19.04" "ubu1904"
  19. # TODO: installation of searx & filtron not yet implemented ..
  20. #
  21. #"$LINUXCONTAINERS_ORG_NAME:archlinux" "archlinux"
  22. #"$LINUXCONTAINERS_ORG_NAME:fedora/31" "fedora31"
  23. )
  24. REMOTE_IMAGES=()
  25. LOCAL_IMAGES=()
  26. for ((i=0; i<${#TEST_IMAGES[@]}; i+=2)); do
  27. REMOTE_IMAGES=("${REMOTE_IMAGES[@]}" "${TEST_IMAGES[i]}")
  28. LOCAL_IMAGES=("${LOCAL_IMAGES[@]}" "${TEST_IMAGES[i+1]}")
  29. done
  30. HOST_USER="${SUDO_USER:-$USER}"
  31. HOST_USER_ID=$(id -u "${HOST_USER}")
  32. HOST_GROUP_ID=$(id -g "${HOST_USER}")
  33. # ----------------------------------------------------------------------------
  34. usage() {
  35. # ----------------------------------------------------------------------------
  36. cat <<EOF
  37. usage::
  38. $(basename "$0") build [containers]
  39. $(basename "$0") delete [containers|subordinate]
  40. $(basename "$0") [start|stop] [containers]
  41. $(basename "$0") inspect [info|config]
  42. $(basename "$0") cmd ...
  43. build / delete
  44. :containers: build and delete all LXC containers
  45. add / delete
  46. :subordinate: lxd permission to map ${HOST_USER}'s user/group id through
  47. start/stop
  48. :containers: start/stop of all containers
  49. inspect
  50. :info: show info of all containers
  51. :config: show config of all containers
  52. cmd ...
  53. run commandline ... in all containers
  54. all LXC containers:
  55. ${LOCAL_IMAGES[@]}
  56. EOF
  57. [ ! -z "${1+x}" ] && err_msg "$1"
  58. }
  59. main() {
  60. required_commands lxc || exit
  61. local _usage="unknown or missing $1 command $2"
  62. case $1 in
  63. --source-only) ;;
  64. -h|--help) usage; exit 0;;
  65. build)
  66. sudo_or_exit
  67. case $2 in
  68. containers) build_instances ;;
  69. *) usage "$_usage"; exit 42;;
  70. esac ;;
  71. delete)
  72. sudo_or_exit
  73. case $2 in
  74. containers) delete_instances ;;
  75. subordinate) echo; del_subordinate_ids ;;
  76. *) usage "$_usage"; exit 42;;
  77. esac ;;
  78. add)
  79. sudo_or_exit
  80. case $2 in
  81. subordinate) echo; add_subordinate_ids ;;
  82. *) usage "$_usage"; exit 42;;
  83. esac ;;
  84. start|stop)
  85. sudo_or_exit
  86. case $2 in
  87. containers) lxc_cmd "$1" ;;
  88. *) usage "$_usage"; exit 42;;
  89. esac ;;
  90. inspect)
  91. sudo_or_exit
  92. case $2 in
  93. config) lxc_cmd config show;;
  94. info) lxc_cmd info;;
  95. *) usage "$_usage"; exit 42;;
  96. esac ;;
  97. cmd)
  98. sudo_or_exit
  99. shift
  100. for i in "${LOCAL_IMAGES[@]}"; do
  101. info_msg "lxc exec ${_BBlue}${HOST_PREFIX}-${i}${_creset} -- ${_BGreen}${*}${_creset}"
  102. lxc exec "${HOST_PREFIX}-${i}" -- "$@"
  103. done
  104. ;;
  105. *)
  106. usage "unknown or missing command $1"; exit 42;;
  107. esac
  108. }
  109. build_instances() {
  110. rst_title "Build LXC instances"
  111. lxc_copy_images_localy
  112. #lxc image list local: && wait_key
  113. lxc_init_containers
  114. lxc_config_containers
  115. lxc list "$HOST_PREFIX"
  116. }
  117. delete_instances() {
  118. rst_title "Delete LXC instances"
  119. echo -en "\\nLXC containers(s)::\\n\\n ${LOCAL_IMAGES[*]}\\n" | $FMT
  120. if ask_yn "Do you really want to delete all images"; then
  121. lxc_delete_containers
  122. fi
  123. # lxc list "$HOST_PREFIX"
  124. # lxc image list local: && wait_key
  125. }
  126. # images
  127. # ------
  128. lxc_copy_images_localy() {
  129. echo
  130. for ((i=0; i<${#TEST_IMAGES[@]}; i+=2)); do
  131. if lxc image info "local:${TEST_IMAGES[i+1]}" &>/dev/null; then
  132. info_msg "image ${TEST_IMAGES[i]} already copied --> ${TEST_IMAGES[i+1]}"
  133. else
  134. info_msg "copy image locally ${TEST_IMAGES[i]} --> ${TEST_IMAGES[i+1]}"
  135. lxc image copy "${TEST_IMAGES[i]}" local: \
  136. --alias "${TEST_IMAGES[i+1]}" prefix_stdout
  137. fi
  138. done
  139. }
  140. lxc_delete_images_localy() {
  141. echo
  142. for i in "${LOCAL_IMAGES[@]}"; do
  143. info_msg "delete image 'local:$i'"
  144. lxc image delete "local:$i"
  145. done
  146. #lxc image list local:
  147. }
  148. # container
  149. # ---------
  150. lxc_cmd() {
  151. echo
  152. for i in "${LOCAL_IMAGES[@]}"; do
  153. info_msg "lxc $* $HOST_PREFIX-$i"
  154. lxc "$@" "$HOST_PREFIX-$i"
  155. done
  156. }
  157. lxc_init_containers() {
  158. echo
  159. for i in "${LOCAL_IMAGES[@]}"; do
  160. if lxc info "$HOST_PREFIX-$i" &>/dev/null; then
  161. info_msg "conatiner '$HOST_PREFIX-$i' already exists"
  162. else
  163. info_msg "create conatiner instance: $HOST_PREFIX-$i"
  164. lxc init "local:$i" "$HOST_PREFIX-$i"
  165. fi
  166. done
  167. }
  168. lxc_config_containers() {
  169. echo
  170. for i in "${LOCAL_IMAGES[@]}"; do
  171. info_msg "map uid/gid from host to conatiner: $HOST_PREFIX-$i"
  172. # https://lxd.readthedocs.io/en/latest/userns-idmap/#custom-idmaps
  173. echo -e -n "uid $HOST_USER_ID 1000\\ngid $HOST_GROUP_ID 1000"\
  174. | lxc config set "$HOST_PREFIX-$i" raw.idmap -
  175. info_msg "share ${REPO_ROOT} (repo_share) from HOST into container: $HOST_PREFIX-$i"
  176. # https://lxd.readthedocs.io/en/latest/instances/#type-disk
  177. lxc config device add "$HOST_PREFIX-$i" repo_share disk \
  178. source="${REPO_ROOT}" \
  179. path="/share/$(basename "${REPO_ROOT}")"
  180. # lxc config show "$HOST_PREFIX-$i" && wait_key
  181. done
  182. }
  183. lxc_delete_containers() {
  184. echo
  185. for i in "${LOCAL_IMAGES[@]}"; do
  186. if lxc info "$HOST_PREFIX-$i" &>/dev/null; then
  187. info_msg "stop & delete instance '$HOST_PREFIX-$i'"
  188. lxc stop "$HOST_PREFIX-$i" &>/dev/null
  189. lxc delete "$HOST_PREFIX-$i" | prefix_stdout
  190. else
  191. warn_msg "instance '$HOST_PREFIX-$i' does not exist / can't delete :o"
  192. fi
  193. done
  194. }
  195. # subordinates
  196. # ------------
  197. #
  198. # see man: subgid(5), subuid(5), https://lxd.readthedocs.io/en/latest/userns-idmap
  199. #
  200. # E.g. in the HOST you have uid=1001(user) and/or gid=1001(user) ::
  201. #
  202. # root:1001:1
  203. #
  204. # in the CONTAINER::
  205. #
  206. # config:
  207. # raw.idmap: |
  208. # uid 1001 1000
  209. # gid 1001 1000
  210. add_subordinate_ids() {
  211. if grep "root:${HOST_USER_ID}:1" /etc/subuid -qs; then
  212. info_msg "lxd already has permission to map ${HOST_USER_ID}'s user/group id through"
  213. else
  214. info_msg "add lxd permission to map ${HOST_USER_ID}'s user/group id through"
  215. usermod --add-subuids "${HOST_USER_ID}-${HOST_USER_ID}" \
  216. --add-subgids "${HOST_GROUP_ID}-${HOST_GROUP_ID}" root
  217. fi
  218. }
  219. del_subordinate_ids() {
  220. local out
  221. if grep "root:${HOST_USER_ID}:1" /etc/subuid -qs; then
  222. # TODO: root user is always in use by process 1, how can we remove subordinates?
  223. info_msg "remove lxd permission to map ${HOST_USER_ID}'s user/group id through"
  224. out=$(usermod --del-subuids "${HOST_USER_ID}-${HOST_USER_ID}" --del-subgids "${HOST_GROUP_ID}-${HOST_GROUP_ID}" root 2>&1)
  225. if [ ! -z $? ]; then
  226. err_msg "$out"
  227. fi
  228. else
  229. info_msg "lxd does not have permission to map ${HOST_USER_ID}'s user/group id through"
  230. fi
  231. }
  232. # ----------------------------------------------------------------------------
  233. main "$@"
  234. # ----------------------------------------------------------------------------