x-labels: &oncall-labels
  - "com.grafana.oncall.env=dev"

x-user: &oncall-user "root"

x-oncall-build: &oncall-build-args
  context: ./engine
  target: ${ONCALL_IMAGE_TARGET:-dev}
  labels: *oncall-labels
  cache_from:
    - grafana/oncall:latest
    - grafana/oncall:dev

x-oncall-volumes: &oncall-volumes
  - ./engine:/etc/app
  # see all the fun answers/comments here on why we need to do this
  # tldr; using /dev/null as a default leads to a lot of fun problems
  # https://stackoverflow.com/a/60456034
  - ${ENTERPRISE_ENGINE:-/dev/null}:${ENTERPRISE_ENGINE_VOLUME_MOUNT_DEST_DIR:-/tmp/empty:ro}
  - ${SQLITE_DB_FILE:-/dev/null}:/var/lib/oncall/oncall.db
  # this is mounted for testing purposes. Some of the authorization tests
  # reference this file
  - ./grafana-plugin/src/plugin.json:/etc/grafana-plugin/src/plugin.json

x-env-files: &oncall-env-files
  - ./dev/.env.dev
  - ./dev/.env.${DB}.dev

x-env-vars: &oncall-env-vars
  BROKER_TYPE: ${BROKER_TYPE}
  GRAFANA_API_URL: http://localhost:3000
  GOOGLE_APPLICATION_CREDENTIALS: /etc/app/gcp_service_account.json
  FCM_PROJECT_ID: oncall-mobile-dev

# basically this is needed because the oncall backend containers have been configured to communicate w/ grafana via
# http://localhost:3000 (GRAFANA_API_URL). This URL is used in two scenarios:
# 1. oncall backend -> grafana API communication (happens within docker)
# 2. accessing templated URLs generated by the oncall backend - meant to be accessed via a browser on your host machine
# The alternative is to set GRAFANA_API_URL to http://grafana:3000. However, this would only work in scenario #1
# as http://grafana:3000 would not be resolvable on the host machine (without modifying /etc/hosts)
#
# by adding this extra_host entry to the oncall backend containers any calls to localhost will get routed to the docker
# gateway, onto the host machine, where localhost:3000 points to grafana
x-extra-hosts: &oncall-extra-hosts
  - "localhost:host-gateway"

services:
  oncall_ui:
    container_name: oncall_ui
    labels: *oncall-labels
    build:
      context: ./grafana-plugin
      dockerfile: Dockerfile.dev
      labels: *oncall-labels
    volumes:
      - ./grafana-plugin:/etc/app
      - node_modules_dev:/etc/app/node_modules
    profiles:
      - oncall_ui

  oncall_engine:
    container_name: oncall_engine
    labels: *oncall-labels
    build: *oncall-build-args
    restart: always
    user: *oncall-user
    command: sh -c "uwsgi --disable-logging --py-autoreload 3 --ini uwsgi.ini"
    env_file: *oncall-env-files
    environment: *oncall-env-vars
    volumes: *oncall-volumes
    extra_hosts: *oncall-extra-hosts
    ports:
      - "8080:8080"
    depends_on:
      oncall_db_migration:
        condition: service_completed_successfully
    profiles:
      - engine

  oncall_telegram_polling:
    container_name: oncall_telegram_polling
    labels: *oncall-labels
    build: *oncall-build-args
    restart: always
    user: *oncall-user
    command: sh -c "python manage.py start_telegram_polling"
    env_file: *oncall-env-files
    environment: *oncall-env-vars
    volumes: *oncall-volumes
    extra_hosts: *oncall-extra-hosts
    depends_on:
      oncall_db_migration:
        condition: service_completed_successfully
    profiles:
      - telegram_polling

  # used to invoke one-off commands, primarily from the Makefile
  # oncall_engine couldn't (easily) be used due to it's depends_on property
  # we could alternatively just use `docker run` however that would require
  # duplicating the env-files, volume mounts, etc in the Makefile
  oncall_engine_commands:
    container_name: oncall_engine_commands
    labels: *oncall-labels
    build: *oncall-build-args
    user: *oncall-user
    env_file: *oncall-env-files
    environment: *oncall-env-vars
    volumes: *oncall-volumes
    extra_hosts: *oncall-extra-hosts
    profiles:
      # no need to start this except from within the Makefile
      - _engine_commands

  oncall_celery:
    container_name: oncall_celery
    labels: *oncall-labels
    build: *oncall-build-args
    restart: always
    user: *oncall-user
    command: "python manage.py start_celery"
    env_file: *oncall-env-files
    environment: *oncall-env-vars
    volumes: *oncall-volumes
    extra_hosts: *oncall-extra-hosts
    depends_on:
      oncall_db_migration:
        condition: service_completed_successfully
    profiles:
      - engine

  flower:
    container_name: flower
    labels: *oncall-labels
    image: mher/flower:1.2.0
    environment:
      # TODO: make this work properly w/ BROKER_TYPE env var
      CELERY_BROKER_URL: "redis://redis:6379/0"
    ports:
      - "5555:5555"
    depends_on:
      oncall_celery:
        condition: service_started
    profiles:
      - engine

  oncall_db_migration:
    container_name: oncall_db_migration
    labels: *oncall-labels
    build: *oncall-build-args
    user: *oncall-user
    command: "python manage.py migrate --noinput"
    env_file: *oncall-env-files
    environment: *oncall-env-vars
    volumes: *oncall-volumes
    extra_hosts: *oncall-extra-hosts
    depends_on:
      postgres:
        condition: service_healthy
        required: false
      mysql:
        condition: service_healthy
        required: false
      rabbitmq:
        condition: service_healthy
        required: false
      redis:
        condition: service_healthy
        required: false
    profiles:
      - engine

  redis:
    container_name: redis
    labels: *oncall-labels
    image: redis:7.0.5
    restart: always
    ports:
      - "6379:6379"
    deploy:
      labels: *oncall-labels
      resources:
        limits:
          memory: 500m
          cpus: "0.5"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      timeout: 5s
      interval: 5s
      retries: 10
    volumes:
      - redisdata_dev:/data
    profiles:
      - redis

  rabbitmq:
    container_name: rabbitmq
    labels: *oncall-labels
    image: "rabbitmq:3.12.0-management"
    restart: always
    environment:
      RABBITMQ_DEFAULT_USER: "rabbitmq"
      RABBITMQ_DEFAULT_PASS: "rabbitmq"
      RABBITMQ_DEFAULT_VHOST: "/"
    ports:
      - "15672:15672"
      - "5672:5672"
    deploy:
      labels: *oncall-labels
      resources:
        limits:
          memory: 1000m
          cpus: "0.5"
    healthcheck:
      test: rabbitmq-diagnostics -q ping
      interval: 30s
      timeout: 30s
      retries: 3
    volumes:
      - rabbitmqdata_dev:/var/lib/rabbitmq
    profiles:
      - rabbitmq

  mysql:
    container_name: mysql
    labels: *oncall-labels
    image: mysql:8.0.32
    command: >-
      --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci --max_connections=1024
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: empty
      MYSQL_DATABASE: oncall_local_dev
    ports:
      - "3306:3306"
    deploy:
      labels: *oncall-labels
      resources:
        limits:
          memory: 1000m
          cpus: "0.5"
    healthcheck:
      test: "mysql -uroot -pempty oncall_local_dev -e 'select 1'"
      timeout: 20s
      retries: 10
    volumes:
      - mysqldata_dev:/var/lib/mysql
    profiles:
      - mysql

  mysql_to_create_grafana_db:
    container_name: mysql_to_create_grafana_db
    labels: *oncall-labels
    image: mysql:8.0.32
    command: >-
      bash -c "mysql -h mysql -uroot -pempty
      -e 'CREATE DATABASE IF NOT EXISTS grafana CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'"
    depends_on:
      mysql:
        condition: service_healthy
    profiles:
      - mysql

  postgres:
    container_name: postgres
    labels: *oncall-labels
    image: postgres:14.4
    restart: always
    environment:
      POSTGRES_DB: oncall_local_dev
      POSTGRES_PASSWORD: empty
      POSTGRES_INITDB_ARGS: --encoding=UTF-8
    ports:
      - "5432:5432"
    deploy:
      labels: *oncall-labels
      resources:
        limits:
          memory: 500m
          cpus: "0.5"
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - postgresdata_dev:/var/lib/postgresql/data
    profiles:
      - postgres

  postgres_to_create_grafana_db:
    container_name: postgres_to_create_grafana_db
    labels: *oncall-labels
    image: postgres:14.4
    command: >-
      bash -c "PGPASSWORD=empty psql -U postgres
      -h postgres -tc \"SELECT 1 FROM pg_database WHERE datname = 'grafana'\" | grep -q 1 || PGPASSWORD=empty psql
      -U postgres -h postgres -c \"CREATE DATABASE grafana\""
    depends_on:
      postgres:
        condition: service_healthy
    profiles:
      - postgres

  prometheus:
    container_name: prometheus
    labels: *oncall-labels
    image: prom/prometheus
    volumes:
      - ./dev/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    profiles:
      - prometheus

  grafana:
    container_name: grafana
    labels: *oncall-labels
    image: "grafana/${GRAFANA_IMAGE:-grafana:latest}"
    restart: always
    environment:
      GF_SECURITY_ADMIN_USER: oncall
      GF_SECURITY_ADMIN_PASSWORD: oncall
      GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app
      GF_FEATURE_TOGGLES_ENABLE: externalServiceAccounts
      ONCALL_API_URL: http://host.docker.internal:8080
    env_file:
      - ./dev/.env.${DB}.dev
    ports:
      - "3000:3000"
    deploy:
      labels: *oncall-labels
      resources:
        limits:
          memory: 500m
          cpus: "0.5"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - grafanadata_dev:/var/lib/grafana
      - ./grafana-plugin:/var/lib/grafana/plugins/grafana-plugin
      - ./dev/grafana/provisioning:/etc/grafana/provisioning
      - ${GRAFANA_DEV_PROVISIONING:-/dev/null}:/etc/grafana/grafana.ini
    depends_on:
      postgres:
        condition: service_healthy
        required: false
      mysql:
        condition: service_healthy
        required: false
    profiles:
      - grafana

volumes:
  redisdata_dev:
    labels: *oncall-labels
  grafanadata_dev:
    labels: *oncall-labels
  rabbitmqdata_dev:
    labels: *oncall-labels
  postgresdata_dev:
    labels: *oncall-labels
  mysqldata_dev:
    labels: *oncall-labels
  node_modules_dev:
    labels: *oncall-labels

networks:
  default:
    name: oncall_dev
    labels: *oncall-labels
