Загрузка данных


stages:
  - build
  - bump-version
  - build-deb
  - update-img

default:
  image: gl.susanin.ai:5050/devops/cicd/ubuntu-builder:latest

variables:
  ENTERYPOINT_BUILD_DIR: "build"
  CONTROL_SERVER_BUILD_DIR: "control_server_build"

build:entrypoint:
  stage: build
  cache:
    key: "nuitka-ccache-${CI_COMMIT_REF_SLUG}"
    paths:
      - .ccache/
  variables:
    CCACHE_DIR: "${CI_PROJECT_DIR}/.ccache/ccache"
    NUITKA_CACHE_DIR: "${CI_PROJECT_DIR}/.ccache"
  script:
    - cd ../
    - |
      python3 -m nuitka "alabuga/entrypoint.py" \
      --clang \
      --lto=yes \
      --include-package=alabuga \
      --nofollow-import-to=map_navigation \
      --nofollow-import-to=runtime \
      --output-dir="alabuga/${ENTERYPOINT_BUILD_DIR}/" \
      --remove-output
  artifacts:
    paths:
      - ${ENTERYPOINT_BUILD_DIR}/
    expire_in: 1 week
    when: on_success

build:contorl_server:
  stage: build
  cache:
    key: "nuitka-ccache-${CI_COMMIT_REF_SLUG}"
    paths:
      - .ccache/
  variables:
    CCACHE_DIR: "${CI_PROJECT_DIR}/.ccache/ccache"
    NUITKA_CACHE_DIR: "${CI_PROJECT_DIR}/.ccache"
  script:
    - cd control_server
    - |
      python3 -m nuitka "app.py" \
      --clang \
      --lto=yes \
      --include-package=routes \
      --include-package=health \
      --include-package=netplan_manager \
      --include-package=config_manager \
      --include-module=compression \
      --nofollow-import-to=map_navigation \
      --nofollow-import-to=runtime \
      --output-dir="control_server_build" \
      --remove-output
    - cp -rf static control_server_build/
  artifacts:
    paths:
      - control_server/${CONTROL_SERVER_BUILD_DIR}/
    expire_in: 1 week
    when: on_success

auto_increment_version:
  stage: bump-version
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  needs:
    - job: build:entrypoint
    - job: build:contorl_server
  before_script:
    - git config --global user.email "ci-bot@gl.susanin.ai"
    - git config --global user.name "GitLab CI Bot"
    - git remote set-url origin https://oauth2:${MY_PUSH_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git
  script:
    - git fetch origin ${CI_COMMIT_BRANCH}
    - git checkout ${CI_COMMIT_BRANCH}
    - git pull origin ${CI_COMMIT_BRANCH}
    
    - |
      python3 -c "
      import json
      
      with open('version.json', 'r') as f:
          data = json.load(f)
      
      version_parts = data['version'].split('.')
      version_parts[-1] = str(int(version_parts[-1]) + 1)
      new_version = '.'.join(version_parts)
      data['version'] = new_version
      
      with open('version.json', 'w') as f:
          json.dump(data, f, indent=2)
      
      print(f'New version calculated: {new_version}')
      "
    
    - NEW_VERSION=$(python3 -c "import json; print(json.load(open('version.json'))['version'])")
    - echo "Target version is v${NEW_VERSION}"
    
    - git tag -d "v${NEW_VERSION}" 2>/dev/null || true
    - git push origin --delete "v${NEW_VERSION}" 2>/dev/null || true
    - git add version.json
    - git commit -m "bump version to ${NEW_VERSION} [skip ci]"
    - git push origin ${CI_COMMIT_BRANCH}
    - git tag -a "v${NEW_VERSION}" -m "Release version v${NEW_VERSION}"
    - git push origin "v${NEW_VERSION}"

build_deb:
  stage: build-deb
  needs:
    - job: build:entrypoint
      artifacts: true
    - job: build:contorl_server
      artifacts: true
    - job: auto_increment_version
      artifacts: false
      optional: true
  variables:
    GIT_STRATEGY: clone
  script:
    # Получаем версии из version.json
    - git fetch origin ${CI_COMMIT_BRANCH}
    - git checkout origin/${CI_COMMIT_BRANCH} -- version.json
    - VERSION=$(jq -r '."version"' version.json)
    - CORE_VERSION=$(jq -r '."core"' version.json)
    - echo "Building DEB package for version ${VERSION} (app version ${VERSION}) with core ${CORE_VERSION}"
    
    # Клонируем core-so для получения .so файлов и config
    - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}/backend/core-so.git core-so
    
    # Создаем структуру для DEB пакета
    - mkdir -p deb-package/DEBIAN
    - mkdir -p deb-package/home/ubuntu/control_server
    - mkdir -p deb-package/home/ubuntu/map_navigation
    - mkdir -p deb-package/home/ubuntu/venv/lib/python3.10/site-packages
    - mkdir -p deb-package/etc/systemd/journald.conf.d
    
    # Копируем control_server
    - cp -rf control_server/${CONTROL_SERVER_BUILD_DIR}/* deb-package/home/ubuntu/control_server/
    
    # Копируем entrypoint.bin
    - cp -f ${ENTERYPOINT_BUILD_DIR}/entrypoint.bin deb-package/home/ubuntu/map_navigation/
    - install -m 755 rtsp_restream.sh deb-package/home/ubuntu/map_navigation/rtsp_restream.sh
    
    # Копируем .env (если есть)
    - if [ -f .env ]; then cp -f .env deb-package/home/ubuntu/map_navigation/; fi
    - if [ -f example.env ]; then cp -f example.env deb-package/home/ubuntu/map_navigation/.env; fi
    
    # Копируем .so файлы из core-so
    - cp -f core-so/v${CORE_VERSION}/core/map_navigation.cpython-310-aarch64-linux-gnu.so deb-package/home/ubuntu/venv/lib/python3.10/site-packages/
    - cp -f core-so/v${CORE_VERSION}/core/runtime.cpython-310-aarch64-linux-gnu.so deb-package/home/ubuntu/venv/lib/python3.10/site-packages/
    
    # Копируем config папку
    - cp -rf core-so/v${CORE_VERSION}/core/config deb-package/home/ubuntu/venv/lib/python3.10/site-packages/
    
    # Копируем version.json в static
    - cp -f version.json deb-package/home/ubuntu/control_server/static/

    # Ограничиваем размер постоянного системного журнала
    - cp -f systemd/journald.conf.d/90-alabuga.conf deb-package/etc/systemd/journald.conf.d/
    
    # Создаем postinst скрипт
    - |
      cat > deb-package/DEBIAN/postinst << EOF
      #!/bin/bash
      set -e
      
      # Проверяем, доступен ли systemd (в chroot его нет)
      if [ "\$(cat /proc/1/comm)" = "systemd" ]; then
          SYSTEMD_AVAILABLE=true
      else
          SYSTEMD_AVAILABLE=false
      fi
      
      echo "Installing Alabuga update package version ${VERSION}"
      
      # ---- Остановка сервисов (только если systemd есть) ----
      if [ "\$SYSTEMD_AVAILABLE" = true ]; then
          echo "Stopping services..."
          for service in map-navigation.service control-server.service rtsp-restream.service mediamtx.service; do
              if systemctl is-active --quiet \$service 2>/dev/null; then
                  systemctl stop \$service
              fi
          done
      else
          echo "Systemd not available, skipping service stop"
      fi

      # ---- Применяем настройки постоянного журнала ----
      if [ "\$SYSTEMD_AVAILABLE" = true ]; then
          systemctl restart systemd-journald || true
      fi
      
      # ---- Установка прав (всегда, ошибки игнорируем) ----
      echo "Setting permissions..."
      chown -R ubuntu:ubuntu /home/ubuntu/control_server 2>/dev/null || true
      chown -R ubuntu:ubuntu /home/ubuntu/map_navigation 2>/dev/null || true
      chown -R ubuntu:ubuntu /home/ubuntu/venv/lib/python3.10/site-packages/ 2>/dev/null || true
      
      # ---- Делаем исполняемыми ----
      chmod +x /home/ubuntu/map_navigation/entrypoint.bin 2>/dev/null || true
      chmod +x /home/ubuntu/control_server/app.bin 2>/dev/null || true
      
      # ---- Создаём симлинк на .env ----
      echo "Creating symlink for .env..."
      ln -sf /home/ubuntu/map_navigation/.env /home/ubuntu/.env
      echo "Symlink created: /home/ubuntu/.env -> /home/ubuntu/map_navigation/.env"
      
      # ---- Запуск сервисов (только если systemd есть) ----
      if [ "\$SYSTEMD_AVAILABLE" = true ]; then
          # Функция для попытки запуска сервиса
          try_start_service() {
              local service=\$1
              echo "Attempting to start \$service..."
              if systemctl start \$service 2>/dev/null; then
                  echo "\$service started successfully"
                  return 0
              else
                  echo "Warning: \$service failed to start, continuing installation"
                  return 1
              fi
          }
      
          echo "Starting services..."
          systemctl daemon-reload
      
          services=(
              "map-navigation.service"
              "control-server.service"
              "rtsp-restream.service"
              "mediamtx.service"
          )
      
          for service in "\${services[@]}"; do
              if systemctl is-enabled --quiet \$service 2>/dev/null; then
                  try_start_service \$service
              else
                  echo "Service \$service is not enabled, skipping..."
              fi
          done
      
          echo "Alabuga update package ${VERSION} installed successfully"
      
          # Финальный статус
          echo "Final service status:"
          for service in "\${services[@]}"; do
              if systemctl is-active --quiet \$service 2>/dev/null; then
                  echo "\$service is running"
              else
                  echo "\$service is not running (this may be normal)"
              fi
          done
      else
          echo "Systemd not available, skipping service management"
          echo "Alabuga update package ${VERSION} installed successfully (files only)"
      fi
      EOF

    - chmod +x deb-package/DEBIAN/postinst
    
    # Создаем control файл
    - |
      cat > deb-package/DEBIAN/control << EOF
      Package: alabuga-update
      Version: ${VERSION}
      Section: base
      Priority: optional
      Architecture: arm64
      Maintainer: GitLab CI <ci-bot@gl.susanin.ai>
      Description: Alabuga update package v${VERSION}
       This package contains updated files for Alabuga system
       App Version: ${VERSION}
       Core version: ${CORE_VERSION}
      EOF
    
    # Создаем md5sums для проверки целостности
    - cd deb-package && find home -type f -exec md5sum {} \; > DEBIAN/md5sums && cd ..
    
    # Создаем DEB пакет
    - dpkg-deb --build deb-package alabuga-update_${VERSION}_arm64.deb
  
  artifacts:
    paths:
      - alabuga-update_*.deb
    expire_in: 1 week
    when: on_success

update-img-cokepi:
  stage: update-img
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  variables:
    GIT_STRATEGY: clone
  needs:
    - project: backend/babkin_hleb
      job: build_deb
      ref: master
      artifacts: true
    - job: build:entrypoint
      artifacts: true
    - job: build:contorl_server
      artifacts: true
    - job: auto_increment_version
    - job: build_deb
      artifacts: true
  before_script:
    - git fetch origin ${CI_COMMIT_BRANCH}
    - git checkout origin/${CI_COMMIT_BRANCH} -- version.json
    - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}/backend/core-so.git core-so
    - IMG_TEMPLATE_VERSION=$(jq -r '."img-template"."cokepi"' version.json)
    - CORE_VERSION=$(jq -r '."core"' version.json)
    - VERSION=$(jq -r '."version"' version.json)
    - MAPS=$(jq -r '."maps"' version.json)
    - SIZE_M=$(du -sm /opt/img/alabuga/maps/${MAPS} | awk '{print $1}')
    - MAPS_SIZE="$((SIZE_M + 1024))M"
    - mkdir -p /mnt/cokepi
  script:
    - cp /opt/img/alabuga/template/cokepi/v${IMG_TEMPLATE_VERSION}.img /opt/img/alabuga/img/cokepi/v${VERSION}.img
    - truncate -s +${MAPS_SIZE} /opt/img/alabuga/img/cokepi/v${VERSION}.img
    - losetup -P /dev/loop0 /opt/img/alabuga/img/cokepi/v${VERSION}.img
    - sgdisk -e /dev/loop0
    - parted -s /dev/loop0 resizepart 2 100%
#    - partx -u /dev/loop0
    - losetup -d /dev/loop0
    - losetup -P /dev/loop0 /opt/img/alabuga/img/cokepi/v${VERSION}.img
    - e2fsck -f -y /dev/loop0p2
    - resize2fs /dev/loop0p2
    - mount /dev/loop0p2 /mnt/cokepi
    - cp -rf /opt/img/alabuga/maps/${MAPS} /mnt/cokepi/home/ubuntu/data/areas/
    - cp alabuga-update_${VERSION}_arm64.deb bread-tracking_${BABKINHLEB_VERSION}_arm64.deb /mnt/cokepi/tmp/
    - chroot /mnt/cokepi dpkg -i /tmp/alabuga-update_${VERSION}_arm64.deb
    - chroot /mnt/cokepi dpkg -i /tmp/bread-tracking_${BABKINHLEB_VERSION}_arm64.deb
  after_script:
    - umount /mnt/cokepi 2>/dev/null || true
    - losetup -d /dev/loop0 2>/dev/null || true


update-img-orangepi:
  stage: update-img
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  variables:
    GIT_STRATEGY: clone
  needs:
    - project: backend/babkin_hleb
      job: build_deb
      ref: master
      artifacts: true
    - job: build:entrypoint
      artifacts: true
    - job: build:contorl_server
      artifacts: true
    - job: auto_increment_version
    - job: build_deb
      artifacts: true
  before_script:
    - git fetch origin ${CI_COMMIT_BRANCH}
    - git checkout origin/${CI_COMMIT_BRANCH} -- version.json
    - git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@${CI_SERVER_HOST}/backend/core-so.git core-so
    - IMG_TEMPLATE_VERSION=$(jq -r '."img-template"."orangepi"' version.json)
    - CORE_VERSION=$(jq -r '."core"' version.json)
    - VERSION=$(jq -r '."version"' version.json)
    - MAPS=$(jq -r '."maps"' version.json)
    - SIZE_M=$(du -sm /opt/img/alabuga/maps/${MAPS} | awk '{print $1}')
    - MAPS_SIZE="$((SIZE_M + 1024))M"
    - mkdir -p /mnt/orangepi
  script:
    - cp /opt/img/alabuga/template/orangepi/v${IMG_TEMPLATE_VERSION}.img /opt/img/alabuga/img/orangepi/v${VERSION}.img
    - truncate -s +${MAPS_SIZE} /opt/img/alabuga/img/orangepi/v${VERSION}.img
    - losetup -P /dev/loop1 /opt/img/alabuga/img/orangepi/v${VERSION}.img
    - sgdisk -e /dev/loop1
    - parted -s /dev/loop1 resizepart 2 100%
#    - partx -u /dev/loop1
    - losetup -d /dev/loop1
    - losetup -P /dev/loop1 /opt/img/alabuga/img/orangepi/v${VERSION}.img
    - e2fsck -f -y /dev/loop1p2
    - resize2fs /dev/loop1p2
    - mount /dev/loop1p2 /mnt/orangepi
    - cp -rf /opt/img/alabuga/maps/${MAPS} /mnt/orangepi/home/ubuntu/data/areas/
    - cp alabuga-update_${VERSION}_arm64.deb bread-tracking_${BABKINHLEB_VERSION}_arm64.deb /mnt/orangepi/tmp/
    - chroot /mnt/orangepi dpkg -i /tmp/alabuga-update_${VERSION}_arm64.deb
    - chroot /mnt/orangepi dpkg -i /tmp/bread-tracking_${BABKINHLEB_VERSION}_arm64.deb
  after_script:
    - umount /mnt/orangepi 2>/dev/null || true
    - losetup -d /dev/loop1 2>/dev/null || true