musare.sh 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. #!/bin/bash
  2. export PATH=/usr/local/bin:/usr/bin:/bin
  3. CYAN='\033[33;36m';
  4. RED='\033[0;31m'
  5. YELLOW='\033[0;93m'
  6. GREEN='\033[0;32m'
  7. NC='\033[0m'
  8. scriptLocation=$(dirname -- "$(readlink -fn -- "$0"; echo x)")
  9. cd "${scriptLocation%x}" || exit
  10. handleServices()
  11. {
  12. validServices=(backend frontend mongo redis)
  13. servicesArray=()
  14. invalidServices=false
  15. for x in "$@"; do
  16. if [[ ${validServices[*]} =~ (^|[[:space:]])"$x"($|[[:space:]]) ]]; then
  17. if ! [[ ${servicesArray[*]} =~ (^|[[:space:]])"$x"($|[[:space:]]) ]]; then
  18. servicesArray+=("${x}")
  19. fi
  20. else
  21. if [[ $invalidServices == false ]]; then
  22. invalidServices="${x}"
  23. else
  24. invalidServices="${invalidServices} ${x}"
  25. fi
  26. fi
  27. done
  28. if [[ $invalidServices == false && ${#servicesArray[@]} -gt 0 ]]; then
  29. echo "1|${servicesArray[*]}"
  30. elif [[ $invalidServices == false ]]; then
  31. echo "1|all"
  32. else
  33. echo "0|Invalid Service(s): ${invalidServices}"
  34. fi
  35. }
  36. dockerCommand()
  37. {
  38. validCommands=(start stop restart build ps)
  39. if [[ ${validCommands[*]} =~ (^|[[:space:]])"$2"($|[[:space:]]) ]]; then
  40. servicesString=$(handleServices "${@:3}")
  41. if [[ ${servicesString:0:1} == 1 ]]; then
  42. if [[ ${servicesString:2:4} == "all" ]]; then
  43. servicesString=""
  44. else
  45. servicesString=${servicesString:2}
  46. fi
  47. if [[ ${2} == "stop" || ${2} == "restart" ]]; then
  48. # shellcheck disable=SC2086
  49. docker-compose stop ${servicesString}
  50. fi
  51. if [[ ${2} == "start" || ${2} == "restart" ]]; then
  52. # shellcheck disable=SC2086
  53. docker-compose up -d ${servicesString}
  54. fi
  55. if [[ ${2} == "build" || ${2} == "ps" ]]; then
  56. # shellcheck disable=SC2086
  57. docker-compose "${2}" ${servicesString}
  58. fi
  59. else
  60. echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: ${1} restart [backend, frontend, mongo, redis]${NC}"
  61. fi
  62. else
  63. echo -e "${RED}Error: Invalid dockerCommand input${NC}"
  64. fi
  65. }
  66. if [[ -x "$(command -v docker)" && -x "$(command -v docker-compose)" ]]; then
  67. case $1 in
  68. start)
  69. echo -e "${CYAN}Musare | Start Services${NC}"
  70. # shellcheck disable=SC2068
  71. dockerCommand "$(basename "$0")" start ${@:2}
  72. ;;
  73. stop)
  74. echo -e "${CYAN}Musare | Stop Services${NC}"
  75. # shellcheck disable=SC2068
  76. dockerCommand "$(basename "$0")" stop ${@:2}
  77. ;;
  78. restart)
  79. echo -e "${CYAN}Musare | Restart Services${NC}"
  80. # shellcheck disable=SC2068
  81. dockerCommand "$(basename "$0")" restart ${@:2}
  82. ;;
  83. build)
  84. echo -e "${CYAN}Musare | Build Services${NC}"
  85. # shellcheck disable=SC2068
  86. dockerCommand "$(basename "$0")" build ${@:2}
  87. ;;
  88. status)
  89. echo -e "${CYAN}Musare | Service Status${NC}"
  90. # shellcheck disable=SC2068
  91. dockerCommand "$(basename "$0")" ps ${@:2}
  92. ;;
  93. reset)
  94. echo -e "${CYAN}Musare | Reset Services${NC}"
  95. servicesString=$(handleServices "${@:2}")
  96. if [[ ${servicesString:0:1} == 1 && ${servicesString:2:4} == "all" ]]; then
  97. echo -e "${GREEN}Are you sure you want to reset all data? ${YELLOW}[y,n]: ${NC}"
  98. read -r confirm
  99. if [[ "${confirm}" == y* ]]; then
  100. docker-compose stop
  101. docker-compose rm -v --force
  102. if [[ -d ".redis" ]]; then
  103. rm -rf .redis
  104. fi
  105. if [[ -d ".db" ]]; then
  106. rm -rf .db
  107. fi
  108. else
  109. echo -e "${RED}Cancelled reset${NC}"
  110. fi
  111. elif [[ ${servicesString:0:1} == 1 ]]; then
  112. echo -e "${GREEN}Are you sure you want to reset all data for $(echo "${servicesString:2}" | tr ' ' ',')? ${YELLOW}[y,n]: ${NC}"
  113. read -r confirm
  114. if [[ "${confirm}" == y* ]]; then
  115. # shellcheck disable=SC2086
  116. docker-compose stop ${servicesString:2}
  117. # shellcheck disable=SC2086
  118. docker-compose rm -v --force ${servicesString:2}
  119. if [[ "${servicesString:2}" == *redis* && -d ".redis" ]]; then
  120. rm -rf .redis
  121. fi
  122. if [[ "${servicesString:2}" == *mongo* && -d ".db" ]]; then
  123. rm -rf .db
  124. fi
  125. else
  126. echo -e "${RED}Cancelled reset${NC}"
  127. fi
  128. else
  129. echo -e "${RED}${servicesString:2}\n${YELLOW}Usage: $(basename "$0") build [backend, frontend, mongo, redis]${NC}"
  130. fi
  131. ;;
  132. attach)
  133. echo -e "${CYAN}Musare | Attach${NC}"
  134. if [[ $2 == "backend" ]]; then
  135. containerId=$(docker-compose ps -q backend)
  136. if [[ -z $containerId ]]; then
  137. echo -e "${RED}Error: Backend offline, please start to attach.${NC}"
  138. else
  139. echo -e "${YELLOW}Detach with CTRL+P+Q${NC}"
  140. docker attach "$containerId"
  141. fi
  142. elif [[ $2 == "mongo" ]]; then
  143. if [[ -f .env ]]; then
  144. # shellcheck disable=SC1091
  145. source .env
  146. if [[ -z $(docker-compose ps -q mongo) ]]; then
  147. echo -e "${RED}Error: Mongo offline, please start to attach.${NC}"
  148. else
  149. echo -e "${YELLOW}Detach with CTRL+C${NC}"
  150. docker-compose exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}"
  151. fi
  152. else
  153. echo -e "${RED}Error: .env does not exist${NC}"
  154. fi
  155. else
  156. echo -e "${RED}Invalid service $2\n${YELLOW}Usage: $(basename "$0") attach [backend,mongo]${NC}"
  157. fi
  158. ;;
  159. eslint)
  160. echo -e "${CYAN}Musare | ESLint${NC}"
  161. fix=""
  162. if [[ $2 == "fix" || $3 == "fix" || $2 == "--fix" || $3 == "--fix" ]]; then
  163. fix="--fix"
  164. echo -e "${GREEN}Auto-fix enabled${NC}"
  165. fi
  166. case $2 in
  167. frontend)
  168. docker-compose exec frontend npx eslint app/src --ext .js,.vue $fix
  169. ;;
  170. backend)
  171. docker-compose exec backend npx eslint app/logic $fix
  172. ;;
  173. ""|fix|--fix)
  174. docker-compose exec frontend npx eslint app/src --ext .js,.vue $fix
  175. docker-compose exec backend npx eslint app/logic $fix
  176. ;;
  177. *)
  178. echo -e "${RED}Invalid service $2\n${YELLOW}Usage: $(basename "$0") eslint [backend, frontend] [fix]${NC}"
  179. ;;
  180. esac
  181. ;;
  182. update)
  183. echo -e "${CYAN}Musare | Update${NC}"
  184. git fetch
  185. if [[ $(git rev-parse HEAD) == $(git rev-parse @\{u\}) ]]; then
  186. echo -e "${GREEN}Already up to date${NC}"
  187. else
  188. dbChange=$(git log --name-only --oneline HEAD..origin/"$(git rev-parse --abbrev-ref HEAD)" | grep "backend/logic/db/schemas")
  189. fcChange=$(git log --name-only --oneline HEAD..origin/"$(git rev-parse --abbrev-ref HEAD)" | grep "frontend/dist/config/template.json")
  190. bcChange=$(git log --name-only --oneline HEAD..origin/"$(git rev-parse --abbrev-ref HEAD)" | grep "backend/config/template.json")
  191. if [[ ( $2 == "auto" && -z $dbChange && -z $fcChange && -z $bcChange ) || -z $2 ]]; then
  192. echo -e "${CYAN}Updating...${NC}"
  193. git pull
  194. docker-compose build
  195. docker-compose stop
  196. docker-compose up -d
  197. echo -e "${GREEN}Updated!${NC}"
  198. if [[ -n $dbChange ]]; then
  199. echo -e "${RED}Database schema has changed, please run migration!${NC}"
  200. fi
  201. if [[ -n $fcChange ]]; then
  202. echo -e "${RED}Frontend config has changed, please update!${NC}"
  203. fi
  204. if [[ -n $bcChange ]]; then
  205. echo -e "${RED}Backend config has changed, please update!${NC}"
  206. fi
  207. elif [[ $2 == "auto" ]]; then
  208. echo -e "${RED}Auto Update Failed! Database and/or config has changed!${NC}"
  209. fi
  210. fi
  211. ;;
  212. logs)
  213. echo -e "${CYAN}Musare | Logs${NC}"
  214. docker-compose logs "${@:2}"
  215. ;;
  216. backup)
  217. echo -e "${CYAN}Musare | Backup${NC}"
  218. if [[ -f .env ]]; then
  219. # shellcheck disable=SC1091
  220. source .env
  221. if [[ -z "${BACKUP_LOCATION}" ]]; then
  222. backupLocation="${scriptLocation%x}/backups"
  223. else
  224. backupLocation="${BACKUP_LOCATION%/}"
  225. fi
  226. if [[ ! -d "${backupLocation}" ]]; then
  227. echo -e "${YELLOW}Creating backup directory at ${backupLocation}${NC}"
  228. mkdir "${backupLocation}"
  229. fi
  230. if [[ -z "${BACKUP_NAME}" ]]; then
  231. backupLocation="${backupLocation}/musare-$(date +"%Y-%m-%d-%s").dump"
  232. else
  233. backupLocation="${backupLocation}/${BACKUP_NAME}"
  234. fi
  235. echo -e "${YELLOW}Creating backup at ${backupLocation}${NC}"
  236. docker-compose exec -T mongo sh -c "mongodump --authenticationDatabase musare -u ${MONGO_USER_USERNAME} -p ${MONGO_USER_PASSWORD} -d musare --archive" > "${backupLocation}"
  237. else
  238. echo -e "${RED}Error: .env does not exist${NC}"
  239. fi
  240. ;;
  241. restore)
  242. echo -e "${CYAN}Musare | Restore${NC}"
  243. if [[ -f .env ]]; then
  244. # shellcheck disable=SC1091
  245. source .env
  246. if [[ -z $2 ]]; then
  247. echo -e "${GREEN}Please enter the full path of the dump you wish to restore: ${NC}"
  248. read -r restoreFile
  249. else
  250. restoreFile=$2
  251. fi
  252. if [[ -z ${restoreFile} ]]; then
  253. echo -e "${RED}Error: no restore path given, cancelled restoration.${NC}"
  254. elif [[ -d ${restoreFile} ]]; then
  255. echo -e "${RED}Error: restore path given is a directory, cancelled restoration.${NC}"
  256. elif [[ ! -f ${restoreFile} ]]; then
  257. echo -e "${RED}Error: no file at restore path given, cancelled restoration.${NC}"
  258. else
  259. docker-compose exec -T mongo sh -c "mongorestore --authenticationDatabase musare -u ${MONGO_USER_USERNAME} -p ${MONGO_USER_PASSWORD} --archive" < "${restoreFile}"
  260. fi
  261. else
  262. echo -e "${RED}Error: .env does not exist${NC}"
  263. fi
  264. ;;
  265. admin)
  266. echo -e "${CYAN}Musare | Add Admin${NC}"
  267. if [[ -f .env ]]; then
  268. # shellcheck disable=SC1091
  269. source .env
  270. if [[ $2 == "add" ]]; then
  271. if [[ -z $3 ]]; then
  272. echo -e "${GREEN}Please enter the username of the user you wish to make an admin: ${NC}"
  273. read -r adminUser
  274. else
  275. adminUser=$3
  276. fi
  277. if [[ -z $adminUser ]]; then
  278. echo -e "${RED}Error: Username for new admin not provided.${NC}"
  279. else
  280. docker-compose exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "db.users.update({username: '${adminUser}'}, {\$set: {role: 'admin'}})"
  281. fi
  282. elif [[ $2 == "remove" ]]; then
  283. if [[ -z $3 ]]; then
  284. echo -e "${GREEN}Please enter the username of the user you wish to remove as admin: ${NC}"
  285. read -r adminUser
  286. else
  287. adminUser=$3
  288. fi
  289. if [[ -z $adminUser ]]; then
  290. echo -e "${RED}Error: Username for new admin not provided.${NC}"
  291. else
  292. docker-compose exec mongo mongo musare -u "${MONGO_USER_USERNAME}" -p "${MONGO_USER_PASSWORD}" --eval "db.users.update({username: '${adminUser}'}, {\$set: {role: 'default'}})"
  293. fi
  294. else
  295. echo -e "${RED}Invalid command $2\n${YELLOW}Usage: $(basename "$0") admin [add,remove] username${NC}"
  296. fi
  297. else
  298. echo -e "${RED}Error: .env does not exist${NC}"
  299. fi
  300. ;;
  301. "")
  302. echo -e "${CYAN}Musare | Available Commands${NC}"
  303. echo -e "${YELLOW}start - Start services${NC}"
  304. echo -e "${YELLOW}stop - Stop services${NC}"
  305. echo -e "${YELLOW}restart - Restart services${NC}"
  306. echo -e "${YELLOW}status - Service status${NC}"
  307. echo -e "${YELLOW}logs - View logs for services${NC}"
  308. echo -e "${YELLOW}update - Update Musare${NC}"
  309. echo -e "${YELLOW}attach [backend,mongo] - Attach to backend service or mongo shell${NC}"
  310. echo -e "${YELLOW}build - Build services${NC}"
  311. echo -e "${YELLOW}eslint - Run eslint on frontend and/or backend${NC}"
  312. echo -e "${YELLOW}backup - Backup database data to file${NC}"
  313. echo -e "${YELLOW}restore - Restore database data from backup file${NC}"
  314. echo -e "${YELLOW}reset - Reset service data${NC}"
  315. echo -e "${YELLOW}admin [add,remove] - Assign/unassign admin role to/from a user${NC}"
  316. ;;
  317. *)
  318. echo -e "${CYAN}Musare${NC}"
  319. echo -e "${RED}Error: Invalid Command $1${NC}"
  320. echo -e "${CYAN}Available Commands:${NC}"
  321. echo -e "${YELLOW}start - Start services${NC}"
  322. echo -e "${YELLOW}stop - Stop services${NC}"
  323. echo -e "${YELLOW}restart - Restart services${NC}"
  324. echo -e "${YELLOW}status - Service status${NC}"
  325. echo -e "${YELLOW}logs - View logs for services${NC}"
  326. echo -e "${YELLOW}update - Update Musare${NC}"
  327. echo -e "${YELLOW}attach [backend,mongo] - Attach to backend service or mongo shell${NC}"
  328. echo -e "${YELLOW}build - Build services${NC}"
  329. echo -e "${YELLOW}eslint - Run eslint on frontend and/or backend${NC}"
  330. echo -e "${YELLOW}backup - Backup database data to file${NC}"
  331. echo -e "${YELLOW}restore - Restore database data from backup file${NC}"
  332. echo -e "${YELLOW}reset - Reset service data${NC}"
  333. echo -e "${YELLOW}admin [add,remove] - Assign/unassign admin role to/from a user${NC}"
  334. ;;
  335. esac
  336. elif [[ -x "$(command -v docker)" && ! -x "$(command -v docker-compose)" ]]; then
  337. echo -e "${RED}Error: docker-compose not installed.${NC}"
  338. elif [[ ! -x "$(command -v docker)" && -x "$(command -v docker-compose)" ]]; then
  339. echo -e "${RED}Error: docker not installed.${NC}"
  340. else
  341. echo -e "${RED}Error: docker and docker-compose not installed.${NC}"
  342. fi