epkg-package
[toc]
背景
为保障epkg软件包的快速上量,需要使用x2epkg(rpm2epkg)对现有软件生态的软件包进行批量转换,提升生成epkg软件的转换效率。本工程负责将现有rpm,archlinux,deb包等转换自动化,并且完成自动测试验证,安装,卸载,--help,保证epkg repo源的质量。
需求
- 基于rpm单包转换工具,生成openEuler,centos,fedora 仓库,并自动更新
- 对软件包进行自动测试验证,安装,卸载,--help
- 打通转换、测试、发布的pipeline全自动化流程
加包工程相关的代码仓
- infrastructure: docker容器与pipeline服务脚本
- 目录结构如下:
- epkg_translate/ <- epkg包批量转换和测试的pipeline服务源码目录> - translate/ <- epkg包批量转换的源码目录> ├── container/ ├── build_image.sh <- 构建转换docker镜像的脚本> ├── Dockerfile <- 转换的的docker描述文件> ├── start_container.sh <- 构建转换docker镜像的脚本> ├── src/ <- 批量epkg转换的源码目录> ├── translate-job.yaml <- lkp-tests转换任务的描述文件> ├── schedule_main.py <- pipeline批量任务的入口,由定时任务触发> ├── schedule_job.py <- 单repo任务的调度入口,及批量任务的处理逻辑> ├── schedule_repos.py <- 解析出哪些repos需要进行转换> ├── data_statistics.py <- 结果数据统计任务> ├── reschedule_main.py <- 为过程调试准备的脚本,如果已经转换过的repo也会再次被转换> ├── rpm-repos/ ├── openeuler-24.03.toml ├── fedora-41.toml ├── openeuler-24.09.toml <!-- repo的配置文件参考 https://gitee.com/openeuler/epkg/commit/07f54a8f3797913666bbb670916b2aa54849505f 进行添加 --> <- 一个操作系统的一个版本对应着一个配置文件> - test/ <- epkg包批量转换的源码目录> ├── container/ ├── build_image.sh ├── Dockerfile ├── start_container.sh ├── src/ ├── test-job.yaml ├── repos-path.yaml <- 需要测试的临时epkg repo源的路径> ├── schedule_main.py ├── schedule_job.py ├── schedule_repos.py ├── data_statistics.py - lkp-tests: 单个repo构建job和测试job
- 目录结构如下:
- programs/epkg_translate/ <- epkg单包执行转换的源码脚本> ├── jobs ├── epkg_translate.yaml ├── meta.yaml ├── parse ├── run <- epkg单包执行转换的入口shell脚本> ├── rpm_down.py <- 批量从 repo url下载rpm包的脚本> ├── epkg_translate.py <- 使用rpm2epkg或x2epkg工具对rpm包进行转换> ├── result_deal.py <- 分析执行结果,将成功的epkg包上传至临时目录> - programs/epkg_test/ ├── jobs ├── epkg_translate.yaml ├── meta.yaml ├── parse ├── run ├── result_deal.py <- 分析执行结果,将测试成功的epkg包发布repo源> - compass-ci: 分布式批量转换与测试的平台
- 目前只是使用compassci的能力,暂时不会修改其代码
输入输出定义
输入定义: rpm-repos 目录下的配置文件,以openeuler-24.03.toml为例
channel = "openEuler-24.03-LTS"
arch = ["aarch64", "x86_64"]
[repos.OS]
baseurl = "https://repo.openeuler.org/openEuler-24.03-LTS/OS"
[repos.update]
baseurl = "https://repo.openeuler.org/openEuler-24.03-LTS/update"
watch_update = true
[repos.everything]
baseurl = "https://repo.openeuler.org/openEuler-24.03-LTS/everything"
[job]
os = "openeuler"
os_version = "24.03-LTS"
输出定义:(具体存储位置待定)
- 正常可用的epkg repo源,比如:
https://repo.oepkgs.net/openeuler/epkg/channel/openEuler-24.09/everything/aarch64/
实现思路

- epkg转换的加包流程,输入为 rpm repo 源的列表,输出为epkg转换成功并且可以正常使用的repo源列表,其中最核心的为转换和测试的两个后台任务。
- 转换任务:批量地将rpm repos转换为临时的 epkg repos,每个repo对应一个compassCI的job;
- 测试任务: 将转换后的epkg 临时repos批量转换为用户可用的epkg repos,每个repo对应一个compassCI的job;
实现约束:
- 全自动化服务使用docker容器化部署至z9管理节点
- 任务的入口和串联脚本集成至docker容器中,每天通过定时任务进行检测是否需要执行批量转换任务
- 按一个repo对应一个job,可能粗粒度地控制每天 repo 的个数进行流量控制,比如每天最多同时跑50个 repo 的转换
- 资源的分配与任务的调度使用compassCI的现有能力(最好是基于最新的compassCI代码部署的服务)
- 测试定时任务与epkg 发布脚本也集成至docker容器中,每天通过定时任务检查是否需要epkg包的测试,如果需要则将测试成功的epkg包发布至对应的repo源
rpm repo 源转换
- 范围:openEuler,centos,fedora 最新版本的所有 repo 源
rpm repo 源的感知主要分为一下两种情况:
- 全量新增: 第一次配置某个操作系统某个版本的rpm源,需要全量进行转换
- 如果后续需要重新构建则调用 reschedule_main.py 的脚本手动触发
- 存量更新: 对每个操作系统的update的repo源进行diff监控,新增软件包才进行转换
转换任务 dokerfile 的定义:
# 最好使用 openeuler:24.03-LTS 的镜像,工具链是最新的
from openeuler:22.03-LTS as BUILDER
WORKDIR /root
RUN sed -i "s|repo.openeuler.org|mirrors.nju.edu.cn/openeuler|g" /etc/yum.repos.d/openEuler.repo \
&& sed -i '/metalink/d' /etc/yum.repos.d/openEuler.repo \
&& sed -i '/metadata_expire/d' /etc/yum.repos.d/openEuler.repo
ENV CCI_SRC=/root/compass-ci
ENV LKP_SRC=/root/lkp-tests
ENV PATH $PATH:$LKP_SRC/sbin:$LKP_SRC/bin
ENV PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
# https://gitee.com/openeuler/infrastructure.git 在这个本地目录下执行
COPY epkg_translate/translate .
RUN yum install -y git ruby rubygems make gcc diffutils util-linux lftp hostname sudo gzip git ruby-devel rubygem-json rubygem-bundler gcc-c++ ruby-devel rubygem-rake rpm-build python3-pip wget \
&& gem install rest-client \
&& git clone https://gitee.com/compass-ci/lkp-tests.git \
&& pip install schedule \
&& pip install requests
WORKDIR /root/epkg_translate/translate/src
CMD python3 schedule_main.py
输入定义: rpm-repos.yaml
- 全量repo源的yaml 文件,包含了新增repo源和存量待更行的update repo源, 即 rpm-repos.yaml 文件
- 全量新增repo源的配置策略: 非 update 的源只做一次转换,如果确实有需要重做转换,通过
reschedule_main.py单独执行该脚本进行转换, 相当于手动触发一次 rpm-repos 目录下配置文件的全量构建 - 存量更新repo源的配置策略:update 的源做持续 diff 转换,先找到新增或转换失败的rpm包,再调用工具做增量转换
输出定义: translate-job.yaml
suite: epkg-translate
category: functional
group_id: epkg-translate
program:
epkg_translate:
custom_repo_name: epkg
mount_repo_name: epkg
runtime: 1d
strategy: {{main.strategy}}
_epkg_repo_server: https://api.compass-ci.openeuler.org:20018
_epkg_repo_dir: /rpm/testing/epkg/{{toml.channel}}
os: {{toml.job.os}}
os_version: {{toml.job.os_version}}
os_arch: {{toml.arch}}
-
需要批量进行转换的repo源信息(repos_list, arch, strategy)
-
strategy 暂定取值为: all(reschedule_main.py入口进行的job提交), delta(schedule_main.py入口进行的job提交)
-
全量新增功能实现思路:
- reschedule_main.py入口进行的job提交
- epkg 临时repo源是空的时,本质上还是一次全量的转换
-
存量功能实现思路:
- 直接通过配置文件中的 watch_update 进行判断, watch_update 为true的是存量任务
- 存量diff的rpm包的获取在job但任务里面进行处理,不在docker容器中进行处理
- 先对比 rpm repo 源和 epkg 临时 repo 源的差异,找出新增的 repo 源
- 如果 epkg 临时 repo 源不存在,则update下的所有rpm包都需要进行转换
- 如果 epkg 临时 repo 源存在,则for循环获取差异,得到待转换的diff列表
转换任务
转换任务本质就是利用epkg的工具链进行rpm包的转换,为了提高资源的使用效率,每个compassCI的job应该批量跑多个epkg包的转换,执行batch 转换。

- 功能实现思路:
- 容器内服务实现思路
# 解析 rpm-repos.yaml 配置文件,获需要在下一个周期进行转换的所有repo源信息 need_repos = get_rpm_repos(repo_config=rpm-repos.yaml) # need_repos 为RepoInfo的数组 class RepoInfo: base_url name # 这个参数是为了区分是否为update 源,是否做diff 增量转换 stategy # 非update的源,在服务启动后的第一个周期执行完转换后,需要将该字段重置为 false force_onece # 遍历分批的rpm包列表,循环提交任务 for repo_info in need_repos: if repo_info.stategy == "all" and repo_info.force_onece == false: continue submit job.yaml rpm_baseurl=repo_info.base_url repo_name=repo_info.name traslate_strategy=repo_info.stategy count++ sleep(30s) # 达到并发上限需要睡眠一段时间再执行,按repo控并发 if count > 5: count = 0 sleep(2h)- 在compassCI执行机上批量执行待转换的rpm包
# epkg 工具链准备,环境初始化 git clone https://gitee.com/rmp2epkg # 下载需要转换的repo源全量的rpm包并解压 wget https://repo.openeuler.org/openEuler-24.03-LTS/OS/aarch64/repodata/*primary.xml.zst && zstd -d primary.xml.zst # 解析出rpm包的列表 rpm_list = xml.etree.ElementTree primary.xml # 获取需要转换的rpm列表 if traslate_strategy == "delta": # 增量 update 更新转换场景 # 获取临时转换成功的rpm的列表 # 可以参考https://gitee.com/openeuler/epkg/blob/master/doc/epkg-format.md,里面有类似RPM repodata的index.json,用里面的store-paths里的软件包清单文件 # 需要解析 repodata/store-paths.txt.zst 这个源数据 rpm_success_list = getOldSuccessRpmList(epkg_path={{job.mount_repo_addr}}) delta_list = getNeedTransformRpmList(rpm_list, rpm_success_list) batch_list = delta_list else: batch_list = rpm_list # 遍历batch_list for one_rpm in batch_list: # 获取repo源和下载rpm包 wget https://repo.openeuler.org/openEuler-24.03-LTS/OS/aarch64/packages/xxx.rpm(one_rpm) # 使用 rpm2epkg 工具将二进制转换为 epkg rpm2epkg -i rpm_path -o epkg_path # 检查转换成功的epkg包,并将epkg上传至对应的epkg repo(临时的repo路径) upload epkg_path=/tmp/xxx.epkg epkg_repo=OS os_version=openEuler24.03 arch=aarch64
测试任务
测试任务本质就是利用epkg包管理器对转换后的rpm包进行安装、--help、卸载测试,为了提高资源的使用效率,每个compassCI的job应该批量跑多个epkg包的测试,执行 batch 测试。

- 功能实现思路:
- 容器内服务实现思路,测试任务的分批逻辑和待测epkg列表的获取和转换任务基本类似;待测试的epkg列表需要利用转换后的临时存储与全量以发布的epkg源对比,得到增量待测试的epkg包列表。
- 在compassCI执行机上批量执行epkg包的测试
# epkg 工具链准备,环境初始化 git clone https://gitee.com/openeuler/epkg.git # 仅root用户可使用global安装模式 wget https://repo.oepkgs.net/openeuler/epkg/rootfs/epkg-installer.sh sh epkg-installer.sh # 安装epkg epkg self install --url=https://tmp/epkg-repo bash // 重新执行.bashrc, 获得新的PATH # 创建epkg的测试环境1 epkg env create t1 # 遍历batch_list for one_epkg in batch_list: epkg install one_epkg one_epkg --help epkg uninstall one_epkg # 检查安装测试是否成功,成功后的epkg包上传至public路径进行发布 upload epkg_path=/public/xxx.epkg epkg_repo=OS os_version=openEuler24.03 arch=aarch64 # 清理掉epkg的环境 epkg destroy env t1
epkg repo 源上传
- 将测试成功的epkg包同步至外网可以正常访问的web服务器
- 策略采取push的模式,需要启动一个定时任务进行全量或增量更新公开的 epkg repo 源
方案待讨论点
- 前期x2epkg工具没有ready,使用rpm2epkg打通加包pipeline流程时,以一个 repo 对应一个job进行?
- 对齐结论:x2epkg 与 rpm2epkg 均以单repo粒度进行包转换
- 需要大量下载 rpm repo,是否需要做rpm的镜像源?如果需要,会有一个单独的任务做repo源镜像?
- 是否需要做增量感知?是否还有比 rpm发布全量 - epkg发布全量 = epkg_delta 更好的方法?
- 为了避免资源的过度占用,每个job批量执行500个epkg的转换或测试是否合理?
- 临时过程文件比如转换后的epkg包、下载的rpm、最后安装测试成功的epkg包是否用单独的 ftp 服务器进行存储?
- 目前以rpm2epkg作为批量工具,怎么将临时的epkg路径使用起来,用epkg 工具链对临时 repo 做测试?