--- # Основные задачи для установки Python 3.12 # Автор: Сергей Антропов # Сайт: https://devops.org.ru - name: "Отладочная информация о системе" debug: msg: - "ansible_distribution: '{{ ansible_distribution }}'" - "ansible_os_family: '{{ ansible_os_family }}'" - "ansible_distribution_version: '{{ ansible_distribution_version }}'" when: (python_log_level | default("INFO")) in ["DEBUG", "INFO"] - name: "Определение переменных для текущей ОС" set_fact: python_distribution: "{{ ansible_distribution | lower }}" python_os_family: "{{ ansible_os_family | lower }}" python_current_package_manager: "{{ python_package_managers[ansible_distribution | lower] | default('unknown') }}" python_current_packages: "{{ python_packages_by_os[ansible_distribution | lower] | default([]) }}" python_current_build_deps: "{{ python_build_deps_by_os[ansible_distribution | lower] | default([]) }}" python_current_executable: "{{ python_executable_paths[ansible_distribution | lower] | default('/usr/bin/python3.12') }}" python_current_pip: "{{ python_pip_paths[ansible_distribution | lower] | default('/usr/bin/pip3.12') }}" - name: "Проверка определенных переменных" debug: msg: - "python_distribution: '{{ python_distribution }}'" - "python_os_family: '{{ python_os_family }}'" - "python_current_package_manager: '{{ python_current_package_manager }}'" - "python_current_packages: {{ python_current_packages }}" - "python_current_build_deps: {{ python_current_build_deps }}" - "python_current_executable: '{{ python_current_executable }}'" - "python_current_pip: '{{ python_current_pip }}'" when: (python_log_level | default("INFO")) in ["DEBUG", "INFO"] # ============================================================================= # ЭТАП 1: ДОБАВЛЕНИЕ РЕПОЗИТОРИЕВ # ============================================================================= - name: "Добавление репозиториев для Ubuntu/Debian" apt_repository: repo: "{{ item.url }}" state: "{{ item.state }}" update_cache: yes loop: "{{ python_repositories[python_distribution] | default([]) }}" when: - python_distribution in ['ubuntu', 'debian'] - python_repositories[python_distribution] is defined ignore_errors: true - name: "Добавление репозиториев для RHEL-семейства" package: name: "{{ item.name }}" state: "{{ item.state }}" loop: "{{ python_repositories[python_distribution] | default([]) }}" when: - python_distribution in ['redhat', 'centos', 'rhel', 'rocky', 'alma', 'fedora'] - python_repositories[python_distribution] is defined - item.name != 'scl' ignore_errors: true - name: "Добавление SCL репозиториев для старых RHEL/CentOS" yum_repository: name: "{{ item.name }}" description: "{{ item.name }} repository" baseurl: "{{ item.url }}" gpgcheck: no enabled: yes loop: "{{ python_repositories[python_distribution] | default([]) }}" when: - python_distribution in ['redhat', 'centos', 'rhel'] - python_repositories[python_distribution] is defined - item.name == 'scl' ignore_errors: true # ============================================================================= # ЭТАП 2: ОБНОВЛЕНИЕ ПАКЕТОВ # ============================================================================= - name: "Обновление списка пакетов" package: name: "*" state: present when: - python_current_package_manager in ['apt', 'dnf', 'zypper'] - python_current_package_manager != 'unknown' - name: "Обновление списка пакетов после добавления репозиториев" package: name: "*" state: present when: - python_repositories[python_distribution] is defined - python_current_package_manager in ['apt', 'dnf'] # ============================================================================= # ЭТАП 3: УСТАНОВКА СИСТЕМНЫХ ЗАВИСИМОСТЕЙ # ============================================================================= - name: "Установка системных зависимостей для компиляции" package: name: "{{ python_current_build_deps }}" state: present when: - python_current_build_deps | length > 0 - python_current_package_manager != 'unknown' ignore_errors: true # ============================================================================= # ЭТАП 4: ПРОВЕРКА И УСТАНОВКА PYTHON СТАНДАРТНЫМ СПОСОБОМ # ============================================================================= - name: "Проверка наличия Python {{ python_version }}" command: "{{ python_current_executable }} --version" register: python_version_check failed_when: false changed_when: false when: python_current_executable is defined and python_current_executable != "" - name: "Установка Python из пакетов (основной способ)" package: name: "{{ python_current_packages }}" state: present when: - python_current_packages | length > 0 - python_current_package_manager != 'unknown' - python_version_check.rc != 0 register: python_package_install ignore_errors: true # ============================================================================= # ЭТАП 5: FALLBACK НА АЛЬТЕРНАТИВНЫЕ СПОСОБЫ # ============================================================================= - name: "Попытка установки альтернативных пакетов Python" package: name: "{{ python_current_packages | select('match', '.*python3\\.1[12].*') | list }}" state: present when: - python_package_install is defined - python_package_install.failed | default(false) - python_current_package_manager != 'unknown' - python_version_check.rc != 0 register: python_alt_install ignore_errors: true - name: "Попытка установки SCL пакетов Python" package: name: "{{ python_current_packages | select('match', '.*rh-python.*') | list }}" state: present when: - python_alt_install is defined - python_alt_install.failed | default(false) - python_current_package_manager != 'unknown' - python_version_check.rc != 0 - python_distribution in ['redhat', 'centos', 'rhel'] register: python_scl_install ignore_errors: true # ============================================================================= # ЭТАП 6: КОМПИЛЯЦИЯ ИЗ ИСХОДНИКОВ (ПОСЛЕДНИЙ СПОСОБ) # ============================================================================= - name: "Скачивание исходного кода Python {{ python_version }}" get_url: url: "https://www.python.org/ftp/python/{{ python_version }}/Python-{{ python_version }}.tar.xz" dest: "/tmp/Python-{{ python_version }}.tar.xz" mode: '0644' register: download_result failed_when: false changed_when: false when: - python_current_packages | length == 0 - python_version_check.rc != 0 - python_package_install is defined - python_package_install.failed | default(false) - python_alt_install is defined - python_alt_install.failed | default(false) ignore_errors: true - name: "Распаковка исходного кода Python" unarchive: src: "/tmp/Python-{{ python_version }}.tar.xz" dest: "/tmp/" remote_src: yes when: - python_current_packages | length == 0 - python_version_check.rc != 0 - download_result is defined - download_result.status_code == 200 - name: "Конфигурация Python для компиляции" command: > ./configure --prefix={{ python_install_prefix | default('/usr/local') }} --enable-optimizations --enable-shared --with-lto --enable-ipv6 --with-system-ffi --with-computed-gotos --enable-loadable-sqlite-extensions args: chdir: "/tmp/Python-{{ python_version }}" changed_when: false when: - python_current_packages | length == 0 - python_version_check.rc != 0 - download_result is defined - download_result.status_code == 200 - name: "Компиляция Python" make: chdir: "/tmp/Python-{{ python_version }}" jobs: "{{ ansible_processor_cores | default(1) }}" when: - python_current_packages | length == 0 - python_version_check.rc != 0 - download_result is defined - download_result.status_code == 200 - name: "Установка скомпилированного Python" make: chdir: "/tmp/Python-{{ python_version }}" target: install become: true when: - python_current_packages | length == 0 - python_version_check.rc != 0 - download_result is defined - download_result.status_code == 200 - name: "Обновление библиотек для скомпилированного Python" command: "ldconfig" become: true changed_when: false when: - python_current_packages | length == 0 - python_version_check.rc != 0 - download_result is defined - download_result.status_code == 200 # ============================================================================= # ЭТАП 7: СОЗДАНИЕ СИМВОЛИЧЕСКИХ ССЫЛОК # ============================================================================= - name: "Создание символических ссылок для Python" file: src: "{{ python_current_executable }}" dest: "/usr/bin/python3" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - name: "Создание символических ссылок для SCL Python" file: src: "/opt/rh/rh-python312/root/usr/bin/python3" dest: "/usr/bin/python3" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - python_distribution in ['redhat', 'centos', 'rhel'] - python_scl_install is defined - python_scl_install.changed | default(false) - name: "Создание символических ссылок для pip" file: src: "{{ python_current_pip }}" dest: "/usr/bin/pip3" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - python_current_pip is defined - python_current_pip != "" - name: "Создание символических ссылок для SCL pip" file: src: "/opt/rh/rh-python312/root/usr/bin/pip3" dest: "/usr/bin/pip3" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - python_distribution in ['redhat', 'centos', 'rhel'] - python_scl_install is defined - python_scl_install.changed | default(false) - name: "Создание символических ссылок для Python (без версии)" file: src: "{{ python_current_executable }}" dest: "/usr/bin/python" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - name: "Создание символических ссылок для SCL Python (без версии)" file: src: "/opt/rh/rh-python312/root/usr/bin/python" dest: "/usr/bin/python" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - python_distribution in ['redhat', 'centos', 'rhel'] - python_scl_install is defined - python_scl_install.changed | default(false) - name: "Создание символических ссылок для pip (без версии)" file: src: "{{ python_current_pip }}" dest: "/usr/bin/pip" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - python_current_pip is defined - python_current_pip != "" - name: "Создание символических ссылок для SCL pip (без версии)" file: src: "/opt/rh/rh-python312/root/usr/bin/pip" dest: "/usr/bin/pip" state: link force: yes when: - (python_create_symlinks | default(true)) | bool - python_version_check.rc != 0 - python_distribution in ['redhat', 'centos', 'rhel'] - python_scl_install is defined - python_scl_install.changed | default(false) # ============================================================================= # ЭТАП 8: НАСТРОЙКА АЛЬТЕРНАТИВ И PIP # ============================================================================= - name: "Настройка альтернатив для Python" alternatives: name: python3 path: "{{ python_current_executable }}" when: - python_current_executable is defined - python_current_executable != "" - ansible_os_family == "RedHat" - name: "Установка pip через get-pip.py если не найден" get_url: url: "https://bootstrap.pypa.io/get-pip.py" dest: "/tmp/get-pip.py" mode: '0755' when: - python_version_check.rc == 0 - python_current_pip is not defined or python_current_pip == "" - name: "Запуск get-pip.py для установки pip" command: "{{ python_current_executable }} /tmp/get-pip.py" changed_when: false when: - python_version_check.rc == 0 - python_current_pip is not defined or python_current_pip == "" # ============================================================================= # ЭТАП 9: ОБНОВЛЕНИЕ PIP # ============================================================================= - name: "Получение последней версии pip" uri: url: "https://pypi.org/pypi/pip/json" method: GET register: pip_version_info when: python_version_check.rc == 0 ignore_errors: true - name: "Извлечение версии pip" set_fact: pip_latest_version: "{{ pip_version_info.json.info.version }}" when: - pip_version_info is defined - pip_version_info.status == 200 - name: "Проверка текущей версии pip" command: "{{ python_current_pip }} --version" register: pip_current_version changed_when: false when: - python_version_check.rc == 0 - python_current_pip is defined - python_current_pip != "" ignore_errors: true - name: "Обновление pip до последней версии" command: "{{ python_current_pip }} install --upgrade pip" changed_when: false when: - python_version_check.rc == 0 - pip_current_version.rc == 0 - pip_latest_version is defined - pip_current_version.stdout is defined - pip_latest_version not in pip_current_version.stdout ignore_errors: true # ============================================================================= # ЭТАП 10: СОЗДАНИЕ ВИРТУАЛЬНОГО ОКРУЖЕНИЯ # ============================================================================= - name: "Создание виртуального окружения" command: "{{ python_current_executable }} -m venv {{ python_venv_path | default('/opt/python-venv') }}" changed_when: false when: - (python_create_venv | default(false)) | bool - python_version_check.rc == 0 ignore_errors: true # ============================================================================= # ЭТАП 11: ФИНАЛЬНЫЙ ОТЧЕТ # ============================================================================= - name: "Сбор информации о системе" setup: gather_subset: - "!all" - "distribution" - "os_family" - "architecture" - "kernel" - "python" register: system_facts - name: "Проверка установленного Python" command: "{{ python_current_executable }} --version" register: final_python_version changed_when: false when: python_version_check.rc == 0 ignore_errors: true - name: "Проверка установленного pip" command: "{{ python_current_pip }} --version" register: final_pip_version changed_when: false when: - python_version_check.rc == 0 - python_current_pip is defined - python_current_pip != "" ignore_errors: true - name: "Проверка символических ссылок" stat: path: "{{ item }}" register: symlink_check loop: - "/usr/bin/python" - "/usr/bin/python3" - "/usr/bin/pip" - "/usr/bin/pip3" - name: "Проверка виртуального окружения" stat: path: "{{ python_venv_path | default('/opt/python-venv') }}" register: venv_check when: python_create_venv | bool - name: "Сбор информации об установленных пакетах Python" package_facts: manager: "{{ python_current_package_manager }}" when: python_current_package_manager != 'unknown' - name: "Финальный отчет об установке" debug: msg: | ================================================================================ 🐍 ОТЧЕТ ОБ УСТАНОВКЕ PYTHON {{ python_version | upper }} ================================================================================ 📊 ИНФОРМАЦИЯ О СИСТЕМЕ: • Дистрибутив: {{ system_facts.ansible_facts.distribution }} {{ system_facts.ansible_facts.distribution_version }} • Семейство ОС: {{ system_facts.ansible_facts.os_family }} • Архитектура: {{ system_facts.ansible_facts.architecture }} • Ядро: {{ system_facts.ansible_facts.kernel }} 🐍 PYTHON: • Версия: {{ final_python_version.stdout | default('НЕ УСТАНОВЛЕН') }} • Исполняемый файл: {{ python_current_executable }} • Путь к pip: {{ python_current_pip | default('НЕ НАЙДЕН') }} 📦 PIP: • Версия: {{ final_pip_version.stdout | default('НЕ УСТАНОВЛЕН') }} 🔗 СИМВОЛИЧЕСКИЕ ССЫЛКИ: • /usr/bin/python: {{ '✅ СОЗДАНА' if symlink_check.results[0].stat.exists else '❌ НЕ СОЗДАНА' }} • /usr/bin/python3: {{ '✅ СОЗДАНА' if symlink_check.results[1].stat.exists else '❌ НЕ СОЗДАНА' }} • /usr/bin/pip: {{ '✅ СОЗДАНА' if symlink_check.results[2].stat.exists else '❌ НЕ СОЗДАНА' }} • /usr/bin/pip3: {{ '✅ СОЗДАНА' if symlink_check.results[3].stat.exists else '❌ НЕ СОЗДАНА' }} 🌐 ВИРТУАЛЬНОЕ ОКРУЖЕНИЕ: • Путь: {{ python_venv_path | default('/opt/python-venv') }} • Статус: {{ '✅ СОЗДАНО' if (venv_check is defined and venv_check.stat.exists) else '❌ НЕ СОЗДАНО' }} 📋 УСТАНОВЛЕННЫЕ ПАКЕТЫ PYTHON: {% if ansible_facts.packages is defined %} {% for package in ansible_facts.packages %} {% if 'python' in package %} • {{ package }}: {{ ansible_facts.packages[package] | map(attribute='version') | list | join(', ') }} {% endif %} {% endfor %} {% else %} • Информация недоступна {% endif %} 🎯 КОМАНДЫ ДЛЯ ПРОВЕРКИ: • python --version • python3 --version • pip --version • pip3 --version • python -m venv test_env ================================================================================ when: python_log_level in ["INFO", "DEBUG"] - name: "Уведомление о завершении установки Python" debug: msg: | ✅ PYTHON {{ python_version | upper }} УСТАНОВЛЕН И НАСТРОЕН! 🎯 Основные команды: • python --version # Проверить версию Python • python3 --version # Проверить версию Python (с версией) • pip --version # Проверить версию pip • pip3 --version # Проверить версию pip (с версией) • python -m venv env # Создать виртуальное окружение • pip install pkg # Установить пакет 🚀 Готово к работе!