review-app.yml 9.0 KB

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