review-app.yml 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. .review_app_scripts:
  2. assign_port:
  3. # Assign an unprivileged port for the web server based on MR ID.
  4. - |
  5. APP_PORT=$(( $CI_MERGE_REQUEST_ID % 64000 + 1024 ))
  6. WS_PORT=$(( $APP_PORT + 1000 ))
  7. ASSETS_PORT=$(( $APP_PORT + 2000 ))
  8. echo "Assigned port number $APP_PORT."
  9. build_docker_compose_files:
  10. - !reference [.review_app_scripts, assign_port]
  11. - |
  12. echo "Creating docker compose files…"
  13. curl https://raw.githubusercontent.com/zammad/zammad-docker-compose/master/docker-compose.yml > docker-compose.yml
  14. cat - <<YML_FILE > docker-compose.review-app.yml
  15. ---
  16. version: '3.8'
  17. services:
  18. zammad-init:
  19. environment:
  20. - ZAMMAD_HTTP_TYPE=https
  21. - ZAMMAD_FQDN=${APP_FQDN}
  22. zammad-railsserver:
  23. ports:
  24. - "127.0.0.1:${APP_PORT}:3000"
  25. zammad-websocket:
  26. ports:
  27. - "127.0.0.1:${WS_PORT}:6042"
  28. zammad-backup:
  29. profiles:
  30. - do-not-start
  31. YML_FILE
  32. cat - <<ENV_FILE >> .env
  33. IMAGE_REPO=${CI_REGISTRY}/${CI_PROJECT_PATH}
  34. VERSION=${APP_NAME}
  35. NGINX_EXPOSE_PORT="127.0.0.1:${ASSETS_PORT}"
  36. ENV_FILE
  37. # cat docker-compose* .env
  38. # Check if containers were previously created, so that this is an update deployment
  39. - |
  40. APP_DEPLOYED_BEFORE=$(${DOCKER_COMPOSE_COMMAND} ps --all --quiet)
  41. if [ "$APP_DEPLOYED_BEFORE" ]
  42. then
  43. echo "This review app was previously deployed."
  44. else
  45. echo "This review app was not deployed yet."
  46. fi
  47. build_and_push_docker_image:
  48. # Build/update docker image and publish it to the GitLab container registry.
  49. - |
  50. echo "Build docker image…"
  51. docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
  52. echo -e "\\e[0Ksection_start:`date +%s`:docker_build[collapsed=true]\\r\\e[0Kdocker build"
  53. if [ ! "${SKIP_DOCKER_BUILD}" ]
  54. then
  55. docker build --pull --no-cache -t $IMAGE_URL .
  56. docker push $IMAGE_URL
  57. fi
  58. echo -e "\\e[0Ksection_end:`date +%s`:docker_build\\r\\e[0K"
  59. create_auto_wizard_json:
  60. - |
  61. cat - <<JSON_FILE > tmp/auto_wizard.json
  62. {
  63. "Token": "${CI_JOB_TOKEN}",
  64. "Users": [
  65. {
  66. "login": "admin@example.com",
  67. "firstname": "Test Admin",
  68. "lastname": "Agent",
  69. "email": "admin@example.com",
  70. "password": "${CI_MERGE_REQUEST_ID}"
  71. },
  72. {
  73. "login": "agent1@example.com",
  74. "firstname": "Agent 1",
  75. "lastname": "Test",
  76. "email": "agent1@example.com",
  77. "password": "${CI_MERGE_REQUEST_ID}",
  78. "roles": ["Agent"]
  79. }
  80. ],
  81. "Groups": [
  82. {
  83. "name": "some group1",
  84. "users": ["admin@example.com", "agent1@example.com"]
  85. },
  86. {
  87. "name": "Users",
  88. "users": ["admin@example.com", "agent1@example.com"],
  89. "signature": "default",
  90. "email_address_id": 1
  91. }
  92. ],
  93. "Channels": [
  94. {
  95. "id": 1,
  96. "area": "Email::Account",
  97. "group": "Users",
  98. "options": {
  99. "inbound": {
  100. "adapter": "imap",
  101. "options": {
  102. "host": "mx1.example.com",
  103. "user": "not_existing",
  104. "password": "not_existing",
  105. "ssl": true
  106. }
  107. },
  108. "outbound": {
  109. "adapter": "sendmail"
  110. }
  111. }
  112. }
  113. ],
  114. "EmailAddresses": [
  115. {
  116. "id": 1,
  117. "channel_id": 1,
  118. "name": "Zammad Helpdesk",
  119. "email": "zammad@localhost"
  120. }
  121. ],
  122. "Settings": [
  123. {
  124. "name": "product_name",
  125. "value": "Zammad Review App ${APP_NAME}"
  126. },
  127. {
  128. "name": "http_type",
  129. "value": "https"
  130. },
  131. {
  132. "name": "fqdn",
  133. "value": "${APP_FQDN}"
  134. },
  135. {
  136. "name": "developer_mode",
  137. "value": true
  138. }
  139. ],
  140. "TextModuleLocale": {
  141. "Locale": "de-de"
  142. }
  143. }
  144. JSON_FILE
  145. create_vhost_config:
  146. - |
  147. cat - <<VHOST_CONFIG > /etc/nginx/conf.d/vhost-includes/${APP_NAME}.conf
  148. server {
  149. listen 443 ssl http2;
  150. listen [::]:443 ssl http2;
  151. server_name ${APP_SLUG}.${SERVER_NAME};
  152. client_max_body_size 50M;
  153. location ~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png) {
  154. expires max;
  155. proxy_pass http://127.0.0.1:${ASSETS_PORT};
  156. }
  157. location / {
  158. proxy_set_header Host \$http_host;
  159. proxy_set_header CLIENT_IP \$remote_addr;
  160. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  161. proxy_set_header X-Forwarded-Proto \$scheme;
  162. # Change this line in an SSO setup
  163. proxy_set_header X-Forwarded-User "";
  164. proxy_read_timeout 300;
  165. proxy_pass http://127.0.0.1:${APP_PORT};
  166. gzip on;
  167. gzip_types text/plain text/xml text/css image/svg+xml application/javascript application/x-javascript application/json application/xml;
  168. gzip_proxied any;
  169. }
  170. # legacy web socket server
  171. location /ws {
  172. proxy_http_version 1.1;
  173. proxy_set_header Upgrade \$http_upgrade;
  174. proxy_set_header Connection "Upgrade";
  175. proxy_set_header CLIENT_IP \$remote_addr;
  176. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  177. proxy_set_header X-Forwarded-Proto \$scheme;
  178. proxy_read_timeout 86400;
  179. proxy_pass http://127.0.0.1:${WS_PORT};
  180. }
  181. # action cable
  182. location /cable {
  183. proxy_http_version 1.1;
  184. proxy_set_header Upgrade \$http_upgrade;
  185. proxy_set_header Connection "Upgrade";
  186. proxy_set_header CLIENT_IP \$remote_addr;
  187. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  188. proxy_set_header X-Forwarded-Proto \$scheme;
  189. proxy_read_timeout 86400;
  190. proxy_pass http://127.0.0.1:${APP_PORT};
  191. }
  192. }
  193. VHOST_CONFIG
  194. delete_vhost_config:
  195. - rm -f /etc/nginx/conf.d/vhost-includes/${APP_NAME}.conf
  196. reload_nginx:
  197. - sudo systemctl reload nginx.service
  198. .review-app:
  199. tags:
  200. - review-apps
  201. stage: pre
  202. cache: []
  203. variables:
  204. SERVER_NAME: review-apps.dc.zammad.com
  205. APP_SLUG: $CI_COMMIT_REF_SLUG
  206. APP_NAME: review-app-${APP_SLUG}
  207. APP_FQDN: ${APP_SLUG}.${SERVER_NAME}
  208. IMAGE_URL: ${CI_REGISTRY}/${CI_PROJECT_PATH}:${APP_NAME}
  209. DOCKER_COMPOSE_COMMAND: docker compose -f docker-compose.yml -f docker-compose.review-app.yml -p ${APP_NAME}
  210. environment:
  211. name: ${APP_NAME}
  212. url: https://${APP_FQDN}#getting_started/auto_wizard/${CI_JOB_TOKEN}
  213. rules:
  214. - if: $CI_MERGE_REQUEST_ID
  215. when: manual
  216. allow_failure: true
  217. - when: never
  218. before_script:
  219. - !reference [.review_app_scripts, build_docker_compose_files]
  220. after_script:
  221. - echo "Clean-up project build directory…" # shell runners don't clean-up, see https://gitlab.com/gitlab-org/gitlab/-/issues/243716
  222. - rm -rf $CI_PROJECT_DIR
  223. - echo "Perform docker clean-up…"
  224. - docker image prune --all --force
  225. - docker volume prune --all --force
  226. - docker network prune --force
  227. review-app:deploy:
  228. extends:
  229. - .review-app
  230. script:
  231. - !reference [.review_app_scripts, build_and_push_docker_image]
  232. # Spawn a new or update an existing docker compose application on the GitLab runner.
  233. # If starting did not complete, bring down the container again to free up resources.
  234. - |
  235. echo "Deploy review app…"
  236. ${DOCKER_COMPOSE_COMMAND} up --force-recreate --detach || FAILED=true
  237. if [ $FAILED ]
  238. then
  239. ${DOCKER_COMPOSE_COMMAND} down
  240. echo "Failed to bring up container, exiting."
  241. exit 1
  242. fi
  243. # Always provide auto_wizard.json, because we don't know when it will be activated.
  244. - !reference [.review_app_scripts, create_auto_wizard_json]
  245. - docker cp tmp/auto_wizard.json ${APP_NAME}-zammad-railsserver-1:/opt/zammad
  246. - !reference [.review_app_scripts, create_vhost_config]
  247. - !reference [.review_app_scripts, reload_nginx]
  248. environment:
  249. on_stop: review-app:stop
  250. auto_stop_in: 1 month
  251. review-app:stop:
  252. extends:
  253. - .review-app
  254. variables:
  255. GIT_STRATEGY: none
  256. script:
  257. - echo "Stop review app…"
  258. - !reference [.review_app_scripts, delete_vhost_config]
  259. - !reference [.review_app_scripts, reload_nginx]
  260. - ${DOCKER_COMPOSE_COMMAND} down
  261. environment:
  262. action: stop
  263. review-app:restart:
  264. extends:
  265. - .review-app
  266. variables:
  267. GIT_STRATEGY: none
  268. script:
  269. - echo "Restart review app…"
  270. - ${DOCKER_COMPOSE_COMMAND} restart