提交 91e6f056 编写于 作者: A air9

init oec-hardware

上级 0562aba3
木兰宽松许可证, 第2版
木兰宽松许可证, 第2版
2020年1月 http://license.coscl.org.cn/MulanPSL2
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
0. 定义
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
“法人实体”是指提交贡献的机构及其“关联实体”。
“关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
1. 授予版权许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
2. 授予专利许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
3. 无商标许可
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。
4. 分发限制
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
5. 免责声明与责任限制
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
6. 语言
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
条款结束
如何将木兰宽松许可证,第2版,应用到您的软件
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
3, 请将如下声明文本放入每个源文件的头部注释中。
Copyright (c) [Year] [name of copyright holder]
oec-hardware is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
Mulan Permissive Software License,Version 2
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
January 2020 http://license.coscl.org.cn/MulanPSL2
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
0. Definition
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
Contribution means the copyrightable work licensed by a particular Contributor under this License.
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
Legal Entity means the entity making a Contribution and all its Affiliates.
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
1. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
2. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
3. No Trademark License
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4.
4. Distribution Restriction
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
5. Disclaimer of Warranty and Limitation of Liability
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
6. Language
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
END OF THE TERMS AND CONDITIONS
How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
iii Attach the statement to the appropriate annotated syntax at the beginning of each source file.
Copyright (c) [Year] [name of copyright holder]
oec-hardware is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
NAME := oec-hardware
VERSION_PY := hwcert/version.py
.PHONY: all clean install
SUBDIRS := hwcert tests server scripts
all: $(VERSION_PY)
for i in $(SUBDIRS); do $(MAKE) -C $$i DESTDIR=$(DESTDIR); done
$(VERSION_PY):
@echo "# $(VERSION_PY) is automatically-generated" > $(VERSION_PY)
@echo "version = '$(VERSION_RELEASE)'" >> $(VERSION_PY)
@echo "name = '$(NAME)'" >> $(VERSION_PY)
install:
mkdir -p $(DESTDIR)/usr/share/eulercert
mkdir -p $(DESTDIR)/var/eulercert
for i in $(SUBDIRS); do $(MAKE) -C $$i DESTDIR=$(DESTDIR) install; done
clean:
for i in $(SUBDIRS); do $(MAKE) -C $$i DESTDIR=$(DESTDIR) clean; done
rm -f $(VERSION_PY)
# oec-hardware
<!-- TOC -->
#### 介绍
Use for check hardware compatibility with openEuler
- [概述](#概述)
- [背景介绍](#背景介绍)
- [原理简介](#原理简介)
- [框架概览](#框架概览)
- [测试流程](#测试流程)
- [使用流程](#使用流程)
- [用户使用流程](#用户使用流程)
- [组网图](#组网图)
- [安装测试框架](#安装测试框架)
- [前提条件](#前提条件)
- [获取安装包](#获取安装包)
- [安装过程](#安装过程)
- [客户端](#客户端)
- [服务端](#服务端)
- [验证安装正确性](#验证安装正确性)
- [使用指导](#使用指导)
- [前提条件](#前提条件-1)
- [使用步骤](#使用步骤)
- [查看结果](#查看结果)
- [如何查看](#如何查看)
- [结果说明&建议](#结果说明建议)
- [附录:测试项说明](#附录测试项说明)
- [已有测试项](#已有测试项)
- [新增测试项](#新增测试项)
#### 软件架构
软件架构说明
<!-- /TOC -->
# 概述
#### 安装教程
## 背景介绍
1. xxxx
2. xxxx
3. xxxx
OS 厂商为了扩大自己产品的兼容性范围,常常寻求与硬件厂商的合作,进行兼容性测试。OS 厂商制定一个测试标准,并提供测试用例,硬件厂商进行实际的测试,测试通过后,OS 厂商和硬件厂商将共同对结果负责。这是一个双赢的合作,双方都可以藉此推销自己的产品。
#### 使用说明
认证目的就是保证 OS 与硬件平台的兼容性,认证仅限于基本功能验证,不包括性能测试等其它测试。
1. xxxx
2. xxxx
3. xxxx
欧拉硬件兼容性认证测试框架有如下特点:
#### 参与贡献
1. 为满足可信要求,必须使用欧拉操作系统,不能随意重编/插入内核模块。
2. 通过扫描机制自适应发现硬件列表,来确定要运行的测试用例集合。
3. 面向对象抽象各种硬件类型以及测试用例类,用于扩展开发。
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
## 原理简介
### 框架概览
#### 码云特技
```
.
├── hwcert 框架主功能
│ ├── certification.py 框架核心功能
│ ├── client.py 上传测试结果到服务端
│ ├── command.py bash命令执行封装
│ ├── commandUI.py 命令行交互工具
│ ├── device.py 扫描设备信息
│ ├── document.py 收集配置信息
│ ├── env.py 全局变量,主要是各个配置文件或目录的路径
│ ├── job.py 测试任务管理
│ ├── log.py 日志模块
│ ├── reboot.py 重启类任务专用,便于机器重启后仍能继续执行测试
│ ├── sysinfo.py 收集系统信息
│ └── test.py 测试套模板
├── scripts 工具脚本
│ ├── eulercert 框架命令行工具
│ ├── eulercert-server.service 框架服务端 service 文件,用于启动 web 服务器
│ ├── eulercert.service 框架客户端 service 文件,用于接管 reboot 用例
│ └── kernelrelease.json 规范可用于认证的系统和内核版本
├── server 服务端
│ ├── eulercert-server-pre.sh 服务预执行脚本
│ ├── results/ 测试结果存放目录
│ ├── server.py 服务端主程序
│ ├── static/ 图片存放目录
│ ├── templates/ 网页模板存放目录
│ ├── uwsgi.conf nginx 服务配置
│ └── uwsgi.ini uwsgi 服务配置
└── tests 测试套
```
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
### 测试流程
![test-flow](docs/test-flow.png)
## 使用流程
### 用户使用流程
![user-flow](docs/user-flow.png)
### 组网图
![test-network](docs/test-network.png)
# 安装测试框架
## 前提条件
安装了 EulerOS 2.0 (SP8) 及更高版本,或 openEuler 20.03 (LTS) 及更高版本。
## 获取安装包
* 安装包从 openEuler 官方网站下载。
* 校验安装包的完整性。
1. 获取校验文件中的校验值:
```
cat oec-hardware-*.rpm.sha256sum
```
2. 计算文件的sha256校验值:
```
sha256sum oec-hardware-*.rpm
```
命令执行完成后,输出校验值。
3. 对比步骤1和步骤2计算的校验值是否一致。
如果校验值一致说明安装文件完整性没有破坏,如果校验值不一致则可以确认文件完整性已被破坏,需要重新获取。
## 安装过程
### 客户端
1. 部分基础用例依赖 fio 和 memtester 工具,需要提前安装依赖(可以用 tools/ 里的源码包编译)。
```
rpm -ivh fio-3.7-2.aarch64.rpm memtester-4.3.0-13.aarch64.rpm
```
2. 安装 oec-hardware-1.0.0-h1.aarch64.rpm。
```
dnf install oec-hardware-1.0.0-h1.aarch64.rpm
```
### 服务端
1. 安装服务端子包。
```
dnf install oec-hardware-server-1.0.0-h1.aarch64.rpm
```
2. 服务端 web 展示页面部分组件系统本身不提供,需要使用 pip 安装(请自行配置可用 pip 源)。
```
pip3 install Flask Flask-bootstrap uwsgi
```
3. 启动服务。本服务默认使用 8080 端口,同时搭配 nginx(默认端口 80)提供 web 服务,请保证这些端口未被占用。
```
systemctl start eulercert-server.service
systemctl start nginx.service
```
4. 关闭防火墙和 SElinux。
```
systemctl stop firewalld
iptables -F
setenforce 0
```
## 验证安装正确性
客户端输入 `eulercert` 命令,可正常运行,则表示安装成功。如果安装有任何问题,可反馈至该邮箱:oecompatibility@openeuler.org 。
# 使用指导
## 前提条件
* `/usr/share/eulercert/kernelrelease.json`文件中列出了当前支持的所有系统版本,使用`uname -a` 命令确认当前系统内核版本是否属于框架支持的版本。
* 框架默认会扫描所有网卡,对网卡进行测试前,请自行筛选被测网卡,并给它配上能`ping`通服务端的 ip ;如果是测试客户端 `InfiniBand`网卡,服务端也必须有一个 `InfiniBand`网卡并提前配好 ip 。
## 使用步骤
1. 在客户端启动测试框架。在客户端启动 `eulercert`,其中 `ID``URL` 可以按需填写,`Server` 必须填写为客户端可以直接访问的服务器域名或 ip,用于展示测试报告和作网络测试的服务端。
```
# eulercert
The openEuler Hardware Certification Test Suite
Please provide your Certification ID:
Please provide your Product URL:
Please provide the Certification Server (Hostname or Ipaddr):
```
2. 进入测试套选择界面。在用例选择界面,框架将自动扫描硬件并选取当前环境可供测试的测试套,输入 `edit` 可以进入测试套选择界面。
```
These tests are recommended to complete the certification:
No. Run-Now? Status Class Device
1 yes NotRun acpi
2 yes NotRun clock
3 yes NotRun cpufreq
4 yes NotRun disk
5 yes NotRun ethernet enp3s0
6 yes NotRun ethernet enp4s0
7 yes NotRun ethernet enp5s0
8 yes NotRun kdump
9 yes NotRun memory
10 yes NotRun perf
11 yes NotRun system
12 yes NotRun usb
13 yes NotRun watchdog
Ready to begin testing? (run|edit|quit)
```
3. 选择测试套。`all|none` 分别用于 `全选|全取消`(必测项 `system` 不可取消);数字编号可选择测试套,每次只能选择一个数字,按回车符之后 `no` 变为 `yes`,表示已选择该测试套。
```
Select tests to run:
No. Run-Now? Status Class Device
1 no NotRun acpi
2 no NotRun clock
3 no NotRun cpufreq
4 no NotRun disk
5 yes NotRun ethernet enp3s0
6 no NotRun ethernet enp4s0
7 no NotRun ethernet enp5s0
8 no NotRun kdump
9 no NotRun memory
10 no NotRun perf
11 yes NotRun system
12 no NotRun usb
13 no NotRun watchdog
Selection (<number>|all|none|quit|run):
```
4. 开始测试。选择完成后输入 `run` 开始测试。
5. 上传测试结果。测试完成后可以上传测试结果到服务器,便于结果展示和日志分析。如果上传失败,请检查网络配置,然后重新上传测试结果。
```
...
------------- Summary -------------
ethernet-enp3s0 PASS
system FAIL
Log saved to /usr/share/eulercert/logs/eulercert-20200228210118-TnvUJxFb50.tar succ.
Do you want to submit last result? (y|n)
```
# 查看结果
## 如何查看
1. 浏览器打开服务端 IP 地址,点击导航栏 `Results` 界面,找到对应的测试 id 进入。
![results](docs/results.png)
2. 进入单个任务页可以看到具体的测试结果展示,包括环境信息和执行结果等。
- `Submit` 表示将结果上传到欧拉官方认证服务器(**当前尚未开放**)。
- `Devices` 查看所有测试设备信息。
- `Runtime` 查看测试运行日志。
- `Attachment` 下载测试附件。
![result-qemu](docs/result-qemu.png)
## 结果说明&建议
**Result** 列展示测试结果,结果有两种:**PASS** 或者 **FAIL**。如果结果为**FAIL**,可以直接点击结果来查看执行日志,根据报错对照用例代码进行排查。
# 附录:测试项说明
## 已有测试项
1. **system**
- 检查 OS 版本和 kernel 版本是否匹配。
- 检查安装的认证工具是否有被修改。
- 检查内核是否被感染。
- 检查 selinux 是否正常。
- 使用 dmidecode 工具读取硬件信息。
2. **cpufreq**
- 测试 cpu 在不同调频策略下运行频率是否同预期。
- 测试 cpu 在不同频率下完全同规格计算量所需时间是否与频率值反相关。
3. **clock**
- 测试时间矢量性,不会倒回。
- 测试 RTC 硬件时钟基本稳定性。
4. **memory**
- 使用 memtester 工具进行内存读写测试。
- mmap 全部系统可用内存,触发 swap,进行 120s 读写测试。
- 测试 hugetlb。
- 内存热插拔测试。
5. **network**
- 使用 ethtool 获取网卡信息和 ifconfig 对网卡进行 down/up 测试。
- 使用 qperf 测试以太网卡tcp/udp延迟和带宽,以及 http 上传、下载速率。
- 使用 perftest 测试 InfiniBand 或 RoCE 网卡延迟和带宽。
- **注意** 进行网络带宽测试时,请提前确认服务端网卡速率不小于客户端,并保证测试网络无其他流量干扰。
6. **disk**
使用 fio 工具进行裸盘/文件系统的顺序/随机读写测试。
7. **kdump**
触发 kdump,测试能否正常生成 vmcore 文件并解析。
8. **watchdog**
触发 watchdog,测试系统是否可以正常复位。
9. **perf**
测试 perf 工具是否能正常使用。
10. **cdrom**
使用 mkisofs 和 cdrecord 对光驱进行刻录和读取测试。
11. **ipmi**
使用 ipmitool 查询 IPMI 信息。
12. **nvme**
使用 nvme-cli 工具对盘进行格式化、读写、查询测试。
13. **tape**
测试磁带是否正常读写。
14. **usb**
插拔 usb 设备,测试 usb 接口能否正常识别。
15. **acpi**
利用 acpidump 工具读取数据。
## 新增测试项
1.`tests/` 添加自己的测试模板,实现自己的测试类继承框架 `Test`
2. 重要成员变量或函数。
- 函数 `test` - **必选**,测试主流程。
- 函数 `setup` - 测试开始前环境准备,主要用于初始化被测设备相关信息,可以参考 network 测试。
- 函数 `teardown` - 测试完成后环境清理,主要用于确保无论测试成功失败都能正确恢复环境,可以参考 network 测试。
- 变量 `requirements` - 以数组形式存放测试依赖的 rpm 包名,测试开始前框架自动安装。
- 变量 `reboot``rebootup` - 若 `reboot = True` 表示该测试套/测试用例会重启系统,且在重启后继续执行 `rebootup` 指定的函数,可以参考 kdump 测试。
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
HWCERT_CLASS_LIB := /usr/share/eulercert/lib
all: ;
install:
rm -rf $(DESTDIR)$(HWCERT_CLASS_LIB)/hwcert
mkdir -p $(DESTDIR)$(HWCERT_CLASS_LIB)/hwcert
cp -r ./*.py $(DESTDIR)$(HWCERT_CLASS_LIB)/hwcert/
clean:
rm -rf $(DESTDIR)$(HWCERT_CLASS_LIB)/hwcert
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import time
import argparse
import shutil
import datetime
import re
from .document import CertDocument, DeviceDocument, FactoryDocument
from .env import CertEnv
from .device import CertDevice, Device
from .command import Command, CertCommandError
from .commandUI import CommandUI
from .job import Job
from .reboot import Reboot
from .client import Client
class EulerCertification():
def __init__(self):
self.certification = None
self.test_factory = list()
self.devices = None
self.ui = CommandUI()
self.client = None
def run(self):
print("The openEuler Hardware Certification Test Suite")
self.load()
certdevice = CertDevice()
while True:
self.submit()
if self.check_result():
print("All cases are passed, test end.")
return True
devices = certdevice.get_devices()
self.devices = DeviceDocument(CertEnv.devicefile, devices)
self.devices.save()
# test_factory format example: [{"name":"nvme", "device":device, "run":True, "status":"PASS", "reboot":False}]
test_factory = self.get_tests(devices)
self.update_factory(test_factory)
if not self.choose_tests():
return True
args = argparse.Namespace(test_factory=self.test_factory)
job = Job(args)
job.run()
self.save(job)
def run_rebootup(self):
try:
self.load()
args = argparse.Namespace(test_factory=self.test_factory)
job = Job(args)
reboot = Reboot(None, job, None)
if reboot.check():
job.run()
reboot.clean()
self.save(job)
return True
except Exception as e:
print(e)
return False
def clean(self):
if self.ui.prompt_confirm("Are you sure to clean all certification data?"):
try:
Command("rm -rf %s" % CertEnv.certificationfile).run()
Command("rm -rf %s" % CertEnv.factoryfile).run()
Command("rm -rf %s" % CertEnv.devicefile).run()
except Exception as e:
print(e)
return False
return True
def load(self):
if not os.path.exists(CertEnv.datadirectory):
os.mkdir(CertEnv.datadirectory)
if not self.certification:
self.certification = CertDocument(CertEnv.certificationfile)
if not self.certification.document:
self.certification.new()
self.certification.save()
if not self.test_factory:
factory_doc = FactoryDocument(CertEnv.factoryfile)
self.test_factory = factory_doc.get_factory()
cert_id = self.certification.get_certify()
hardware_info = self.certification.get_hardware()
self.client = Client(hardware_info, cert_id)
print(" Certification ID: ".ljust(30) + cert_id)
print(" Hardware Info: ".ljust(30) + hardware_info)
print(" Product URL: ".ljust(30) + self.certification.get_url())
print(" OS Info: ".ljust(30) + self.certification.get_os())
print(" Kernel Info: ".ljust(30) + self.certification.get_kernel())
print(" Test Server: ".ljust(30) + self.certification.get_server())
print("")
def save(self, job):
doc_dir = os.path.join(CertEnv.logdirectoy, job.job_id)
if not os.path.exists(doc_dir):
return
FactoryDocument(CertEnv.factoryfile, self.test_factory).save()
shutil.copy(CertEnv.certificationfile, doc_dir)
shutil.copy(CertEnv.devicefile, doc_dir)
shutil.copy(CertEnv.factoryfile, doc_dir)
cwd = os.getcwd()
os.chdir(os.path.dirname(doc_dir))
dir_name = "eulercert-" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + "-" + job.job_id
pack_name = dir_name +".tar"
cmd = Command("tar -cf %s %s" % (pack_name, dir_name))
try:
os.rename(job.job_id, dir_name)
cmd.run()
except CertCommandError:
print("Error:Job log collect failed.")
return
print("Log saved to %s succ." % os.path.join(os.getcwd(), pack_name))
shutil.copy(pack_name, CertEnv.datadirectory)
for (rootdir, dirs, filenams) in os.walk("./"):
for dirname in dirs:
shutil.rmtree(dirname)
break
os.chdir(cwd)
def submit(self):
packages = list()
pattern = re.compile("^eulercert-[0-9]{14}-[0-9a-zA-Z]{10}.tar$")
for (root, dirs, files) in os.walk(CertEnv.datadirectory):
break
packages.extend(filter(pattern.search, files))
if len(packages) == 0:
return
packages.sort()
if self.ui.prompt_confirm("Do you want to submit last result?"):
server = self.certification.get_server()
path = os.path.join(CertEnv.datadirectory, packages[-1])
if not self.upload(path, server):
print("Upload failed.")
else:
print("Successfully upload result to server %s." % server)
time.sleep(2)
for filename in packages:
os.remove(os.path.join(CertEnv.datadirectory, filename))
def upload(self, path, server):
print("uploading...")
if not self.client:
cert_id = self.certification.get_certify()
hardware_info = self.certification.get_hardware()
self.client = Client(hardware_info, cert_id)
return self.client.upload(path, server)
def get_tests(self, devices):
nodevice = ["cpufreq", "memory", "clock", "profiler", "system", "stress", "kdump", "perf", "acpi", "watchdog"]
ethernet = ["ethernet"]
infiniband = ["infiniband"]
storage = ["nvme", "disk", "nvdimm"]
cdrom = ["cdrom"]
sort_devices = self.sort_tests(devices)
empty_device = Device()
test_factory = list()
casenames = []
for (dirpath, dirs, filenames) in os.walk(CertEnv.testdirectoy):
dirs.sort()
for filename in filenames:
if filename.endswith(".py") and not filename.startswith("__init__"):
casenames.append(filename.split(".")[0])
for testname in casenames:
if sort_devices.get(testname):
for device in sort_devices[testname]:
test = dict()
test["name"] = testname
test["device"] = device
test["run"] = True
test["status"] = "NotRun"
test["reboot"] = False
test_factory.append(test)
elif testname in nodevice:
test = dict()
test["name"] = testname
test["device"] = empty_device
test["run"] = True
test["status"] = "NotRun"
test["reboot"] = False
test_factory.append(test)
return test_factory
def sort_tests(self, devices):
sort_devices = dict()
empty_device = Device()
for device in devices:
if device.get_property("SUBSYSTEM") == "usb" and \
device.get_property("ID_VENDOR_FROM_DATABASE") == "Linux Foundation" and \
("2." in device.get_property("ID_MODEL_FROM_DATABASE") or \
"3." in device.get_property("ID_MODEL_FROM_DATABASE")):
sort_devices["usb"] = [empty_device]
continue
if device.get_property("PCI_CLASS") == "30000" or device.get_property("PCI_CLASS") == "38000":
sort_devices["video"] = [device]
continue
if device.get_property("SUBSYSTEM") == "tape" and "/dev/st" in device.get_property("DEVNAME"):
try:
sort_devices["tape"].extend([device])
except KeyError:
sort_devices["tape"] = [device]
continue
if (device.get_property("DEVTYPE") == "disk" and not device.get_property("ID_TYPE")) or \
device.get_property("ID_TYPE") == "disk":
if "nvme" in device.get_property("DEVPATH"):
sort_devices["disk"] = [empty_device]
try:
sort_devices["nvme"].extend([device])
except KeyError:
sort_devices["nvme"] = [device]
continue
elif "/host" in device.get_property("DEVPATH"):
sort_devices["disk"] = [empty_device]
continue
if device.get_property("SUBSYSTEM") == "net" and device.get_property("INTERFACE"):
interface = device.get_property("INTERFACE")
nmcli = Command("nmcli device")
nmcli.start()
while True:
line = nmcli.readline()
if line:
if interface in line and "infiniband" in line:
try:
sort_devices["infiniband"].extend([device])
except KeyError:
sort_devices["infiniband"] = [device]
elif interface in line and "ethernet" in line:
try:
sort_devices["ethernet"].extend([device])
except KeyError:
sort_devices["ethernet"] = [device]
elif interface in line and "wifi" in line:
try:
sort_devices["wlan"].extend([device])
except KeyError:
sort_devices["wlan"] = [device]
else:
break
continue
if device.get_property("ID_CDROM") == "1":
types = ["DVD_RW", "DVD_PLUS_RW", "DVD_R", "DVD_PLUS_R", "DVD", \
"BD_RE", "BD_R", "BD", "CD_RW", "CD_R", "CD"]
for type in types:
if device.get_property("ID_CDROM_" + type) == "1":
try:
sort_devices["cdrom"].extend([device])
except KeyError:
sort_devices["cdrom"] = [device]
break
if device.get_property("SUBSYSTEM") == "ipmi":
sort_devices["ipmi"] = [empty_device]
try:
Command("dmidecode").get_str("IPMI Device Information", single_line=False)
sort_devices["ipmi"] = [empty_device]
except:
pass
return sort_devices
def edit_tests(self):
while True:
for test in self.test_factory:
if test["name"] == "system":
test["run"] = True
if test["status"] == "PASS":
test["status"] = "Force"
os.system("clear")
print("Select tests to run:")
self.show_tests()
reply = self.ui.prompt("Selection (<number>|all|none|quit|run): ")
reply = reply.lower()
if reply in ["r", "run"]:
return True
if reply in ["q", "quit"]:
return False
if reply in ["n", "none"]:
for test in self.test_factory:
test["run"] = False
continue
if reply in ["a", "all"]:
for test in self.test_factory:
test["run"] = True
continue
try:
num = int(reply)
except:
continue
if num > 0 and num <= len(self.test_factory):
self.test_factory[num-1]["run"] = not self.test_factory[num-1]["run"]
continue
def show_tests(self):
print("\033[1;35m" + "No.".ljust(4) + "Run-Now?".ljust(10) \
+ "Status".ljust(8) + "Class".ljust(14) + "Device\033[0m")
num = 0
for test in self.test_factory:
name = test["name"]
if name == "system":
test["run"] = True
if test["status"] == "PASS":
test["status"] = "Force"
status = test["status"]
device = test["device"].get_name()
run = "no"
if test["run"] == True:
run = "yes"
num = num + 1
if status == "PASS":
print("%-6d"%num + run.ljust(8) + "\033[0;32mPASS \033[0m" \
+ name.ljust(14) + "%s"%device)
elif status == "FAIL":
print("%-6d"%num + run.ljust(8) + "\033[0;31mFAIL \033[0m" \
+ name.ljust(14) + "%s"%device)
elif status == "Force":
print("%-6d"%num + run.ljust(8) + "\033[0;33mForce \033[0m" \
+ name.ljust(14) + "%s"%device)
else:
print("%-6d"%num + run.ljust(8) + "\033[0;34mNotRun \033[0m" \
+ name.ljust(14) + "%s"%device)
def choose_tests(self):
for test in self.test_factory:
if test["status"] == "PASS":
test["run"] = False
else:
test["run"] = True
os.system("clear")
print("These tests are recommended to complete the certification:")
self.show_tests()
action = self.ui.prompt("Ready to begin testing?", ["run", "edit", "quit"])
action = action.lower()
if action in ["r", "run"]:
return True
elif action in ["q", "quit"]:
return False
elif action in ["e", "edit"]:
return self.edit_tests()
else:
print("Invalid choice!")
return self.choose_tests()
def check_result(self):
if len(self.test_factory) == 0:
return False
for test in self.test_factory:
if test["status"] != "PASS":
return False
return True
def update_factory(self, test_factory):
if not self.test_factory:
self.test_factory = test_factory
else:
factory_changed = False
for test in self.test_factory:
if not self.search_factory(test, test_factory):
self.test_factory.remove(test)
print("delete %s test %s" % (test["name"], test["device"].get_name()))
for test in test_factory:
if not self.search_factory(test, self.test_factory):
self.test_factory.append(test)
print("add %s test %s" % (test["name"], test["device"].get_name()))
self.test_factory.sort(key=lambda k: k["name"])
FactoryDocument(CertEnv.factoryfile, self.test_factory).save()
def search_factory(self, obj_test, test_factory):
for test in test_factory:
if test["name"] == obj_test["name"] and test["device"].path == obj_test["device"].path:
return True
return False
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import base64
try:
from urllib.parse import urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError
except ImportError:
from urllib import urlencode
from urllib2 import urlopen, Request, HTTPError
class Client:
def __init__(self, host, id):
self.host = host
self.id = id
self.form = {}
def upload(self, file, server='localhost'):
filename = os.path.basename(file)
try:
job = filename.split('.')[0]
with open(file, 'rb') as f:
filetext = base64.b64encode(f.read())
except Exception as e:
print(e)
return False
if not self.host or not self.id:
print("Missing host({0}) or id({1})".format(self.host, self.id))
return False
self.form['host'] = self.host
self.form['id'] = self.id
self.form['job'] = job
self.form['filetext'] = filetext
url = 'http://{}/api/job/upload'.format(server)
data = urlencode(self.form).encode('utf8')
headers = {
'Content-type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'
}
try:
# print(url)
req = Request(url, data=data, headers=headers)
res = urlopen(req)
if res.code != 200:
print("Error: upload failed, %s" % res.msg)
return False
return True
except Exception as e:
print(e)
return False
if __name__ == '__main__':
c = Client(' Taishan 2280', ' Certid-123523')
import sys
file = sys.argv[1]
c.upload(file)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import sys
import re
import subprocess
class Command:
def __init__(self, command):
""" Creates a Command object that wraps the shell command """
self.command = command
self.origin_output = None
self.output = None
self.errors = None
self.returncode = 0
self.pipe = None
self.regex = None
self.single_line = True
self.regex_group = None
def _run(self):
if sys.version_info.major < 3:
self.pipe = subprocess.Popen(self.command, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
else:
self.pipe = subprocess.Popen(self.command, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding='utf8')
(output, errors) = self.pipe.communicate()
if output:
#Strip new line character/s if any from the end of output string
output = output.rstrip('\n')
self.origin_output = output
self.output = output.splitlines()
if errors:
self.errors = errors.splitlines()
self.returncode = self.pipe.returncode
def start(self):
if sys.version_info.major < 3:
self.pipe = subprocess.Popen(self.command, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
else:
self.pipe = subprocess.Popen(self.command, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding='utf8')
def run(self, ignore_errors=False):
""" run the command
ignore_errors: do not raise exceptions
"""
self._run()
if not ignore_errors:
if self.returncode != 0:
self.print_output()
self.print_errors()
raise CertCommandError(self, "returned %d" % self.returncode)
if self.errors and len(self.errors) > 0:
self.print_errors()
# raise CertCommandError(self, "has output on stderr")
def run_quiet(self):
self._run()
if self.returncode != 0:
raise CertCommandError(self, "returned %d" % self.returncode)
def echo(self, ignore_errors=False):
self.run(ignore_errors)
self.print_output()
return
def print_output(self):
if self.output:
for line in self.output:
sys.stdout.write( line )
sys.stdout.write("\n")
sys.stdout.flush()
def print_errors(self):
if self.errors:
for line in self.errors:
sys.stderr.write( line )
sys.stderr.write("\n")
sys.stderr.flush()
def pid(self):
if self.pipe:
return self.pipe.pid
def readline(self):
if self.pipe:
return self.pipe.stdout.readline()
def read(self):
self.pipe = subprocess.Popen(self.command, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
if self.pipe:
return self.pipe.stdout.read().decode('utf-8', 'ignore').rstrip()
def poll(self):
if self.pipe:
return self.pipe.poll()
def _get_str(self, regex=None, regex_group=None, single_line=True, return_list=False, ignore_errors=False):
self.regex = regex
self.single_line = single_line
self.regex_group = regex_group
self._run()
if self.single_line:
if self.output and len(self.output) > 1:
raise CertCommandError(self, "Found %u lines of output, expected 1" % len(self.output))
if self.output:
line = self.output[0].strip()
if not self.regex:
return line
# otherwise, try the regex
pattern = re.compile(self.regex)
match = pattern.match(line)
if match:
if self.regex_group:
return match.group(self.regex_group)
# otherwise, no group, return the whole line
return line
# no regex match try a grep-style match
if not self.regex_group:
match = pattern.search(line)
if match:
return match.group()
# otherwise
raise CertCommandError(self, "no match for regular expression %s" % self.regex)
#otherwise, multi-line or single-line regex
if not self.regex:
raise CertCommandError(self, "no regular expression set for multi-line command")
pattern = re.compile(self.regex)
result = None
if return_list:
result = list()
if self.output:
for line in self.output:
if self.regex_group:
match = pattern.match(line)
if match:
if self.regex_group:
if return_list:
result.append(match.group(self.regex_group))
else:
return match.group(self.regex_group)
else:
# otherwise, return the matching line
match = pattern.search(line)
if match:
if return_list:
result.append(match.group())
else:
return match.group()
if result:
return result
raise CertCommandError(self, "no match for regular expression %s" % self.regex)
def get_str(self, regex=None, regex_group=None, single_line=True, return_list=False, ignore_errors=False):
result = self._get_str(regex, regex_group, single_line, return_list)
if not ignore_errors:
if self.returncode != 0:
self.print_output()
self.print_errors()
raise CertCommandError(self, "returned %d" % self.returncode)
# if self.errors and len(self.errors) > 0:
# raise CertCommandError(self, "has output on stderr")
return result
class CertCommandError(Exception):
def __init__(self, command, message):
self.message = message
self.command = command
def __str__(self):
return "\"%s\" %s" % (self.command.command, self.message)
def _get_message(self): return self.__message
def _set_message(self, value): self.__message = value
message = property(_get_message, _set_message)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import sys
import readline
class CommandUI:
def __init__(self, echoResponses=False):
self.echo = echoResponses
def printPipe(self, pipe):
while 1:
line = pipe.readline()
if line:
print(line)
else:
return pipe.close()
def prompt(self, question, choices=None):
while True:
sys.stdout.write(question)
if choices:
sys.stdout.write(" (")
sys.stdout.write("|".join(choices))
sys.stdout.write(") ")
sys.stdout.flush()
reply = sys.stdin.readline()
if reply.strip() and self.echo:
sys.stdout.write("reply: %s" % reply)
if not choices or reply.strip():
return reply.strip()
sys.stdout.write("Please enter a choice\n")
def prompt_integer(self, question, choices=None):
while True:
sys.stdout.write(question)
if choices:
sys.stdout.write(" (")
sys.stdout.write("|".join(choices))
sys.stdout.write(") ")
sys.stdout.flush()
reply = sys.stdin.readline()
try:
value = int(reply.strip())
if self.echo:
sys.stdout.write("reply: %u\n" % value)
return value
except ValueError:
sys.stdout.write("Please enter an integer.\n")
def prompt_confirm(self, question):
YES = "y"
SAMEASYES = ["y", "yes"]
NO = "n"
SAMEASNO = ["n", "no"]
while True:
reply = self.prompt(question, (YES, NO))
if reply.lower() in SAMEASYES:
return True
if reply.lower() in SAMEASNO:
return False
sys.stdout.write("Please reply %s or %s.\n" %(YES, NO))
def prompt_edit(self, label, value, choices=None):
if not value:
value = ""
if choices:
label += " ("
label += "|".join(choices)
label += ") "
while True:
readline.set_startup_hook(lambda: readline.insert_text(value))
try:
input = raw_input
except NameError:
from builtins import input
try:
reply = input(label).strip()
if not choices or reply in choices:
return reply
print("Please enter one of the following: %s" % " | ".join(choices))
finally:
readline.set_startup_hook()
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
from .command import Command, CertCommandError
def filter_char(str):
ascii_blacklist = map(chr, range(9) + range(11,13) + range(14,32))
filtered = u''
start = 0
for i in range(len(str)):
c = str[i]
if c in ascii_blacklist or (type(str) != unicode and ord(c) >= 128):
if start < i:
filtered += str[start:i]
start = i+1
filtered += str[start:]
return filtered
class CertDevice:
def __init__(self):
self.devices = None
def get_devices(self):
self.devices = list()
try:
pipe = Command("udevadm info --export-db")
pipe.start()
properties = dict()
while True:
line = pipe.readline()
if line:
if line == "\n":
if len(properties) > 0:
device = Device(properties)
if device.path != "":
self.devices.append(device)
properties = dict()
else:
property = line.split(":", 1)
if len(property) == 2:
type = property[0].strip('\ \'\n')
attribute = property[1].strip('\ \'\n')
if type == "E":
keyvalue = attribute.split("=", 1)
if len(keyvalue) == 2:
properties[keyvalue[0]]= keyvalue[1]
elif type == "P":
properties["INFO"] = attribute
else:
break
except Exception as e:
print("Warning: get devices fail")
print(e)
self.devices.sort(key=lambda k: k.path)
return self.devices
class Device:
def __init__(self, properties=None):
self.path = ""
if properties:
self.properties = properties
self.path = properties["DEVPATH"]
else:
self.properties = dict()
def get_property(self, property):
try:
return self.properties[property]
except KeyError:
return ""
def get_name(self):
if "INTERFACE" in self.properties.keys():
return self.properties["INTERFACE"]
elif "DEVNAME" in self.properties.keys():
return self.properties["DEVNAME"].split("/")[-1]
elif self.path:
return self.path.split("/")[-1]
else:
return ""
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import json
from .commandUI import CommandUI
from .command import Command, CertCommandError
from .device import Device
from .sysinfo import SysInfo
from .env import CertEnv
class Document():
def __init__(self, filename, document=dict()):
self.document = document
self.filename = filename
def new(self):
print("doc new")
def save(self):
try:
with open(self.filename, "w+") as save_f:
json.dump(self.document, save_f, indent=4)
save_f.close()
except Exception as e:
print("Error: doc save fail.")
print(e)
return False
return True
def load(self):
try:
with open(self.filename, "r") as load_f:
self.document = json.load(load_f)
load_f.close()
return True
except:
return False
class CertDocument(Document):
def __init__(self, filename, document=dict()):
self.document = dict()
self.filename = filename
if not document:
self.load()
else:
self.documemt = document
def new(self):
try:
pipe = Command("/usr/sbin/dmidecode -t 1")
pipe.start()
self.document = dict()
while True:
line = pipe.readline()
if line:
property = line.split(":", 1)
if len(property) == 2:
key = property[0].strip()
value = property[1].strip()
if key in ["Manufacturer", "Product Name", "Version"]:
self.document[key] = value
else:
break
except Exception as e:
print("Error: get hardware info fail.")
print(e)
sysinfo = SysInfo(CertEnv.releasefile)
self.document["eulerversion"] = sysinfo.product + " " + sysinfo.get_version()
self.document["kernelversion"] = sysinfo.kernel
self.document["certify"] = CommandUI().prompt("Please provide your Certification ID:")
self.document["Product URL"] = CommandUI().prompt("Please provide your Product URL:")
self.document["server"] = CommandUI().prompt("Please provide the Certification Server (Hostname or Ipaddr):")
def get_hardware(self):
return self.document["Manufacturer"] + " " + self.document["Product Name"] + " " + self.document["Version"]
def get_os(self):
return self.document["eulerversion"]
def get_server(self):
return self.document["server"]
def get_url(self):
return self.document["Product URL"]
def get_certify(self):
return self.document["certify"]
def get_kernel(self):
return self.document["kernelversion"]
class DeviceDocument(Document):
def __init__(self, filename, devices=list()):
self.filename = filename
self.document = list()
if not devices:
self.load()
else:
for device in devices:
self.document.append(device.properties)
class FactoryDocument(Document):
def __init__(self, filename, factory=list()):
self.document = list()
self.filename = filename
if not factory:
self.load()
else:
for member in factory:
element = dict()
element["name"] = member["name"]
element["device"] = member["device"].properties
element["run"] = member["run"]
element["status"] = member["status"]
self.document.append(element)
def get_factory(self):
factory = list()
for element in self.document:
test = dict()
device = Device(element["device"])
test["device"] = device
test["name"] = element["name"]
test["run"] = element["run"]
test["status"] = element["status"]
factory.append(test)
return factory
class ConfigFile:
def __init__(self, filename):
self.filename = filename
self.parameters = dict()
self.config = list()
self.load()
def load(self):
file = open(self.filename)
self.config = file.readlines()
for line in self.config:
if line.strip() and line.strip()[0] == "#":
continue
words = line.strip().split(" ")
if words[0]:
self.parameters[words[0]] = " ".join(words[1:])
file.close()
def get_parameter(self, name):
if self.parameters:
try:
return self.parameters[name]
except KeyError:
pass
return None
def dump(self):
for line in self.config:
string = line.strip()
if not string or string[0] == "#":
continue
print(string)
def add_parameter(self, name, value):
if not self.getParameter(name):
self.parameters[name] = value
self.config.append("%s %s\n" % (name, value))
self.save()
return True
return False
def remove_parameter(self, name):
if self.getParameter(name):
del self.parameters[name]
newconfig = list()
for line in self.config:
if line.strip() and line.strip()[0] == "#":
newconfig.append(line)
continue
words = line.strip().split(" ")
if words and words[0] == name:
continue
else:
newconfig.append(line)
self.config = newconfig
self.save()
def save(self):
file = open(self.filename, "w")
for line in self.config:
file.write(line)
file.close()
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
class CertEnv:
environmentfile = "/etc/eulercert.json"
releasefile = "/etc/os-release"
datadirectory = "/var/eulercert"
certificationfile = datadirectory + "/certification.json"
devicefile = datadirectory + "/device.json"
factoryfile = datadirectory + "/factory.json"
rebootfile = datadirectory + "/reboot.json"
testdirectoy = "/usr/share/eulercert/lib/tests"
logdirectoy = "/usr/share/eulercert/logs"
resultdirectoy = "/usr/share/eulercert/lib/server/results"
kernelinfo = "/usr/share/eulercert/kernelrelease.json"
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import sys
import string
import random
import argparse
from .test import Test
from .env import CertEnv
from .command import Command, CertCommandError
from .commandUI import CommandUI
from .log import Logger
from .document import FactoryDocument
from .reboot import Reboot
class Job(object):
def __init__(self, args=None):
"""
Creates an instance of Job class.
:param args: the job configuration, usually set by command
line options and argument parsing
:type args: :class:`argparse.Namespace`
"""
self.args = args or argparse.Namespace()
self.test_factory = getattr(args, "test_factory", [])
self.test_suite = []
self.job_id = ''.join(random.sample(string.ascii_letters + string.digits, 10))
self.ui = CommandUI()
self.subtests_filter = getattr(args, "subtests_filter", None)
self.test_parameters = None
if "test_parameters" in self.args:
self.test_parameters = {}
for parameter_name, parameter_value in self.args.test_parameters:
self.test_parameters[parameter_name] = parameter_value
def discover(self, testname, device, subtests_filter=None):
if not testname:
print("testname not specified, discover test failed")
return None
filename = testname + ".py"
for (dirpath, dirs, files) in os.walk(CertEnv.testdirectoy):
if filename in files:
break
pth = os.path.join(dirpath, filename)
if not os.access(pth, os.R_OK):
return None
sys.path.insert(0, dirpath)
try:
module = __import__(testname, globals(), locals())
except Exception as e:
print("Error: module import failed for %s" % testname)
print(e)
return None
for thing in dir(module):
test_class = getattr(module, thing)
try:
from types import ClassType as ct
except ImportError:
ct = type
if isinstance(test_class, ct) and issubclass(test_class, Test):
if "test" not in dir(test_class):
continue
if (subtests_filter and not subtests_filter in dir(test_class)):
continue
test = test_class()
if "pri" not in dir(test):
continue
return test
return None
def create_test_suite(self, subtests_filter=None):
if self.test_suite:
return
self.test_suite = []
for test in self.test_factory:
if test["run"]:
testclass = self.discover(test["name"], test["device"], subtests_filter)
if testclass:
testcase = dict()
testcase["test"] = testclass
testcase["name"] = test["name"]
testcase["device"] = test["device"]
testcase["status"] = "FAIL"
self.test_suite.append(testcase)
else:
if not subtests_filter:
test["status"] = "FAIL"
print("not found %s" % test["name"])
if not len(self.test_suite):
print("No test found")
def check_test_depends(self):
required_rpms = []
for tests in self.test_suite:
for pkg in tests["test"].requirements:
try:
Command("rpm -q " + pkg).run_quiet()
except CertCommandError:
if not pkg in required_rpms:
required_rpms.append(pkg)
if len(required_rpms):
print("Installing required packages: %s" % ", ".join(required_rpms))
try:
cmd = Command("yum install -y " + " ".join(required_rpms))
cmd.echo()
except CertCommandError as e:
print(e)
print("Fail to install required packages.")
return False
return True
def _run_test(self, testcase, subtests_filter=None):
name = testcase["name"]
if testcase["device"].get_name():
name = testcase["name"] + "-" + testcase["device"].get_name()
logname = name + ".log"
reboot = None
try:
test = testcase["test"]
logger = Logger(logname, self.job_id, sys.stdout, sys.stderr)
logger.start()
if subtests_filter:
return_code = getattr(test, subtests_filter)()
else:
print("---- start to run test %s ----" % name)
args = argparse.Namespace(device=testcase["device"], logdir=logger.log.dir)
test.setup(args)
if test.reboot:
reboot = Reboot(testcase["name"], self, test.rebootup)
return_code = False
if reboot.setup():
return_code = test.test()
else:
return_code = test.test()
except Exception as e:
print(e)
return_code = False
if reboot:
reboot.clean()
if not subtests_filter:
test.teardown()
logger.stop()
print("")
return return_code
def run_tests(self, subtests_filter=None):
if not len(self.test_suite):
print("No test to run.")
return
self.test_suite.sort(key=lambda k: k["test"].pri)
for testcase in self.test_suite:
if self._run_test(testcase, subtests_filter):
testcase["status"] = "PASS"
else:
testcase["status"] = "FAIL"
def run(self):
logger = Logger("job.log", self.job_id, sys.stdout, sys.stderr)
logger.start()
self.create_test_suite(self.subtests_filter)
if not self.check_test_depends():
print("Required rpm package not installed, test stopped.")
logger.stop()
return
self.run_tests(self.subtests_filter)
self.save_result()
logger.stop()
self.show_summary()
def show_summary(self):
print("------------- Summary -------------")
for test in self.test_factory:
if test["run"]:
name = test["name"]
if test["device"].get_name():
name = test["name"] + "-" + test["device"].get_name()
if test["status"] == "PASS":
print(name.ljust(33) + "\033[0;32mPASS\033[0m")
else:
print(name.ljust(33) + "\033[0;31mFAIL\033[0m")
print("")
def save_result(self):
for test in self.test_factory:
for testcase in self.test_suite:
if test["name"] == testcase["name"] and test["device"].path == testcase["device"].path:
test["status"] = testcase["status"]
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import sys
import datetime
from .env import CertEnv
class Log(object):
def __init__(self, logname='eulercert.log', logdir='__temp__'):
if not logdir:
curtime = datetime.datetime.now().isoformat()
logdir = os.path.join(CertEnv.logdirectoy, curtime)
if not logdir.startswith(os.path.sep):
logdir = os.path.join(CertEnv.logdirectoy, logdir)
if not os.path.exists(logdir):
os.makedirs(logdir)
self.dir = logdir
logfile = os.path.join(logdir, logname)
sys.stdout.flush()
self.terminal = sys.stdout
self.log = open(logfile, "a+")
def write(self, message):
self.terminal.write(message)
if self.log:
self.log.write(message)
def flush(self):
self.terminal.flush()
if self.log:
self.log.flush()
def close(self):
self.log.close()
self.log = None
class Logger():
def __init__(self, logname, logdir, out, err):
self.log = Log(logname, logdir)
self.stdout = out
self.stderr = err
def start(self):
sys.stdout = self.log
sys.stderr = sys.stdout
def stop(self):
sys.stdout.close()
sys.stdout = self.stdout
sys.stderr = self.stderr
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import datetime
from .document import Document, FactoryDocument
from .env import CertEnv
from .command import Command, CertCommandError
class Reboot:
def __init__(self, testname, job, rebootup):
self.testname = testname
self.rebootup = rebootup
self.job = job
self.reboot = dict()
def clean(self):
if not (self.job and self.testname):
return
for test in self.job.test_factory:
if test["run"] and self.testname == test["name"]:
test["reboot"] = False
Command("rm -rf %s" % CertEnv.rebootfile).run(ignore_errors=True)
Command("systemctl disable eulercert").run(ignore_errors=True)
def setup(self):
if not (self.job and self.testname):
print("Error: invalid reboot input.")
return False
self.job.save_result()
for test in self.job.test_factory:
if test["run"] and self.testname == test["name"]:
test["reboot"] = True
test["status"] = "FAIL"
if not FactoryDocument(CertEnv.factoryfile, self.job.test_factory).save():
print("Error: save testfactory doc fail before reboot.")
return False
self.reboot["job_id"] = self.job.job_id
self.reboot["time"] = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
self.reboot["test"] = self.testname
self.reboot["rebootup"] = self.rebootup
if not Document(CertEnv.rebootfile, self.reboot).save():
print("Error: save reboot doc fail.")
return False
try:
Command("systemctl daemon-reload").run_quiet()
Command("systemctl enable eulercert").run_quiet()
except:
print("Error: enable eulercert.service fail.")
return False
return True
def check(self):
doc = Document(CertEnv.rebootfile)
if not doc.load():
print("Error: reboot file load fail.")
return False
try:
self.testname = doc.document["test"]
self.reboot = doc.document
self.job.job_id = self.reboot["job_id"]
self.job.subtests_filter = self.reboot["rebootup"]
time_reboot = datetime.datetime.strptime(self.reboot["time"], "%Y%m%d%H%M%S")
except:
print("Error: reboot file format not as expect.")
return False
time_now = datetime.datetime.now()
time_delta = (time_now - time_reboot).seconds
cmd = Command("last reboot -s '%s seconds ago'" % time_delta)
reboot_list = cmd.get_str("^reboot .*$", single_line=False, return_list=True)
if len(reboot_list) != 1:
print("Errot:reboot times check fail.")
return False
return True
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import re
class SysInfo:
def __init__(self, file):
self.product = None
self.version = None
self.update = None
self.valid = False
self.kernel = None
self.arch = None
self.kernel_rpm = None
self.kerneldevel_rpm = None
self.kernel_version = None
self.debug_kernel = False
self.load(file)
def load(self, file):
try:
f = open(file)
text = f.read()
f.close()
except:
print("Release file not found.")
return
if text:
pattern = re.compile('NAME="(\w+)"')
results = pattern.findall(text)
self.product = results[0].strip() if results else ""
pattern = re.compile('VERSION="(.+)"')
results = pattern.findall(text)
self.version = results[0].strip() if results else ""
with os.popen('uname -m') as p:
self.arch = p.readline().strip()
self.debug_kernel = "debug" in self.arch
with os.popen('uname -r') as p:
self.kernel = p.readline().strip()
self.kernel_rpm = "kernel-{}".format(self.kernel)
self.kerneldevel_rpm = "kernel-devel-{}".format(self.kernel)
self.kernel_version = self.kernel.split('-')[0]
def get_version(self):
return self.version
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
class Test:
def __init__(self, name=None):
self.pri = 0
self.requirements = list()
self.reboot = False
self.rebootup = None
def setup(self, args=None):
pass
def teardown(self):
pass
%define version 1.0.0
%define release h1
%define debug_package %{nil}
%global _build_id_links none
%undefine __brp_mangle_shebangs
Name: oec-hardware
Summary: openEuler Hardware Certification Test Suite
Version: %{version}
Release: %{release}
Group: Development/Tools
License: Mulan PSL v2
URL: https://gitee.com/openeuler/oec-hardware
Source0: %{name}-%{version}-%{release}.tar.bz2
Buildroot: %{_tmppath}/%{name}-%{version}-root
BuildRequires: gcc
Requires: kernel-devel, kernel-headers, dmidecode
Requires: qperf, fio, memtester
Requires: kernel >= 4
Requires: python3
# server subpackage
%package server
Summary: openEuler Hardware Certification Test Server
Group: Development/Tools
Requires: python3, python3-devel, nginx, qperf, psmisc
%description
openEuler Hardware Certification Test Suite
%description server
openEuler Hardware Certification Test Server
%prep
%setup -q -c
%build
[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT;
DESTDIR=$RPM_BUILD_ROOT VERSION_RELEASE=%{version} make
%install
DESTDIR=$RPM_BUILD_ROOT make install
%clean
[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT;
%pre
%post
%files
%defattr(-,root,root)
/usr/bin/eulercert
/usr/share/eulercert/kernelrelease.json
/usr/share/eulercert/lib/hwcert
/usr/share/eulercert/lib/tests
/usr/lib/systemd/system/eulercert.service
%dir /var/eulercert
%dir /usr/share/eulercert/lib
%dir /usr/share/eulercert
%files server
%defattr(-,root,root)
/usr/share/eulercert/lib/server
/usr/share/eulercert/lib/server/uwsgi.ini
/usr/share/eulercert/lib/server/uwsgi.conf
/usr/lib/systemd/system/eulercert-server.service
%postun
rm -rf /var/lock/eulercert.lock
%changelog
* Fri Jul 26 2019 Lu Tianxiong <lutianxiong@huawei.com> - 1.0.0-h1
- Initial spec
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
rm -rf $(DESTDIR)/usr/bin/eulercert
mkdir -p $(DESTDIR)/usr/bin
cp eulercert $(DESTDIR)/usr/bin
chmod u+x $(DESTDIR)/usr/bin/eulercert
mkdir -p $(DESTDIR)/usr/share/eulercert/lib
cp kernelrelease.json $(DESTDIR)/usr/share/eulercert/
mkdir -p $(DESTDIR)/usr/lib/systemd/system/
cp *.service $(DESTDIR)/usr/lib/systemd/system/
clean:
rm -rf $(DESTDIR)/usr/bin/eulercert
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import sys
import fcntl
import argparse
sys.path.append("/usr/share/eulercert/lib/")
os.putenv("PYTHONPATH", "/usr/share/eulercert/lib/")
from hwcert.certification import EulerCertification
import hwcert.version
class CertLock:
def __init__(self, filename):
self.filename = filename
self.fd = open(filename, 'w')
def acquire(self):
try:
fcntl.flock(self.fd, fcntl.LOCK_EX|fcntl.LOCK_NB)
return True
except IOError:
return False
def release(self):
fcntl.flock(self.fd, fcntl.LOCK_UN)
def __del__(self):
self.fd.close()
if __name__ == '__main__':
if os.getuid() > 0:
sys.stderr.write("You need to be root to run this program.\n")
sys.exit(1)
parser = argparse.ArgumentParser(description="Run openEuler Hardware Certification Test Suite")
parser.add_argument('--clean', action='store_true',
help='Clean saved testsuite.')
parser.add_argument('--rebootup', action='store_true',
help='Continue run testsuite after reboot system.')
parser.add_argument('--version', action='store_true',
help='Show testsuite version.')
args = parser.parse_args()
lock = CertLock("/var/lock/eulercert.lock")
if not lock.acquire():
sys.stderr.write("The eulercert may be running already, you should not run it repeated.\n")
sys.exit(1)
cert = EulerCertification()
if args.clean:
if not cert.clean():
lock.release()
sys.exit(1)
elif args.rebootup:
if not cert.run_rebootup():
lock.release()
sys.exit(1)
elif args.version:
print("version: %s" % hwcert.version.version)
else:
if not cert.run():
lock.release()
sys.exit(1)
lock.release()
sys.exit(0)
[Unit]
Description=openEuler Hardware Certification Server
After=network.target
[Service]
Type=notify
ExecStartPre=/usr/share/eulercert/lib/server/eulercert-server-pre.sh
ExecStart=/usr/local/bin/uwsgi --ini /usr/share/eulercert/lib/server/uwsgi.ini
[Install]
WantedBy=multi-user.target
[Unit]
Description=openEuler Hardware Certification Test Suite
After=basic.target network.target
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/bin/eulercert --rebootup
RemainAfterExit=yes
TimeoutSec=0
[Install]
WantedBy=multi-user.target
{
"EulerOS 2.0 (SP8)": "4.19.36",
"openEuler 20.03 (LTS)": "4.19.90"
}
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
HWCERT_CLASS_LIB := /usr/share/eulercert/lib
all: ;
install:
rm -rf $(DESTDIR)$(HWCERT_CLASS_LIB)/server
mkdir -p $(DESTDIR)$(HWCERT_CLASS_LIB)/server
cp -raf `ls | grep -v Makefile` $(DESTDIR)$(HWCERT_CLASS_LIB)/server/
chmod u+x $(DESTDIR)$(HWCERT_CLASS_LIB)/server/*
clean:
rm -rf $(DESTDIR)$(HWCERT_CLASS_LIB)/server
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
#!/bin/bash
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
dir_nginx=/etc/nginx/default.d
dir_cert=/usr/share/eulercert/lib/server
test -f ${dir_nginx}/uwsgi.conf || cp -af ${dir_cert}/uwsgi.conf ${dir_nginx}
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import json
import time
import subprocess
import base64
try:
from urllib.parse import urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError
except ImportError:
from urllib import urlencode
from urllib2 import urlopen, Request, HTTPError
from flask import Flask, render_template, redirect, url_for, abort, request, \
make_response, send_from_directory, flash
from flask_bootstrap import Bootstrap
app = Flask(__name__)
app.secret_key = os.urandom(24)
bootstrap = Bootstrap(app)
dir_server = os.path.dirname(os.path.realpath(__file__))
dir_results = os.path.join(dir_server, 'results')
dir_files = os.path.join(dir_server, 'files')
@app.errorhandler(400)
def bad_request(e):
return render_template('error.html', error='400 - Bad Request'), 400
@app.errorhandler(404)
def page_not_found(e):
return render_template('error.html', error='404 - Page Not Found'), 404
@app.errorhandler(500)
def internal_server_error(e):
return render_template('error.html', error='500 - Internal Server Error'), 500
@app.route('/')
def index():
return render_template('index.html')
@app.route('/results')
def get_results():
results = {}
for host in next(os.walk(dir_results))[1]:
dir_host = os.path.join(dir_results, host)
results[host] = {}
for id in next(os.walk(dir_host))[1]:
dir_id = os.path.join(dir_host, id)
results[host][id] = next(os.walk(dir_id))[1]
return render_template('results.html', results=results)
@app.route('/results/<host>/<id>/<job>')
def get_job(host, id, job):
dir_job = os.path.join(dir_results, host, id, job)
json_info = os.path.join(dir_job, 'certification.json')
json_results = os.path.join(dir_job, 'factory.json')
try:
with open(json_info, 'r') as f:
info = json.load(f)
with open(json_results, 'r') as f:
results = json.load(f)
except Exception as e:
abort(404)
return render_template('job.html', host=host, id=id, job=job, info=info, results=results)
@app.route('/results/<host>/<id>/<job>/devices/<interface>')
def get_device(host, id, job, interface):
dir_job = os.path.join(dir_results, host, id, job)
json_results = os.path.join(dir_job, 'factory.json')
try:
with open(json_results, 'r') as f:
results = json.load(f)
except Exception as e:
abort(404)
for testcase in results:
device = testcase.get('device')
if device and device.get('INTERFACE') == interface:
return render_template('device.html', device=device, interface=interface)
else:
abort(404)
@app.route('/results/<host>/<id>/<job>/devices')
def get_devices(host, id, job):
dir_job = os.path.join(dir_results, host, id, job)
json_devices = os.path.join(dir_job, 'device.json')
try:
with open(json_devices, 'r') as f:
devices = json.load(f)
except Exception as e:
abort(404)
return render_template('devices.html', devices=devices)
@app.route('/results/<host>/<id>/<job>/attachment')
def get_attachment(host, id, job):
dir_job = os.path.join(dir_results, host, id, job)
attachment = dir_job + '.tar.gz'
filedir = os.path.dirname(attachment)
filename = os.path.basename(attachment)
return send_from_directory(filedir, filename, as_attachment=True)
@app.route('/results/<host>/<id>/<job>/logs/<name>')
def get_log(host, id, job, name):
dir_job = os.path.join(dir_results, host, id, job)
logpath = os.path.join(dir_job, name + '.log')
try:
with open(logpath, 'r') as f:
log = f.read().split('\n')
except Exception as e:
abort(404)
return render_template('log.html', name=name, log=log)
@app.route('/results/<host>/<id>/<job>/submit')
def submit(host, id, job):
dir_job = os.path.join(dir_results, host, id, job)
tar_job = dir_job + '.tar.gz'
json_cert = os.path.join(dir_job, 'certification.json')
try:
with open(json_cert, 'r') as f:
cert = json.load(f)
with open(tar_job, 'rb') as f:
attachment = base64.b64encode(f.read())
except Exception as e:
print(e)
abort(500)
form = {}
form['certid'] = cert.get('certid')
form['attachment'] = attachment
server = cert.get('server')
url = 'http://{}/api/job/upload'.format(server)
data = urlencode(form).encode('utf8')
headers = {
'Content-type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'
}
try:
req = Request(url, data=data, headers=headers)
res = urlopen(req)
except HTTPError as e:
print(e)
res = e
if res.code == 200:
flash('Submit Successful', 'success')
else:
flash('Submit Failed - {} {}'.format(res.code, res.msg),
'danger')
return redirect(request.referrer or url_for('get_job', host=host, id=id, job=job))
@app.route('/api/job/upload', methods=['GET', 'POST'])
def upload_job():
host = request.values.get('host', '').strip().replace(' ', '-')
id = request.values.get('id', '').strip().replace(' ', '-')
job = request.values.get('job', '').strip().replace(' ', '-')
filetext = request.values.get('filetext', '')
if not(all([host, id, job, filetext])):
return render_template('upload.html', host=host, id=id, job=job,
filetext=filetext, ret='Failed'), 400
dir_job = os.path.join(dir_results, host, id, job)
tar_job = dir_job + '.tar.gz'
if not os.path.exists(dir_job):
os.makedirs(dir_job)
try:
with open(tar_job, 'wb') as f:
f.write(base64.b64decode(filetext))
os.system("tar xf %s -C %s" % (tar_job, os.path.dirname(dir_job)))
except Exception as e:
print(e)
abort(400)
return render_template('upload.html', host=host, id=id, job=job,
filetext=filetext, ret='Successful')
@app.route('/files')
def get_files():
files = os.listdir(dir_files)
return render_template('files.html', files=files)
@app.route('/files/<path:path>')
def download_file(path):
return send_from_directory('files', path, as_attachment=True)
@app.route('/api/file/upload', methods=['GET', 'POST'])
def upload_file():
filename = request.values.get('filename', '')
filetext = request.values.get('filetext', '')
if not(all([filename, filetext])):
return render_template('upload.html', filename=filename, filetext=filetext,
ret='Failed'), 400
filepath = os.path.join(dir_files, filename)
if not os.path.exists(dir_files):
os.makedirs(dir_files)
try:
with open(filepath, 'wb') as f:
f.write(base64.b64decode(filetext))
except Exception as e:
print(e)
abort(400)
return render_template('upload.html', filename=filename, filetext=filetext,
ret='Successful')
@app.route('/api/<act>', methods=['GET', 'POST'])
def test_server(act):
valid_commands = ['rping', 'rcopy', 'ib_read_bw', 'ib_write_bw', 'ib_send_bw',
'qperf']
cmd = request.values.get('cmd', '')
cmd = cmd.split()
if (not cmd) or (cmd[0] not in valid_commands + ['all']):
print("Invalid command: {0}".format(cmd))
abort(400)
if act == 'start':
if 'rping' == cmd[0]:
cmd = ['rping', '-s']
if 'ib_' in cmd[0]:
ib_server_ip = request.values.get('ib_server_ip', '')
if not ib_server_ip:
print("No ib_server_ip assigned.")
abort(400)
ibdev, ibport = __get_ib_dev_port(ib_server_ip)
if not all([ibdev, ibport]):
print("No ibdev or ibport found.")
abort(400)
cmd.extend(['-d', ibdev, '-i', ibport])
elif act == 'stop':
if 'all' == cmd[0]:
cmd = ['killall', '-9'] + valid_commands
else:
cmd = ['killall', '-9', cmd[0]]
else:
abort(404)
print(' '.join(cmd))
# pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pipe = subprocess.Popen(cmd)
time.sleep(3)
if pipe.poll(): ## supposed to be 0(foreground) or None(background)
abort(400)
else:
return render_template('index.html')
def __get_ib_dev_port(ib_server_ip):
try:
cmd = "ip -o a | grep -w %s | awk '{print $2}'" % ib_server_ip
# print(cmd)
netdev = os.popen(cmd).read().strip()
cmd = "udevadm info --export-db | grep DEVPATH | grep -w %s | awk -F= '{print $2}'" % netdev
# print(cmd)
path_netdev = ''.join(['/sys', os.popen(cmd).read().strip()])
path_pci = path_netdev.split('net')[0]
path_ibdev = 'infiniband_verbs/uverb*/ibdev'
path_ibdev = ''.join([path_pci, path_ibdev])
cmd = "cat %s" % path_ibdev
# print(cmd)
ibdev = os.popen(cmd).read().strip()
path_ibport = '/sys/class/net/%s/dev_id' % netdev
cmd = "cat %s" % path_ibport
# print(cmd)
ibport = os.popen(cmd).read().strip()
ibport = int(ibport, 16) + 1
ibport = str(ibport)
return ibdev, ibport
except Exception as e:
print(e)
return None, None
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
{% extends "bootstrap/base.html" %}
{% include "flash.html" %}
{% block title %}EulerCert{% endblock %}
{% block head %}
{{ super() }}
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
{% endblock %}
{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">EulerCert</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="/results">Results</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
{% block page_content %}{% endblock %}
</div>
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>openEuler Hardware Certification</h3>
</div>
<table class="table table-striped table-hover">
<thead>
<th colspan="2">{{ interface }}</th>
</thead>
<tbody>
{% for key in device %}
<tr>
<td>{{ key }}</td>
<td>{{ device.get(key) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>openEuler Hardware Certification</h3>
</div>
{% for device in devices %}
<table class="table table-striped table-hover">
<thead>
<th colspan="2"> {{ device.get("DEVPATH") }}</th>
</thead>
<tbody>
{% for key in device %}
<tr>
<td width="30%">{{ key }}</td>
<td>{{ device.get(key) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert - {{ error }}{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>{{ error }}</h3>
</div>
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>Directory listing for /files</h3>
</div>
<ul>
{% for file in files %}
<li><a href="/files/{{ file }}">{{ file }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}" style="text-align: center">
<button data-dismiss="alert" class="close" type="button">×</button>
<strong>{{ message }}</strong>
</div>
{% endfor %}
{% endif %}
{% endwith %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>EulerCert Test Server</h1>
</div>
<p>Welcome to the openEuler Hardware Certification.</p>
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>openEuler Hardware Certification</h3>
<br>
<a class='btn btn-primary' href="/results/{{ host }}/{{ id }}/{{ job }}/submit">Submit</a>
<a class='btn' href="/results/{{ host }}/{{ id }}/{{ job }}/devices">Devices</a>
<a class='btn' href="/results/{{ host }}/{{ id }}/{{ job }}/logs/job">Runtime</a>
<a class='btn' href="/results/{{ host }}/{{ id }}/{{ job }}/attachment">Attachment</a>
</div>
<div class="page-header">
<table class="table table-striped table-hover">
<thead>
<th colspan="2">Environment</th>
</thead>
<tbody>
{% for key in info %}
<tr>
<td width="50%">{{ key }}</td>
<td>{{ info.get(key) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="page-header">
<table class="table table-striped table-hover">
<thead>
<th>Testcase</th>
<th>Device</th>
<th>Result</th>
</thead>
<tbody>
{% for d in results %}
<tr>
{% set int = d.get("device").get("INTERFACE", "") %}
{% if int %}
{% set testcase = d.get("name") + "-" + int %}
{% else %}
{% set testcase = d.get("name") %}
{% endif %}
{% if d.get("run") %}
{% set result = d.get("status") %}
{% else %}
{% set result = "" %}
{% endif %}
<td>{{ testcase }}</td>
<td><a href="/results/{{ host }}/{{ id }}/{{ job }}/devices/{{ int }}">{{ int }}</a></td>
<td><a href="/results/{{ host }}/{{ id }}/{{ job }}/logs/{{ testcase }}">{{ result }}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>openEuler Hardware Certification</h3>
</div>
<h4>{{ testcase }}</h4>
{% for line in log %}
{{ line }}<br>
{% endfor %}
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>openEuler Hardware Certification</h3>
</div>
<table class="table table-striped table-hover">
<tbody>
{% for host, id_dict in results.items() %}
<tr>
<td>
<div class="dropdown">
<div class="dropdown-toggle" data-toggle="dropdown">
{{ host }} <span class="caret"></span>
</div>
<ul class="dropdown-menu">
{% set use_divider = [] %}
{% for id, job_list in id_dict.items() %}
{% if use_divider %}
<li class="divider"></li>
<!-- `set` do not support global varible
use `do` instead -->
{% do use_divider.pop() %}
{% endif %}
{% do use_divider.append(1) %}
<li class="dropdown-header">Cert ID: {{ id }}</li>
{% for job in job_list %}
<li><a href="/results/{{ host }}/{{ id }}/{{ job }}">{{ job }}</a></li>
{% endfor %}
{% endfor %}
</ul>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% extends "base.html" %}
{% block title %}EulerCert{% endblock %}
{% block page_content %}
<div class="page-header">
<h3>Upload {{ ret }}</h3>
</div>
<table class="table table-striped table-hover">
<tbody>
<tr>
<td>id</td>
<td>{{ id }}</td>
</tr>
<tr>
<td>host</td>
<td>{{ host }}</td>
</tr>
<tr>
<td>job</td>
<td>{{ job }}</td>
</tr>
{% if filename %}
<tr>
<td>filename</td>
<td>{{ filename }}</td>
</tr>
{% endif %}
<tr>
<td>filetext(base64)</td>
<td>{{ filetext }}</td>
</tr>
</tbody>
</table>
{% endblock %}
charset utf-8;
client_max_body_size 10G;
location ~ ^/ {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8080;
uwsgi_param UWSGI_PYTHON /usr/bin/python3;
uwsgi_param UWSGI_CHDIR /usr/share/eulercert/lib/server;
uwsgi_param UWSGI_SCRIPT run:app;
}
[uwsgi]
socket = 127.0.0.1:8080
chdir = /usr/share/eulercert/lib/server
wsgi-file = server.py
callable = app
processes = 4
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: all clean install
HWCERT_TEST_LIB := $(DESTDIR)/usr/share/eulercert/lib/tests/
SUBDIRS := $(shell ls | grep -v Makefile)
all:
for i in $(SUBDIRS); do $(MAKE) -C $$i; done
clean:
for i in $(SUBDIRS); do $(MAKE) -C $$i DEST=$(HWCERT_TEST_LIB)/$$i clean; done
rm -rf $(HWCERT_TEST_LIB)
install:
mkdir -p $(HWCERT_TEST_LIB)
for i in $(SUBDIRS); do $(MAKE) -C $$i DEST=$(HWCERT_TEST_LIB)/$$i install; done
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
from hwcert.test import Test
from hwcert.command import Command
class AcpiTest(Test):
def __init__(self):
Test.__init__(self)
self.requirements = ["acpica-tools"]
def test(self):
try:
Command("acpidump").echo()
return True
except Exception as e:
print(e)
return False
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import sys
import time
import shutil
import argparse
from hwcert.test import Test
from hwcert.commandUI import CommandUI
from hwcert.command import Command, CertCommandError
class CDRomTest(Test):
def __init__(self):
Test.__init__(self)
self.requirements = ["dvd+rw-tools", "genisoimage", "wodim", "util-linux"]
self.method = None
self.device = None
self.type = None
self.ui = CommandUI()
self.test_dir = "/usr/share/doc"
def setup(self, args=None):
self.args = args or argparse.Namespace()
self.device = getattr(args, "device", None)
self.type = self.get_type(self.device)
self.get_mode(self.type)
def test(self):
if not (self.method and self.device and self.type):
return False
if self.method not in dir(self):
return False
devname = self.device.get_property("DEVNAME")
Command("eject %s" % devname).run(ignore_errors=True)
while True:
print("Please insert %s disc into %s, then close the tray manually." % (self.type.lower(), devname))
if self.method == "write_test":
print(" tips:disc should be new.")
elif self.method == "read_test":
print(" tips:disc should not be blank.")
if self.ui.prompt_confirm("Done well?"):
break
Command("eject -t %s" % devname).run(ignore_errors=True)
print("Waiting media..).")
time.sleep(20)
if not getattr(self, self.method)():
return False
return True
def get_type(self, device):
if not device:
return None
bd_types = ["BD_RE", "BD_R", "BD"]
dvd_types = ["DVD_RW", "DVD_PLUS_RW", "DVD_R", "DVD_PLUS_R", "DVD"]
cd_types = ["CD_RW", "CD_R", "CD"]
for type in bd_types:
if device.get_property("ID_CDROM_" + type) == "1":
return type
for type in dvd_types:
if device.get_property("ID_CDROM_" + type) == "1":
return type
for type in cd_types:
if device.get_property("ID_CDROM_" + type) == "1":
return type
print("Can not find pr)oper test-type for %s." % device.get_name())
return None
def get_mode(self, type):
if not type:
return
if "RW" in type or "RE" in type:
self.method = "rw_test"
elif "_R" in type:
self.method = "write_test"
else:
self.method = "read_test"
def rw_test(self):
try:
devname = self.device.get_property("DEVNAME")
Command("umount %s" % devname).run(ignore_errors=True)
if "BD" in self.type:
print("Formatting ...")
sys.stdout.flush()
Command("dvd+rw-format -format=full %s 2>/dev/null" % devname).echo()
self.reload_disc(devname)
sys.stdout.flush()
return self.write_test()
elif "DVD_PLUS" in self.type:
print("Formatting ...")
sys.stdout.flush()
Command("dvd+rw-format -force %s 2>/dev/null" % devname).echo()
self.reload_disc(devname)
sys.stdout.flush()
return self.write_test()
else:
print("Blanking ...")
sys.stdout.flush()
blankCommand = Command("cdrecord -v dev=%s blank=fast" % devname).echo()
self.reload_disc(devname)
sys.stdout.flush()
return self.write_test()
except CertCommandError as e:
return False
def write_test(self):
try:
devname = self.device.get_property("DEVNAME")
Command("umount %s" % devname).run(ignore_errors=True)
if "BD" in self.type or "DVD_PLUS" in self.type:
Command("growisofs -Z %s -quiet -R %s" % (devname, self.test_dir)).echo()
self.reload_disc(devname)
sys.stdout.flush()
return True
else:
write_opts ="-sao"
try:
command = Command("cdrecord dev=%s -checkdrive" % devname)
modes = command.get_str(regex="^Supported modes[^:]*:(?P<modes>.*$)", regex_group="modes", single_line=False, ignore_errors=True)
if "TAO" in modes:
write_opts="-tao"
if "SAO" in modes:
write_opts="-sao"
flags = command.get_str(regex="^Driver flags[^:]*:(?P<flags>.*$)", regex_group="flags", single_line=False, ignore_errors=True)
if "BURNFREE" in flags:
write_opts += " driveropts=burnfree"
except CertCommandError as e:
print(e)
size = Command("mkisofs -quiet -R -print-size %s " % self.test_dir).get_str()
blocks = int(size)
Command("mkisofs -quiet -R %s | cdrecord -v %s dev=%s fs=32M tsize=%ss -" % (self.test_dir, write_opts, devname, blocks)).echo()
self.reload_disc(devname)
sys.stdout.flush()
return True
except CertCommandError as e:
return False
def read_test(self):
try:
devname = self.device.get_property("DEVNAME")
if os.path.exists("mnt_cdrom"):
shutil.rmtree("mnt_cdrom")
os.mkdir("mnt_cdrom")
print("Mounting media ...")
Command("umount %s" % devname).echo(ignore_errors=True)
Command("mount -o ro %s ./mnt_cdrom" % devname).echo()
size = Command("df %s | tail -n1 | awk '{print $3}'" % devname).get_str()
size = int(size)
if size == 0:
print("Error: blank disc.")
Command("umount ./mnt_cdrom").run(ignore_errors=True)
Command("rm -rf ./mnt_cdrom").run(ignore_errors=True)
return False
if os.path.exists("device_dir"):
shutil.rmtree("device_dir")
os.mkdir("device_dir")
print("Copying files ...")
sys.stdout.flush()
Command("cp -dpRf ./mnt_cdrom/. ./device_dir/").run()
print("Comparing files ...")
sys.stdout.flush()
return_code = self.cmp_tree("mnt_cdrom", "device_dir")
Command("umount ./mnt_cdrom").run(ignore_errors=True)
Command("rm -rf ./mnt_cdrom ./device_dir").run(ignore_errors=True)
return return_code
except CertCommandError as e:
print(e)
return False
def cmp_tree(self, dir1, dir2):
if not (dir1 and dir2):
print("Error: invalid input dir.")
return False
try:
Command("diff -r %s %s" % (dir1, dir2)).run()
return True
except CertCommandError as e:
print("Error: file comparison failed.")
return False
def reload_disc(self, device):
if not device:
return False
print("Reloading the media ... ")
sys.stdout.flush()
try:
Command("eject %s" % device).run()
print("tray ejected.")
sys.stdout.flush()
except:
pass
try:
Command("eject -t %s" % device).run()
print("tray auto-closed.\n")
sys.stdout.flush()
except:
print("Could not auto-close the tray, please close the tray manually.")
self.ui.prompt_confirm("Done well?")
time.sleep(20)
return True
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: all install clean
all: clock
CFLAGS+=-Wall
CFLAGS+=-DCPU_ALLOC
# sched_setaffinity has no size_t argument on older systems.
ifeq ($(shell grep 'sched_setaffinity.*size_t' /usr/include/sched.h),)
CFLAGS+=-DOLD_SCHED_SETAFFINITY
endif
clock: clock.c
$(CC) $(CFLAGS) -lrt $< -o $@
install:
mkdir -p $(DEST)
cp -a clock *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
rm -rf clock
/*
* Copyright (c) 2020 Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#define _GNU_SOURCE 1
#include <linux/rtc.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
int test_clock_direction()
{
time_t starttime = 0;
time_t stoptime = 0;
int sleeptime = 60;
int delta = 0;
printf("clock direction test start\n");
time(&starttime);
sleep(sleeptime);
time(&stoptime);
delta = (int)stoptime - (int)starttime - sleeptime;
if (delta != 0) {
printf("clock direction test fail\n");
return 1;
} else {
printf("clock direction test complete\n");
return 0;
}
}
int test_rtc_clock()
{
int rtc, delta;
struct tm rtc_tm1, rtc_tm2;
int sleeptime = 120;
printf("rtc_clock test start\n");
if ((rtc = open("/dev/rtc", O_WRONLY)) < 0) {
perror("could not open RTC device");
return 1;
}
if (ioctl(rtc, RTC_RD_TIME, &rtc_tm1) < 0) {
perror("could not get the RTC time");
close(rtc);
return 1;
}
sleep(sleeptime);
if (ioctl(rtc, RTC_RD_TIME, &rtc_tm2) < 0) {
perror("could not get the RTC time");
close(rtc);
return 1;
}
close(rtc);
delta = (int)mktime(&rtc_tm2) - (int)mktime(&rtc_tm1) - sleeptime;
if (delta != 0) {
printf("rtc_clock test fail\n");
return 1;
} else {
printf("rtc_clock test complete\n");
return 0;
}
}
int main()
{
int ret = 0;
ret += test_clock_direction();
ret += test_rtc_clock();
return ret;
}
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
from hwcert.test import Test
from hwcert.command import Command
clock_dir = os.path.dirname(os.path.realpath(__file__))
class ClockTest(Test):
def test(self):
return 0 == os.system("cd %s; ./clock" % clock_dir)
if __name__ == '__main__':
t = ClockTest()
t.setup()
t.test()
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import decimal
import time
def cal():
decimal.getcontext().prec = 1000
one = decimal.Decimal(1)
for i in range(1000):
j = (i * one).sqrt()
if __name__ == '__main__':
time_start = time.time()
while 1:
cal()
time_delta = time.time() - time_start
if time_delta >= 2:
print(time_delta)
break
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
from random import randint
from time import sleep
from hwcert.env import CertEnv
from hwcert.test import Test
from hwcert.command import Command
class CPU:
def __init__(self):
self.requirements = ['util-linux', 'kernel-tools']
self.cpu = None
self.nums = None
self.list = None
self.numa_nodes = None
self.governors = None
self.original_governor = None
self.max_freq = None
self.min_freq = None
def get_info(self):
cmd = Command("lscpu")
try:
nums = cmd.get_str('CPU\(s\):\s+(?P<cpus>\d+)', 'cpus', False)
except:
return False
self.nums = int(nums)
self.list = range(self.nums)
cmd = Command("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq")
try:
max_freq = cmd.get_str()
except:
return False
self.max_freq = int(max_freq)
cmd = Command("cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq")
try:
min_freq = cmd.get_str()
except:
return False
self.min_freq = int(min_freq)
return True
def set_freq(self, freq, cpu='all'):
cmd = Command("cpupower -c %s frequency-set --freq %s" % (cpu, freq))
try:
cmd.run()
return cmd.returncode
except:
return False
def get_freq(self, cpu):
cmd = Command("cpupower -c %s frequency-info -w" % cpu)
try:
return int(cmd.get_str('.* frequency: (?P<freq>\d+) .*', 'freq', False))
except:
return False
def set_governor(self, governor, cpu='all'):
cmd = Command("cpupower -c %s frequency-set --governor %s" % (cpu, governor))
try:
cmd.run()
return cmd.returncode
except:
return False
def get_governor(self, cpu):
cmd = Command("cpupower -c %s frequency-info -p" % cpu)
try:
return cmd.get_str('.* governor "(?P<governor>\w+)".*', 'governor', False)
except:
return False
def find_path(self, parent_dir, target_name):
cmd = Command("find %s -name %s" % (parent_dir, target_name))
try:
cmd.run()
return cmd.returncode
except:
return False
class Load:
def __init__(self, cpu):
self.cpu = cpu
self.process = Command("taskset -c {} python -u {}/cpufreq/cal.py".format(self.cpu, CertEnv.testdirectoy))
self.returncode = None
def run(self):
self.process.start() ## background
def get_runtime(self):
if not self.process:
return None
while self.returncode is None:
self.returncode = self.process.poll()
if self.returncode == 0:
line = self.process.readline()
return float(line)
else:
return False
class CPUFreqTest(Test):
def test_userspace(self):
target_cpu = randint(0, self.cpu.nums-1)
target_freq = randint(self.cpu.min_freq, self.cpu.max_freq)
if self.cpu.set_freq(target_freq, cpu=target_cpu) != 0:
print("[X] Set CPU%s to freq %d failed." % (target_cpu, target_freq))
return False
print("[.] Set CPU%s to freq %d." % (target_cpu, target_freq))
target_cpu_freq = self.cpu.get_freq(target_cpu)
print("[.] Current freq of CPU%s is %d." % (target_cpu, target_cpu_freq))
target_cpu_governor = self.cpu.get_governor(target_cpu)
if target_cpu_governor != 'userspace':
print("[X] The governor of CPU%s(%s) is not userspace." %
(target_cpu, target_cpu_governor))
return False
print("[.] The governor of CPU%s is %s." %
(target_cpu, target_cpu_governor))
## min_freq -> max_runtime
self.cpu.set_freq(self.cpu.min_freq)
load_list = []
runtime_list = []
for cpu in self.cpu.list:
load_test = Load(cpu)
load_test.run()
load_list.append(load_test)
for cpu in self.cpu.list:
runtime = load_list[cpu].get_runtime()
runtime_list.append(runtime)
max_average_runtime = 1.0 * sum(runtime_list) / len(runtime_list)
if max_average_runtime == 0:
print("[X] Max average time is 0.")
return False
print("[.] Max average time of all CPUs userspace load test: %.2f" %
max_average_runtime)
## max_freq -> min_runtime
self.cpu.set_freq(self.cpu.max_freq)
load_list = []
runtime_list = []
for cpu in self.cpu.list:
load_test = Load(cpu)
load_test.run()
load_list.append(load_test)
for cpu in self.cpu.list:
runtime = load_list[cpu].get_runtime()
runtime_list.append(runtime)
min_average_runtime = 1.0 * sum(runtime_list) / len(runtime_list)
if min_average_runtime == 0:
print("[X] Min average time is 0.")
return False
print("[.] Min average time of all CPUs userspace load test: %.2f" %
min_average_runtime)
measured_speedup = 1.0 * max_average_runtime / min_average_runtime
expected_speedup = 1.0 * self.cpu.max_freq / self.cpu.min_freq
tolerance = 1.0
min_speedup = expected_speedup - (expected_speedup - 1.0) * tolerance
max_speedup = expected_speedup + (expected_speedup - 1.0) * tolerance
if not min_speedup < measured_speedup < max_speedup:
print("[X] The speedup(%.2f) is not between %.2f and %.2f" %
(measured_speedup, min_speedup, max_speedup))
return False
print("[.] The speedup(%.2f) is between %.2f and %.2f" %
(measured_speedup, min_speedup, max_speedup))
return True
def test_ondemand(self):
if self.cpu.set_governor('powersave') != 0:
print("[X] Set governor of all CPUs to powersave failed.")
return False
print("[.] Set governor of all CPUs to powersave.")
if self.cpu.set_governor('ondemand') != 0:
print("[X] Set governor of all CPUs to ondemand failed.")
return False
print("[.] Set governor of all CPUs to ondemand.")
target_cpu = randint(0, self.cpu.nums)
target_cpu_governor = self.cpu.get_governor(target_cpu)
if target_cpu_governor != 'ondemand':
print("[X] The governor of CPU%s(%s) is not ondemand." %
(target_cpu, target_cpu_governor))
return False
print("[.] The governor of CPU%s is %s." %
(target_cpu, target_cpu_governor))
load_test = Load(target_cpu)
load_test.run()
sleep(1)
target_cpu_freq = self.cpu.get_freq(target_cpu)
if target_cpu_freq != self.cpu.max_freq:
print("[X] The freq of CPU%s(%d) is not scaling_max_freq(%d)." %
(target_cpu, target_cpu_freq, self.cpu.max_freq))
return False
print("[.] The freq of CPU%s is scaling_max_freq(%d)." %
(target_cpu, target_cpu_freq))
load_test_time = load_test.get_runtime()
print("[.] Time of CPU%s ondemand load test: %.2f" %
(target_cpu, load_test_time))
target_cpu_freq = self.cpu.get_freq(target_cpu)
if not target_cpu_freq <= self.cpu.max_freq:
print("[X] The freq of CPU%s(%d) is not less equal than %d." %
(target_cpu, target_cpu_freq, self.cpu.max_freq))
return False
print("[.] The freq of CPU%s(%d) is less equal than %d." %
(target_cpu, target_cpu_freq, self.cpu.max_freq))
return True
def test_conservative(self):
if self.cpu.set_governor('powersave') != 0:
print("[X] Set governor of all CPUs to powersave failed.")
return False
print("[.] Set governor of all CPUs to powersave.")
if self.cpu.set_governor('conservative') != 0:
print("[X] Set governor of all CPUs to conservative failed.")
return False
print("[.] Set governor of all CPUs to conservative.")
target_cpu = randint(0, self.cpu.nums)
target_cpu_governor = self.cpu.get_governor(target_cpu)
if target_cpu_governor != 'conservative':
print("[X] The governor of CPU%s(%s) is not conservative." %
(target_cpu, target_cpu_governor))
return False
print("[.] The governor of CPU%s is %s." %
(target_cpu, target_cpu_governor))
load_test = Load(target_cpu)
load_test.run()
sleep(1)
target_cpu_freq = self.cpu.get_freq(target_cpu)
if not self.cpu.min_freq < target_cpu_freq < self.cpu.max_freq:
print("[X] The freq of CPU%s(%d) is not between %d~%d." %
(target_cpu, target_cpu_freq, self.cpu.min_freq, self.cpu.max_freq))
return False
print("[.] The freq of CPU%s(%d) is between %d~%d." %
(target_cpu, target_cpu_freq, self.cpu.min_freq, self.cpu.max_freq))
load_test_time = load_test.get_runtime()
print("[.] Time of CPU%s conservative load test: %.2f" %
(target_cpu, load_test_time))
target_cpu_freq = self.cpu.get_freq(target_cpu)
print("[.] Current freq of CPU%s is %d." % (target_cpu, target_cpu_freq))
return True
def test_powersave(self):
if self.cpu.set_governor('powersave') != 0:
print("[X] Set governor of all CPUs to powersave failed.")
return False
print("[.] Set governor of all CPUs to powersave.")
target_cpu = randint(0, self.cpu.nums)
target_cpu_governor = self.cpu.get_governor(target_cpu)
if target_cpu_governor != 'powersave':
print("[X] The governor of CPU%s(%s) is not powersave." %
(target_cpu, target_cpu_governor))
return False
print("[.] The governor of CPU%s is %s." %
(target_cpu, target_cpu_governor))
target_cpu_freq = self.cpu.get_freq(target_cpu)
if target_cpu_freq != self.cpu.min_freq:
print("[X] The freq of CPU%s(%d) is not scaling_min_freq(%d)." %
(target_cpu, target_cpu_freq, self.cpu.min_freq))
return False
print("[.] The freq of CPU%s is %d." % (target_cpu, target_cpu_freq))
load_test = Load(target_cpu)
load_test.run()
load_test_time = load_test.get_runtime()
print("[.] Time of CPU%s powersave load test: %.2f" %
(target_cpu, load_test_time))
target_cpu_freq = self.cpu.get_freq(target_cpu)
print("[.] Current freq of CPU%s is %d." % (target_cpu, target_cpu_freq))
return True
def test_performance(self):
if self.cpu.set_governor('performance') != 0:
print("[X] Set governor of all CPUs to performance failed.")
return False
print("[.] Set governor of all CPUs to performance.")
target_cpu = randint(0, self.cpu.nums)
target_cpu_governor = self.cpu.get_governor(target_cpu)
if target_cpu_governor != 'performance':
print("[X] The governor of CPU%s(%s) is not performance." %
(target_cpu, target_cpu_governor))
return False
print("[.] The governor of CPU%s is %s." %
(target_cpu, target_cpu_governor))
target_cpu_freq = self.cpu.get_freq(target_cpu)
if target_cpu_freq != self.cpu.max_freq:
print("[X] The freq of CPU%s(%d) is not scaling_max_freq(%d)." %
(target_cpu, target_cpu_freq, self.cpu.max_freq))
return False
print("[.] The freq of CPU%s is %d." % (target_cpu, target_cpu_freq))
load_test = Load(target_cpu)
load_test.run()
load_test_time = load_test.get_runtime()
print("[.] Time of CPU%s performance load test: %.2f" %
(target_cpu, load_test_time))
target_cpu_freq = self.cpu.get_freq(target_cpu)
print("[.] Current freq of CPU%s is %d." % (target_cpu, target_cpu_freq))
return True
def test(self):
self.cpu = CPU()
self.original_governor = self.cpu.get_governor(0)
if not self.cpu.get_info():
print("[X] Fail to get CPU info." \
" Please check if the CPU supports cpufreq.")
return False
ret = True
print("")
print("[.] Test userspace")
if not self.test_userspace():
print("[X] Test userspace FAILED")
ret = False
print("")
print("[.] Test ondemand")
if not self.test_ondemand():
print("[X] Test ondemand FAILED")
ret = False
print("")
print("[.] Test conservative")
if not self.test_conservative():
print("[X] Test conservative FAILED")
ret = False
print("")
print("[.] Test powersave")
if not self.test_powersave():
print("[X] Test powersave FAILED")
ret = False
print("")
print("[.] Test performance")
if not self.test_performance():
print("[X] Test performance FAILED")
ret = False
self.cpu.set_governor(self.original_governor)
return ret
if __name__ == "__main__":
t = CPUFreqTest()
t.setup()
t.test()
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import sys
import time
import shutil
import string
from hwcert.test import Test
from hwcert.command import Command, CertCommandError
from hwcert.commandUI import CommandUI
from hwcert.device import CertDevice, Device
class DiskTest(Test):
def __init__(self):
Test.__init__(self)
self.disks = list()
self.filesystems = ["ext4"]
self.ui = CommandUI()
def setup(self, args=None):
try:
print("Disk Info:")
Command("fdisk -l").echo(ignore_errors=True)
print("\nPartition Info:")
Command("df -h").echo(ignore_errors=True)
print("\nMount Info:")
Command("mount").echo(ignore_errors=True)
print("\nSwap Info:")
Command("cat /proc/swaps").echo(ignore_errors=True)
print("\nLVM Info:")
Command("pvdisplay").echo(ignore_errors=True)
Command("vgdisplay").echo(ignore_errors=True)
Command("lvdisplay").echo(ignore_errors=True)
print("Md Info:")
Command("cat /proc/mdstat").echo(ignore_errors=True)
sys.stdout.flush()
print("\n")
except Exception as e:
print("Warning: could not get disk info")
print(e)
def test(self):
self.get_disk()
if len(self.disks) == 0:
print("No suite disk found to test.")
return False
self.disks.append("all")
disk = self.ui.prompt_edit("Which disk would you like to test: ", self.disks[0], self.disks)
return_code = True
if disk == "all":
for disk in self.disks[:-1]:
if not self.raw_test(disk):
return_code = False
if not self.vfs_test(disk):
return_code = False
else:
if not self.raw_test(disk):
return_code = False
if not self.vfs_test(disk):
return_code = False
return return_code
def get_disk(self):
self.disks = list()
disks = list()
devices = CertDevice().get_devices()
for device in devices:
if (device.get_property("DEVTYPE") == "disk" and not device.get_property("ID_TYPE")) or \
device.get_property("ID_TYPE") == "disk":
if "/host" in device.get_property("DEVPATH"):
disks.append(device.get_name())
partition_file = open("/proc/partitions", "r")
partition = partition_file.read()
partition_file.close()
os.system("swapon -a 2>/dev/null")
swap_file = open("/proc/swaps", "r")
swap = swap_file.read()
swap_file.close()
mdstat_file = open("/proc/mdstat", "r")
mdstat = mdstat_file.read()
mdstat_file.close()
mtab_file = open("/etc/mtab", "r")
mtab = mtab_file.read()
mtab_file.close()
mount_file = open("/proc/mounts", "r")
mounts = mount_file.read()
mount_file.close()
for disk in disks:
if disk not in partition or ("/dev/%s" % disk) in swap:
continue
if ("/dev/%s" % disk) in mounts or ("/dev/%s" % disk) in mtab:
continue
if disk in mdstat or os.system("pvs 2>/dev/null | grep -q '/dev/%s'" % disk) == 0:
continue
self.disks.append(disk)
un_suitable = list(set(disks).difference(set(self.disks)))
if len(un_suitable) > 0:
print("These disks %s are in use now, skip them." % "|".join(un_suitable))
def raw_test(self, disk):
print("\n#############")
print("%s raw IO test" % disk)
device = "/dev/" + disk
if not os.path.exists(device):
print("Error: device %s not exists." % device)
proc_path="/sys/block/" + disk
if not os.path.exists(proc_path):
proc_path="/sys/block/*/" + disk
size = Command("cat %s/size" % proc_path).get_str()
size = int(size)/2
if size <= 0:
print("Error: device %s size not suitable to do test." % device)
return False
elif size > 1048576:
size = 1048576
print("\nStarting sequential raw IO test...")
opts = "-direct=1 -iodepth 4 -rw=rw -rwmixread=50 -group_reporting -name=file -runtime=300"
if not self.do_fio(device, size, opts):
print("%s sequential raw IO test fail." % device)
print("#############")
return False
print("\nStarting rand raw IO test...")
opts = "-direct=1 -iodepth 4 -rw=randrw -rwmixread=50 -group_reporting -name=file -runtime=300"
if not self.do_fio(device, size, opts):
print("%s rand raw IO test fail." % device)
print("#############")
return False
print("#############")
return True
def vfs_test(self, disk):
print("\n#############")
print("%s vfs test" % disk)
device = "/dev/" + disk
if not os.path.exists(device):
print("Error: device %s not exists." % device)
proc_path="/sys/block/" + disk
if not os.path.exists(proc_path):
proc_path="/sys/block/*/" + disk
size = Command("cat %s/size" % proc_path).get_str()
size = int(size)/2/2
if size <= 0:
print("Error: device %s size not suitable to do test." % device)
return False
elif size > 1048576:
size = 1048576
if os.path.exists("vfs_test"):
shutil.rmtree("vfs_test")
os.mkdir("vfs_test")
path = os.path.join(os.getcwd(), "vfs_test")
return_code = True
for fs in self.filesystems:
try:
print("\nFormatting %s to %s ..." % (device, fs))
Command("umount %s" % device).echo(ignore_errors=True)
Command("mkfs -t %s -F %s 2>/dev/null" % (fs, device)).echo()
Command("mount -t %s %s %s" % (fs, device, "vfs_test")).echo()
print("\nStarting sequential vfs IO test...")
opts = "-direct=1 -iodepth 4 -rw=rw -rwmixread=50 -name=directoy -runtime=300"
if not self.do_fio(path, size, opts):
return_code = False
break
print("\nStarting rand vfs IO test...")
opts = "-direct=1 -iodepth 4 -rw=randrw -rwmixread=50 -name=directoy -runtime=300"
if not self.do_fio(path, size, opts):
return_code = False
break
except Exception as e:
print(e)
return_code = False
break
Command("umount %s" % device).echo(ignore_errors=True)
Command("rm -rf vfs_test").echo(ignore_errors=True)
print("#############")
return return_code
def do_fio(self, filepath, size, option):
if os.path.isdir(filepath):
file_opt = "-directory=%s" % filepath
else:
file_opt = "-filename=%s" % filepath
max_bs = 64
bs = 4
while bs <= max_bs:
if os.system("fio %s -size=%dK -bs=%dK %s" % (file_opt, size, bs, option)) != 0:
print("Error: %s fio failed." % filepath)
return False
print("\n")
sys.stdout.flush()
bs = bs *2
return True
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
from hwcert.test import Test
from hwcert.command import Command
class IpmiTest(Test):
def __init__(self):
Test.__init__(self)
self.requirements = ["OpenIPMI", "ipmitool"]
def start_ipmi(self):
try:
Command("systemctl start ipmi").run()
Command("systemctl status ipmi.service").get_str(regex="Active: active", single_line=False)
except:
print("ipmi service cant't be started")
return False
return True
def ipmitool(self):
cmd_list = ["ipmitool fru","ipmitool sensor"]
for cmd in cmd_list:
try:
Command(cmd).echo()
except:
print("%s return error." % cmd)
return False
return True
def test(self):
if not self.start_ipmi():
return False
if not self.ipmitool():
return False
return True
if __name__ == "__main__":
i = IpmiTest()
i.test()
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import sys
import time
import re
from hwcert.test import Test
from hwcert.commandUI import CommandUI
from hwcert.document import ConfigFile
from hwcert.command import Command, CertCommandError
class KdumpTest(Test):
def __init__(self):
Test.__init__(self)
self.pri = 9
self.reboot = True
self.rebootup = "verify_vmcore"
self.kdump_conf = "/etc/kdump.conf"
self.vmcore_path = "/var/crash"
self.requirements = ["crash", "kernel-debuginfo", "kexec-tools"]
def test(self):
try:
Command("cat /proc/cmdline").get_str("crashkernel=[^\ ]*")
except:
print("Error: no crashkernel found.")
return False
config = ConfigFile(self.kdump_conf)
if not config.get_parameter("path"):
config.add_parameter("path", self.vmcore_path)
else:
self.vmcore_path = config.get_parameter("path")
if config.get_parameter("kdump_obj") == "kbox":
config.remove_parameter("kdump_obj")
config.add_parameter("kdump_obj", "all")
try:
Command("systemctl restart kdump").run()
Command("systemctl status kdump").get_str(regex="Active: active", single_line=False)
except:
print("Error: kdump service not working.")
return False
print("kdump config:")
print("#############")
config.dump()
print("#############")
ui = CommandUI()
if ui.prompt_confirm("System will reboot, are you ready?"):
print("\ntrigger crash...")
sys.stdout.flush()
os.system("sync")
os.system("echo c > /proc/sysrq-trigger")
time.sleep(30)
return False
else:
print("")
return False
def verify_vmcore(self):
config = ConfigFile(self.kdump_conf)
if config.get_parameter("path"):
self.vmcore_path = config.get_parameter("path")
dir_pattern = re.compile("(?P<ipaddr>[0-9]+\.[0-9]+\.[0-9]+)-(?P<date>[0-9]+(-|\.)[0-9]+(-|\.)[0-9]+)-(?P<time>[0-9]+:[0-9]+:[0-9]+)")
vmcore_dirs = list()
for (root, dirs, files) in os.walk(self.vmcore_path):
for dir in dirs:
if dir_pattern.search(dir):
vmcore_dirs.append(dir)
vmcore_dirs.sort()
vmcore_file = os.path.join(self.vmcore_path, vmcore_dirs[-1], "vmcore")
try:
Command("echo \"sys\nq\" | crash -s %s /usr/lib/debug/lib/modules/`uname -r`/vmlinux" % vmcore_file).echo()
print("kdump image %s verified" % vmcore_file)
return True
except CertCommandError as e:
print("Error: could not verify kdump image %s" % vmcore_file)
print(e)
return False
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: all install clean
all: eatmem_test hugetlb_test
eatmem_test: eatmem_test.c
$(CC) $(CFLAGS) -lpthread $< -o $@
hugetlb_test: hugetlb_test.c
$(CC) $(CFLAGS) $< -o $@
install:
mkdir -p $(DEST)
cp -a eatmem_test hugetlb_test *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
rm -rf eatmem_test hugetlb_test
/*
* Copyright (c) 2020 Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <fcntl.h>
#include <string.h>
#define __USE_GNU
#include <pthread.h>
#include <sched.h>
#define MEM_CHECK_MAGIC (0xFEE1DEAD)
unsigned long num_cpus = 1;
unsigned long num_threads = 2;
unsigned long memsize = 1024 * 1024 * 1024;
unsigned long thread_mem = 0;
unsigned done = 0;
unsigned mmap_done = 0;
unsigned init_thread = 0;
unsigned long test_time = 120;
pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t run_mutex = PTHREAD_MUTEX_INITIALIZER;
char **mmap_zone = NULL;
void usage(void)
{
printf("Usage: eatmem_test [-h] [-m size] [-t time]\n");
printf(" -h: show this help\n");
printf(" -m: memory size,unit MB. default: 1024MB\n");
printf(" -t: test time,in seconds. default: 120\n");
}
void *mem_eat(void *data)
{
unsigned long pages, page_size, i;
unsigned long *page_area;
unsigned thread, page, offset;
char *my_zone;
unsigned thread_id;
pthread_mutex_lock(&thread_mutex);
thread_id = init_thread++;
pthread_mutex_unlock(&thread_mutex);
page_size = getpagesize();
pages = thread_mem / page_size;
my_zone = mmap(NULL, thread_mem, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if (my_zone == MAP_FAILED) {
fprintf(stderr, "mmap fail in thread %u\n", thread_id);
exit(1);
}
for (i = 0; i < pages; i++) {
page_area = (unsigned long *)&(my_zone[i * page_size]);
page_area[0] = MEM_CHECK_MAGIC + i + thread_id;
}
mmap_zone[thread_id] = my_zone;
pthread_mutex_lock(&thread_mutex);
mmap_done++;
pthread_mutex_unlock(&thread_mutex);
printf("thread %u finish eat memory\n", thread_id);
pthread_mutex_lock(&run_mutex);
pthread_mutex_unlock(&run_mutex);
while (!done) {
thread = rand() % num_threads;
page = rand() % pages;
page_area = (unsigned long *)&(mmap_zone[thread][page * page_size]);
if (page_area[0] != MEM_CHECK_MAGIC + page + thread) {
fprintf(stderr, "thread %u read fail\n", thread_id);
exit(1);
}
offset = (rand() % ((page_size / sizeof(unsigned long)) - 1)) + 1;
page_area[offset] = rand();
}
}
int main(int argc, char **argv)
{
unsigned i = 0;
unsigned long count = 0;
cpu_set_t cpuset;
pthread_t *threads;
int ch = 0;
while ((ch = getopt(argc, argv, "hm:t:")) != -1) {
switch (ch) {
case 'h':
usage();
return 0;
case 'm':
memsize = strtoul(optarg, NULL, 0);;
if (!memsize) {
fprintf(stderr, "bad memory size\n");
return 1;
}
memsize <<= 20;
break;
case 't':
test_time = atoi(optarg);
if (!test_time) {
fprintf(stderr, "bad test time\n");
return 1;
}
break;
}
}
printf("Memory size: %luMB\tTest time: %lus\n", memsize >> 20, test_time);
num_cpus = sysconf(_SC_NPROCESSORS_CONF);
if (num_threads < num_cpus * 2)
num_threads = num_cpus * 2;
thread_mem = memsize / num_threads;
if (thread_mem < getpagesize())
thread_mem = getpagesize();
threads = (pthread_t *)malloc(num_threads * sizeof(pthread_t));
mmap_zone = (char **)malloc(num_threads * sizeof(char *));
pthread_mutex_lock(&run_mutex);
printf("Start memory eating\n");
for (i = 0; i < num_threads; i++) {
if (pthread_create(&threads[i], NULL, mem_eat, NULL) != 0) {
fprintf(stderr, "thread %u create fail\n", i);
exit(1);
}
CPU_ZERO(&cpuset);
CPU_SET(i%num_cpus, &cpuset);
if (pthread_setaffinity_np(threads[i], sizeof(cpu_set_t), &cpuset) != 0) {
fprintf(stderr, "thread %u setaffinity fail\n", i);
exit(1);
}
}
i = 0;
while (mmap_done < num_threads) {
sleep(1);
i++;
if (i >= test_time) {
fprintf(stderr, "thread mmap not finished after %lu seconds\n", test_time);
exit(1);
}
}
pthread_mutex_unlock(&run_mutex);
printf("Start memory rw testing\n");
while (count < test_time) {
sleep(2);
count = count + 2;
printf(".");
fflush(stdout);
}
done = 1;
for (i = 0; i < num_threads; i++)
pthread_join(threads[i], NULL);
printf("\neatmem_test complete\n");
free(threads);
return 0;
}
/*
* Copyright (c) 2020 Huawei Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#define LENGTH (1024UL*1024*1024)
#define RANGE 128
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
static void write_test(char *addr)
{
unsigned long i;
printf("Writing...\n");
for (i = 0; i < LENGTH; i++)
*(addr + i) = i % RANGE;
}
static int read_test(char *addr)
{
unsigned long i;
printf("Reading...\n");
for (i = 0; i < LENGTH; i++) {
if (*(addr + i) != (i % RANGE)) {
printf("Mismatch at %lu\n", i);
return 1;
}
}
return 0;
}
int main(int argc, char **argv)
{
void *addr;
int ret;
size_t length = LENGTH;
printf("Mapping %lu Mbytes\n", (unsigned long)length >> 20);
addr = mmap(NULL, length, PROT_READ | PROT_WRITE, FLAGS, -1, 0);
if (addr == MAP_FAILED) {
perror("mmap");
exit(1);
}
write_test(addr);
ret = read_test(addr);
printf("Unmapping %lu Mbytes\n", (unsigned long)length >> 20);
if (munmap(addr, LENGTH)) {
perror("munmap");
exit(1);
}
return ret;
}
此差异已折叠。
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import argparse
from hwcert.test import Test
from hwcert.command import Command
from hwcert.env import CertEnv
from hwcert.document import CertDocument
from rdma import RDMATest
class EthernetTest(RDMATest):
def __init__(self):
RDMATest.__init__(self)
self.subtests = [self.test_ip_info, self.test_eth_link, self.test_icmp,
self.test_udp_tcp, self.test_http]
self.target_bandwidth_percent = 0.75
def is_RoCE(self):
path_netdev = ''.join(['/sys', self.device.get_property("DEVPATH")])
path_pci = path_netdev.split('net')[0]
cmd = "ls %s | grep -q infiniband" % path_pci
print(cmd)
return 0 == os.system(cmd)
def setup(self, args=None):
self.args = args or argparse.Namespace()
self.device = getattr(self.args, 'device', None)
self.interface = self.device.get_property("INTERFACE")
self.cert = CertDocument(CertEnv.certificationfile)
self.server_ip = self.cert.get_server()
if self.is_RoCE():
try:
input = raw_input
except NameError:
from builtins import input
choice = input("[!] RoCE interface found. " \
"Run RDMA tests instead? [y/N] ")
if choice.lower() != "y":
return
print("[+] Testing RoCE interface %s..." % self.interface)
self.link_layer = 'Ethernet'
self.subtests = [self.test_ip_info, self.test_ibstatus,
self.test_eth_link, self.test_icmp, self.test_rdma]
def test(self):
for subtest in self.subtests:
if not subtest():
return False
return True
if __name__ == '__main__':
t = EthernetTest()
t.server_ip = '199.1.1.2'
from hwcert.device import Device
properties = {
'DEVPATH': '/devices/pci0000:80/0000:80:01.0/0000:81:00.0/net/enp129s0f0',
'INTERFACE': 'enp129s0f0'
}
t.device = Device(properties)
t.interface = t.device.get_property("INTERFACE")
# t.setup()
t.test()
#!/usr/bin/env python
# coding: utf-8
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
import os
import argparse
from hwcert.test import Test
from hwcert.command import Command
from rdma import RDMATest
class InfiniBandTest(RDMATest):
def __init__(self):
RDMATest.__init__(self)
self.link_layer = 'InfiniBand'
self.subtests = [self.test_ip_info, self.test_ibstatus, self.test_ib_link,
self.test_icmp, self.test_rdma]
self.speed = 56000 # Mb/s
self.target_bandwidth_percent = 0.5
def test_ib_link(self):
if 'LinkUp' not in self.phys_state:
print("[X] Device is not LinkUp.")
if 'ACTIVE' not in self.state:
print("[X] Link is not ACTIVE.")
if 0x0 == self.base_lid:
print("[X] Fail to get base lid of %s." % self.interface)
return False
print("[.] The base lid is %s" % self.base_lid)
if 0x0 == self.sm_lid:
print("[X] Fail to get subnet manager lid of %s." % self.interface)
return False
print("[.] The subnet manager lid is %s" % self.sm_lid)
return True
if __name__ == '__main__':
t = InfiniBandTest()
t.server_ip = '199.1.37.20'
t.speed = 10000 # Mb/s
from hwcert.device import Device
properties = {
'DEVPATH': '/devices/pci0000:d7/0000:d7:02.0/0000:d8:00.0/net/ib0',
'INTERFACE': 'ib0'
}
t.device = Device(properties)
t.interface = t.device.get_property("INTERFACE")
# t.setup()
t.test()
此差异已折叠。
此差异已折叠。
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
此差异已折叠。
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
此差异已折叠。
# Copyright (c) 2020 Huawei Technologies Co., Ltd.
# oec-hardware is licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Create: 2020-04-01
.PHONY: install clean
all: ;
install:
mkdir -p $(DEST)
cp -a *.py $(DEST)
chmod a+x $(DEST)/*.py
clean:
rm -rf $(DEST)
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册