18_apollo_aem_ansible子模块软件架构分析

12 阅读11分钟

18_apollo_aem_ansible子模块软件架构分析

1. 概述

  apollo_aem_ansible子模块是Apollo自动驾驶平台环境管理(AEM)系统的核心配置模块,基于Ansible自动化运维工具实现开发环境的初始化和依赖管理。该模块通过角色化的Playbook设计,将环境配置分解为多个独立的角色,包括基础环境、Cyber依赖、模块基础、普通模块、驱动依赖、DreamView依赖、贡献依赖、GPU支持和可视化依赖等。模块支持Ubuntu和Gentoo操作系统,能够根据不同的系统架构(x86_64、aarch64)自动选择合适的安装脚本,为Apollo开发环境提供一键式配置能力。

2. 软件架构图

graph TB
    subgraph "AEM入口层"
        A1[aem命令]
        A2[aem-bootstrap]
        A3[aem-create]
        A4[aem-start]
    end

    subgraph "Ansible配置层"
        C1[ansible.cfg]
        C2[playbook.yaml]
        C3[galaxy.yml]
        C4[galaxy-requirements.yaml]
    end

    subgraph "角色管理层"
        R1[base_env角色]
        R2[cyber_deps角色]
        R3[modules_base角色]
        R4[ordinary_modules角色]
        R5[drivers_deps角色]
        R6[dreamview_deps角色]
        R7[contrib_deps角色]
        R8[gpu_support角色]
        R9[visualizer_deps角色]
        R10[legacy_scripts角色]
        R11[tests角色]
    end

    subgraph "任务执行层"
        T1[OS检测任务]
        T2[包安装任务]
        T3[脚本执行任务]
        T4[配置文件任务]
        T5[服务启动任务]
    end

    subgraph "安装器层"
        I1[install_protobuf.sh]
        I2[install_ffmpeg.sh]
        I3[install_opencv.sh]
        I4[install_pcl.sh]
        I5[install_vtk.sh]
        I6[install_qt.sh]
        I7[install_grpc.sh]
        I8[install_libtorch.sh]
    end

    subgraph "输出层"
        O1[开发环境]
        O2[依赖库]
        O3[配置文件]
        O4[服务进程]
    end

    A1 --> C2
    A2 --> C2
    A3 --> C2
    A4 --> C2
    C1 --> C2
    C2 --> R1
    C2 --> R2
    C2 --> R3
    C2 --> R4
    C2 --> R5
    C2 --> R6
    C2 --> R7
    C2 --> R8
    C2 --> R9
    C2 --> R10
    C2 --> R11
    R1 --> T1
    R1 --> T2
    R2 --> T2
    R2 --> T3
    R3 --> T3
    R4 --> T3
    R5 --> T3
    R6 --> T3
    R7 --> T3
    R8 --> T3
    R9 --> T3
    R10 --> T3
    T3 --> I1
    T3 --> I2
    T3 --> I3
    T3 --> I4
    T3 --> I5
    T3 --> I6
    T3 --> I7
    T3 --> I8
    I1 --> O2
    I2 --> O2
    I3 --> O2
    I4 --> O2
    I5 --> O2
    I6 --> O2
    I7 --> O2
    I8 --> O2
    T2 --> O2
    T4 --> O3
    T5 --> O4
    O2 --> O1

    style C2 fill:#e1f5fe
    style R1 fill:#f3e5f5
    style R2 fill:#fff3e0
    style R3 fill:#e8f5e8
    style I1 fill:#fce4ec

3. 调用流程图

sequenceDiagram
    participant User as 用户
    participant AEM as AEM命令
    participant Ansible as Ansible引擎
    participant Playbook as playbook.yaml
    participant BaseEnv as base_env角色
    participant CyberDeps as cyber_deps角色
    participant ModulesBase as modules_base角色
    participant OrdinaryModules as ordinary_modules角色
    participant DriversDeps as drivers_deps角色
    participant DreamviewDeps as dreamview_deps角色
    participant ContribDeps as contrib_deps角色
    participant GpuSupport as gpu_support角色
    participant VisualizerDeps as visualizer_deps角色
    participant Installer as 安装脚本
    participant System as 目标系统

    User->>AEM: 执行aem create
    AEM->>Ansible: 启动Ansible
    Ansible->>Playbook: 加载playbook.yaml
    Playbook->>Playbook: 收集系统信息
    Playbook->>Playbook: 验证操作系统

    Playbook->>BaseEnv: 执行base_env角色
    BaseEnv->>BaseEnv: 检测操作系统
    BaseEnv->>BaseEnv: 选择任务文件
    BaseEnv->>BaseEnv: 安装基础包
    BaseEnv-->>Playbook: 基础环境完成

    Playbook->>CyberDeps: 执行cyber_deps角色
    CyberDeps->>CyberDeps: 更新apt缓存
    CyberDeps->>CyberDeps: 安装ncurses
    CyberDeps->>CyberDeps: 配置ldconfig
    CyberDeps->>Installer: 执行install_protobuf.sh
    Installer->>System: 安装protobuf
    System-->>Installer: 安装完成
    Installer-->>CyberDeps: 返回结果
    CyberDeps-->>Playbook: Cyber依赖完成

    Playbook->>ModulesBase: 执行modules_base角色
    ModulesBase->>Installer: 执行install_ffmpeg.sh
    Installer->>System: 安装ffmpeg
    System-->>Installer: 安装完成
    Installer-->>ModulesBase: 返回结果
    ModulesBase-->>Playbook: 模块基础完成

    Playbook->>OrdinaryModules: 执行ordinary_modules角色
    OrdinaryModules->>OrdinaryModules: 检测操作系统
    OrdinaryModules->>OrdinaryModules: 选择任务文件
    OrdinaryModules->>OrdinaryModules: 安装普通模块
    OrdinaryModules-->>Playbook: 普通模块完成

    Playbook->>DriversDeps: 执行drivers_deps角色
    DriversDeps->>Installer: 执行驱动安装脚本
    Installer->>System: 安装驱动依赖
    System-->>Installer: 安装完成
    Installer-->>DriversDeps: 返回结果
    DriversDeps-->>Playbook: 驱动依赖完成

    Playbook->>DreamviewDeps: 执行dreamview_deps角色
    DreamviewDeps->>Installer: 执行DreamView安装脚本
    Installer->>System: 安装DreamView依赖
    System-->>Installer: 安装完成
    Installer-->>DreamviewDeps: 返回结果
    DreamviewDeps-->>Playbook: DreamView依赖完成

    Playbook->>ContribDeps: 执行contrib_deps角色
    ContribDeps->>Installer: 执行贡献依赖安装脚本
    Installer->>System: 安装贡献依赖
    System-->>Installer: 安装完成
    Installer-->>ContribDeps: 返回结果
    ContribDeps-->>Playbook: 贡献依赖完成

    Playbook->>GpuSupport: 执行gpu_support角色
    GpuSupport->>GpuSupport: 检测GPU
    GpuSupport->>Installer: 执行GPU安装脚本
    Installer->>System: 安装GPU支持
    System-->>Installer: 安装完成
    Installer-->>GpuSupport: 返回结果
    GpuSupport-->>Playbook: GPU支持完成

    Playbook->>VisualizerDeps: 执行visualizer_deps角色
    VisualizerDeps->>VisualizerDeps: 检测操作系统
    VisualizerDeps->>VisualizerDeps: 选择任务文件
    VisualizerDeps->>Installer: 执行可视化安装脚本
    Installer->>System: 安装可视化依赖
    System-->>Installer: 安装完成
    Installer-->>VisualizerDeps: 返回结果
    VisualizerDeps-->>Playbook: 可视化依赖完成

    Playbook-->>Ansible: 所有角色完成
    Ansible-->>AEM: 环境配置完成
    AEM-->>User: 返回成功结果

4. UML类图

4.1 核心角色类图

classDiagram
    class AnsibleRole {
        +name: string
        +description: string
        +tasks: list
        +handlers: list
        +vars: dict
        +defaults: dict
        +meta: dict
        +execute()
    }

    class BaseEnvRole {
        +name: string
        +tasks: list
        +include_tasks()
        +install_base_packages()
    }

    class CyberDepsRole {
        +name: string
        +tasks: list
        +update_apt_cache()
        +install_ncurses()
        +configure_ldconfig()
        +install_protobuf()
    }

    class ModulesBaseRole {
        +name: string
        +tasks: list
        +install_ffmpeg()
        +install_proj()
        +install_vtk()
        +install_pcl()
        +install_opencv()
    }

    class OrdinaryModulesRole {
        +name: string
        +tasks: list
        +include_tasks()
        +install_ordinary_modules()
    }

    class DriversDepsRole {
        +name: string
        +tasks: list
        +install_drivers_deps()
    }

    class DreamviewDepsRole {
        +name: string
        +tasks: list
        +install_dreamview_deps()
    }

    class ContribDepsRole {
        +name: string
        +tasks: list
        +install_contrib_deps()
    }

    class GpuSupportRole {
        +name: string
        +tasks: list
        +detect_gpu()
        +install_gpu_support()
    }

    class VisualizerDepsRole {
        +name: string
        +tasks: list
        +include_tasks()
        +install_visualizer_deps()
    }

    AnsibleRole <|-- BaseEnvRole
    AnsibleRole <|-- CyberDepsRole
    AnsibleRole <|-- ModulesBaseRole
    AnsibleRole <|-- OrdinaryModulesRole
    AnsibleRole <|-- DriversDepsRole
    AnsibleRole <|-- DreamviewDepsRole
    AnsibleRole <|-- ContribDepsRole
    AnsibleRole <|-- GpuSupportRole
    AnsibleRole <|-- VisualizerDepsRole

4.2 安装器类图

classDiagram
    class Installer {
        +name: string
        +version: string
        +install_prefix: string
        +install()
        +download()
        +compile()
        +configure()
    }

    class ProtobufInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    class FfmpegInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    class OpencvInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    class PclInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    class VtkInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    class QtInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    class GrpcInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    class LibtorchInstaller {
        +name: string
        +version: string
        +install_atom: string
        +install_prefix: string
        +install()
    }

    Installer <|-- ProtobufInstaller
    Installer <|-- FfmpegInstaller
    Installer <|-- OpencvInstaller
    Installer <|-- PclInstaller
    Installer <|-- VtkInstaller
    Installer <|-- QtInstaller
    Installer <|-- GrpcInstaller
    Installer <|-- LibtorchInstaller

4.3 Playbook类图

classDiagram
    class Playbook {
        +name: string
        +hosts: list
        +connection: string
        +gather_facts: bool
        +become_method: string
        +tasks: list
        +execute()
    }

    class Task {
        +name: string
        +module: string
        +params: dict
        +when: list
        +with_items: list
        +execute()
    }

    class IncludeRoleTask {
        +name: string
        +role_name: string
        +execute()
    }

    class PackageFactsTask {
        +name: string
        +manager: string
        +execute()
    }

    class FailTask {
        +name: string
        +msg: string
        +when: list
        +execute()
    }

    class ShellTask {
        +name: string
        +cmd: string
        +executable: string
        +environment: dict
        +execute()
    }

    class AptTask {
        +name: string
        +package: list
        +state: string
        +update_cache: bool
        +execute()
    }

    Playbook --> Task
    Task <|-- IncludeRoleTask
    Task <|-- PackageFactsTask
    Task <|-- FailTask
    Task <|-- ShellTask
    Task <|-- AptTask

5. 状态机

5.1 环境配置状态机

stateDiagram-v2
    [*] --> INIT: 开始配置
    INIT --> GATHERING_FACTS: 收集系统信息
    GATHERING_FACTS --> FACTS_GATHERED: 信息收集完成
    FACTS_GATHERED --> VERIFYING_OS: 验证操作系统
    VERIFYING_OS --> OS_VALID: 操作系统有效
    VERIFYING_OS --> OS_INVALID: 操作系统无效
    OS_VALID --> INSTALLING_BASE: 安装基础环境
    OS_INVALID --> FAILED: 配置失败
    INSTALLING_BASE --> BASE_INSTALLED: 基础环境安装完成
    BASE_INSTALLED --> INSTALLING_CYBER: 安装Cyber依赖
    INSTALLING_CYBER --> CYBER_INSTALLED: Cyber依赖安装完成
    CYBER_INSTALLED --> INSTALLING_MODULES_BASE: 安装模块基础
    INSTALLING_MODULES_BASE --> MODULES_BASE_INSTALLED: 模块基础安装完成
    MODULES_BASE_INSTALLED --> INSTALLING_ORDINARY: 安装普通模块
    INSTALLING_ORDINARY --> ORDINARY_INSTALLED: 普通模块安装完成
    ORDINARY_INSTALLED --> INSTALLING_DRIVERS: 安装驱动依赖
    INSTALLING_DRIVERS --> DRIVERS_INSTALLED: 驱动依赖安装完成
    DRIVERS_INSTALLED --> INSTALLING_DREAMVIEW: 安装DreamView依赖
    INSTALLING_DREAMVIEW --> DREAMVIEW_INSTALLED: DreamView依赖安装完成
    DREAMVIEW_INSTALLED --> INSTALLING_CONTRIB: 安装贡献依赖
    INSTALLING_CONTRIB --> CONTRIB_INSTALLED: 贡献依赖安装完成
    CONTRIB_INSTALLED --> INSTALLING_GPU: 安装GPU支持
    INSTALLING_GPU --> GPU_INSTALLED: GPU支持安装完成
    GPU_INSTALLED --> INSTALLING_VISUALIZER: 安装可视化依赖
    INSTALLING_VISUALIZER --> VISUALIZER_INSTALLED: 可视化依赖安装完成
    VISUALIZER_INSTALLED --> COMPLETED: 配置完成
    FAILED --> [*]: 配置失败
    COMPLETED --> [*]: 配置成功

    note right of GATHERING_FACTS: 收集操作系统、架构等信息
    note right of VERIFYING_OS: 验证Ubuntu 18.04/20.04/22.04或Gentoo
    note right of INSTALLING_BASE: 安装基础系统包
    note right of INSTALLING_CYBER: 安装protobuf等Cyber依赖
    note right of INSTALLING_MODULES_BASE: 安装ffmpeg等模块基础
    note right of INSTALLING_ORDINARY: 安装普通模块依赖
    note right of INSTALLING_DRIVERS: 安装传感器驱动依赖
    note right of INSTALLING_DREAMVIEW: 安装DreamView依赖
    note right of INSTALLING_CONTRIB: 安装贡献模块依赖
    note right of INSTALLING_GPU: 安装GPU支持库
    note right of INSTALLING_VISUALIZER: 安装可视化工具依赖

5.2 角色执行状态机

stateDiagram-v2
    [*] --> LOADING: 加载角色
    LOADING --> LOADED: 角色加载完成
    LOADED --> READING_TASKS: 读取任务文件
    READING_TASKS --> TASKS_READ: 任务文件读取完成
    TASKS_READ --> SELECTING_OS: 选择操作系统任务
    SELECTING_OS --> OS_SELECTED: 操作系统任务选择完成
    OS_SELECTED --> EXECUTING_TASKS: 执行任务
    EXECUTING_TASKS --> TASK_EXECUTED: 任务执行完成
    TASK_EXECUTED --> CHECKING_HANDLERS: 检查处理器
    CHECKING_HANDLERS --> HANDLERS_CHECKED: 处理器检查完成
    HANDLERS_CHECKED --> COMPLETED: 角色执行完成
    TASK_EXECUTED --> FAILED: 任务执行失败
    FAILED --> [*]: 角色执行失败
    COMPLETED --> [*]: 角色执行成功

    note right of LOADING: 加载角色元数据和变量
    note right of READING_TASKS: 读取tasks/main.yml
    note right of SELECTING_OS: 根据操作系统选择任务文件
    note right of EXECUTING_TASKS: 按顺序执行任务列表
    note right of CHECKING_HANDLERS: 检查是否需要触发处理器

5.3 安装器执行状态机

stateDiagram-v2
    [*] --> PREPARING: 准备安装
    PREPARING --> CHECKING_DEPS: 检查依赖
    CHECKING_DEPS --> DEPS_OK: 依赖满足
    CHECKING_DEPS --> INSTALLING_DEPS: 安装依赖
    INSTALLING_DEPS --> DEPS_INSTALLED: 依赖安装完成
    DEPS_OK --> DOWNLOADING: 下载源码
    DEPS_INSTALLED --> DOWNLOADING: 下载源码
    DOWNLOADING --> DOWNLOADED: 源码下载完成
    DOWNLOADED --> EXTRACTING: 解压源码
    EXTRACTING --> EXTRACTED: 源码解压完成
    EXTRACTED --> CONFIGURING: 配置编译
    CONFIGURING --> CONFIGURED: 编译配置完成
    CONFIGURED --> COMPILING: 编译源码
    COMPILING --> COMPILED: 源码编译完成
    COMPILED --> INSTALLING: 安装文件
    INSTALLING --> INSTALLED: 文件安装完成
    INSTALLED --> CLEANING: 清理临时文件
    CLEANING --> CLEANED: 清理完成
    CLEANED --> COMPLETED: 安装完成
    DOWNLOADING --> FAILED: 下载失败
    EXTRACTING --> FAILED: 解压失败
    CONFIGURING --> FAILED: 配置失败
    COMPILING --> FAILED: 编译失败
    INSTALLING --> FAILED: 安装失败
    FAILED --> [*]: 安装失败
    COMPLETED --> [*]: 安装成功

    note right of CHECKING_DEPS: 检查编译依赖是否满足
    note right of DOWNLOADING: 从源下载源码包
    note right of EXTRACTING: 解压源码包
    note right of CONFIGURING: 执行configure脚本
    note right of COMPILING: 执行make编译
    note right of INSTALLING: 执行make install
    note right of CLEANING: 删除临时文件

6. 源码分析

6.1 Playbook配置分析

6.1.1 主Playbook结构

  playbook.yaml定义了AEM环境配置的主要流程。

- name: Initialize host
  hosts: localhost
  connection: local
  gather_facts: true
  become_method: sudo
  tasks:
    - name: Gather package facts
      ansible.builtin.package_facts:
        manager: auto

    - name: Verify OS
      ansible.builtin.fail:
        msg: "{{ ansible_distribution }} {{ ansible_distribution_version }} is not supported."
      when:
        - ansible_distribution != 'Ubuntu' and ansible_distribution_version not in ['22.04', '20.04', '18.04']
        - ansible_distribution != 'Gentoo'

    - name: Install Base Environment
      include_role:
        name: apolloauto.dev_env.base_env

    - name: Install Cyber Dependencies
      include_role:
        name: apolloauto.dev_env.cyber_deps

    - name: Install Modules Base Dependencies
      include_role:
        name: apolloauto.dev_env.modules_base

    - name: Install Oridinary Modules Dependencies
      include_role:
        name: apolloauto.dev_env.ordinary_modules

    - name: Install Drivers Dependencies
      include_role:
        name: apolloauto.dev_env.drivers_deps

    - name: Install Dreamview Dependencies
      include_role:
        name: apolloauto.dev_env.dreamview_deps

    - name: Install Contrib Dependencies
      include_role:
        name: apolloauto.dev_env.contrib_deps

    - name: Install GPU Support
      include_role:
        name: apolloauto.dev_env.gpu_support

    - name: Install Visualizer Dependencies
      include_role:
        name: apolloauto.dev_env.visualizer_deps

  该Playbook定义了环境配置的完整流程,包括系统信息收集、操作系统验证和多个角色的顺序执行。每个角色负责安装特定类型的依赖,确保环境的完整性和一致性。

6.1.2 操作系统验证

  操作系统验证任务使用fail模块检查目标系统是否受支持。

- name: Verify OS
  ansible.builtin.fail:
    msg: "{{ ansible_distribution }} {{ ansible_distribution_version }} is not supported."
  when:
    - ansible_distribution != 'Ubuntu' and ansible_distribution_version not in ['22.04', '20.04', '18.04']
    - ansible_distribution != 'Gentoo'

  该任务检查操作系统是否为Ubuntu 18.04、20.04、22.04或Gentoo,如果不满足条件则失败并显示错误消息。这种验证机制确保了环境配置只在受支持的系统上执行。

6.2 基础环境角色分析

6.2.1 基础环境任务

  base_env/tasks/main.yml定义了基础环境安装的任务。

---
# tasks file for ansible/roles/base_env

- name: Install Base Packages by OS
  ansible.builtin.include_tasks: "{{ lookup('ansible.builtin.first_found', params) }}"
  vars:
    params:
      files:
        - "{{ ansible_distribution }}.{{ ansible_distribution_version }}.{{ ansible_architecture }}.yml"
        - "{{ ansible_distribution }}.{{ ansible_distribution_version }}.yml"
        - "{{ ansible_distribution }}.{{ ansible_architecture }}.yml"
        - "{{ ansible_distribution }}.yml"
        - "{{ ansible_os_family }}.yml"
        - "default.yaml"
      paths:
        - 'tasks'

  该任务使用first_found查找器根据操作系统、版本和架构选择合适的任务文件。查找顺序从最具体到最通用,确保在不同系统上都能找到合适的配置。这种设计实现了跨平台支持。

6.3 Cyber依赖角色分析

6.3.1 Cyber依赖任务

  cyber_deps/tasks/main.yml定义了Cyber RT中间件依赖的安装任务。

---
# tasks file for ansible/roles/cyber_deps
- name: Update apt cache
  become: true
  ansible.builtin.apt:
    update_cache: yes

- name: Install ncurses
  become: true
  ansible.builtin.apt:
    name:
      - libncurses5-dev
    state: latest
    update_cache: false

- name: Add sysroot to ldconfig
  become: true
  ansible.builtin.lineinfile:
    path: /etc/ld.so.conf.d/apolloauto.conf
    line: /opt/apollo/sysroot/lib
    create: yes

- name: Install protobuf
  become: true
  ansible.builtin.shell:
    cmd: /opt/apollo/installers/install_protobuf.sh
    executable: /bin/bash
  args: []
  environment:
    INSTALL_ATOM: "protobuf-3.14.0"
    PROTOBUF_INSTALL_PREFIX: "/usr"

  该角色首先更新apt缓存,然后安装ncurses库(cyber_monitor需要)。接着配置ldconfig,将sysroot库路径添加到动态链接器搜索路径。最后执行protobuf安装脚本,通过环境变量指定安装版本和前缀。这种分步骤的安装方式确保了依赖的正确安装和配置。

6.3.2 ldconfig配置

  ldconfig配置任务使用lineinfile模块添加库路径。

- name: Add sysroot to ldconfig
  become: true
  ansible.builtin.lineinfile:
    path: /etc/ld.so.conf.d/apolloauto.conf
    line: /opt/apollo/sysroot/lib
    create: yes

  该任务在/etc/ld.so.conf.d/目录下创建apolloauto.conf文件,并添加sysroot库路径。create=yes参数确保文件不存在时自动创建。这种配置方式使得动态链接器能够找到Apollo的库文件。

6.4 模块基础角色分析

6.4.1 模块基础任务

  modules_base/tasks/main.yml定义了模块基础依赖的安装任务。

---
# tasks file for ansible/roles/modules_base
- name: Install ffmpeg
  become: true
  ansible.builtin.shell:
    cmd: /opt/apollo/installers/install_ffmpeg.sh
    executable: /bin/bash
  args: []
  environment:
    INSTALL_ATOM: "ffmpeg-4.3.1"
    INSTALL_PREFIX: "/opt/apollo/sysroot"

  该角色执行ffmpeg安装脚本,通过环境变量指定安装版本和安装前缀。ffmpeg是Apollo中音视频处理的重要依赖,用于音频模块和视频处理功能。安装到sysroot目录确保了库文件的集中管理。

6.5 安装脚本分析

6.5.1 安装脚本结构

  安装脚本位于aem/ansible/roles/legacy_scripts/files/installers/目录,每个脚本负责安装特定的依赖库。

#!/bin/bash
# install_protobuf.sh
set -e

INSTALL_ATOM="${INSTALL_ATOM:-protobuf-3.14.0}"
PROTOBUF_INSTALL_PREFIX="${PROTOBUF_INSTALL_PREFIX:-/usr}"

# 下载源码
wget https://github.com/protocolbuffers/protobuf/archive/v3.14.0.tar.gz

# 解压
tar -xzf v3.14.0.tar.gz
cd protobuf-3.14.0

# 配置
./configure --prefix=${PROTOBUF_INSTALL_PREFIX}

# 编译
make -j$(nproc)

# 安装
make install

# 清理
cd ..
rm -rf protobuf-3.14.0 v3.14.0.tar.gz

  安装脚本遵循标准的编译安装流程:下载源码、解压、配置、编译、安装和清理。set -e确保任何命令失败时脚本立即退出。环境变量INSTALL_ATOM和PROTOBUF_INSTALL_PREFIX允许自定义安装版本和路径。

6.5.2 安装器基础脚本

  installer_base.sh提供了安装器的基础功能。

#!/bin/bash
# installer_base.sh
set -e

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 检查命令是否存在
check_command() {
    if ! command -v $1 &> /dev/null; then
        log_error "$1 is not installed"
        exit 1
    fi
}

# 下载文件
download_file() {
    local url=$1
    local output=$2
    log_info "Downloading $url to $output"
    wget -O $output $url
}

# 解压文件
extract_file() {
    local file=$1
    local dest=$2
    log_info "Extracting $file to $dest"
    mkdir -p $dest
    tar -xzf $file -C $dest
}

  该基础脚本提供了通用的安装功能,包括日志输出、命令检查、文件下载和解压。其他安装脚本可以source该脚本,复用这些基础功能。这种模块化设计减少了代码重复,提高了可维护性。

6.6 角色元数据分析

6.6.1 角色元数据结构

  每个角色都包含meta/main.yml文件,定义角色的元数据。

---
galaxy_info:
  author: Apollo Auto
  description: Apollo Development Environment Role
  company: Apollo Auto
  license: Apache 2.0
  min_ansible_version: 2.9

  platforms:
    - name: Ubuntu
      versions:
        - bionic
        - focal
        - jammy
    - name: Gentoo
      versions:
        - all

  galaxy_tags:
    - apollo
    - autonomous
    - driving
    - development
    - environment

dependencies: []

  该元数据文件定义了角色的作者、描述、许可证、最低Ansible版本、支持的平台和标签。这些信息用于Ansible Galaxy的角色发布和发现。dependencies字段定义了角色的依赖关系,当前为空表示无依赖。

6.7 角色变量分析

6.7.1 默认变量

  每个角色都包含defaults/main.yml文件,定义角色的默认变量。

---
# defaults file for ansible/roles/base_env
base_packages:
  - build-essential
  - cmake
  - git
  - wget
  - curl
  - vim
  - unzip
  - pkg-config

base_packages_ubuntu:
  - software-properties-common
  - apt-transport-https
  - ca-certificates
  - gnupg
  - lsb-release

base_packages_gentoo:
  - app-portage/eix
  - app-portage/gentoolkit

  该文件定义了基础包的列表,包括通用包、Ubuntu特定包和Gentoo特定包。这些变量可以在任务中使用,实现包列表的集中管理。通过定义不同平台的包列表,实现了跨平台支持。

6.7.2 角色变量

  vars/main.yml文件定义了角色的变量,这些变量优先级高于默认变量。

---
# vars file for ansible/roles/base_env
install_dir: /opt/apollo
installers_dir: /opt/apollo/installers
sysroot_dir: /opt/apollo/sysroot

protobuf_version: "3.14.0"
protobuf_url: "https://github.com/protocolbuffers/protobuf/archive/v{{ protobuf_version }}.tar.gz"

ffmpeg_version: "4.3.1"
ffmpeg_url: "https://ffmpeg.org/releases/ffmpeg-{{ ffmpeg_version }}.tar.gz"

  该文件定义了安装目录、安装器目录、sysroot目录等路径变量,以及各个依赖的版本和下载URL。这些变量在安装脚本中使用,实现了版本和URL的集中管理。

6.8 处理器分析

6.8.1 处理器定义

  handlers/main.yml文件定义了角色的处理器,用于在任务状态变化时执行特定操作。

---
# handlers file for ansible/roles/base_env
- name: Update ldconfig
  become: true
  ansible.builtin.command:
    cmd: ldconfig
  listen: ldconfig_changed

- name: Restart service
  become: true
  ansible.builtin.service:
    name: "{{ service_name }}"
    state: restarted
  listen: service_changed

  该文件定义了两个处理器:更新ldconfig和重启服务。处理器通过listen关键字监听特定事件,当任务触发notify时执行。这种机制确保了在配置变更后执行必要的后续操作。

6.9 Ansible配置分析

6.9.1 Ansible配置文件

  ansible.cfg定义了Ansible的配置选项。

[defaults]
stdout_callback = community.general.yaml
nocows = 1

  该配置文件设置了两个选项:stdout_callback指定输出格式为YAML,nocows禁用cowsay输出。YAML输出格式便于解析和日志记录,禁用cowsay使输出更加简洁。

6.10 Galaxy配置分析

6.10.1 Galaxy元数据

  galaxy.yml定义了Ansible Galaxy的元数据。

---
namespace: apolloauto
name: dev_env
version: 1.0.0
authors:
  - Apollo Auto
description: Apollo Development Environment
readme: README.md
license:
  - Apache-2.0
min_ansible_version: "2.9"

dependencies: []

  该文件定义了集合的命名空间、名称、版本、作者、描述、许可证和最低Ansible版本。这些信息用于Ansible Galaxy的集合发布和管理。

6.10.2 Galaxy依赖

  galaxy-requirements.yaml定义了Galaxy集合的依赖。

---
collections:
  - name: community.general
    version: ">=4.0.0"
  - name: ansible.posix
    version: ">=1.3.0"

  该文件定义了所需的Ansible集合,包括community.general和ansible.posix。这些集合提供了额外的模块和功能,用于环境配置。

7. 设计模式

7.1 角色模式(Role Pattern)

  Ansible角色实现了角色模式,将配置任务组织成可重用的单元。

- name: Install Base Environment
  include_role:
    name: apolloauto.dev_env.base_env

- name: Install Cyber Dependencies
  include_role:
    name: apolloauto.dev_env.cyber_deps

  每个角色封装了特定的配置逻辑,通过include_role任务调用。这种角色模式实现了配置的模块化和可重用性,简化了复杂配置的管理。

7.2 策略模式(Strategy Pattern)

  任务文件选择实现了策略模式,根据不同的操作系统选择不同的安装策略。

- name: Install Base Packages by OS
  ansible.builtin.include_tasks: "{{ lookup('ansible.builtin.first_found', params) }}"
  vars:
    params:
      files:
        - "{{ ansible_distribution }}.{{ ansible_distribution_version }}.{{ ansible_architecture }}.yml"
        - "{{ ansible_distribution }}.{{ ansible_distribution_version }}.yml"
        - "{{ ansible_distribution }}.{{ ansible_architecture }}.yml"
        - "{{ ansible_distribution }}.yml"
        - "{{ ansible_os_family }}.yml"
        - "default.yaml"

  该任务使用first_found查找器根据操作系统特征选择合适的任务文件。这种策略模式实现了跨平台支持,不同平台使用不同的安装策略。

7.3 模板方法模式(Template Method Pattern)

  安装脚本实现了模板方法模式,定义了安装的标准流程。

#!/bin/bash
set -e

# 1. 下载源码
download_file $URL $OUTPUT

# 2. 解压源码
extract_file $ARCHIVE $DEST

# 3. 配置编译
./configure --prefix=$PREFIX

# 4. 编译
make -j$(nproc)

# 5. 安装
make install

# 6. 清理
cleanup

  该脚本定义了安装的标准流程,包括下载、解压、配置、编译、安装和清理。这种模板方法模式确保了安装流程的一致性,不同库的安装脚本遵循相同的模式。

7.4 工厂模式(Factory Pattern)

  安装器基础脚本实现了工厂模式,提供通用的安装功能。

#!/bin/bash
# installer_base.sh

# 下载文件
download_file() {
    local url=$1
    local output=$2
    log_info "Downloading $url to $output"
    wget -O $output $url
}

# 解压文件
extract_file() {
    local file=$1
    local dest=$2
    log_info "Extracting $file to $dest"
    mkdir -p $dest
    tar -xzf $file -C $dest
}

  该基础脚本提供了通用的下载和解压功能,其他安装脚本可以复用这些功能。这种工厂模式减少了代码重复,提高了可维护性。

7.5 观察者模式(Observer Pattern)

  处理器实现了观察者模式,在任务状态变化时执行特定操作。

---
# handlers file for ansible/roles/base_env
- name: Update ldconfig
  become: true
  ansible.builtin.command:
    cmd: ldconfig
  listen: ldconfig_changed

  处理器监听特定事件,当任务触发notify时执行。这种观察者模式确保了在配置变更后执行必要的后续操作,如更新动态链接器缓存。

7.6 建造者模式(Builder Pattern)

  Playbook实现了建造者模式,逐步构建完整的开发环境。

- name: Install Base Environment
  include_role:
    name: apolloauto.dev_env.base_env

- name: Install Cyber Dependencies
  include_role:
    name: apolloauto.dev_env.cyber_deps

- name: Install Modules Base Dependencies
  include_role:
    name: apolloauto.dev_env.modules_base

  该Playbook通过顺序执行多个角色,逐步构建完整的开发环境。这种建造者模式确保了环境配置的有序性和完整性。

8. 总结

  apollo_aem_ansible子模块通过精心设计的Ansible角色和Playbook,实现了Apollo开发环境的自动化配置。其核心优势在于模块化的角色设计、跨平台支持、灵活的任务选择和完善的安装脚本管理。通过角色模式、策略模式、模板方法模式等设计模式的应用,该模块实现了配置流程的解耦和可扩展性,为Apollo开发环境提供了稳定可靠的自动化配置基础设施。模块的多平台支持和角色化设计显著提升了环境配置的灵活性和可维护性,为自动驾驶系统的快速开发和部署提供了有力支持。