Проверка конфигурации

Перед установкой платформы умного дома следует перепроверить, что в конфигурацию были внесены все требуемые изменения.
Для этого ниже приведены примеры всех полных файлов конфигурации, которые редактировались в рамках данного документа:

---
# Параметры установки платформы.
iot:
  # Имя (IP-адрес) сервера, на котором будет производиться развертывание платформы IoT.
  #  ВАЖНО!!! В 'serverName' нужно прописывать то имя (IP-адрес), по которому будет доступна платформа.
  serverName: "********.ru"
  # Содержит путь до директории, в которую будет произведена установка.
  installDir: /storage/iot
  # Ссылка на политику конфиденциальности
  privacyPolicyUrl: "https://********.ru/.well-known/privacy_policy"
  # Ссылка на базу знаний
  knowledgeBaseUrl: "https://********.ru/support/"

  # Параметры MongoDB.
  mongodb:
    # Версия MongoDB. На старом железе, не поддерживающем оптимизацию, нужно выставить значение `4`.
    version: 6
    external:
      # Если указано значение true, будет использоваться внешняя MongoDB.
      # ВАЖНО!!! MongoDB должна быть настроена, а параметры подключения нужно указать в 'addr' и 'port'.
      enable: true
      # Адрес внешней MongoDB.
      addr: "***.***.***.***:27017,***.***.***.***:27017,***.***.***.***"
      # Порт внешней MongoDB.
      port: 27017

  # Параметры WEB.
  web:
    # Порт HTTP, по которому будет осуществляться доступ в WEB.
    httpPort: 80
    # Порт HTTPS, по которому будет осуществляться доступ в WEB.
    httpsPort: 443
    # Автоматически перенаправлять запросы с порта HTTP на порт HTTPS
    redirectHttpToHttps: true
    # Нужно ли использовать HTTPS при формировании ссылок на WEB ('true' по умолчанию, при этом будет использован порт,
    # указанный в 'iot.web.httpsPort'). Если поставить в 'false', будет использован HTTP и порт,
    # указанный в 'iot.web.httpPort'.
    useHttpsByDefault: true
    nginx:
      # Максимальное число соединений, которые одновременно может открыть рабочий процесс
      worker_connections: 2048
      # Ограничение скорости обработки запросов модулем Nginx Rate Limiting
      rateLimit:
        enable: true
    certbot:
      # Использовать ли certbot для получения сертификатов Let's Encrypt.
      enable: true
      # Email владельца домена. Необходим для подтверждения валидности домена при получении сертификата Let's Encrypt.
      email: ********@********.ru
    fail2ban:
      enable: false

  # Параметры сервера отправки email.
  mail:
    smtp:
      submitter: ********@*******.ru
      password: "********"
      senderPrefix: "Сервер Eltex-SC"
      auth: "true"
      host: ********.********.ru
      port: 465
      # Протокол шифрования, используемый при подключении к серверу. Допустимые значения: none, starttls, ssl.
      protection: ssl

  # Параметры authorization server.
  authorization:
    # Уровень отладки внутри IoT Authorization Server.
    logLevel: ERROR

    # Уровень сложности captcha: easy, medium, hard
    captchaLevel: "easy"

    # Параметры для управления доступностью саморегистрации.
    selfRegistration:
      allow: true
      allowDemo: true
      allowSocialNetworks: true

    # Параметры клиентских регистраций (через соцсети).
    clientRegistrations:
      google:
        enable: false
        clientId: "GoogleClientIdChangeMe"
        clientSecret: "GoogleClientSecretChangeMe"
      microsoft:
        enable: false
        clientId: "MicrosoftClientIdChangeMe"
        clientSecret: "MicrosoftClientSecretChangeMe"
      apple:
        enable: false
        clientId: "AppleClientIdChangeMe"
        keyId: "AppleKeyIdChangeMe"
        teamId: "AppleTeamIdChangeMe"
      yandex:
        enable: true
        clientId: "********"
        clientSecret: "********"
      vk:
        enable: true
        clientId: "*********"
        clientSecret: "********"
      mailRu:
        enable: true
        clientId: "********"
        clientSecret: "********"

    skills:
      # Параметры навыка Яндекс для интеграции с Умным домом (Алисой). Отображается в карточке навыка.
      yandex:
        enabled: true
        # Параметры для Basic Authentication.
        clientId: "********"
        password: "********"
        # Id навыка, который необходимо указывать при отправке уведомлений.
        skillId: "********"
        # OAuth-токен, который необходимо указывать при отправке уведомлений.
        oauthToken: "********"

      # Параметры проекта умного дома Сбера для интеграции с Салютом. Отображается в карточке проекта.
      sber:
        enabled: true
        # Параметры для Basic Authentication.
        clientId: "********"
        password: "********"
        # Bearer-токен, который необходимо указывать при отправке уведомлений.
        bearerToken: "********"

      # Параметры проекта умного дома Mail.ru для интеграции с Марусей. Отображается в карточке проекта/приложения.
      marusya:
        enabled: true
        # Параметры для Basic Authentication.
        clientId: "********"
        password: "********"
        # App ID, который был назначен приложению VK при создании.
        appId: "********"
        # OAuth-токен, который необходимо указывать при отправке уведомлений.
        oauthToken: ""

  # Параметры платформы IoT core.
  core:
    # Уровень отладки внутри IoT Core.
    logLevel: ERROR

    # Порты платформы для подключения Z-Wave-контроллеров.
    ctlGate:
      port: 8070
      tcpPort: 8069
      sslPort: 8072

    links:
      # Нужно ли использовать HTTPS при формировании ссылок на ресурсы самой платформы (например, прошивки).
      useHttpsForApi: false
      # Нужно ли использовать HTTPS при формировании ссылок на фото с камер наблюдения.
      useHttpsForCameraLinks: true
      # Нужно ли использовать 'iot.web.httpPort'/'iot.web.httpsPort' при формировании ссылок на API.
      useUiProxyForApi: true

    push:
      firebase:
        enabled: true
      apns:
        enabled: true

    # Параметры для работы с видеосерверами
    video:
      # Параметры Flussonic.
      flussonic:
        url: ""
        apiKey: ""
        operatorId: ""
        adminLogin: ""
        motion:
          enabled: false
      # Параметры видеосервера EVI
      evi:
        url: "https://******.********.ru:10000"
        apiKey: "********"
        operatorId: ""
        adminLogin: "********"

    acquiring:
      # Период после завершения действия последней подписки, в течение которого услуга продолжает (ограниченно) действовать
      advancePeriod: 3d
      paykeeper:
        url: "CHANGE_ME"
        secret: "PaykeeperSecretChangeMe"
        user: "PaykeeperUsernameChangeMe"
        password: "PaykeeperPasswordChangeMe"

    # Настройки ИК-пульта.
    irc:
      # Время ожидания ИК-команды от пользователя
      recTimeout: 15s
      # Таймаут записи команды (отсутствия фронтов)
      cmdTimeout: 100ms

     # Настройки охраны
    guard:
      # Время, которое дается на включение FLIRS-устройств (ждем подтверждение от контроллера)
      # при постановке на охрану.
      deviceRequestDelay: 15s
      # Время, которое прибавляется ко времени задержки на очистку охранного кэша при постановке/снятии с охраны
      # на случай если охрана не завершила процесс постановки/снятия.
      # Время задержки равняется количеству охранных устройств, умноженному на deviceRequestDelay.
      clearContextExtraCacheDelay: 1m 

# Параметры установки сервисов логирования (Elasticsearch + Logstash + Kibana).
elk:
  # Нужно ли добавлять в платформу appender, отправляющий логи в logstash.
  # В нем нет необходимости, если ELK не развернут или не настроен; это лишь спровоцирует сообщения об ошибках отправки
  # в логах платформы.
  enable: true
  # Имя (IP-адрес) сервера, на котором будет развернут ELK.
  # По умолчанию совпадает с 'iot.serverName', что предполагает установку рядом с платформой (на том же хосте).
  # В таком случае хосты в инвентаре в группах [iot] и [monitoring] должны совпадать.
  serverName: "********.********.ru"
  # Директория для установки системы логирования.
  installDir: /storage/elk

# Параметры установки сервисов мониторинга (Prometheus + Grafana).
monitoring:
  # Имя (IP-адрес) сервера, на котором будут развернуты сервисы мониторинга (Prometheus + Grafana).
  # По умолчанию совпадает с 'iot.serverName', что предполагает установку рядом с платформой (на том же хосте).
  # В таком случае хосты в инвентаре в группах [iot] и [elk] должны совпадать.
  serverName: "{{ iot.serverName }}"
  # Директория для установки системы мониторинга.
  installDir: /storage/monitoring

slgate:
  # Имя сервера, на котором будет развернут SLGATE.
  # ВАЖНО!!! Нельзя использовать IP-адрес, т.к. такая схема не будет работать!
  # По умолчанию совпадает с 'iot.serverName', что предполагает установку рядом с платформой (на том же хосте).
  # В таком случае хосты в инвентаре в группах [iot] и [slgate] должны совпадать.
  serverName: "{{ iot.serverName }}"
  # Директория для установки SLGATE.
  installDir: /storage/slgate
---
# Версия контейнеров.
release: "1.34"

swarm:
  enabled: false
  # Имя stack для запуска в docker-swarm.
  stack: swarm_iot

# Имя репозитория docker registry, содержащего docker-образы для развертывания.
registry: hub.eltex-co.ru

# Список сервисов для перезапуска (при запуске плейбуков restart_*.yml).
# Можно оставить пустым, а при запуске передавать параметром командной строки.
services: []

# Нужно ли выполнять подготовку дистрибутива к установке. Этот шаг полезен при "чистой" установке
# на только что созданный сервер. Если ранее уже была выполнена установка компонентов IoT через ansible,
# то такая подготовка не требуется и этот шаг можно пропустить для экономии времени.
withDistroPreparingStep: true

# Суффикс, добавляемый к имени каждого контейнера (помогает избежать конфликта имен контейнеров).
containerNameSuffix: ""

# Суффикс, добавляемый к имени создаваемой сети docker (помогает избежать конфликта имен сетей docker).
networkNameSuffix: ""

# Параметры сервисов IoT (для docker-compose), сгруппированные по именам.
# 'enable' — должен ли присутствовать сервис в docker-compose.yml.
# 'port.map' — номер порта сервиса в сети хоста.
# 'port.export' — нужно ли выполнять маппинг порта из контейнера в сеть хоста.
# 'db.name' — имя БД, используемой сервисом (связкой сервисов).
iot:
  # Параметры мониторинга использования дискового пространства. Должны соответствовать требованию:
  # warnThreshold > criticalThreshold > 0, иначе мониторинг дискового пространства будет отключен.
  diskUsage:
    # Порог дискового пространства (в %), при достижении которого все логгеры микросервисов переводятся в режим WARN
    # (отображаются сообщения с тегами WARN и ERROR). Количество бэкапов баз уменьшается пропорционально приближению к
    # порогу criticalThreshold.
    warnThreshold: 20
    # Порог дискового пространства (в %), при достижении которого все логгеры микросервисов переводятся в режим ERROR
    # (отображаются только сообщения с тегом ERROR). Бэкапы баз не выполняются.
    criticalThreshold: 10
  # Нужно ли установить лимиты на сервисы в docker compose.
  limits:
    enable: false
  replication:
    core:
      enabled: false
      replicaCount: 1
    mqttBroker:
      enabled: false
      replicaCount: 2
    zwayproxy:
      enabled: false
      replicaCount: 1
    wsproxy:
      enabled: false
      replicaCount: 1
  mongodb:
    limits:
      enable: false
      cpus: 1.0
      memory: 4G
    port:
      map: 27017
      export: false
  broker:
    logLevel: INFO
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    external:
      # Будет ли развернут брокер на стороннем хосте.
      enable: false
      # Нужно ли устанавливать брокер на сторонний хост средствами ansible.
      install: false
      # Если установка брокера на сторонний хост будет выполняться средствами ansible, то в какую директорию.
      installDir: /storage/broker
      # Внешний адрес стороннего хоста, по которому к брокеру будут подключаться платформа и устройства.
      host: "external.broker.address"
      port:
        map: 8883
    internal:
      port:
        map: 8083
        export: false
    db:
      name: iot-broker
    jconsole:
      enable: false
      port: 32002
      # Необходимо указать адрес хоста, куда будет подключаться jconsole-клиент.
      # При развертывании докера здесь указывается адреса хоста, где работает докер.
      host: "10.20.30.40"
    hivemq:
      rootFolder: /hivemq/
  olapservice:
    logLevel: INFO
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    external:
      # Будет ли развернут olapservice на стороннем хосте.
      enable: false
      # Нужно ли устанавливать olapservice на сторонний хост средствами ansible.
      install: false
      # Если установка olapservice на сторонний хост будет выполняться средствами ansible, то в какую директорию.
      installDir: /storage/olapservice
      # Внешний адрес стороннего хоста, по которому платформа будет подключаться к olapservice'у.
      host: "external.olapservice.address"
    port:
      map: 8023
      export: false
    db:
      name: iotcore
      # Нужно ли устанавливать clickhouse (полезно для разработки olapservice).
      install: true
      limits:
        enable: false
        cpus: 1.0
        memory: 4G
      port:
        map: 8123
        export: false
  captcha:
    enable: true
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    port:
      map: 8088
      export: false
    caseSensitive: true
    allowedSizes:
      - "312x45"
      - "270x40"
    instance: "captcha:8088"
    proportion: 100
  zscaptcha:
    enable: false
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    port:
      map: 8089
      export: false
    caseSensitive: false
    instance: "zs-captcha:8089"
    proportion: 0
  authorization:
    # Развертывание окружения без auth server, полезно для разработки auth server.
    enable: true
    # API-ключ для авторизации HTTP-запросов в сервис авторизации от внешних систем, таких как Core.
    # Специальное значение 'autogenerated' означает, что apiKey будет сгенерирован в процессе установки.
    apiKey: "autogenerated"
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    external:
      host: "external.authorization.address"
    port:
      map: 8091
      export: false
      ssl:
        map: 8093
        export: false
    db:
      name: iot-authorization-server
    jconsole:
      enable: false
      port: 32003
      # Необходимо указать адрес хоста, куда будет подключаться jconsole-клиент.
      # При развертывании докера здесь указывается адрес хоста, где работает докер.
      host: "10.20.30.40"
    swagger:
      enable: false
    rabbit:
      eventQueue:
        name: platform-rpc-event-queue
      # Количество консьюмеров на стороне платформы
      platformConsumers:
        # Данный параметр не может быть больше чем maxCount.
        count: 16
        # Максимальное количество одновременных консьюмеров очереди.
        maxCount: 16
  core:
    # Развертывание окружения без платформы, полезно для разработки core.
    enable: true
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    port:
      map: 8071
      export: false
      ssl:
        map: 8073
        export: false
    db:
      name: iot-core
      # Имена устаревших БД в MongoDB, используемые платформой.
      deprecated:
        fs:
          name: iot-fs
        licenses:
          name: iot-licenses
        events:
          name: iot-events
    jconsole:
      enable: false
      port: 32001
      # Необходимо указать адрес хоста, куда будет подключаться jconsole-клиент.
      # При развертывании докера здесь указывается адрес хоста, где работает докер.
      host: "10.20.30.40"
    swagger:
      enable: false
    broker:
      # Нужно ли платформе пытаться подключиться к MQTT Broker.
      enable: true
      threadPools:
        main:
          size: 16
    olapservice:
      # Нужно ли платформе пытаться подключиться к OlapService.
      enable: true
    mjollnir:
      # URL для Mjollnir.
      url: "http://smart.eltex-co.ru:8078/api/v1"
    slgate:
      instances:
        - ********.********.ru:4443
      ignoreServerCertCheck: true
    video:
      evi:
        ignoreServerCertCheck: true
        checkEventSenderAddress: true
      # Параметры WebRTC, которые необходимы камере для формирования своих ICE-кандидатов.
      webrtc:
        # Параметры STUN-сервера.
        stun:
          # URL STUN-серверов.
          urls:
            - "stun:***.***.***.***:3478"
            - "stun:***.***.***.***:3478"
        # Параметры TURN-сервера.
        turn:
          # Параметры TURN:SFU
          sfu:
            # Принудительное включение
            force: true
            # Таймаут на ожидание ивента от EVI о начале webrtc-сессии между камерой и TURN:SFU
            eventTimeout: 10s
        # Параметры P2P
        p2p:
          # Таймаут на ожидание SDP-answer от камеры
          sdpAnswerTimeout: 60s
        # Время ожидания проверки камерой типа своего NAT
        checkCameraNatTypeTimeout: 10s
        # Время выполнения ping к host candidate клиента
        pingHostCandidateTimeout: 10s
  web:
    # Развертывание окружения без WEB, полезно для разработки web.
    enable: true
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
  hazelcast:
    clusterName: iot-core
    instanceName: iot-core-hazelcast-instance
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    external:
      port:
        map: 5701
        export: false
  rabbitmq:
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    admin:
      user: guest
      password: guest
      port:
        map: 15671
        export: false
      sslPort:
        map: 15672
        export: false
    port:
      map: 5672
      export: false
  zwayproxy:
    enable: true
    logLevel: INFO
    external:
      enable: false
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    port:
      map: 8070
      export: true
    sslPort:
      map: 8072
      export: true
    rabbit:
      queue:
        # Идентификатор очереди для отправки сообщений из прокси в платформу.
        platform: zway-proxy-platform
      exchange:
        # Идентификатор топик-коллектора.
        proxy: zway-proxy-topic-exchange
      # Количество консьюмеров на стороне платформы
      platformConsumers:
        # Данный параметр не может быть больше чем maxCount.
        count: 16
        # Максимальное количество одновременных консьюмеров очереди.
        maxCount: 16
      # Количество консьюмеров на стороне zwayProxy service
      proxyConsumers:
        # Количество одновременных консьюмеров очереди. Данный параметр не может быть больше чем maxCount.
        count: 1
        # Максимальное количество одновременных консьюмеров очереди.
        maxCount: 1
  wsproxy:
    logLevel: INFO
    maxConnections: 25000
    external:
      enable: false
      # Адрес хоста куда nginx будет проксировать запросы.
      host: "1.2.3.4"
      port: 8075
    limits:
      enable: true
      cpus: 1.0
      memory: 4G
    port:
      map: 8075
      export: true
    rabbit:
      queue:
        # Идентификатор очереди для отправки сообщений из прокси в платформу.
        platform: ws-proxy-platform
      exchange:
        # Идентификатор топик-коллектора.
        proxy: ws-proxy-topic-exchange
      # Количество консьюмеров на стороне платформы
      platformConsumers:
        # Данный параметр не может быть больше чем maxCount.
        count: 16
        # Максимальное количество одновременных консьюмеров очереди.
        maxCount: 16
      # Количество консьюмеров на стороне wsProxy service
      proxyConsumers:
        # Количество одновременных консьюмеров очереди. Данный параметр не может быть больше чем maxCount.
        count: 16
        # Максимальное количество одновременных консьюмеров очереди.
        maxCount: 16

slgate:
  db:
    name: "activator"
    user: "activator"
    password: "activator"
    port:
      map: 5432
      export: false
  vpn:
    port:
      map: 1194
    protocol: udp
    maxClients: 1024
  easyrsa:
    req:
      country: "RU"
      province: "Novosibirsk"
      city: "Novosibirsk"
      organization: "Eltex"
      organizationUnit: "EMS"
      email: "eltex@eltex-co.ru"
  activator:
    port:
      map: 8899
      export: false
  proxy:
    scheme: "https://"
    useClientCert: true
    clientCertPassword: "************"
    port:
      map: 4443

# Параметры сервисов ELK (для docker-compose), сгруппированные по именам.
# 'port.map' — номер порта сервиса в сети хоста.
# 'port.export' — нужно ли выполнять маппинг порта из контейнера в сеть хоста.
elk:
  elasticsearch:
    rest:
      port:
        map: 9200
    nodes:
      port:
        map: 9300
  logstash:
    port:
      map: 5001
    api:
      port:
        map: 9600
  kibana:
    port:
      map: 5601

# Параметры сервисов мониторинга (для docker-compose), сгруппированные по именам.
# 'port.map' — номер порта сервиса в сети хоста.
# 'port.export' — нужно ли выполнять маппинг порта из контейнера в сеть хоста.
monitoring:
  prometheus:
    port:
      map: 9090
    # Период опроса сервисов со стороны Prometheus в секундах. Небольшие значения (менее десятков секунд) значительно
    # увеличат нагрузку на сеть.
    # При изменении параметра рекомендуется поменять переменную grafana.scrapeInterval на значение не ниже указанного
    # для Prometheus, чтобы не терять метрики.
    scrapeInterval: 60
  grafana:
    port:
      map: 3000
    # Период опроса Prometheus со стороны Grafana в секундах.
    scrapeInterval: 60
  nginxExporter:
    enable: false
    port:
      map: 9113
server:
  # Доменное имя сервера, на котором развернута платформа
  name: "{{ iot.serverName }}"
  # Язык отображения событий и сообщений по умолчанию
  language: "ru"
  port: {{ iot.authorization.port.map }}
  ssl:
    port: {{ iot.authorization.port.ssl.map }}
    key: "/etc/ssl/private/authorization-server.key"
    crt: "/etc/ssl/certs/authorization-server.crt"
  ui:
    # Доменное имя сервера, на котором развернут UI (WEB)
    name: "{{ iot.serverName }}"
    # Порты UI нужны для формирования на платформе ссылок, которые пользователь сможет открыть через UI.
    port: {{ iot.web.httpPort }}
    ssl:
      port: {{ iot.web.httpsPort }}
  # Параметры для формирования ссылок на UI(WEB) и API
  links:
    # Использовать схему https:// при формировании ссылок на UI
    useHttpsForUi: {{ 'true' if iot.web.useHttpsByDefault else 'false' }}
  # Ссылка на политику конфиденциальности
  privacyPolicyUrl: "{{ iot.privacyPolicyUrl }}"
  # Конфигурация tomcat
  tomcat:
    # Время простоя соединения
    connection-timeout: 2m
    max-connections: 25000
    max-http-form-post-size: 200000B
    # Конфигурация потоков
    threads:
      # Минимальное количество потоков
      min-spare: 32
      # Максимальное количество потоков
      max: 512
      # Максимальный размер очереди задач для потоков
      max-queue-capacity: 32768

services:
  # Параметры внутренних сервисов (компонентов) платформы.
  internal:
    loginInfo:
      # Время жизни разлогиненных записей loginInfo, с даты выхода из учетной записи
      ttl: 10000d
      # Максимально допустимый интервал времени отсутствия активности со стороны пользователя
      # по истечении которого неактивные loginInfo (и привязанные к ним авторизации) автоматически разлогиниваются
      activityTimeLimit: 10000d
    user:
      guardUserPassword: "42211224"
      # Максимально допустимый интервал времени отсутствия активности со стороны пользователя
      # перед его деактивацией
      allowedInactivePeriod: 10000d
      selfRegistration:
        allow: {{ 'true' if iot.authorization.selfRegistration.allow else 'false' }}
        allowDemo: {{ 'true' if iot.authorization.selfRegistration.allowDemo else 'false' }}

  # Параметры для подключения к внешним сервисам, а также параметры внутренних сервисов (компонентов) платформы,
  # обеспечивающих работу с внешними сервисами.
  external:
    captcha:
      # Список инстансов captcha (Libre CAPTCHA, Zero Storage Captcha)
      instances: {{ captcha_instances | join(', ') }}
      proportions: {{ captcha_proportions | join(', ') }}
      level: "{{ iot.authorization.captchaLevel }}"
    hazelcast:
      instanceName: "{{ iot.hazelcast.instanceName }}"
      clusterName: "{{ iot.hazelcast.clusterName }}"
      clientNetworking:
        # Пример: "127.0.0.1:5701, 127.0.0.1:5702"
        addresses: "hazelcast:5701"
    rpc:
      rabbit:
        eventQueue:
          name: {{ iot.authorization.rabbit.eventQueue.name }}
    wsproxy:
      manager:
        replicaCheckPeriod: 5s
        replicaDeadPeriod: 15s
        connectAliveWaitPeriod: 15s
      rabbit:
        queue:
          # Идентификатор очереди для отправки сообщений из прокси в платформу.
          platform: {{ iot.wsproxy.rabbit.queue.platform }}
        exchange:
          # Идентификатор топик-коллектора.
          proxy: {{ iot.wsproxy.rabbit.exchange.proxy }}
        consumers:
          # Количество одновременных консьюмеров очереди. Данный параметр не может быть больше чем maxCount.
          count: {{ iot.wsproxy.rabbit.platformConsumers.count }}
          # Максимальное количество одновременных консьюмеров очереди.
          maxCount: {{ iot.wsproxy.rabbit.platformConsumers.maxCount }}

db:
  host: "{{ mongodb_addr }}"
  port: {{ mongodb_port }}
  user: ""
  password: ""
  database: "{{ iot.authorization.db.name }}"
  # Используется для миграции, переносящей авторизационные сущности из БД core в БД authorization server
  coreDatabase: "{{ iot.core.db.name }}"

spring:
  security:
    oauth2:
      # API-ключ для авторизации HTTP-запросов в сервис авторизации от внешних систем, таких как Core.
      apiKey: "{{ authorization_server_api_key }}"
      # Время жизни access-токена, должно быть не менее 5 сек.
      # Также нужно учесть, что authorization server добавляет запас времени 60 секунд до того, как токен будет считаться
      # просроченным. Т.о. итоговое время жизни токена: accessTokenTimeToLive + 60 сек.
      accessTokenTimeToLive: 1h
      registration-parameters:
        apple:
          keyId: "{{ iot.authorization.clientRegistrations.apple.keyId }}"
          keyFile: "/etc/eltex-sc/apple-credentials/AuthKey_{keyId}.p8"
          teamId: "{{ iot.authorization.clientRegistrations.apple.teamId }}"
        yandex:
          avatarUrl: "https://avatars.yandex.net/get-yapic/{avatarId}/islands-50"
      client-parameters:
        web-client:
          type: WEB
          password: password
          clientAuthenticationMethod: client_secret_basic
          authorizationGrantTypes:
            - authorization_code
            - password
            - refresh_token
{% if iot.web.httpsPort != 443 %}
          redirectUri: "https://{{ iot.serverName }}:{{ iot.web.httpsPort }}/ng/login"
{% else %}
          redirectUri: "https://{{ iot.serverName }}/ng/login"
{% endif %}
          allowAdminLogin: true
          allowRevokeAll: true
          integration: false
        android-client:
          type: ANDROID
          password: password
          clientAuthenticationMethod: client_secret_basic
          authorizationGrantTypes:
            - authorization_code
            - password
            - refresh_token
          redirectUri: "https://eltex.iot.app/authorization"
          allowRevokeAll: true
          integration: false
        ios-client:
          type: IOS
          password: password
          clientAuthenticationMethod: client_secret_basic
          authorizationGrantTypes:
            - authorization_code
            - password
            - refresh_token
          scopes:
            - read
            - write
            - trust
          redirectUri: "https://eltex.iot.app/authorization"
          allowRevokeAll: true
          integration: false
{% if iot.authorization.skills.yandex.enabled %}
        {{ iot.authorization.skills.yandex.clientId }}:
          type: YANDEX
          password: "{{ iot.authorization.skills.yandex.password }}"
          clientAuthenticationMethod: client_secret_post
          authorizationGrantTypes:
            - authorization_code
            - refresh_token
          redirectUri: "https://social.yandex.net/broker/redirect"
          integration: true
{% endif %}
{% if iot.authorization.skills.sber.enabled %}
        {{ iot.authorization.skills.sber.clientId }}:
          type: SBER
          password: "{{ iot.authorization.skills.sber.password }}"
          clientAuthenticationMethod: client_secret_post
          authorizationGrantTypes:
            - authorization_code
            - refresh_token
          redirectUri: "https://gateway.iot.sberdevices.ru/gateway/v1/binder/backward"
          integration: true
{% endif %}
{% if iot.authorization.skills.marusya.enabled %}
        {{ iot.authorization.skills.marusya.clientId }}:
          type: MARUSYA
          password: "{{ iot.authorization.skills.marusya.password }}"
          clientAuthenticationMethod: client_secret_post
          authorizationGrantTypes:
            - authorization_code
            - refresh_token
          redirectUri: "https://vc.go.mail.ru/smarthouse/{{ iot.authorization.skills.marusya.appId }}/callback"
          integration: true
{% endif %}
{% if iot.authorization.selfRegistration.allowSocialNetworks %}
      client:
        provider:
{% if iot.authorization.clientRegistrations.microsoft.enable %}
          microsoft:
            authorization-uri: "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?response_mode=form_post"
            token-uri: "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
            jwk-set-uri: "https://login.microsoftonline.com/consumers/discovery/v2.0/keys"
            user-info-uri: "https://graph.microsoft.com/oidc/userinfo"
            user-info-authentication-method: "header"
            user-name-attribute: "sub"
{% endif %}
{% if iot.authorization.clientRegistrations.apple.enable %}
          apple:
            authorization-uri: "https://appleid.apple.com/auth/authorize?response_mode=form_post"
            token-uri: "https://appleid.apple.com/auth/token"
            jwk-set-uri: "https://appleid.apple.com/auth/keys"
            issuer-uri: "https://appleid.apple.com"
            user-info-uri: "not_provided"
            user-name-attribute: "sub"
{% endif %}
{% if iot.authorization.clientRegistrations.yandex.enable %}
          yandex:
            authorization-uri: "https://oauth.yandex.ru/authorize"
            token-uri: "https://oauth.yandex.ru/token"
            user-info-uri: "https://login.yandex.ru/info"
            user-info-authentication-method: "header"
            user-name-attribute: "id"
{% endif %}
{% if iot.authorization.clientRegistrations.vk.enable %}
          vk:
            authorization-uri: "https://oauth.vk.com/authorize"
            token-uri: "https://oauth.vk.com/access_token"
            user-info-uri: "https://api.vk.com/method/users.get?v=5.131&fields=bdate,photo_50"
            user-info-authentication-method: "header"
            user-name-attribute: "id"
{% endif %}
{% if iot.authorization.clientRegistrations.mailRu.enable %}
          mail-ru:
            authorization-uri: "https://oauth.mail.ru/login"
            token-uri: "https://oauth.mail.ru/token"
            user-info-uri: "https://oauth.mail.ru/userinfo"
            user-info-authentication-method: "query"
            user-name-attribute: "id"
{% endif %}
        registration:
{% if iot.authorization.clientRegistrations.google.enable %}
          google:
            client-id: "{{ iot.authorization.clientRegistrations.google.clientId }}"
            client-secret: "{{ iot.authorization.clientRegistrations.google.clientSecret }}"
{% endif %}
{% if iot.authorization.clientRegistrations.microsoft.enable %}
          microsoft:
            provider: microsoft
            client-name: Microsoft
            client-id: "{{ iot.authorization.clientRegistrations.microsoft.clientId }}"
            client-secret: "{{ iot.authorization.clientRegistrations.microsoft.clientSecret }}"
            client-authentication-method: client_secret_post
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            scope:
              - openid
              - profile
              - email
{% endif %}
{% if iot.authorization.clientRegistrations.apple.enable %}
          apple:
            provider: apple
            client-name: Apple
            client-id: "{{ iot.authorization.clientRegistrations.apple.clientId }}"
            client-secret: "autogenerated"
            client-authentication-method: client_secret_post
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            scope:
              - openid
              - name
              - email
{% endif %}
{% if iot.authorization.clientRegistrations.yandex.enable %}
          yandex:
            provider: yandex
            client-name: Yandex
            client-id: "{{ iot.authorization.clientRegistrations.yandex.clientId }}"
            client-secret: "{{ iot.authorization.clientRegistrations.yandex.clientSecret }}"
            client-authentication-method: client_secret_basic
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            scope:
              - login:avatar
              - login:birthday
              - login:email
              - login:info
              - login:default_phone
{% endif %}
{% if iot.authorization.clientRegistrations.vk.enable %}
          vk:
            provider: vk
            client-name: VK
            client-id: "{{ iot.authorization.clientRegistrations.vk.clientId }}"
            client-secret: "{{ iot.authorization.clientRegistrations.vk.clientSecret }}"
            client-authentication-method: client_secret_post
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            scope:
              - email
              - phone_number
{% endif %}
{% if iot.authorization.clientRegistrations.mailRu.enable %}
          mail-ru:
            provider: mail-ru
            client-name: Mail.ru
            client-id: "{{ iot.authorization.clientRegistrations.mailRu.clientId }}"
            client-secret: "{{ iot.authorization.clientRegistrations.mailRu.clientSecret }}"
            client-authentication-method: client_secret_basic
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            scope:
              - userinfo
{% endif %}
{% endif %}
  mail:
    host: "{{ iot.mail.smtp.host }}"
    port: {{ iot.mail.smtp.port }}
    username: "{{ iot.mail.smtp.submitter }}"
    password: "{{ iot.mail.smtp.password }}"
    properties:
      mail:
        from: "{{ iot.mail.smtp.submitter }}"
        personal: "{{ iot.mail.smtp.senderPrefix }}"
        smtp:
          auth: true
{% if iot.mail.smtp.protection == "starttls" %}
          starttls:
            enable: true
            required: true
{% elif iot.mail.smtp.protection == "ssl" %}
          ssl:
            enable: true
{% endif %}
  rabbitmq:
    host: rabbitmq
    port: 5672

springdoc:
  swagger-ui:
    # Включение и отключение swagger.
    enabled: {{ 'true' if iot.authorization.swagger.enable else 'false' }}

logging:
  config: "{{ iot.logbackConfig }}"
  logback:
    dir: "/var/log/elis"
{% if elk.enable %}
  logstash:
    host: "{{ elk.serverName }}"
    port: {{ elk.logstash.port.map }}
{% endif %}
  level:
    root: {{ iot.authorization.logLevel }}
    org.springframework: WARN
    org.springframework.cache: WARN
    org.springframework.data: WARN
    org.springframework.web: WARN
    _org.springframework.web: WARN
    org.springframework.security: WARN
    org.springframework.security.oauth2: WARN
    org.springdoc: WARN
    org.mongodb: WARN
    org.apache.http: WARN
    org.thymeleaf: WARN
    io.swagger: WARN
    io.mongock: WARN
    io.micrometer: WARN
    com.hazelcast: WARN
server:
  replication:
    enabled: {{ 'true' if iot.replication.core.enabled else 'false' }}
  # Доменное имя сервера, на котором развернута платформа
  name: "{{ iot.serverName }}"
  # Язык отображения событий и сообщений по умолчанию
  language: "ru"
  port: {{ iot.core.port.map }}
  ssl:
    port: {{ iot.core.port.ssl.map }}
    key: "/etc/ssl/private/eltex-sc-api.key"
    crt: "/etc/ssl/certs/eltex-sc-api.crt"
  ui:
    # Доменное имя сервера, на котором развернут UI (WEB)
    name: "{{ iot.serverName }}"
    # Порты UI нужны для формирования на платформе ссылок, которые пользователь сможет открыть через UI.
    port: {{ iot.web.httpPort }}
    ssl:
      port: {{ iot.web.httpsPort }}
  controllerGate:
    port: {{ iot.core.ctlGate.port }}
    tcp:
      port: {{ iot.core.ctlGate.tcpPort }}
    ssl:
      port: {{ iot.core.ctlGate.sslPort }}
      key: "/etc/ssl/private/eltex-sc-ctl-gate.key"
      crt: "/etc/ssl/certs/eltex-sc-ctl-gate.crt"
  # Параметры для формирования ссылок на UI(WEB) и API
  links:
    # Использовать схему https:// при формировании ссылок на UI
    useHttpsForUi: {{ 'true' if iot.web.useHttpsByDefault else 'false' }}
    # Использовать схему https:// при формировании ссылок на API
    useHttpsForApi: {{ 'true' if iot.core.links.useHttpsForApi else 'false' }}
    # Использовать схему https:// при формировании ссылок на фото с камер
    useHttpsForCameraLinks: {{ 'true' if iot.core.links.useHttpsForCameraLinks else 'false' }}
    # Использовать ui.name вместо server.name и ui.port/ui.ssl.port вместо port/ssl.port
    # при формировании ссылок на API
    useUiProxyForApi: {{ 'true' if iot.core.links.useUiProxyForApi else 'false' }}
  # Ссылка на политику конфиденциальности
  privacyPolicyUrl: "{{ iot.privacyPolicyUrl }}"
  # Ссылка на базу знаний
  knowledgeBaseUrl: "{{ iot.knowledgeBaseUrl }}"
  # Конфигурация jetty
  jetty:
    # Время простоя соединения
    connection-idle-timeout: 2m
    max-http-form-post-size: 200000B
    # Конфигурация потоков
    threads:
      acceptors: -1
      selectors: -1
      # Время простоя потока
      idle-timeout: 2m
      # Минимальное количество потоков
      min: 32
      # Максимальное количество потоков
      max: 256
      # Максимальный размер очереди задач для потоков
      max-queue-capacity: 32768

services:
  # Параметры внутренних сервисов (компонентов) платформы.
  internal:
    alarm:
      enabled: false
    firmware:
      batch:
        maxPoolSize: 2
        corePoolSize: 1
        # Параметры ежедневной очистки БД от завершенных и отмененных планировщиков обновлений прошивки и связанных
        # Batch-задач.
        cleanup:
          enabled: true
          # Промежуток времени с момента начала задачи, после которого задача считается подлежащей удалению.
          removeAfter: 180d
      # Время ожидания обновления одного устройства
      updateTimeOut:
        mqttDevice: 10m
        zwayDevice: 2h
    controller:
      delayAnswerFromControl: 12s
      numberOfPingThreads: 1
      zway:
        logStringsLimit: 50
      zigbee:
        homed:
          device:
            # Время, которое мы ждем ответа об успешном удалении девайса, если ответа не поступило
            # генерируем timeout сообщение.
            removeTimeout: 30s
    deviceRequests:
      countAttempt: 3
    diskUsage:
      warnThreshold: {{ iot.diskUsage.warnThreshold }}
      criticalThreshold: {{ iot.diskUsage.criticalThreshold }}
    electricMeterScheduler:
      cron: "0 0/30 * * * ?"
      archive:
        cron: "0 0 17 * * ?"
    emergency:
      enabled: false
    # Настройки охраны.
    guard:
      # Время, которое дается на включение FLIRS-устройств (ждем подтверждение от контроллера)
      # при постановке на охрану.
      deviceRequestDelay: {{ iot.core.guard.deviceRequestDelay }}
      # Время, которое прибавляется ко времени задержки на очистку охранного кэша при постановке/снятия с охраны
      # на случай если охрана не завершила процесс постановки/снятия.
      # Время задержки формируется как количество охранных устройств умноженное на deviceRequestDelay.
      clearContextExtraCacheDelay: {{ iot.core.guard.clearContextExtraCacheDelay }}
    # Настройки ИК-пульта.
    irc:
      # Время ожидания ИК-команды от пользователя
      recTimeout: {{ iot.core.irc.recTimeout }}
      # Таймаут записи команды (отсутствия фронтов)
      cmdTimeout: {{ iot.core.irc.cmdTimeout }}
    meterDevice:
      enabled: false
    meterInfo:
      enabled: false
    metrics:
      refresh:
        cron: "0 0 3 * * ?"
    mqttZwayModule:
      enabled: false
    scriptEngine:
      # Предельное количество выполнений скрипта за период времени scriptTimeLimit.
      # Если запуски скрипта происходят чаще чем executionNumberLimit раз в интервал времени scriptTimeLimit,
      # то скрипт останавливается.
      frequentScript:
        executionNumberLimit: 60
        scriptTimeLimit: 1m
      # Предельное количество выполнений скриптов одного дома за период времени scriptTimeLimit.
      # Если запуски скриптов происходят чаще чем executionNumberLimit раз в интервал времени scriptTimeLimit,
      # то все скрипты дома останавливаются.
      frequentScriptsInHouse:
        executionNumberLimit: 120
        scriptTimeLimit: 2m
    # Локальные сценарии, которые работают на хабе.
    localScripts:
      # Время, через которое в случае неуспеха статус синхронизации локальных скриптов с хабом перейдет
      # в состояние FAILED
      syncStatusFailedTimeLimit: 10m
    sshDeviceModule:
      enabled: false
    support:
      entityLimits:
        # Максимальное количество открытых за последние 30 дней тикетов у одного пользователя.
        maxNumberOfOpenTickets: 30
        # Максимальное количество сообщений допустимое для обычного пользователя в чате конкретного тикета.
        maxNumberOfMessagesPerDay: 1000
        # Количество дней, через которое закрытый тикет будет удален. Используется время последнего обновления тикета.
        numberOfDaysForTicketExpired: 365d
      fileLimits:
        # Максимально допустимое количество и суммарный размер файлов (в МБ) логов, прикладываемых с UI к тикету.
        maxNumberOfUiLogFilesLinkToTicket: 2
        maxSizeOfUiLogFilesLinkToTicket: 10
        # Максимально допустимое количество и суммарный размер файлов (в МБ), приложенных пользователем к тикету.
        maxNumberOfAttachedFilesLinkToTicket: 15
        maxSizeOfAttachedFilesLinkToTicket: 15
        # Максимально допустимое количество и суммарный размер файлов (в МБ). приложенных пользователем к сообщению.
        maxNumberOfAttachedFilesLinkToMessage: 1
        maxSizeOfAttachedFilesLinkToMessage: 10
        # Максимальный размер файлов (в МБ), приложенных в чате. Наиболее старые файлы будут удалены в ходе ротации.
        maxSizeForFilesAttachedToChat: 20
        # Количество дней, после которого будут удалены все приложенные к сообщениям чата файлы.
        # Используется время последнего обновления тикета.
        numberOfDaysForExpiredAttachmentsInChat: 7d
    # Мониторинг properties устройств — счетчик их использования. По умолчанию — выключен
    monitoring:
      propertyKind:
        enabled: false
    # Параметры видеонаблюдения
    video:
      cameraScreenshot:
        maxNumberPerCamera: 100

  # Параметры для подключения к внешним сервисам, а также параметры внутренних сервисов (компонентов) платформы,
  # обеспечивающих работу с внешними сервисами.
  external:
    acquiring:
      subscriptionCheckingCron: "0 0 2 * * ?"
      # Период после завершения действия последней подписки, в течение которого услуга продолжает (ограниченно) действовать
      advancePeriod: {{ iot.core.acquiring.advancePeriod }}
      paykeeper:
        url: "{{ iot.core.acquiring.paykeeper.url }}"
        secret: "{{ iot.core.acquiring.paykeeper.secret }}"
        user: "{{ iot.core.acquiring.paykeeper.user }}"
        password: "{{ iot.core.acquiring.paykeeper.password }}"
    billing:
      cron: "0 0 0 * * ?"
      ftp:
        host: "127.0.0.1"
        port: 21
        login: "user"
        password: "password"
        workdir: "test"
    hazelcast:
      instanceName: "{{ iot.hazelcast.instanceName }}"
      clusterName: "{{ iot.hazelcast.clusterName }}"
      clientNetworking:
        # Пример: "127.0.0.1:5701, 127.0.0.1:5702"
        addresses: "hazelcast:5701"
      helper:
        # Максимальное время удержания блокировки в секундах, для процесса
        # добавления/обновления данных в карте.
        maxLockTime:
          # В качестве ключа имя карты в таком же виде, как и в HazelcastMapName. Пример: HOMED_DEVICE_ADD_CACHE: 10
          EXAMPLE_KEY: 10
        # Время в секундах, по истечению которого сущность будет удалена из карты.
        ttl:
          # В качестве ключа имя карты в таком же виде, как и в HazelcastMapName. Пример: HOMED_DEVICE_ADD_CACHE: 600
          EXAMPLE_KEY: 600
    mjollnir:
      url: "{{ iot.core.mjollnir.url }}"
      login: "platform"
      password: "platform"
    mqttBroker:
      enabled: {{ 'true' if iot.core.broker.enable else 'false' }}
      # Хост MQTT брокера, используется платформой
      host: "{{ iot.broker.external.host if iot.broker.external.enable else 'broker' }}"
      # Порт MQTT брокера, используется платформой для связи по протоколу MQTT
      port: 8883
      # Порт на котором у брокера поднимается REST API, используется платформой
      apiPort: 8083
      # Внешний URL по которому доступен MQTT брокер, передаётся MQTT клиентам
      remoteAccessURL: "{{ iot.broker.external.host if iot.broker.external.enable else iot.serverName }}:{{ iot.broker.external.port.map }}"
      # Таймаут, по достижении которого выставляется статус "Offline" mqtt устройствам
      offlineTimeout: 5m
{% if iot.replication.core.enabled %}
      shareName: "iotcore"
{% endif %}
      threadPools:
        main:
          size: {{ iot.core.broker.threadPools.main.size }}
      # В каком режиме работать с брокером.
      # true — реплицированный режим через rabbitmq.
      # false — нереплицированный через mqtt5client.
      replication:
        enabled: {{ 'true' if iot.replication.mqttBroker.enabled else 'false' }}
        rabbit:
          exchange:
            broker: "mqtt-broker-exchange"
          queue:
            platform: "mqtt-broker-platform-queue"
          consumers:
            # Количество одновременных консьюмеров очереди. Данный параметр не может быть больше чем maxCount.
            count: 4
            # Максимальное количество одновременных консьюмеров очереди.
            maxCount: 4
    olapservice:
      enabled: {{ 'true' if iot.core.olapservice.enable else 'false' }}
      host: "{{ iot.olapservice.external.host if iot.olapservice.external.enable else 'olapservice' }}"
      port: 8023
    proxy:
      enabled: false
      host: ""
      port: 8050
    push:
      firebase:
        enabled: {{ 'true' if iot.core.push.firebase.enabled else 'false' }}
        # Период между отправкой пушей, для достижения ограничения частоты отправки пушей.
        delayPushTime: 250ms
      apns:
        enabled: {{ 'true' if iot.core.push.apns.enabled else 'false' }}
      antispam:
        # Если пользователь получил последнее пуш-уведомление такого же содержания в течении указанного времени,
        # пуш не отправится.
        duplicateDelay: 0
        # Если пользователь получил последнее пуш-уведомление такого же типа в течении указанного времени,
        # пуш не отправится.
        antispamTime: 0
    skills:
      # Параметры навыка Яндекс для интеграции с Умным домом (Алисой)
      # https://yandex.ru/dev/dialogs/smart-home/doc/concepts/about.html
      yandex:
        enabled: {{ "true" if iot.authorization.skills.yandex.enabled else "false" }}
{% if iot.authorization.skills.yandex.enabled %}
        # ID навыка, который необходимо указывать при отправке уведомлений (отображается в карточке навыка)
        id: "{{ iot.authorization.skills.yandex.skillId }}"
        # Настройки клиента необходимо указать в секции oauth2.clientParameters под указанным client-id
        clientId: "{{ iot.authorization.skills.yandex.clientId }}"
        # Ссылка на API сервиса уведомлений Яндекса
        callbackUri: "https://dialogs.yandex.net/api/v1/skills"
        # OAuth-токен, который необходимо указывать при отправке уведомлений (необходимо получить через карточку навыка)
        oauthToken: "{{ iot.authorization.skills.yandex.oauthToken }}"
{% endif %}
      # Параметры проекта умного дома Сбера для интеграции с Салютом
      # https://developers.sber.ru/docs/ru/smarthome/overview
      sber:
        enabled: {{ "true" if iot.authorization.skills.sber.enabled else "false" }}
{% if iot.authorization.skills.sber.enabled %}
        # Настройки клиента необходимо указать в секции oauth2.clientParameters под указанным client-id
        clientId: "{{ iot.authorization.skills.sber.clientId }}"
        # Ссылка на API сервиса уведомлений Сбера
        callbackUri: "https://partners.iot.sberdevices.ru"
        # Bearer-токен, который необходимо указывать при отправке уведомлений (необходимо получить через карточку проекта)
        bearerToken: "{{ iot.authorization.skills.sber.bearerToken }}"
{% endif %}
      # Параметры проекта умного дома Mail.ru для интеграции с Марусей
      # https://help.mail.ru/marusia/smart_home
      marusya:
        enabled: {{ "true" if iot.authorization.skills.marusya.enabled else "false" }}
{% if iot.authorization.skills.marusya.enabled %}
        # ID приложения, который необходимо указывать при отправке уведомлений (отображается в карточке приложения)
        id: "{{ iot.authorization.skills.marusya.appId }}"
        # Настройки клиента необходимо указать в секции oauth2.clientParameters под указанным client-id
        clientId: "{{ iot.authorization.skills.marusya.clientId }}"
        # Ссылка на API сервиса уведомлений Маруси
        callbackUri: "https://vc.go.mail.ru/smarthouse/events/yandex"
        # OAuth-токен, который необходимо указывать при отправке уведомлений (необходимо получить через карточку приложения)
        oauthToken: "{{ iot.authorization.skills.marusya.oauthToken }}"
{% endif %}
    slgate:
      # Список инстансов SL-Gate, через запятую
      instances: {{ iot.core.slgate.instances | join(', ') }}
      # Параметры клиентского сертификата, используемого для авторизованного подключения к slgate
      clientKeyStoreParams:
        # Нужно ли использовать клиентский сертификат
        enable: {{ 'true' if slgate.proxy.useClientCert else 'false' }}
        # Путь до файла с форматом PKCS12, содержащего клиентский сертификат
        path: "/etc/ssl/private/slgate_client.p12"
        # Пароль от клиентского сертификата (.p12)
        password: "{{ slgate.proxy.clientCertPassword }}"
      # Максимальное количество попыток пересоздать конфиг туннеля через slgate при его невалидности.
      attemptsToRecreateTunnelConfig: 3
      # Игнорировать ошибки при проверке сертификата сервера (полезно при работе с самоподписанными сертификатами)
      ignoreServerCertCheck: {{ 'true' if iot.core.slgate.ignoreServerCertCheck else 'false' }}
    video:
      flussonic:
        # Адрес Flussonic
        url: "{{ iot.core.video.flussonic.url }}"
        # Ключ для авторизации запросов
        apiKey: "{{ iot.core.video.flussonic.apiKey }}"
        # Идентификатор платформы flussonic (30620).
        operatorId: "{{ iot.core.video.flussonic.operatorId }}"
        # Логин администратора в платформе flussonic watcher.
        adminLogin: "{{ iot.core.video.flussonic.adminLogin }}"
        motion:
          enabled: {{ 'true' if iot.core.video.flussonic.motion.enabled else 'false' }}
      evi:
        # Адрес EVI Cloud
        url: "{{ iot.core.video.evi.url }}"
        # Ключ для авторизации запросов
        apiKey: "{{ iot.core.video.evi.apiKey }}"
        # Логин администратора в платформе EVI Cloud.
        adminLogin: "{{ iot.core.video.evi.adminLogin }}"
        # Запас по времени для motionDelay, гарантирующий обнаружение ключевого кадра в буфере.
        motionDelayTimeReserve: 5s
        # Игнорировать ошибки при проверке сертификата сервера (полезно при работе с самоподписанными сертификатами)
        ignoreServerCertCheck: {{ 'true' if iot.core.video.evi.ignoreServerCertCheck else 'false' }}
        # Нужно ли проверять IP-адрес отправителя ивента на соответствие IP-адресу EVI Cloud перед его обработкой
        checkEventSenderAddress: {{ 'true' if iot.core.video.evi.checkEventSenderAddress else 'false' }}
        clipMaxDuration:
          timeout: 180s
      # Параметры WebRTC, которые необходимы камере для формирования своих ICE-кандидатов.
      webrtc:
        # Параметры STUN-сервера.
        stun:
          # URL STUN-серверов.
          urls:
{% for stun_url in iot.core.video.webrtc.stun.urls %}
            - "{{ stun_url }}"
{% endfor %}
        # Параметры TURN-сервера.
        turn:
          # Параметры TURN:SFU
          sfu:
            # Принудительное включение
            force: {{ 'true' if iot.core.video.webrtc.turn.sfu.force else 'false' }}
            # Таймаут на ожидание ивента от EVI о начале webrtc-сессии между камерой и TURN:SFU
            eventTimeout: {{ iot.core.video.webrtc.turn.sfu.eventTimeout }}
        # Параметры P2P
        p2p:
          # Таймаут на ожидание SDP-answer от камеры
          sdpAnswerTimeout: {{ iot.core.video.webrtc.p2p.sdpAnswerTimeout }}
        # Время ожидания проверки камерой типа своего NAT
        checkCameraNatTypeTimeout: {{ iot.core.video.webrtc.checkCameraNatTypeTimeout }}
        # Время выполнения ping к host candidate клиента
        pingHostCandidateTimeout: {{ iot.core.video.webrtc.pingHostCandidateTimeout }}
    auth:
      enabled: true
      host: "{{ 'authorization-server' if iot.authorization.enable else iot.authorization.external.host }}"
      port: {{ iot.authorization.port.map }}
      # Ключ для авторизации запросов
      apiKey: "{{ authorization_server_api_key }}"
      rabbit:
        eventQueue:
          name: {{ iot.authorization.rabbit.eventQueue.name }}
        consumers:
          # Количество одновременных консьюмеров очереди. Данный параметр не может быть больше чем maxCount.
          count: {{ iot.authorization.rabbit.platformConsumers.count }}
          # Максимальное количество одновременных консьюмеров очереди.
          maxCount: {{ iot.authorization.rabbit.platformConsumers.maxCount }}
    wsproxy:
      rabbit:
        exchange:
          # Идентификатор топик-коллектора.
          proxy: {{ iot.wsproxy.rabbit.exchange.proxy }}
    zwayproxy:
      enabled: {{ 'true' if iot.zwayproxy.enable else 'false' }}
      manager:
        replicaCheckPeriod: 5s
        replicaDeadPeriod: 15s
        connectAliveWaitPeriod: 15s
      rabbit:
        queue:
          # Идентификатор очереди для отправки сообщений из прокси в платформу.
          platform: {{ iot.zwayproxy.rabbit.queue.platform }}
        exchange:
          # Идентификатор топик-коллектора.
          proxy: {{ iot.zwayproxy.rabbit.exchange.proxy }}
        consumers:
          # Количество одновременных консьюмеров очереди. Данный параметр не может быть больше чем maxCount.
          count: {{ iot.zwayproxy.rabbit.platformConsumers.count }}
          # Максимальное количество одновременных консьюмеров очереди.
          maxCount: {{ iot.zwayproxy.rabbit.platformConsumers.maxCount }}

triggers:
  embeddedThreadPool:
    corePoolSize: 2
    maxPoolSize: 4
    # Максимальное время, когда количество потоков превышает количество ядер,
    # в течение которого лишние простаивающие потоки будут ждать новых задач перед завершением.
    keepAliveTime: 4s
  rabbit:
    oneTime:
      # Идентификатор коллектора для отправки отложенных сообщений платформы самой себе.
      exchange: platform-triggers-oneTime-exchange
      # Идентификатор очереди для отправки отложенных сообщений платформы самой себе.
      queue: platform-triggers-oneTime-queue
    broadcast:
      # Идентификатор коллектора для отправки отложенных сообщений платформы самой себе в broadcast-режиме.
      exchange: platform-triggers-broadcast-exchange
      # Идентификатор очереди для отправки отложенных сообщений платформы самой себе в broadcast-режиме.
      queue: platform-triggers-broadcast-queue
    consumers:
      # Количество одновременных консьюмеров очереди. Данный параметр не может быть больше чем maxCount.
      count: 1
      # Максимальное количество одновременных консьюмеров очереди.
      maxCount: 1
  mqttDevices:
    # Таймаут от создания MQTT устройства со статусом "VIRTUAL" до его перехода в статус "ONLINE"
    # в конце хендшейка платформы с устройством через брокер. По истечении таймаута устройство будет удалено.
    virtualStatusTimeout: 10m
    # Таймаут от начала регистрации MQTT камеры на EVI Cloud до ее успешного добавления на EVI Cloud и платформу.
    # При превышении таймаута камера будет удалена.
    cameraInitializationOnEviTimeout: 10m
    # Таймаут от отправки команды на MQTT-устройство с ожиданием синхронного ответа.
    requestTimeout: 20s
  localPlatform:
    # Таймаут от отключения всех мобильных websocket сессий до переведения туннеля локальной платформы в sleep
    mobileWebsocketOfflineTimeout: 10m
    # Таймаут от создания окружения (дом, контроллер, параметры локальной платформы) для локальной платформы,
    # до добавления устройства
    initializationTimeout: 10m

db:
  # Основная база данных iot-core
  core:
    host: "{{ mongodb_addr }}:{{ mongodb_port }}/{{ iot.core.db.name }}?socketTimeoutMS=20000&replicaSet=iotRepl&w=majority&appName="
    port: {{ mongodb_port }}
    user: ""
    password: ""
    database: "{{ iot.core.db.name }}"
  #todo Удалить блок в #225317
  file:
    host: "{{ mongodb_addr }}"
    port: {{ mongodb_port }}
    user: ""
    password: ""
    database: "{{ iot.core.db.deprecated.fs.name }}"
  #todo Удалить блок в #225317
  license:
    host: "{{ mongodb_addr }}"
    port: {{ mongodb_port }}
    user: ""
    password: ""
    database: "{{ iot.core.db.deprecated.licenses.name }}"
  #todo Удалить блок в #225317
  eventLog:
    host: "{{ mongodb_addr }}"
    port: {{ mongodb_port }}
    user: ""
    password: ""
    database: "{{ iot.core.db.deprecated.events.name }}"

spring:
  mail:
    host: "{{ iot.mail.smtp.host }}"
    port: {{ iot.mail.smtp.port }}
    username: "{{ iot.mail.smtp.submitter }}"
    password: "{{ iot.mail.smtp.password }}"
    properties:
      mail:
        from: "{{ iot.mail.smtp.submitter }}"
        personal: "{{ iot.mail.smtp.senderPrefix }}"
        smtp:
          auth: true
{% if iot.mail.smtp.protection == "starttls" %}
          starttls:
            enable: true
            required: true
{% elif iot.mail.smtp.protection == "ssl" %}
          ssl:
            enable: true
{% endif %}
  kafka:
    enabled: false
    producer:
      bootstrap-servers: "localhost:9092"
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
  rabbitmq:
    host: rabbitmq
    port: 5672

springdoc:
  swagger-ui:
    # Включение и отключение swagger.
    enabled: {{ 'true' if iot.core.swagger.enable else 'false' }}
    # При вводе корректного key открываются скрытые пункты в swagger.
    key: ""

logging:
  config: "{{ iot.logbackConfig }}"
  logback:
    dir: "/var/log/eltex-sc"
{% if elk.enable %}
  logstash:
    host: "{{ elk.serverName }}"
    port: {{ elk.logstash.port.map }}
{% endif %}
  level:
    root: {{ iot.core.logLevel }}
    org.springframework: WARN
    org.springframework.cache: WARN
    org.springframework.data: WARN
    org.springframework.web: WARN
    _org.springframework.web: WARN
    org.springframework.security: WARN
    org.springframework.security.oauth2: WARN
    org.springdoc: WARN
    org.mongodb: WARN
    org.eclipse.jetty: WARN
    org.apache.http: WARN
    org.hibernate: WARN
    org.jboss: WARN
    org.quartz.core.QuartzSchedulerThread: WARN
    org.thymeleaf: WARN
    io.swagger: WARN
    io.github.resilience4j: WARN
    io.netty: WARN
    io.mongock: WARN
    io.micrometer: WARN
    com.hazelcast: WARN
    com.hivemq: WARN
services:

{% if not iot.mongodb.external.enable %}
{% include "templates/iot/docker-compose/db/include/docker-compose.yml.j2" ignore missing %}
{% endif %}


{% if not iot.broker.external.enable %}
{% include "templates/iot/docker-compose/broker/include/docker-compose.yml.j2" ignore missing %}
{% endif %}

  # ----------------------------------------------------- Hazelcast ----------------------------------------------------

  hazelcast:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-hazelcast:{{ release }}"
    container_name: "iot-hazelcast{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.hazelcast.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.hazelcast.limits.cpus }}'
          memory: {{ iot.hazelcast.limits.memory }}
{% endif %}
    environment:
      - HZ_CLUSTERNAME={{ iot.hazelcast.clusterName }}
      - HZ_INSTANCENAME={{ iot.hazelcast.instanceName }}
{% if iot.hazelcast.external.port.export %}
    ports:
      - {{ iot.hazelcast.external.port.map }}:5701
{% endif %}
    restart: unless-stopped

  # ----------------------------------------------------- RabbitMQ -----------------------------------------------------

  rabbitmq:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-rabbitmq:{{ release }}"
    container_name: "iot-rabbitmq{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.rabbitmq.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.rabbitmq.limits.cpus }}'
          memory: {{ iot.rabbitmq.limits.memory }}
{% endif %}
    environment:
      - RABBITMQ_DEFAULT_USER={{ iot.rabbitmq.admin.user }}
      - RABBITMQ_DEFAULT_PASS={{ iot.rabbitmq.admin.password }}
    healthcheck:
      test: rabbitmq-diagnostics -q ping
      interval: 30s
      timeout: 10s
      retries: 3
{% if iot.rabbitmq.port.export or iot.zwayproxy.external.enable or iot.wsproxy.external.enable or iot.rabbitmq.admin.port.export or iot.rabbitmq.admin.sslPort.export %}
    ports:
{% if iot.rabbitmq.port.export or iot.zwayproxy.external.enable or iot.wsproxy.external.enable %}
      - {{ iot.rabbitmq.port.map }}:5672
{% endif %}
{% if iot.rabbitmq.admin.port.export %}
      - {{ iot.rabbitmq.admin.port.map }}:15671
{% endif %}
{% if iot.rabbitmq.admin.sslPort.export %}
      - {{ iot.rabbitmq.admin.sslPort.map }}:15672
{% endif %}
{% endif %}
    restart: unless-stopped

  # ---------------------------------------------------- ZwayProxy -----------------------------------------------------

{% if iot.zwayproxy.enable and not iot.zwayproxy.external.enable %}
  zwayproxy:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-zwayproxy:{{ release }}"
    container_name: "iot-zwayproxy{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.zwayproxy.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.zwayproxy.limits.cpus }}'
          memory: {{ iot.zwayproxy.limits.memory }}
{% endif %}
    depends_on:
      rabbitmq:
        condition: service_healthy
    environment:
      - spring.rabbitmq.host=rabbitmq
      - zwayproxy.rabbit.queue.platform={{ iot.zwayproxy.rabbit.queue.platform }}
      - zwayproxy.rabbit.queue.proxy=zway-proxy-1
      - zwayproxy.rabbit.exchange.proxy={{ iot.zwayproxy.rabbit.exchange.proxy }}
      - zwayproxy.rabbit.consumers.count={{ iot.zwayproxy.rabbit.proxyConsumers.count }}
      - zwayproxy.rabbit.consumers.maxCount={{ iot.zwayproxy.rabbit.proxyConsumers.maxCount }}
      - logging.level.root={{ iot.zwayproxy.logLevel }}
      - logging.config={{ iot.logbackConfig }}
{% if elk.enable %}
      - logging.logstash.host={{ elk.serverName }}
      - logging.logstash.port={{ elk.logstash.port.map }}
{% endif %}
    volumes:
      - "{{ install_dir }}/zwayproxy/var/log/elis:/var/log/elis"
{% if iot.zwayproxy.port.export or iot.zwayproxy.sslPort.export %}
    ports:
{% if iot.zwayproxy.port.export %}
      - {{ iot.zwayproxy.port.map }}:8070
{% endif %}
{% if iot.zwayproxy.sslPort.export %}
      - {{ iot.zwayproxy.sslPort.map }}:8072
{% endif %}
{% endif %}
    restart: unless-stopped
{% endif %}

  # ------------------------------------------------------ WSProxy -----------------------------------------------------

{% if not iot.wsproxy.external.enable %}
  wsproxy:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-wsproxy:{{ release }}"
    container_name: "iot-wsproxy{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.wsproxy.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.wsproxy.limits.cpus }}'
          memory: {{ iot.wsproxy.limits.memory }}
{% endif %}
    depends_on:
      rabbitmq:
        condition: service_healthy
    environment:
      - server.tomcat.max-connections={{ iot.wsproxy.maxConnections }}
      - spring.rabbitmq.host=rabbitmq
      - wsproxy.rabbit.queue.platform={{ iot.wsproxy.rabbit.queue.platform }}
      - wsproxy.rabbit.queue.proxy=ws-proxy-1
      - wsproxy.rabbit.exchange.proxy={{ iot.wsproxy.rabbit.exchange.proxy }}
      - wsproxy.rabbit.consumers.count={{ iot.wsproxy.rabbit.proxyConsumers.count }}
      - wsproxy.rabbit.consumers.maxCount={{ iot.wsproxy.rabbit.proxyConsumers.maxCount }}
      - logging.level.root={{ iot.wsproxy.logLevel }}
      - logging.config={{ iot.logbackConfig }}
{% if elk.enable %}
      - logging.logstash.host={{ elk.serverName }}
      - logging.logstash.port={{ elk.logstash.port.map }}
{% endif %}
    volumes:
      - "{{ install_dir }}/wsproxy/var/log/elis:/var/log/elis"
{% if iot.wsproxy.port.export %}
    ports:
      - {{ iot.wsproxy.port.map }}:8075
{% endif %}
    restart: unless-stopped
{% endif %}

{% if not iot.olapservice.external.enable or (not iot.olapservice.external.install and iot.olapservice.db.install) %}
{% include "templates/iot/docker-compose/olapservice/include/db/docker-compose.yml.j2" ignore missing %}
{% endif %}


{% if not iot.olapservice.external.enable %}
{% include "templates/iot/docker-compose/olapservice/include/docker-compose.yml.j2" ignore missing %}
{% endif %}

  # ----------------------------------------------------- Captcha ------------------------------------------------------

{% if iot.captcha.enable %}
  captcha:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-captcha:{{ release }}"
    container_name: "iot-captcha{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.captcha.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.captcha.limits.cpus }}'
          memory: {{ iot.captcha.limits.memory }}
{% endif %}
    environment:
      - TZ={{ timezone.stdout }}
    volumes:
      - "{{ install_dir }}/captcha/data:/lc-core/data"
{% if iot.captcha.port.export %}
    ports:
      - {{ iot.captcha.port.map }}:8088
{% endif %}
    restart: unless-stopped
{% endif %}

{% if iot.zscaptcha.enable %}
  zs-captcha:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-zs-captcha:{{ release }}"
    container_name: "iot-zs-captcha{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.zscaptcha.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.zscaptcha.limits.cpus }}'
          memory: {{ iot.zscaptcha.limits.memory }}
{% endif %}
    environment:
      - TZ={{ timezone.stdout }}
      - CAPTCHA_CASE_SENSITIVE={{ 'true' if iot.zscaptcha.caseSensitive else 'false' }}
    volumes:
      - "{{ install_dir }}/captcha/data:/data"
{% if iot.zscaptcha.port.export %}
    ports:
      - {{ iot.zscaptcha.port.map }}:8089
{% endif %}
    restart: unless-stopped
{% endif %}

  # ------------------------------------------------ Authorization Server ----------------------------------------------

{% if iot.authorization.enable %}
  authorization-server:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-authorization-server:{{ release }}"
    container_name: "iot-authorization-server{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.authorization.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.authorization.limits.cpus }}'
          memory: {{ iot.authorization.limits.memory }}
{% endif %}
    depends_on:
{% if not iot.mongodb.external.enable %}
      db:
        condition: service_started
{% endif %}
      rabbitmq:
        condition: service_healthy
{% if iot.captcha.enable %}
      captcha:
        condition: service_started
{% endif %}
{% if iot.zscaptcha.enable %}
      zs-captcha:
        condition: service_started
{% endif %}
      hazelcast:
        condition: service_started
    links:
{% if not iot.mongodb.external.enable %}
      - db
{% endif %}
{% if iot.captcha.enable %}
      - captcha
{% endif %}
{% if iot.zscaptcha.enable %}
      - zs-captcha
{% endif %}
{% if not iot.wsproxy.external.enable %}
      - wsproxy
{% endif %}
    entrypoint:
      - /extras/app-starter.sh
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:{{ iot.authorization.port.map }}/api/v1/common/ping"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 3m
    environment:
      - TZ={{ timezone.stdout }}
      - JAVA_TOOL_OPTIONS=-Xms512m -Xmx4g {{ "" if not iot.authorization.jconsole.enable else "-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=" ~ iot.authorization.jconsole.port ~ " -Dcom.sun.management.jmxremote.rmi.port=" ~ iot.authorization.jconsole.port ~ " -Djava.rmi.server.hostname=" ~ iot.authorization.jconsole.host }}
    volumes:
      - "{{ install_dir }}/authorization/var/lib/elis:/var/lib/elis"
      - "{{ install_dir }}/authorization/var/log/elis:/var/log/elis"
      - "{{ install_dir }}/authorization/etc/elis:/etc/elis"
      - "{{ install_dir }}/ssl/certs/authorization-server.crt:/etc/ssl/certs/authorization-server.crt"
      - "{{ install_dir }}/ssl/private/authorization-server.key:/etc/ssl/private/authorization-server.key"
{% if iot.authorization.port.export or iot.authorization.port.ssl.export or iot.authorization.jconsole.enable %}
    ports:
{% if iot.authorization.port.export %}
      - {{ iot.authorization.port.map }}:{{ iot.authorization.port.map }}
{% endif %}
{% if iot.authorization.port.ssl.export %}
      - {{ iot.authorization.port.ssl.map }}:{{ iot.authorization.port.ssl.map }}
{% endif %}
{% if iot.authorization.jconsole.enable %}
      - {{ iot.authorization.jconsole.port }}:{{ iot.authorization.jconsole.port }}
{% endif %}
{% endif %}
    restart: unless-stopped
{% endif %}

  # ------------------------------------------------------- Core -------------------------------------------------------

{% if iot.core.enable %}
  core:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-core:{{ release }}"
    container_name: "iot-core{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.core.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.core.limits.cpus }}'
          memory: {{ iot.core.limits.memory }}
{% endif %}
    depends_on:
{% if not iot.mongodb.external.enable %}
      db:
        condition: service_started
{% endif %}
      rabbitmq:
        condition: service_healthy
{% if iot.authorization.enable %}
      authorization-server:
        condition: service_healthy
{% endif %}
{% if not iot.broker.external.enable %}
      broker:
        condition: service_healthy
{% endif %}
{% if not iot.olapservice.external.enable %}
      olapservice:
        condition: service_healthy
{% endif %}
      hazelcast:
        condition: service_started
    links:
{% if not iot.mongodb.external.enable %}
      - db
{% endif %}
{% if not iot.broker.external.enable %}
      - broker
{% endif %}
{% if not iot.olapservice.external.enable %}
      - olapservice
{% endif %}
{% if iot.zwayproxy.enable and not iot.zwayproxy.external.enable %}
      - zwayproxy
{% endif %}
{% if not iot.wsproxy.external.enable %}
      - wsproxy
{% endif %}
    entrypoint:
      - /extras/app-starter.sh
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:{{ iot.core.port.map }}/api/v1/common/ping"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 3m
    environment:
      - TZ={{ timezone.stdout }}
      - JAVA_TOOL_OPTIONS=-Xms1024m -Xmx8g {{ "" if not iot.core.jconsole.enable else "-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=" ~ iot.core.jconsole.port ~ " -Dcom.sun.management.jmxremote.rmi.port=" ~ iot.core.jconsole.port ~ " -Djava.rmi.server.hostname=" ~ iot.core.jconsole.host }}
    volumes:
      - "{{ install_dir }}/core/var/lib/eltex-sc:/var/lib/eltex-sc"
      - "{{ install_dir }}/core/var/log/eltex-sc:/var/log/eltex-sc"
      - "{{ install_dir }}/core/etc/eltex-sc:/etc/eltex-sc"
      - "{{ install_dir }}/ssl/certs/eltex-sc-api.crt:/etc/ssl/certs/eltex-sc-api.crt"
      - "{{ install_dir }}/ssl/certs/eltex-sc-ctl-gate.crt:/etc/ssl/certs/eltex-sc-ctl-gate.crt"
      - "{{ install_dir }}/ssl/private/eltex-sc-api.key:/etc/ssl/private/eltex-sc-api.key"
      - "{{ install_dir }}/ssl/private/eltex-sc-ctl-gate.key:/etc/ssl/private/eltex-sc-ctl-gate.key"
{% if slgate.proxy.useClientCert %}
      - "{{ install_dir }}/ssl/private/slgate_client.p12:/etc/ssl/private/slgate_client.p12"
{% endif %}
    ports:
      - {{ iot.core.ctlGate.tcpPort }}:{{ iot.core.ctlGate.tcpPort }}
{% if not iot.zwayproxy.enable %}
      - {{ iot.core.ctlGate.port }}:{{ iot.core.ctlGate.port }}
      - {{ iot.core.ctlGate.sslPort }}:{{ iot.core.ctlGate.sslPort }}
{% endif %}
{% if iot.core.port.export %}
      - {{ iot.core.port.map }}:{{ iot.core.port.map }}
{% endif %}
{% if iot.core.port.ssl.export %}
      - {{ iot.core.port.ssl.map }}:{{ iot.core.port.ssl.map }}
{% endif %}
{% if iot.core.jconsole.enable %}
      - {{ iot.core.jconsole.port }}:{{ iot.core.jconsole.port }}
{% endif %}
    restart: unless-stopped
{% endif %}

  # ------------------------------------------------------- Web --------------------------------------------------------

{% if iot.web.enable %}
  web:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-double-web:{{ release }}"
    container_name: "iot-double-web{{ containerNameSuffix }}"
    cap_add:
          - NET_ADMIN
{% if iot.limits.enable and iot.web.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.web.limits.cpus }}'
          memory: {{ iot.web.limits.memory }}
{% endif %}
{% if iot.core.enable %}
    links:
      - core
{% endif %}
    environment:
      - ENABLE_CERTBOT={{ '1' if iot.web.certbot.enable else '0' }}
      - ENABLE_FAIL2BAN={{ '1' if iot.web.fail2ban.enable else '0' }}
      - SERVER_NAME={{ iot.serverName }}
      - CERTBOT_EMAIL={{ iot.web.certbot.email }}
      - HTTPS_PORT={{ iot.web.httpsPort }}
      - TZ={{ timezone.stdout }}
    volumes:
      - "{{ install_dir }}/web/etc/nginx/nginx.conf:/etc/nginx/nginx.conf"
      - "{{ install_dir }}/web/etc/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf"
      - "{{ install_dir }}/web/well-known:/usr/share/eltex-sc-web/www/.well-known"
{% if iot.web.certbot.enable %}
      - "{{ install_dir }}/web/etc/letsencrypt:/etc/letsencrypt"
      - "{{ install_dir }}/web/var/log/letsencrypt:/var/log/letsencrypt"
{% endif %}
      - "{{ install_dir }}/ssl/certs/eltex-sc-web.crt:/etc/ssl/certs/eltex-sc-web.crt"
      - "{{ install_dir }}/ssl/private/eltex-sc-web.key:/etc/ssl/private/eltex-sc-web.key"
{% include docker_compose_web_additional_volumes ignore missing %}

{% if not iot.core.enable %}
      - "{{ install_dir }}/web/etc/dnsmasq.d/core.conf:/etc/dnsmasq.d/core.conf"
{% endif %}
{% if not iot.authorization.enable %}
      - "{{ install_dir }}/web/etc/dnsmasq.d/authorization-server.conf:/etc/dnsmasq.d/authorization-server.conf"
{% endif %}
{% if not iot.core.enable or not iot.authorization.enable %}
    extra_hosts:
{% if not iot.core.enable %}
      - core:host-gateway
{% endif %}
{% if not iot.authorization.enable %}
      - authorization-server:host-gateway
{% endif %}
{% endif %}
    ports:
      - "{{ iot.web.httpPort }}:{{ iot.web.httpPort }}"
      - "{{ iot.web.httpsPort }}:{{ iot.web.httpsPort }}"
{% include docker_compose_web_additional_ports ignore missing %}

    restart: unless-stopped
{% endif %}

networks:
  default:
    name: "iot{{ networkNameSuffix }}"
    external: true
  # ------------------------------------------------------ Broker ------------------------------------------------------

  broker:
    image: "{{ registry }}{{ registry_iot_subdir }}/iot-mqttbroker-mongo:{{ release }}"
    container_name: "iot-mqtt-broker{{ containerNameSuffix }}"
{% if iot.limits.enable and iot.broker.limits.enable %}
    deploy:
      resources:
        limits:
          cpus: '{{ iot.broker.limits.cpus }}'
          memory: {{ iot.broker.limits.memory }}
{% endif %}
{% if not iot.mongodb.external.enable %}
    depends_on:
      - db
    links:
      - db
{% endif %}
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8083/common/ping"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 3m
    environment:
      - JAVA_TOOL_OPTIONS=-Xms512m -Xmx6g {{ "" if not iot.broker.jconsole.enable else "-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=" ~ iot.broker.jconsole.port ~ " -Dcom.sun.management.jmxremote.rmi.port=" ~ iot.broker.jconsole.port ~ " -Djava.rmi.server.hostname=" ~ iot.broker.jconsole.host }}
      - TZ={{ timezone.stdout }}
      - IOT_MQTTBROKER_API_PORT=8083
      - IOT_MQTTBROKER_DISK_USAGE_THRESHOLD_WARN={{ iot.diskUsage.warnThreshold }}
      - IOT_MQTTBROKER_DISK_USAGE_THRESHOLD_CRITICAL={{ iot.diskUsage.criticalThreshold }}
      - IOT_MQTT_BROKER_USE_RABBIT_MQ={{ iot.replication.mqttBroker.enabled }}
      - HIVEMQ_ROOT_FOLDER={{ iot.broker.hivemq.rootFolder }}
      - SPRING_RABBITMQ_HOST=rabbitmq
      - SPRING_DATA_MONGODB_URI=mongodb://{{ mongodb_addr }}:{{ mongodb_port }}/?socketTimeoutMS=20000&replicaSet=iotRepl&w=majority
      - SPRING_DATA_MONGODB_DATABASE={{ iot.broker.db.name }}
      - LOGGING_CONFIG={{ iot.logbackConfig }}
      - LOGGING_LOGBACK_DIR=/var/log/broker
{% if elk.enable %}
      - LOGGING_LOGSTASH_HOST={{ elk.serverName }}
      - LOGGING_LOGSTASH_PORT={{ elk.logstash.port.map }}
{% endif %}
      - LOGGING_LEVEL_ROOT={{ iot.broker.logLevel }}
      - LOGGING_LEVEL_HIVEMQ={{ iot.broker.logLevel }}
    ports:
      - {{ iot.broker.external.port.map }}:8883
{% if iot.broker.internal.port.export or iot.broker.external.enable %}
      - {{ iot.broker.internal.port.map }}:8083
{% endif %}
{% if iot.broker.jconsole.enable %}
      - {{ iot.broker.jconsole.port }}:{{ iot.broker.jconsole.port }}
{% endif %}
    volumes:
      - "{{ install_dir }}/mqtt/hivemq/:/hivemq/"
      - "{{ install_dir }}/mqtt/var/log/broker:/var/log/broker"
    restart: unless-stopped
# IoT server configuration
{% if iot.web.nginx.rateLimit.enable %}
limit_req_zone $binary_remote_addr zone=perip:10m rate=30r/m;
limit_req_zone $binary_remote_addr zone=api_perip:10m rate=60r/m;
{% endif %}

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=STATIC:60m max_size=256m inactive=24h use_temp_path=off;

{% if iot.web.redirectHttpToHttps %}
server {
    listen {{ iot.web.httpPort }};

    server_name {{ iot.serverName }};
  
    # use internal dnsmasq for resolving hostnames from /etc/hosts inside docker container
    resolver 127.0.0.1 valid=10s;

    location ~ ^/api/v1/(?:ctl/.+/zway/backup|files/download/.+) {
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        add_header X-Cache-Status $upstream_cache_status;
        proxy_cache STATIC;
        proxy_cache_key "$request_method$host$request_uri";
        proxy_ignore_headers Expires Cache-Control Set-Cookie Vary;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache_valid 200 24h;
        client_max_body_size 20M;
    }

    location / {
{% if iot.web.httpsPort != 443 %}
        return 301 https://$host:{{ iot.web.httpsPort }}$request_uri;
{% else %}
        return 301 https://$host$request_uri;
{% endif %}
    }
}
{% endif %}

server {
{% if not iot.web.redirectHttpToHttps %}
    listen {{ iot.web.httpPort }};
{% endif %}
    listen {{ iot.web.httpsPort }} ssl;

{% include web_ssl_parameters %}


    root /usr/share/eltex-sc-web/www/;

    index index.html;

    server_name {{ iot.serverName }};

    # use internal dnsmasq for resolving hostnames from /etc/hosts inside docker container
    resolver 127.0.0.1 valid=10s;

    # use gzip compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript font/woff2;

    location =/ {
        rewrite ^(.+)$ /ko permanent;
    }

    location ~* "^/api/v1/files/download/\w{24}/(?:preview|\w{8}-\w{4}-\w{4}-\w{4}-\w{12}).jpg" {
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 20M;
    }

    location /api/v1/actuator/prometheus {
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 20M;
        allow 172.16.0.0/12;
        allow ***.***.***.***/24;
        deny all;
    }

    location ~* ^/api/v1/files/download/.+ {
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        add_header X-Cache-Status $upstream_cache_status;
        proxy_cache STATIC;
        proxy_cache_key "$request_method$host$request_uri";
        proxy_ignore_headers Expires Cache-Control Set-Cookie Vary;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache_valid 200 24h;
        client_max_body_size 20M;
    }

    location /ko/ {
        # kill browser cache for all html pages
        add_header Last-Modified $date_gmt;
        add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
        if_modified_since off;
        expires off;
        etag off;

        try_files $uri $uri/ /ko/index.html;
    }

    location ~* (\.html|js/web-version\.js)$ {
        # kill browser cache for all html pages
        add_header Last-Modified $date_gmt;
        add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
        if_modified_since off;
        expires off;
        etag off;
        try_files $uri =404;
    }

    location ~ ^/(firebase-messaging-sw|js/firebase-app-compat|js/firebase-messaging-compat|js/ajv.min).js {
        try_files /ko/$uri =404;
    }

    location /ko/js/conf.js {
        set $apiAddress $scheme://$http_host;
        set $apiAddressJs "localStorage.setItem('apiAddress', '$apiAddress/api/v1');";
        set $wsAddressJs "localStorage.setItem('wsAddress', '$apiAddress/api/v1/stomp');";
        default_type application/javascript;
        return 200 "$apiAddressJs\n$wsAddressJs";
    }

    location /ng/assets/config.json {
        set $apiAddress $scheme://$http_host;
        set $api "\"api\": \"$apiAddress/api/v1\"";
        set $ws "\"ws\": \"$apiAddress/api/v1/stomp\"";
        set $apiEvi "\"api_evi\": \"$apiAddress/evi/vsaas/api/v2\"";
        set $stunUrls "\"stunUrls\":[ \"{{ iot.core.video.webrtc.stun.urls | join('\\\", \\\"') }}\" ]";
        default_type application/json;
        return 200 "{ $api, $ws, $apiEvi, $stunUrls }";
    }

    location /ng/ {
        # kill browser cache for all html pages
        add_header Last-Modified $date_gmt;
        add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
        if_modified_since off;
        expires off;
        etag off;

        try_files $uri /ng/index.html;
    }

    location ~ ^/api/v1/(?:login|images|oauth2|captcha|emailChange|users/logins|user/deleteyourself|profiles|security/roles|password|registration) {
{% if iot.web.nginx.rateLimit.enable %}
        limit_req zone=perip burst=20 nodelay;
{% endif %}
        proxy_buffering off;
        proxy_pass https://authorization-server:{{ iot.authorization.port.ssl.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 15M;
    }

    location /api/v1/sber {
        proxy_buffering off;
        proxy_pass https://core:{{ iot.core.port.ssl.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 15M;
    }

# link websockets to ws-proxy
    location /api/v1/stomp {
{% if not iot.wsproxy.external.enable %}
        proxy_pass http://wsproxy:8075$request_uri;
{% else %}
        proxy_pass http://{{ iot.wsproxy.external.host }}:{{ iot.wsproxy.external.port }}$request_uri;
{% endif %}
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /api/v1/event_ws {
{% if not iot.wsproxy.external.enable %}
        proxy_pass http://wsproxy:8075$request_uri;
{% else %}
        proxy_pass http://{{ iot.wsproxy.external.host }}:{{ iot.wsproxy.external.port }}$request_uri;
{% endif %}
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

{% if iot.core.video.evi.url != '' and iot.core.video.evi.apiKey != '' %}
  #--------------------- Proxy auth for evi admin --------------------------------
    location ~ ^/evi/(?<suffix>.*) {
        auth_request /auth;
        proxy_pass {{ iot.core.video.evi.url }}/$suffix?$args;
        proxy_set_header X-Vsaas-Api-Key {{ iot.core.video.evi.apiKey }};
    }

    location = /auth {
        if ($request_method = OPTIONS) {
            return 200;
        }

        internal;
        proxy_pass https://authorization-server:{{ iot.authorization.port.ssl.map }}/api/v1/authorization/verify?roleId=admin;
        proxy_http_version 1.1;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
    }
  #-------------------------------------------------------------------------------
{% endif %}

    # firmware files for rule upload
    # TODO delete after http://red.eltex.loc/issues/352170
    location /api/v1/firmware/rule/upload {
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 256M;
    }

    # firmware files for direct upload
    location /api/v1/files/upload {
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 40M;
    }

    location /api {
{% if iot.web.nginx.rateLimit.enable %}
        limit_req zone=api_perip burst=100 nodelay;
{% endif %}
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 20M;
    }

    location /stomp {
        proxy_pass http://core:{{ iot.core.port.map }}$request_uri;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /.well-known/apple-app-site-association {
        add_header Content-Type application/json;
        default_type application/json;
        try_files $uri /.well-known/apple-app-site-association.json;
    }

    location /.well-known/assetlinks.json {
        add_header Content-Type application/json;
        default_type application/json;
        try_files $uri /.well-known/assetlinks.json;
    }

    location /nginx_status {
    stub_status on;
    access_log off;
    allow 172.16.0.0/12;
    allow ***.***.***.***/24;
    deny all;
    }

    location /authorization-server/actuator/prometheus {
        proxy_pass https://authorization-server:{{ iot.authorization.port.ssl.map }}/api/v1/actuator/prometheus;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 20M;
        allow 172.16.0.0/12;
        allow ***.***.***.***/24;
        deny all;
    }

    location /broker/actuator/prometheus {
        proxy_pass http://{{ iot.broker.external.host if iot.broker.external.enable else 'broker' }}:{{ iot.broker.internal.port.map }}/actuator/prometheus;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 20M;
        allow 172.16.0.0/12;
        allow ***.***.***.***/24;
        deny all;
    }
}

{% include web_additional_server_blocks ignore missing %}

Установка платформы

По завершении конфигурации платформы умного дома, необходимо произвести ее установку на сервер при помощи следующих команд:

cd /etc/ansible-iot/latest
sudo ansible-playbook install_iot.yml

Пример вывода команд по установке платформы:

PLAY [Preparing a host for an MQTT-Broker] ************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/detect_logback_config.yml for localhost

TASK [Detect logback config for core] *****************************************************************************************************************************************************************************
ok: [localhost] => (item={'key': 'logbackConfig', 'value': 'classpath:logback-prod.xml'})

TASK [Include external mongodb parameters] ************************************************************************************************************************************************************************
ok: [localhost]

TASK [Include registry hub.eltex-co.ru parameters] ****************************************************************************************************************************************************************
ok: [localhost]

TASK [Correct ansible_become variable] ****************************************************************************************************************************************************************************
ok: [localhost]

TASK [Correct install directory path for MQTT-Broker] *************************************************************************************************************************************************************
ok: [localhost]

TASK [Check if need install MQTT-Broker] **************************************************************************************************************************************************************************
ok: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/get_timezone.yml for localhost

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/get_timezone/systemd.yml for localhost

TASK [Get current timezone of host via systemd] *******************************************************************************************************************************************************************
changed: [localhost]

PLAY [Preparing a host for an OlapService] ************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/detect_logback_config.yml for localhost

TASK [Include registry hub.eltex-co.ru parameters] ****************************************************************************************************************************************************************
ok: [localhost]

TASK [Correct ansible_become variable] ****************************************************************************************************************************************************************************
ok: [localhost]

TASK [Correct install directory path for OlapService] *************************************************************************************************************************************************************
ok: [localhost]

TASK [Check if need install OlapService] **************************************************************************************************************************************************************************
ok: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/get_timezone.yml for localhost

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/get_timezone/systemd.yml for localhost

TASK [Get current timezone of host via systemd] *******************************************************************************************************************************************************************
changed: [localhost]

PLAY [Install IoT] ************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/detect_logback_config.yml for localhost

TASK [Include external mongodb parameters] ************************************************************************************************************************************************************************
ok: [localhost]

TASK [Include registry hub.eltex-co.ru parameters] ****************************************************************************************************************************************************************
ok: [localhost]

TASK [Correct ansible_become variable] ****************************************************************************************************************************************************************************
ok: [localhost]

TASK [Correct install directory path] *****************************************************************************************************************************************************************************
ok: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/get_timezone.yml for localhost

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/get_timezone/systemd.yml for localhost

TASK [Get current timezone of host via systemd] *******************************************************************************************************************************************************************
changed: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/distros/Ubuntu.yml for localhost

TASK [Remove old versions of docker for Ubuntu 22.04] *************************************************************************************************************************************************************
ok: [localhost] => (item=docker-compose)
ok: [localhost] => (item=docker)
ok: [localhost] => (item=docker-engine)
ok: [localhost] => (item=docker.io)
ok: [localhost] => (item=containerd)
ok: [localhost] => (item=runc)

TASK [Install utils and components for Ubuntu 22.04] **************************************************************************************************************************************************************
ok: [localhost] => (item=ca-certificates)
ok: [localhost] => (item=curl)
ok: [localhost] => (item=gnupg)
ok: [localhost] => (item=lsb-release)

TASK [Get Ubuntu release codename] ********************************************************************************************************************************************************************************
changed: [localhost]

TASK [Add key for official docker repository to Ubuntu 22.04] *****************************************************************************************************************************************************
changed: [localhost]

TASK [Add official docker repository to Ubuntu 22.04] *************************************************************************************************************************************************************
changed: [localhost]

TASK [Install docker and components for Ubuntu 22.04] *************************************************************************************************************************************************************
ok: [localhost] => (item=docker-ce)
ok: [localhost] => (item=docker-ce-cli)
ok: [localhost] => (item=containerd.io)
ok: [localhost] => (item=docker-buildx-plugin)
ok: [localhost] => (item=docker-compose-plugin)
ok: [localhost] => (item=python3-cryptography)
ok: [localhost] => (item=python3-requests)
ok: [localhost] => (item=python3-docker)

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/enable_docker.yml for localhost

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/enable_docker/systemd.yml for localhost

TASK [Enable service docker via systemd] **************************************************************************************************************************************************************************
ok: [localhost]

TASK [Copy iot directory] *****************************************************************************************************************************************************************************************
changed: [localhost]

TASK [Detect that need tear down all services] ********************************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/mongodb/data/db] ****************************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/mongodb/mongobackups] ***********************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/mongodb/dictionaries] ***********************************************************************************************************************************************
changed: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/prepare_install_dir/broker.yml for localhost

TASK [Copy ./iot/mqtt/ directory to MQTT-Broker Host /storage/iot/mqtt/] ******************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/mqtt/hivemq/data] ***************************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/mqtt/var/log/broker] ************************************************************************************************************************************************
changed: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/prepare_install_dir/olapservice.yml for localhost

TASK [Copy ./iot/olapdb/ directory to OlapService Host /storage/iot/olapdb/] **************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/olapdb/data] ********************************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/olapdb/clickhouse-backup/archives] **********************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/olapdb/var/log/olapservice] *****************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/olapdb/var/log/clickhouse-server] ***********************************************************************************************************************************
changed: [localhost]

TASK [Append Libre Captcha parameters] ****************************************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/captcha/data] *******************************************************************************************************************************************************
changed: [localhost]

TASK [Prepare captcha config.json] ********************************************************************************************************************************************************************************
changed: [localhost]

TASK [Remove captcha data] ****************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/wsproxy/var/log/elis] ***********************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/zwayproxy/var/log/elis] *********************************************************************************************************************************************
changed: [localhost]

TASK [Append Yandex skill] ****************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Append Sber skill] ******************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Append Marusya skill] ***************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/authorization/etc/elis] *********************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/authorization/var/lib/elis] *****************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/authorization/var/log/elis] *****************************************************************************************************************************************
changed: [localhost]

TASK [Generate api key for authorization server] ******************************************************************************************************************************************************************
ok: [localhost]

TASK [Prepare authorization-server.yml] ***************************************************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/core/etc/eltex-sc] **************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/core/var/lib/eltex-sc] **********************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/core/var/log/eltex-sc] **********************************************************************************************************************************************
changed: [localhost]

TASK [Prepare core.yml] *******************************************************************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/web/etc/nginx] ******************************************************************************************************************************************************
changed: [localhost]

TASK [Prepare nginx.conf] *****************************************************************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/web/etc/nginx/conf.d] ***********************************************************************************************************************************************
changed: [localhost]

TASK [Prepare default.conf for web] *******************************************************************************************************************************************************************************
changed: [localhost]

TASK [Prepare docker-compose.yml] *********************************************************************************************************************************************************************************
changed: [localhost]

TASK [Remove old docker-compose.override.yml] *********************************************************************************************************************************************************************
ok: [localhost]

TASK [Prepare .env file for docker-compose] ***********************************************************************************************************************************************************************
changed: [localhost]

TASK [Check and create directory /storage/iot/web/etc/letsencrypt] ***********************************************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate for authorization server] ***************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/generate_cert.yml for localhost

TASK [Check and create directory /storage/iot/ssl/private] ********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/certs] **********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/csr] ************************************************************************************************************************************************************
changed: [localhost]

TASK [Check that the authorization-server.key already exists] *****************************************************************************************************************************************************
ok: [localhost]

TASK [Check that the authorization-server.crt already exists] *****************************************************************************************************************************************************
ok: [localhost]

TASK [Generate an OpenSSL private key authorization-server.key] ***************************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate Signing Request with Subject information authorization-server.csr] **********************************************************************************************************
changed: [localhost]

TASK [Generate a Self Signed OpenSSL certificate authorization-server.crt] ****************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate for api] ********************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/generate_cert.yml for localhost

TASK [Check and create directory /storage/iot/ssl/private] ********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/certs] **********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/csr] ************************************************************************************************************************************************************
ok: [localhost]

TASK [Check that the eltex-sc-api.key already exists] *************************************************************************************************************************************************************
ok: [localhost]

TASK [Check that the eltex-sc-api.crt already exists] *************************************************************************************************************************************************************
ok: [localhost]

TASK [Generate an OpenSSL private key eltex-sc-api.key] ***********************************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate Signing Request with Subject information eltex-sc-api.csr] ******************************************************************************************************************
changed: [localhost]

TASK [Generate a Self Signed OpenSSL certificate eltex-sc-api.crt] ************************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate for zway controller] ********************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/generate_cert.yml for localhost

TASK [Check and create directory /storage/iot/ssl/private] ********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/certs] **********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/csr] ************************************************************************************************************************************************************
ok: [localhost]

TASK [Check that the eltex-sc-ctl-gate.key already exists] ********************************************************************************************************************************************************
ok: [localhost]

TASK [Check that the eltex-sc-ctl-gate.crt already exists] ********************************************************************************************************************************************************
ok: [localhost]

TASK [Generate an OpenSSL private key eltex-sc-ctl-gate.key] ******************************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate Signing Request with Subject information eltex-sc-ctl-gate.csr] *************************************************************************************************************
changed: [localhost]

TASK [Generate a Self Signed OpenSSL certificate eltex-sc-ctl-gate.crt] *******************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate for web] ********************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/generate_cert.yml for localhost

TASK [Check and create directory /storage/iot/ssl/private] ********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/certs] **********************************************************************************************************************************************************
ok: [localhost]

TASK [Check and create directory /storage/iot/ssl/csr] ************************************************************************************************************************************************************
ok: [localhost]

TASK [Check that the eltex-sc-web.key already exists] *************************************************************************************************************************************************************
ok: [localhost]

TASK [Check that the eltex-sc-web.crt already exists] *************************************************************************************************************************************************************
ok: [localhost]

TASK [Generate an OpenSSL private key eltex-sc-web.key] ***********************************************************************************************************************************************************
changed: [localhost]

TASK [Generate an OpenSSL Certificate Signing Request with Subject information eltex-sc-web.csr] ******************************************************************************************************************
changed: [localhost]

TASK [Generate a Self Signed OpenSSL certificate eltex-sc-web.crt] ************************************************************************************************************************************************
changed: [localhost]

TASK [Create a iot network with options] **************************************************************************************************************************************************************************
changed: [localhost]

TASK [Tear down all services] *************************************************************************************************************************************************************************************
changed: [localhost]

TASK [Install dictionaries to mongo] ******************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/dictionaries/install_dictionaries_for_external_mongodb.yml for localhost

TASK [Copy mongodb dictionaries] **********************************************************************************************************************************************************************************
changed: [localhost]

TASK [Install collections from dictionaries] **********************************************************************************************************************************************************************
changed: [localhost] => (item={'root': '/etc/ansible-iot/latest/dictionaries/', 'path': 'iot-core/irTemplate.bson', 'state': 'file', 'src': '/etc/ansible-iot/latest/dictionaries/iot-core/irTemplate.bson', 'uid': 0, 'gid': 0, 'owner': 'root', 'group': 'root', 'mode': '0664', 'size': 3342255, 'mtime': 1744352484.0, 'ctime': 1744778635.9637227})

TASK [Delete mongodb dictionaries] ********************************************************************************************************************************************************************************
changed: [localhost] => (item={'root': '/etc/ansible-iot/latest/dictionaries/', 'path': 'iot-core', 'state': 'directory', 'uid': 0, 'gid': 0, 'owner': 'root', 'group': 'root', 'mode': '0775', 'size': 4096, 'mtime': 1744352484.0, 'ctime': 1744778635.9637227})

TASK [Create and start services] **********************************************************************************************************************************************************************************
changed: [localhost]

TASK [include_tasks] **********************************************************************************************************************************************************************************************
included: /etc/ansible-iot/latest/include/docker_prune.yml for localhost

TASK [Prune unused images, containers and networks] ***************************************************************************************************************************************************************
changed: [localhost]

TASK [Prune unused volumes] ***************************************************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost                  : ok=125  changed=54   unreachable=0    failed=0    skipped=68   rescued=0    ignored=0

В выводе команды необходимо дождаться появления строки "PLAY RECAP" и убедиться, что параметры unreachable и failed на следующей строке равны нулю, что означает успешную установку платформы.
Если любой из этих параметров не равен нулю, то в процессе установки платформы произошла ошибка. В таком случае в выводе команды будет присутствовать задача, статус которой равен failed или unreachable. Изучение текста ошибки этой задачи поможет выявить причину проблемы и исправить её.

Проверка работоспособности

1. После успешной установки платформы, проверьте состояние контейнеров микросервисов платформы умного дома при помощи следующей команды:

sudo docker ps -a

Вывод данной команды должен иметь следующий вид:

CONTAINER ID   IMAGE                                               COMMAND                  CREATED              STATUS                        PORTS                                                                                      NAMES
92b417858fa1   hub.eltex-co.ru/iot/iot-double-web:1.34             "/docker-entrypoint.…"   About a minute ago   Up 25 seconds                 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp               iot-double-web
2dc9dbebeddd   hub.eltex-co.ru/iot/iot-core:1.34                   "/extras/app-starter…"   About a minute ago   Up 25 seconds (healthy)       0.0.0.0:8069->8069/tcp, [::]:8069->8069/tcp                                                iot-core
3d797342ca41   hub.eltex-co.ru/iot/iot-authorization-server:1.34   "/extras/app-starter…"   About a minute ago   Up 41 seconds (healthy)                                                                                                  iot-authorization-server
371a0fe28027   hub.eltex-co.ru/iot/iot-wsproxy:1.34                "java -cp @/app/jib-…"   About a minute ago   Up 41 seconds                 0.0.0.0:8075->8075/tcp, [::]:8075->8075/tcp                                                iot-wsproxy
c6883b33158b   hub.eltex-co.ru/iot/iot-zwayproxy:1.34              "java -cp @/app/jib-…"   About a minute ago   Up 41 seconds                 0.0.0.0:8070->8070/tcp, [::]:8070->8070/tcp, 0.0.0.0:8072->8072/tcp, [::]:8072->8072/tcp   iot-zwayproxy
c6e279cf29d0   hub.eltex-co.ru/iot/iot-olapservice:1.34            "java -cp @/app/jib-…"   About a minute ago   Up About a minute (healthy)                                                                                              iot-olapservice
df468d19639d   hub.eltex-co.ru/iot/iot-captcha:1.34                "java -cp /app/resou…"   About a minute ago   Up About a minute                                                                                                        iot-captcha
5b914eaae6ec   hub.eltex-co.ru/iot/iot-hazelcast:1.34              "java --add-modules …"   About a minute ago   Up About a minute                                                                                                        iot-hazelcast
3ba2aa70940a   hub.eltex-co.ru/iot/iot-rabbitmq:1.34               "docker-entrypoint.s…"   About a minute ago   Up About a minute (healthy)   4369/tcp, 5671-5672/tcp, 15671-15672/tcp, 15691-15692/tcp, 25672/tcp                       iot-rabbitmq
b88642f4c504   hub.eltex-co.ru/iot/iot-mqttbroker-mongo:1.34       "java -cp @/app/jib-…"   About a minute ago   Up About a minute (healthy)   0.0.0.0:8883->8883/tcp, [::]:8883->8883/tcp                                                iot-mqtt-broker
8711c760a2b5   hub.eltex-co.ru/iot/iot-clickhouse-server:1.34      "/entrypoint.sh"         About a minute ago   Up About a minute (healthy)   9000/tcp, 0.0.0.0:8123->8123/tcp, [::]:8123->8123/tcp, 9009/tcp                            iot-olapservice-db

Запуск всех контейнеров может занять от 2 до 10 минут, в зависимости от размера БД.

Необходимо убедиться, что все контейнеры имеют статус Up и не происходит их перезапуска (статус Restarting).
Если в строке статуса контейнера присутствует состояние здоровья (в скобках)  то, также необходимо убедиться, что он равен healthy, либо health: starting.

В выводе команды должны присутствовать следующие контейнеры:

Название контейнераОжидаемый статус
iot-double-webUp
iot-coreUp (healthy)
iot-authorization-serverUp (healthy)
iot-wsproxyUp
iot-zwayproxyUp
iot-olapserviceUp (healthy)
iot-captchaUp
iot-hazelcastUp
iot-rabbitmqUp (healthy)
iot-mqtt-brokerUp (healthy)
iot-olapservice-dbUp (healthy)

2. После успешного запуска всех контейнеров требуется проверить доступность API платформы умного дома при помощи следующей команды:

curl -w "\n" -k https://domain.name:port/api/v1/common/ping

где domain.name — доменное имя сервера платформы умного дома (файл vars/default.yml, параметр iot.serverName);

      port — HTTPS-порт (файл vars/default.yml, параметр iot.web.httpsPort).

Вывод команды должен содержать одну строку со значением true, что означает доступность API платформы умного дома.

3. Проверьте доступность веб-интерфейса платформы умного дома по следующему адресу:

https://domain.name:port/

где domain.name — доменное имя сервера платформы умного дома (файл vars/default.yml, параметр iot.serverName);

      port — HTTPS-порт (файл vars/default.yml, параметр iot.web.httpsPort).

4. Авторизуйтесь в веб-интерфейсе администратора платформы умного дома при помощи следующих учетных данных по умолчанию:

Логинadmin
ПарольTest18plat34Form

В целях безопасности настоятельно рекомендуется сменить пароль учетной записи администратора.