aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md20
-rw-r--r--.github/ISSUE_TEMPLATE/new-kernel-branch.md57
-rw-r--r--.github/ISSUE_TEMPLATE/new-kernelci-api-tokens.md44
-rw-r--r--.travis.yml15
-rw-r--r--build-configs.yaml242
-rw-r--r--jenkins/bisect.jpl145
-rw-r--r--jenkins/build-trigger.jpl152
-rw-r--r--jenkins/build.jpl20
-rw-r--r--jenkins/buster-v4l2.jpl (renamed from jenkins/stretch-v4l2.jpl)6
-rwxr-xr-xjenkins/debian/debos/scripts/buster-v4l2.sh (renamed from jenkins/debian/debos/scripts/stretch-v4l2.sh)2
-rw-r--r--jenkins/dockerfiles/debos/Dockerfile2
-rwxr-xr-xjenkins/kernel-arch-complete.sh34
-rwxr-xr-xjenkins/lava-boot-v2.sh22
-rw-r--r--jenkins/monitor.jpl2
-rw-r--r--jenkins/test-runner.jpl178
-rwxr-xr-xkci_build198
-rwxr-xr-xkci_test204
-rw-r--r--kernelci/build.py198
-rw-r--r--kernelci/cli.py321
-rw-r--r--kernelci/config/build.py45
-rw-r--r--kernelci/config/lab.py111
-rw-r--r--kernelci/config/test.py36
-rw-r--r--kernelci/lab/__init__.py99
-rw-r--r--kernelci/lab/lava.py146
-rw-r--r--kernelci/test.py145
-rw-r--r--lab-configs.yaml124
-rwxr-xr-xlava-v2-jobs-from-api.py43
-rw-r--r--src/org/kernelci/build/Kernel.groovy66
-rw-r--r--templates/base/kernel-ci-base.jinja21
-rw-r--r--templates/baseline/baseline.jinja244
-rw-r--r--templates/baseline/generic-fastboot-baseline-template.jinja29
-rw-r--r--templates/boot-fastboot/generic-fastboot-boot-template.jinja295
-rw-r--r--templates/boot-fastboot/mkbootimg.jinja220
-rw-r--r--templates/igt/igt.jinja26
-rw-r--r--templates/v4l2-compliance/v4l2-compliance.jinja26
-rw-r--r--test-configs.yaml615
36 files changed, 2808 insertions, 665 deletions
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..bbcbbe7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/new-kernel-branch.md b/.github/ISSUE_TEMPLATE/new-kernel-branch.md
new file mode 100644
index 0000000..7e91170
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/new-kernel-branch.md
@@ -0,0 +1,57 @@
+---
+name: New kernel branch
+about: Add a kernel git branch to kernelci.org
+title: Add branch BRANCH from TREE
+labels: ''
+assignees: ''
+
+---
+
+Each git kernel branch is monitored every hour by kernelci.org. Whenever a new
+revision is detected, it will be built for a number of combinations of
+architectures, defconfigs and compilers. Then a build report will be sent,
+some tests will be run and test reports will also be sent.
+
+Please provide the information described below in order to add a new branch to
+kernelci.org:
+
+- **How much build coverage do you need for your branch?**
+
+Generally speaking, a good rule is to build fewer variants for branches that
+are "further" away from mainline and closer to individual developers. This can
+be fine-tuned with arbitrary filters, but essentially there are 3 main options:
+
+1. Build everything, including allmodconfig, which amounts to about 220 builds.
+This is we do with linux-next.
+
+2. Skip a few things such as allmodconfig as it's very long to build and
+doesn't really boot, and also architectures that are less useful such as MIPS
+which saves 80 builds and doesn't have much test platforms in KernelCI. This
+is we do with some subsystems such as linux-media.
+
+3. Build only the main defconfig for each architecture to save a lot of build
+power, get the fastest results and highest boots/builds ratio. This is what do
+with some maintainer branches such as linusw' GPIO branch.
+
+⇨ Choice:
+
+- **How often do you expect this branch to be updated?**
+
+If you push once a week or less, it's easier to allow for many build variants
+as this reduces the build load on average. Conversely, if you push several
+times every day then a small set of builds should be used.
+
+It's also possible to increase the build capacity if needed but this comes with
+a cost. Avoiding unnecessary builds is always a good way to reduce turnaround
+time and not waste resources.
+
+⇨ Estimated frequency:
+
+- **Who should the email reports be sent to?**
+
+Standard email reports inlude builds and basic tests that are run on all
+platforms. Please provide a list of email recipients for these. Typical ones
+are the regular KernelCI reports list, kernel mailing lists associated with the
+changes going into the branch and related maintainers.
+
+⇨ Recipients:
diff --git a/.github/ISSUE_TEMPLATE/new-kernelci-api-tokens.md b/.github/ISSUE_TEMPLATE/new-kernelci-api-tokens.md
new file mode 100644
index 0000000..f9316e2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/new-kernelci-api-tokens.md
@@ -0,0 +1,44 @@
+---
+name: New KernelCI API tokens
+about: Request to get some KernelCI API tokens
+title: Request API tokens for USER
+labels: ''
+assignees: ''
+
+---
+
+KernelCI uses kernelci-backend to manage its database which contains all the data about builds and tests. There are 2 main instances, a production one for kernelci.org and a test one for staging.kernelci.org. Separate tokens can be provided for either or both, with several permissions to choose from. KernelCI labs will also typically need a token to be able to push their test results.
+
+Please answer the questions below to request some API tokens:
+
+**Contact details**
+
+⇨ User name:
+
+⇨ Email address:
+
+If this is for a lab token:
+
+⇨ Lab owner first and last names:
+
+⇨ Lab name:
+
+**Production**
+
+The production instance is the one behind `https://kernelci.org`. Production tokens are only provided for labs that are able to send useful data, or with read-only permissions to create dashboards or consume the results data in any way (stats, reports...). Uses of the kernelci.org production data should ideally be made public.
+
+The URL of the production API server is `https://api.kernelci.org`.
+
+Do you need a token to access the production API? If so, is this to be able to read the data or also send some test results from a lab?
+
+⇨ Read-only or also to to push results:
+
+**Staging**
+
+The URL of the staging API server is `https://staging-api.kernelci.org`.
+
+The staging instance is used for experimental features without impacting the production instance. This is useful for anything new that needs to be tested in a full KernelCI environment with results publicly available on `https://staging.kernelci.org` but not sent to regular mailing lists.
+
+Do you need a token to access the staging API? If so, is this to be able to read the data or send some test results from a lab?
+
+⇨ Read-only or also to push results:
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..31308fb
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,15 @@
+dist: xenial
+
+language: python
+
+python:
+ - "2.7"
+
+install:
+ - pip install -r requirements.txt
+ - pip install pycodestyle
+
+script:
+ - make test
+ - pycodestyle kernelci
+ - pycodestyle kci_*
diff --git a/build-configs.yaml b/build-configs.yaml
index c41cf23..75b70dc 100644
--- a/build-configs.yaml
+++ b/build-configs.yaml
@@ -19,6 +19,9 @@ trees:
ardb:
url: "git://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git"
+ arm64:
+ url: "git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git"
+
arnd:
url: "https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git"
@@ -58,6 +61,9 @@ trees:
krzysztof:
url: "https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git"
+ lee:
+ url: "https://git.kernel.org/pub/scm/linux/kernel/git/lee/linux.git"
+
linaro-android:
url: "https://android-git.linaro.org/git/kernel/linaro-android.git"
@@ -100,6 +106,9 @@ trees:
samsung:
url: "https://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git"
+ sashal:
+ url: "https://git.kernel.org/pub/scm/linux/kernel/git/sashal/linux-stable.git"
+
soc:
url: "https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git"
@@ -112,6 +121,9 @@ trees:
tegra:
url: "https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git"
+ thermal:
+ url: "https://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux.git"
+
ulfh:
url: "https://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git"
@@ -149,7 +161,7 @@ fragments:
- 'CONFIG_VIDEO_VIVID_MAX_DEVS=64'
x86_kvm_guest:
- path: "arch/x86/configs/kvm_guest.config"
+ path: "kernel/configs/kvm_guest.config"
build_environments:
@@ -196,64 +208,67 @@ build_environments:
# Default config with full build coverage
build_configs_defaults:
-
- gcc-8:
-
- build_environment: gcc-8
-
- fragments: &default_fragments
- - 'debug'
- - 'kselftest'
- - 'tinyconfig'
-
- architectures: &default_architectures
-
- arc: &arc_arch
- base_defconfig: 'nsim_hs_defconfig'
- extra_configs: ['allnoconfig']
- filters: &arc_default_filters
- # remove any non-ARCv2 defconfigs since we only have ARCv2 toolchain
- - blacklist:
- defconfig:
- - 'axs101_defconfig'
- - 'nps_defconfig'
- - 'nsim_700_defconfig'
- - 'nsimosci_defconfig'
- - 'tb10x_defconfig'
-
- arm: &arm_arch
- base_defconfig: 'multi_v7_defconfig'
- extra_configs:
- - 'allnoconfig'
- - 'multi_v7_defconfig+CONFIG_CPU_BIG_ENDIAN=y'
- - 'multi_v7_defconfig+CONFIG_SMP=n'
- - 'multi_v7_defconfig+CONFIG_EFI=y+CONFIG_ARM_LPAE=y'
-
- arm64: &arm64_arch
- extra_configs:
- - 'allmodconfig'
- - 'allnoconfig'
- - 'defconfig+CONFIG_CPU_BIG_ENDIAN=y'
- - 'defconfig+CONFIG_RANDOMIZE_BASE=y'
-
- i386: &i386_arch
- base_defconfig: 'i386_defconfig'
- extra_configs: ['allnoconfig']
-
- mips: &mips_arch
- base_defconfig: '32r2el_defconfig'
- extra_configs: ['allnoconfig']
- filters: &mips_default_filters
- - blacklist: {defconfig: ['generic_defconfig']}
-
- riscv: &riscv_arch
- extra_configs: ['allnoconfig']
-
- x86_64: &x86_64_arch
- base_defconfig: 'x86_64_defconfig'
- extra_configs: ['allmodconfig', 'allnoconfig']
- fragments: [x86_kvm_guest]
-
+ variants:
+ gcc-8:
+ build_environment: gcc-8
+
+ fragments: &default_fragments
+ - 'debug'
+ - 'kselftest'
+ - 'tinyconfig'
+
+ architectures: &default_architectures
+
+ arc: &arc_arch
+ base_defconfig: 'nsim_hs_defconfig'
+ extra_configs: ['allnoconfig']
+ filters: &arc_default_filters
+ # remove any non-ARCv2 defconfigs since we only have ARCv2 toolchain
+ - blacklist:
+ defconfig:
+ - 'axs101_defconfig'
+ - 'nps_defconfig'
+ - 'nsim_700_defconfig'
+ - 'nsimosci_defconfig'
+ - 'tb10x_defconfig'
+
+ arm: &arm_arch
+ base_defconfig: 'multi_v7_defconfig'
+ extra_configs:
+ - 'allmodconfig'
+ - 'allnoconfig'
+ - 'multi_v7_defconfig+CONFIG_CPU_BIG_ENDIAN=y'
+ - 'multi_v7_defconfig+CONFIG_SMP=n'
+ - 'multi_v7_defconfig+CONFIG_EFI=y+CONFIG_ARM_LPAE=y'
+
+ arm64: &arm64_arch
+ extra_configs:
+ - 'allmodconfig'
+ - 'allnoconfig'
+ - 'defconfig+CONFIG_CPU_BIG_ENDIAN=y'
+ - 'defconfig+CONFIG_RANDOMIZE_BASE=y'
+
+ i386: &i386_arch
+ base_defconfig: 'i386_defconfig'
+ extra_configs: ['allnoconfig']
+
+ mips: &mips_arch
+ base_defconfig: '32r2el_defconfig'
+ extra_configs: ['allnoconfig']
+ filters: &mips_default_filters
+ - blacklist: {defconfig: ['generic_defconfig']}
+
+ riscv: &riscv_arch
+ extra_configs: ['allnoconfig']
+
+ x86_64: &x86_64_arch
+ base_defconfig: 'x86_64_defconfig'
+ extra_configs: ['allmodconfig', 'allnoconfig']
+ fragments: [x86_kvm_guest]
+
+ reference:
+ tree: mainline
+ branch: 'master'
# Minimum architecture defconfigs
arch_defconfigs: &arch_defconfigs
@@ -283,6 +298,12 @@ arch_defconfigs: &arch_defconfigs
- regex: { defconfig: 'x86_64_defconfig' }
+minimal_variants: &minimal_variants
+ gcc-8:
+ build_environment: gcc-8
+ architectures: *arch_defconfigs
+
+
# Build fewer kernel configs with stable branches
stable_variants: &stable_variants
gcc-8:
@@ -386,6 +407,10 @@ build_configs:
tree: android
branch: 'android-4.9-q'
+ android_4.9-q-release:
+ tree: android
+ branch: 'android-4.9-q-release'
+
android_4.14-p:
tree: android
branch: 'android-4.14-p'
@@ -398,6 +423,10 @@ build_configs:
tree: android
branch: 'android-4.14-q'
+ android_4.14-q-release:
+ tree: android
+ branch: 'android-4.14-q-release'
+
android_4.14-r:
tree: android
branch: 'android-4.14-r'
@@ -406,6 +435,10 @@ build_configs:
tree: android
branch: 'android-4.19-q'
+ android_4.19-q-release:
+ tree: android
+ branch: 'android-4.19-q-release'
+
android_4.19-r:
tree: android
branch: 'android-4.19-r'
@@ -441,6 +474,19 @@ build_configs:
- 'multi_v7_defconfig+CONFIG_THUMB2_KERNEL=y+CONFIG_RANDOMIZE_BASE=y'
- 'omap2plus_defconfig+CONFIG_RANDOMIZE_BASE=y'
+ arm64:
+ tree: arm64
+ branch: 'for-kernelci'
+ variants:
+ gcc-8:
+ build_environment: gcc-8
+ architectures:
+ arm64:
+ base_defconfig: 'defconfig'
+ extra_configs:
+ - 'allmodconfig'
+ - 'allnoconfig'
+
arnd:
tree: arnd
branch: 'to-build'
@@ -502,6 +548,17 @@ build_configs:
tree: krzysztof
branch: 'for-next'
+ lee_android_3.18:
+ tree: lee
+ branch: 'android-3.18-preview'
+ variants:
+ gcc-8:
+ build_environment: gcc-8
+ architectures:
+ x86_64: *x86_64_arch
+ arm64: *arm64_arch
+ arm: *arm_arch
+
linaro-android:
tree: linaro-android
branch: 'linaro-android-llct'
@@ -509,26 +566,17 @@ build_configs:
linusw_devel:
tree: linusw
branch: 'devel'
- variants:
- gcc-8:
- build_environment: gcc-8
- architectures: *arch_defconfigs
+ variants: *minimal_variants
linusw_fixes:
tree: linusw
branch: 'fixes'
- variants:
- gcc-8:
- build_environment: gcc-8
- architectures: *arch_defconfigs
+ variants: *minimal_variants
linusw_for-next:
tree: linusw
branch: 'for-next'
- variants:
- gcc-8:
- build_environment: gcc-8
- architectures: *arch_defconfigs
+ variants: *minimal_variants
lsk_for-test:
tree: lsk
@@ -709,6 +757,11 @@ build_configs:
tree: samsung
branch: 'for-next'
+ sashal_stable-next:
+ tree: sashal
+ branch: 'stable-next'
+ variants: *stable_variants
+
# Disabled as the branch name contains a '/'. See discussion here:
# https://github.com/kernelci/kernelci-core/issues/23
#
@@ -760,50 +813,92 @@ build_configs:
branch: 'linux-5.2.y'
variants: *stable_variants
+ stable_5.3:
+ tree: stable
+ branch: 'linux-5.3.y'
+ variants: *stable_variants
+
stable-rc_3.18:
tree: stable-rc
branch: 'linux-3.18.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-3.18.y'
stable-rc_4.4:
tree: stable-rc
branch: 'linux-4.4.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-4.4.y'
stable-rc_4.9:
tree: stable-rc
branch: 'linux-4.9.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-4.9.y'
stable-rc_4.14:
tree: stable-rc
branch: 'linux-4.14.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-4.14.y'
stable-rc_4.19:
tree: stable-rc
branch: 'linux-4.19.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-4.19.y'
stable-rc_5.0:
tree: stable-rc
branch: 'linux-5.0.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-5.0.y'
stable-rc_5.1:
tree: stable-rc
branch: 'linux-5.1.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-5.1.y'
stable-rc_5.2:
tree: stable-rc
branch: 'linux-5.2.y'
variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-5.2.y'
+
+ stable-rc_5.3:
+ tree: stable-rc
+ branch: 'linux-5.3.y'
+ variants: *stable_variants
+ reference:
+ tree: stable
+ branch: 'linux-5.3.y'
tegra:
tree: tegra
branch: 'for-next'
+ thermal:
+ tree: thermal
+ branch: 'testing'
+ variants: *minimal_variants
+
ulfh:
tree: ulfh
branch: 'next'
@@ -811,7 +906,4 @@ build_configs:
vireshk:
tree: vireshk
branch: 'for-kernelci'
- variants:
- gcc-8:
- build_environment: gcc-8
- architectures: *arch_defconfigs
+ variants: *minimal_variants
diff --git a/jenkins/bisect.jpl b/jenkins/bisect.jpl
index f8eb68d..b0eae35 100644
--- a/jenkins/bisect.jpl
+++ b/jenkins/bisect.jpl
@@ -53,8 +53,10 @@ BUILD_ENVIRONMENT
Name of the build environment
LAB
Name of the lab in which to run the bisection tests
-PLAN (boot)
- Name of the test plan
+TEST_PLAN
+ Name of the KernelCI test plan (e.g. baseline)
+TEST_PLAN_VARIANT:
+ Name of the KernelCI test plan variant (e.g. baseline_qemu)
TEST_RUNS (1)
Number of LAVA jobs to run before considering pass or fail.
KCI_API_URL (https://api.kernelci.org)
@@ -84,7 +86,6 @@ TREES_WHITELIST
@Library('kernelci') _
-import org.kernelci.build.Kernel
import org.kernelci.util.Job
/* Working around some seemingly broken Python set-up... */
@@ -210,7 +211,8 @@ git symbolic-ref HEAD refs/heads/${params.KERNEL_BRANCH}
def buildKernel(kdir, kci_core) {
def output = "${kdir}/build-${params.ARCH}-${params.BUILD_ENVIRONMENT}"
dir(kci_core) {
- sh(script: "rm -f ${env._BUILD_JSON}")
+ sh(script: "rm -f ${env._BMETA_JSON}")
+ sh(script: "rm -f ${env._DTBS_JSON}")
sh(script: """\
for d in \$(find ${kdir} -name "build-*" -type d); do
@@ -262,14 +264,10 @@ push_kernel \
""")
}
- sh(script: """\
-./kci_build \
-publish_kernel \
---kdir=${kdir} \
---json-path=${env._BUILD_JSON} \
-""")
-
- stash(name: env._BUILD_JSON, includes: env._BUILD_JSON)
+ dir("${kdir}/_install_") {
+ stash(name: env._BMETA_JSON, includes: env._BMETA_JSON)
+ stash(name: env._DTBS_JSON, includes: env.DTBS_JSON)
+ }
}
}
@@ -284,41 +282,68 @@ def buildRevision(kdir, kci_core, git_rev, name) {
* kernel test with LAVA v2
*/
-def submitJob(kci_core, describe, hook) {
+def fetchLabInfo(kci_core) {
dir(kci_core) {
- sh(script: "rm -rf ${env._BUILD_JSON}; rm -rf data; mkdir data")
- unstash(env._BUILD_JSON)
- sh(script: """
-./lava-v2-jobs-from-api.py \
+ def token = "${params.LAB}-lava-api"
+
+ withCredentials([string(credentialsId: token, variable: 'SECRET')]) {
+ sh(script: """\
+./kci_test \
+get_lab_info \
--lab=${params.LAB} \
---builds=${env._BUILD_JSON} \
---storage=${params.KCI_STORAGE_URL} \
---plans=${params.PLAN} \
---jobs=data \
---arch=${params.ARCH} \
---tree=${params.KERNEL_TREE} \
---describe=${describe} \
---branch=${params.KERNEL_BRANCH} \
---defconfig_full=${params.DEFCONFIG} \
---priority=${params.LAVA_PRIORITY} \
---callback=${params.LAVA_CALLBACK} \
---callback-url=${hook.getURL()} \
---callback-dataset=results \
---callback-type=custom \
---targets=${params.TARGET}
+--lab-json=${env._LAB_JSON} \
+--user=kernel-ci \
+--token=${SECRET} \
""")
+ }
+ stash(name: env._LAB_JSON, includes: env._LAB_JSON)
+ }
+}
+
+def submitJob(kci_core, describe, hook) {
+ dir(kci_core) {
+ sh(script: """\
+rm -f ${env._BMETA_JSON} \
+rm -f ${env._DTBS_JSON} \
+rm -f ${env._LAB_JSON} \
+rm -rf data; mkdir data \
+""")
+ unstash(env._BMETA_JSON)
+ unstash(env._DTBS_JSON)
+ unstash(env._LAB_JSON)
def egg_cache = eggCache()
def token = "${params.LAB}-lava-api"
+ /* ToDo: deal with params.LAVA_PRIORITY or drop it */
+
withCredentials([string(credentialsId: token, variable: 'SECRET')]) {
- sh(script: """
-PYTHON_EGG_CACHE=${egg_cache} \
-./lava-v2-submit-jobs.py \
---username=kernel-ci \
+ sh(script: """ \
+./kci_test \
+generate \
+--bmeta-json=${env._BMETA_JSON} \
+--dtbs-json=${env._DTBS_JSON} \
+--lab-json=${env._LAB_JSON} \
+--storage=${params.KCI_STORAGE_URL} \
+--lab=${params.LAB} \
+--user=kernel-ci \
--token=${SECRET} \
+--output=data \
+--callback-id=${params.LAVA_CALLBACK} \
+--callback-url=${hook.getURL()} \
+--callback-dataset=results \
+--callback-type=custom \
+--target=${params.TARGET} \
+--plan=${params.TEST_PLAN_VARIANT} \
+""")
+
+ sh(script: """ \
+./kci_test \
+submit \
--lab=${params.LAB} \
---jobs=data
+--user=kernel-ci \
+--token=${SECRET} \
+--jobs=data/* \
""")
}
}
@@ -381,7 +406,7 @@ def runTest(kci_core, describe, expected=0, runs=0) {
* bisection
*/
-def findMergeBase(kdir, good, bad) {
+def findMergeBase(kdir, kci_core, good, bad) {
def base = good
dir(kdir) {
@@ -390,16 +415,32 @@ def findMergeBase(kdir, good, bad) {
script: "git merge-base --is-ancestor ${base} HEAD")
if (good_base != 0) {
- def ref = "${params.REF_KERNEL_TREE}/${params.REF_KERNEL_BRANCH}"
+ def ref_url = params.REF_KERNEL_URL
+ def ref_tree = params.REF_KERNEL_TREE
+ def ref_branch = params.REF_KERNEL_BRANCH
+
+ if (!(ref_url && ref_tree && ref_branch)) {
+ dir(kci_core) {
+ ref_config = sh(script: """\
+ ./kci_build get_reference --tree-name ${params.KERNEL_TREE} \
+ --branch ${params.KERNEL_BRANCH}""", returnStdout: true).trim().tokenize("\n")
+ if (ref_config.size() > 0) {
+ ref_url = ref_config[0]
+ ref_tree = ref_config[1]
+ ref_branch = ref_config[2]
+ }
+ }
+ }
+ def ref = "${ref_tree}/${ref_branch}"
print("Good commit not in current branch, finding base in ${ref}")
print("""\
Reference:
- Tree: ${params.REF_KERNEL_TREE}
- URL: ${params.REF_KERNEL_URL}
- Branch: ${params.REF_KERNEL_BRANCH}""")
+ Tree: ${ref_tree}
+ URL: ${ref_url}
+ Branch: ${ref_branch}""")
- setRemote(kdir, params.REF_KERNEL_TREE, params.REF_KERNEL_URL)
+ setRemote(kdir, ref_tree, ref_url)
base = sh(script: "git merge-base ${bad} ${ref}",
returnStdout: true).trim()
print("Merge base: ${base}")
@@ -451,7 +492,9 @@ def bisectNext(kdir, status) {
*/
def pushResults(kci_core, kdir, checks, params_summary) {
- def subject = "${params.KERNEL_TREE}/${params.KERNEL_BRANCH} ${params.PLAN} bisection: ${params.KERNEL_NAME} on ${params.TARGET}"
+ def subject = "\
+${params.KERNEL_TREE}/${params.KERNEL_BRANCH} bisection: \
+${params.TEST_PLAN} on ${params.TARGET}"
dir(kci_core) {
withCredentials([string(credentialsId: params.KCI_TOKEN_ID,
@@ -536,10 +579,11 @@ def bisection(kci_core, kdir, checks) {
kci_core: { cloneKciCore(kci_core) },
kdir: { cloneLinux(kdir) },
)
+ fetchLabInfo(kci_core)
}
bad = params.BAD_COMMIT
- good = findMergeBase(kdir, params.GOOD_COMMIT, bad)
+ good = findMergeBase(kdir, kci_core, params.GOOD_COMMIT, bad)
}
stage("Check pass") {
@@ -631,7 +675,9 @@ def bisection(kci_core, kdir, checks) {
node("docker && bisection") {
/* Global pipeline constants */
- env._BUILD_JSON = "build-data.json"
+ env._BMETA_JSON = "bmeta.json"
+ env._DTBS_JSON = "dtbs.json"
+ env._LAB_JSON = "lab-info.json"
def j = new Job()
def kci_core = "${env.WORKSPACE}/kernelci-core"
@@ -648,14 +694,15 @@ node("docker && bisection") {
Lab: ${params.LAB}
Defconfig: ${params.DEFCONFIG}
Compiler: ${params.BUILD_ENVIRONMENT}
- Plan: ${params.PLAN}"""
+ Plan: ${params.TEST_PLAN}
+ Variant: ${params.TEST_PLAN_VARIANT}"""
print("""\
Good: ${params.GOOD_COMMIT}
Bad: ${params.BAD_COMMIT}
${params_summary}""")
- if ((params.PLAN != 'boot') && (params.PLAN != 'simple')) {
- echo "Only doing boot and simple plans for now, aborting."
+ if (params.TEST_PLAN != 'boot') {
+ echo "Only doing boot bisections for now, aborting."
currentBuild.result = 'ABORTED'
return
}
diff --git a/jenkins/build-trigger.jpl b/jenkins/build-trigger.jpl
index 9e23b6f..20e159d 100644
--- a/jenkins/build-trigger.jpl
+++ b/jenkins/build-trigger.jpl
@@ -28,6 +28,8 @@ PUBLISH (boolean)
Publish build results via the KernelCI backend API
EMAIL (boolean)
Send build results via email
+LABS_WHITELIST
+ List of labs to include in the tests, all labs will be tested by default.
KCI_API_URL (https://api.kernelci.org)
URL of the KernelCI backend API
KCI_TOKEN_ID
@@ -45,7 +47,6 @@ ALLOW_REBUILD (false)
*/
@Library('kernelci') _
-import org.kernelci.build.Kernel
import org.kernelci.util.Job
def configAlreadyBuilt(config, kci_core) {
@@ -53,7 +54,7 @@ def configAlreadyBuilt(config, kci_core) {
dir(kci_core) {
new_commit = sh(
- script: """
+ script: """\
./kci_build \
check_new_commit \
--config=${config} \
@@ -73,13 +74,23 @@ update_mirror \
--mirror=${mirror} \
""")
- sh(script: """\
+ while (true) {
+ try {
+ sh(script: """\
./kci_build \
update_repo \
--config=${config} \
--kdir=${kdir} \
--mirror=${mirror} \
""")
+ break
+ } catch (error) {
+ print("Failed to update repo: ${error}")
+ print("Removing clone and retrying")
+ sh(script: "rm -rf ${kdir}")
+ sleep 1
+ }
+ }
def describe_raw = sh(script: """\
./kci_build \
@@ -143,21 +154,10 @@ list_kernel_configs \
}
}
-def addBuildOpts(config, kci_core, opts) {
- dir(kci_core) {
- opts['config'] = config
-
- def opts_raw = sh(
- script: """\
-./kci_build \
-tree_branch \
---config=${config} \
-""", returnStdout: true).trim()
- def opt_list = opts_raw.tokenize('\n')
- opts['tree'] = opt_list[0]
- opts['git_url'] = opt_list[1]
- opts['branch'] = opt_list[2]
+def listArchitectures(kci_core, config) {
+ def arch_list = []
+ dir(kci_core) {
def raw_variants = sh(
script: """\
./kci_build \
@@ -166,7 +166,6 @@ list_variants \
""", returnStdout: true).trim()
def variants = raw_variants.tokenize('\n')
- def arch_list = []
for (String variant: variants) {
def raw_variant_arch_list = sh(
script: """\
@@ -181,11 +180,61 @@ arch_list \
if (!arch_list.contains(arch))
arch_list.add(arch)
}
- opts['arch_list'] = arch_list
}
+
+ return arch_list
}
-def buildKernelStep(job, arch, defconfig, build_env, opts) {
+def addBuildOpts(config, kci_core, opts) {
+ dir(kci_core) {
+ opts['config'] = config
+
+ def opts_raw = sh(
+ script: """\
+./kci_build \
+tree_branch \
+--config=${config} \
+""", returnStdout: true).trim()
+ def opt_list = opts_raw.tokenize('\n')
+ opts['tree'] = opt_list[0]
+ opts['git_url'] = opt_list[1]
+ opts['branch'] = opt_list[2]
+ }
+}
+
+def scheduleTests(build_job_name, build_job_number, labs, kci_core) {
+ dir(kci_core) {
+ def labs_str = ""
+ for (lab in labs)
+ labs_str += "${lab} "
+
+ def str_params = [
+ 'LABS': labs_str.trim(),
+ 'TRIGGER_JOB_NAME': env.JOB_NAME,
+ 'TRIGGER_JOB_NUMBER': env.BUILD_NUMBER,
+ 'BUILD_JOB_NAME': build_job_name,
+ 'BUILD_JOB_NUMBER': "${build_job_number}",
+ ]
+ def params = []
+
+ def j = new Job()
+ j.addStrParams(params, str_params)
+ build(job: 'test-runner', parameters: params, propagate: false)
+ }
+}
+
+def buildKernelStep(job, arch, defconfig, build_env, opts, labs, kci_core) {
+ def node_label = "builder"
+ def parallel_builds = "4"
+
+ if (defconfig.matches(".*allmodconfig.*")) {
+ node_label = "big-config-builder"
+ parallel_builds = ""
+ } else if (defconfig.matches("^defconfig.*") && arch == "arm64") {
+ node_label = "medium-config-builder"
+ parallel_builds = ""
+ }
+
def str_params = [
'ARCH': arch,
'DEFCONFIG': defconfig,
@@ -195,13 +244,20 @@ def buildKernelStep(job, arch, defconfig, build_env, opts) {
'SRC_TARBALL': opts['tarball_url'],
'BUILD_CONFIG': opts['config'],
'BUILD_ENVIRONMENT': build_env,
+ 'NODE_LABEL': node_label,
+ 'PARALLEL_BUILDS': parallel_builds,
]
def job_params = []
def j = new Job()
j.addStrParams(job_params, str_params)
- return { build(job: job, parameters: job_params, propagate: false) }
+ return {
+ def res = build(job: job, parameters: job_params, propagate: false)
+ print("${res.number}: ${arch} ${defconfig} ${build_env} ${res.result}")
+ if (res.result == "SUCCESS")
+ scheduleTests(job, res.number, labs, kci_core)
+ }
}
def buildsComplete(job, opts, arch) {
@@ -225,10 +281,10 @@ def buildsComplete(job, opts, arch) {
node("docker && build-trigger") {
def j = new Job()
- def k = new Kernel()
def kci_core = "${env.WORKSPACE}/kernelci-core"
def kdir = "${env.WORKSPACE}/configs/${params.BUILD_CONFIG}"
def mirror = "${env.WORKSPACE}/linux.git"
+ def labs_info = "${env.WORKSPACE}/labs"
def docker_image = "${params.DOCKER_BASE}base"
def opts = [:]
def configs = []
@@ -238,11 +294,57 @@ node("docker && build-trigger") {
Container: ${docker_image}""")
j.dockerPullWithRetry(docker_image).inside() {
+ def labs = []
+
stage("Init") {
timeout(time: 15, unit: 'MINUTES') {
j.cloneKciCore(
kci_core, params.KCI_CORE_URL, params.KCI_CORE_BRANCH)
}
+
+ sh(script: "rm -rf ${labs_info}; mkdir -p ${labs_info}")
+
+ dir(kci_core) {
+ def raw_lab_names = sh(
+ script: "./kci_test list_labs", returnStdout: true).trim()
+ def all_lab_names = raw_lab_names.tokenize('\n')
+ def labs_list = []
+
+ if (params.LABS_WHITELIST) {
+ def whitelist = params.LABS_WHITELIST.tokenize(' ')
+
+ for (lab in all_lab_names)
+ if (whitelist.contains(lab))
+ labs_list.add(lab)
+ } else {
+ labs_list = all_lab_names
+ }
+
+ for (lab in labs_list) {
+ def lab_json = "${labs_info}/${lab}.json"
+ def token = "${lab}-lava-api"
+ try {
+ withCredentials([string(credentialsId: token,
+ variable: 'SECRET')]) {
+ sh(script: """\
+./kci_test \
+get_lab_info \
+--lab=${lab} \
+--lab-json=${lab_json} \
+--user=kernel-ci \
+--token=${SECRET} \
+""")
+ }
+ labs.add(lab)
+ } catch (error) {
+ print("Error with ${lab}: ${error}")
+ }
+ }
+ }
+
+ dir(labs_info) {
+ archiveArtifacts("*.json")
+ }
}
if (params.ALLOW_REBUILD != true) {
@@ -276,7 +378,8 @@ node("docker && build-trigger") {
print(step_name)
builds[step_name] = buildKernelStep(
- "kernel-build", arch, defconfig, build_env, opts)
+ "kernel-build", arch, defconfig, build_env, opts, labs,
+ kci_core)
i += 1
}
@@ -286,7 +389,8 @@ node("docker && build-trigger") {
stage("Complete") {
/* ToDo: convert kernel-arch-complete as a stage in this job */
- for (String arch: opts['arch_list']) {
+ def arch_list = listArchitectures(kci_core, params.BUILD_CONFIG)
+ for (String arch: arch_list) {
buildsComplete("kernel-arch-complete", opts, arch)
}
}
diff --git a/jenkins/build.jpl b/jenkins/build.jpl
index ed1b106..05bdeeb 100644
--- a/jenkins/build.jpl
+++ b/jenkins/build.jpl
@@ -38,6 +38,8 @@ COMMIT_ID
Git commit SHA1 at the revision of the snapshot
BUILD_ENVIRONMENT
Name of the build environment
+NODE_LABEL
+ Label to use to choose a node on which to run this job
PUBLISH (boolean)
Publish build results via the KernelCI backend API
EMAIL (boolean)
@@ -59,10 +61,11 @@ PARALLEL_BUILDS
@Library('kernelci') _
-import org.kernelci.build.Kernel
import org.kernelci.util.Job
def buildConfig(kdir, kci_core) {
+ def jopt = ""
+
if (params.PARALLEL_BUILDS)
jopt = "-j${params.PARALLEL_BUILDS}"
@@ -108,11 +111,14 @@ publish_kernel \
""")
}
}
+
+ dir("linux/_install_") {
+ archiveArtifacts("*.json")
+ }
}
-node("docker && builder") {
+node("docker" && params.NODE_LABEL) {
def j = new Job()
- def k = new Kernel()
def kci_core = "${env.WORKSPACE}/kernelci-core"
def kdir = "${env.WORKSPACE}/linux"
def docker_image = null
@@ -135,7 +141,13 @@ node("docker && builder") {
j.dockerPullWithRetry(docker_image).inside() {
stage("Init") {
timeout(time: 30, unit: 'MINUTES') {
- k.downloadTarball(kdir, params.SRC_TARBALL)
+ dir(kci_core) {
+ sh(script: """./kci_build pull_tarball \
+ --kdir ${kdir} \
+ --url ${params.SRC_TARBALL} \
+ --retries=12 \
+ """)
+ }
}
}
diff --git a/jenkins/stretch-v4l2.jpl b/jenkins/buster-v4l2.jpl
index 9ef7b48..c88163b 100644
--- a/jenkins/stretch-v4l2.jpl
+++ b/jenkins/buster-v4l2.jpl
@@ -11,12 +11,12 @@ DOCKER_BASE
def r = new RootFS()
-def config = ['name':"stretch-v4l2",
+def config = ['name':"buster-v4l2",
'arch_list':["armhf", "arm64", "amd64"],
- 'debian_release':"stretch",
+ 'debian_release':"buster",
'extra_packages':"",
'extra_packages_remove':"bash e2fsprogs e2fslibs",
- 'script':"scripts/stretch-v4l2.sh",
+ 'script':"scripts/buster-v4l2.sh",
'test_overlay': "overlays/v4l2",
'docker_image': "${params.DOCKER_BASE}debos",
]
diff --git a/jenkins/debian/debos/scripts/stretch-v4l2.sh b/jenkins/debian/debos/scripts/buster-v4l2.sh
index 81015d4..b971274 100755
--- a/jenkins/debian/debos/scripts/stretch-v4l2.sh
+++ b/jenkins/debian/debos/scripts/buster-v4l2.sh
@@ -66,7 +66,7 @@ cd /tmp
rm -rf /tmp/tests
apt-get remove --purge -y ${BUILD_DEPS}
-apt-get remove --purge -y perl-modules-5.24
+apt-get remove --purge -y perl-modules-5.28
apt-get autoremove --purge -y
apt-get clean
diff --git a/jenkins/dockerfiles/debos/Dockerfile b/jenkins/dockerfiles/debos/Dockerfile
index 69f7010..492ffde 100644
--- a/jenkins/dockerfiles/debos/Dockerfile
+++ b/jenkins/dockerfiles/debos/Dockerfile
@@ -1,4 +1,4 @@
-FROM debian:stretch-slim
+FROM debian:buster-slim
ARG DEBIAN_FRONTEND=noninteractive
diff --git a/jenkins/kernel-arch-complete.sh b/jenkins/kernel-arch-complete.sh
index bb0b40b..cdad9ff 100755
--- a/jenkins/kernel-arch-complete.sh
+++ b/jenkins/kernel-arch-complete.sh
@@ -121,8 +121,8 @@ if [[ BUILDS_FINISHED -eq 1 ]]; then
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "send_to": ["krzk@kernel.org", "kgene.kim@samsung.com", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 12600}' ${API}/send
elif [ "$TREE_NAME" == "agross" ]; then
echo "Sending results to Andy Gross"
- curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "send_to": ["agross@codeaurora.org", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 10}' ${API}/send
- curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "send_to": ["agross@codeaurora.org", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 12600}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "send_to": ["agross@kernel.org", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 10}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "send_to": ["agross@kernel.org", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 12600}' ${API}/send
elif [ "$TREE_NAME" == "broonie-regmap" ]; then
echo "Sending results to Mark Brown"
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "send_to": ["broonie@kernel.org", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 10}' ${API}/send
@@ -151,6 +151,7 @@ if [[ BUILDS_FINISHED -eq 1 ]]; then
echo "Sending results to Ard Biesheuvel"
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "send_to": ["ard.biesheuvel@linaro.org", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 10}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "send_to": ["ard.biesheuvel@linaro.org", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 12600}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan: "baseline-uefi", "send_to": ["ard.biesheuvel@linaro.org", "anders.roxell@linaro.org", "fellows@kernelci.org"], "format": ["txt""], "delay": 10}' ${API}/send
elif [ "$TREE_NAME" == "evalenti" ]; then
echo "Sending results to Eduardo Valentin"
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "send_to": ["edubezval@gmail.com", "fellows@kernelci.org"], "format": ["txt", "html"], "delay": 10}' ${API}/send
@@ -179,6 +180,9 @@ if [[ BUILDS_FINISHED -eq 1 ]]; then
curl -XPOST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "format": ["txt"], "send_to": ["kernel-team+kernelci@android.com", "gregkh@google.com", "fellows@kernelci.org"], "delay": 12600}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "send_to": ["tom.gall@linaro.org", "sumit.semwal@linaro.org", "amit.pundir@linaro.org", "arnd.bergmann@linaro.org", "anmar.oueja@linaro.org"], "format": ["txt"], "delay": 10}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "send_to": ["tom.gall@linaro.org", "sumit.semwal@linaro.org", "amit.pundir@linaro.org", "arnd.bergmann@linaro.org", "anmar.oueja@linaro.org"], "format": ["txt"], "delay": 12600}' ${API}/send
+ if [ "$BRANCH" == "android-3.18" ]; then
+ curl -XPOST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["lee.jones@linaro.org"], "delay": 60}' ${API}/send
+ fi
elif [ "$TREE_NAME" == "mattface" ]; then
echo "Sending results to Matt"
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["matt@mattface.org"], "delay": 60}' ${API}/send
@@ -190,7 +194,7 @@ if [[ BUILDS_FINISHED -eq 1 ]]; then
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline", "send_to": ["guillaume.tucker@collabora.com"], "format": ["txt"], "delay": 1800}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "v4l2-compliance-vivid", "send_to": ["guillaume.tucker@collabora.com"], "format": ["txt"], "delay": 2700}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "v4l2-compliance-uvc", "send_to": ["guillaume.tucker@collabora.com"], "format": ["txt"], "delay": 3600}' ${API}/send
- curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "igt_drm_kms", "send_to": ["guillaume.tucker@collabora.com"], "format": ["txt"], "delay": 3600}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "igt-drm-kms", "send_to": ["guillaume.tucker@collabora.com"], "format": ["txt"], "delay": 3600}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "cros-ec", "send_to": ["guillaume.tucker@collabora.com"], "format": ["txt"], "delay": 3600}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "sleep", "send_to": ["guillaume.tucker@collabora.com"], "format": ["txt"], "delay": 3600}' ${API}/send
elif [ "$TREE_NAME" == "tomeu" ]; then
@@ -218,14 +222,36 @@ if [[ BUILDS_FINISHED -eq 1 ]]; then
echo "Sending results for vireshk's tree"
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["vireshk@kernel.org"], "delay": 60}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "format": ["txt"], "send_to": ["vireshk@kernel.org"], "delay": 2700}' ${API}/send
+ elif [ "$TREE_NAME" == "sashal" ]; then
+ echo "Sending results for sashal's tree"
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["sashal@kernel.org", "kernel-build-reports@lists.linaro.org"], "delay": 60}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "format": ["txt"], "send_to": ["sashal@kernel.org", "kernel-build-reports@lists.linaro.org"], "delay": 2700}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline", "send_to": ["sashal@kernel.org", "kernel-build-reports@lists.linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
+ elif [ "$TREE_NAME" == "thermal" ]; then
+ echo "Sending results for the thermal tree"
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["daniel.lezcano@linaro.org", "kernel-build-reports@lists.linaro.org"], "delay": 60}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "format": ["txt"], "send_to": ["daniel.lezcano@linaro.org", "kernel-build-reports@lists.linaro.org"], "delay": 2700}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline", "send_to": ["daniel.lezcano@linaro.org", "kernel-build-reports@lists.linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
+ elif [ "$TREE_NAME" == "arm64" ]; then
+ echo "Sending results for the arm64 tree"
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["will@kernel.org", "catalin.marinas@arm.com", "linux-arm-kernel@lists.infradead.org", "kernel-build-reports@lists.linaro.org"], "delay": 60}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "format": ["txt"], "send_to": ["will@kernel.org", "catalin.marinas@arm.com", "linux-arm-kernel@lists.infradead.org", "kernel-build-reports@lists.linaro.org"], "delay": 2700}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline", "send_to": ["will@kernel.org", "catalin.marinas@arm.com", "linux-arm-kernel@lists.infradead.org", "kernel-build-reports@lists.linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
+ elif [ "$TREE_NAME" == "lee" ]; then
+ echo "Sending results for lee's tree"
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["lee.jones@linaro org", "kernel-build-reports@lists.linaro.org"], "delay": 60}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "format": ["txt"], "send_to": ["lee.jones@linaro org", "kernel-build-reports@lists.linaro.org"], "delay": 2700}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline", "send_to": ["lee.jones@linaro org", "kernel-build-reports@lists.linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
elif [ "$TREE_NAME" == "kernelci" ]; then
echo "Sending results to kernelci folks"
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "build_report": 1, "format": ["txt"], "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "delay": 0}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "boot_report": 1, "format": ["txt"], "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "delay": 1800}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 1800}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline-uefi", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 1800}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "baseline-fastboot", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 1800}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "v4l2-compliance-vivid", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "v4l2-compliance-uvc", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
- curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "igt_drm_kms", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
+ curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "igt-drm-kms", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "cros-ec", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
curl -X POST -H "Authorization: $EMAIL_AUTH_TOKEN" -H "Content-Type: application/json" -d '{"job": "'$TREE_NAME'", "kernel": "'$GIT_DESCRIBE'", "git_branch": "'$BRANCH'", "report_type": "test", "plan": "sleep", "send_to": ["gtucker@collabora.com", "mgalka@collabora.com", "alexandra.pereira@collabora.com", "dan.rue@linaro.org", "matthew.hart@linaro.org", "broonie@kernel.org", "kernelci@baylibre.com", "anders.roxell@linaro.org"], "format": ["txt"], "delay": 2700}' ${API}/send
else
diff --git a/jenkins/lava-boot-v2.sh b/jenkins/lava-boot-v2.sh
index f8ab5be..7434d07 100755
--- a/jenkins/lava-boot-v2.sh
+++ b/jenkins/lava-boot-v2.sh
@@ -18,22 +18,22 @@ if [ ${LAB} = "lab-tbaker" ] || [ ${LAB} = "lab-tbaker-dev" ]; then
python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp kselftest --token ${API_TOKEN}
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_TBAKER_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-mhart" ] || [ ${LAB} = "lab-mhart-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp simple --token ${API_TOKEN} --priority medium
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp simple --token ${API_TOKEN} --priority medium
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_MHART_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-collabora" ] || [ ${LAB} = "lab-collabora-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp cros-ec igt_drm_kms kselftest simple sleep usb v4l2-compliance-vivid v4l2-compliance-uvc --token ${API_TOKEN} --priority medium
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp cros-ec igt-drm-kms kselftest simple sleep usb v4l2-compliance-vivid v4l2-compliance-uvc --token ${API_TOKEN} --priority medium
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_COLLABORA_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-baylibre" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi kselftest --token ${API_TOKEN} --priority medium
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline baseline-fastboot boot boot-kvm boot-kvm-uefi kselftest --token ${API_TOKEN} --priority medium
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_BAYLIBRE_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-baylibre-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi kselftest --token ${API_TOKEN} --priority medium
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline baseline-fastboot boot boot-kvm boot-kvm-uefi kselftest --token ${API_TOKEN} --priority medium
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_BAYLIBRE_TOKEN} --lab ${LAB}
# for dev lab, also send results to BayLibre kernelCI development backend
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback kernelci-dev-baylibre-callback --callback-url http://kernelci.dev.baylibre.com:8081 --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans simple usb --token ${API_TOKEN} --priority low
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback kernelci-dev-baylibre-callback --callback-url http://kernelci.dev.baylibre.com:8081 --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline simple usb --token ${API_TOKEN} --priority low
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_BAYLIBRE_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-free-electrons" ] || [ ${LAB} = "lab-free-electrons-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp --token ${API_TOKEN} --priority medium
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp --token ${API_TOKEN} --priority medium
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_FREE_ELECTRONS_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-broonie" ]; then
python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp --token ${API_TOKEN}
@@ -42,18 +42,18 @@ elif [ ${LAB} = "lab-embeddedbits" ]; then
python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp --token ${API_TOKEN}
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_EMBEDDEDBITS_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-pengutronix" ] || [ ${LAB} = "lab-pengutronix-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi --token ${API_TOKEN}
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot boot-kvm boot-kvm-uefi --token ${API_TOKEN}
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_PENGUTRONIX_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-linaro-lkft" ] || [ ${LAB} = "lab-linaro-lkft-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot uefi_arm uefi_arm64 uefi_i386 uefi_x86_64 uefi_x86-mixed --token ${API_TOKEN} --priority low
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline baseline-uefi boot --token ${API_TOKEN} --priority low
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_LINARO_LKFT_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-theobroma-systems" ] || [ ${LAB} = "lab-theobroma-systems-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot kselftest --token ${API_TOKEN}
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot kselftest --token ${API_TOKEN}
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_THEOBROMA_SYSTEMS_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-drue" ] || [ ${LAB} = "lab-drue-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp simple sleep --token ${API_TOKEN} --priority medium
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp simple sleep --token ${API_TOKEN} --priority medium
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_DRUE_TOKEN} --lab ${LAB}
elif [ ${LAB} = "lab-clabbe" ] || [ ${LAB} = "lab-clabbe-dev" ]; then
- python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp simple sleep --token ${API_TOKEN} --priority medium
+ python lava-v2-jobs-from-api.py --defconfigs ${DEFCONFIG_COUNT} --callback ${CALLBACK} --api ${API} --storage ${STORAGE} --lab ${LAB} --describe ${GIT_DESCRIBE} --tree ${TREE} --branch ${BRANCH} --arch ${ARCH} --plans baseline boot boot-kvm boot-kvm-uefi boot-nfs boot-nfs-mp simple sleep --token ${API_TOKEN} --priority medium
python lava-v2-submit-jobs.py --username kernel-ci --jobs ${LAB} --token ${LAVA_CLABBE_TOKEN} --lab ${LAB}
fi
diff --git a/jenkins/monitor.jpl b/jenkins/monitor.jpl
index f82a199..953420e 100644
--- a/jenkins/monitor.jpl
+++ b/jenkins/monitor.jpl
@@ -49,7 +49,7 @@ def checkConfig(config, kci_core, trees_dir) {
def commit = sh(
script: """
${kci_core}/kci_build \
---build-configs=${kci_core}/build-configs.yaml \
+--yaml-configs=${kci_core}/build-configs.yaml \
check_new_commit \
--config=${config} \
--storage=${params.KCI_STORAGE_URL} \
diff --git a/jenkins/test-runner.jpl b/jenkins/test-runner.jpl
new file mode 100644
index 0000000..19daff2
--- /dev/null
+++ b/jenkins/test-runner.jpl
@@ -0,0 +1,178 @@
+#!/usr/bin/env groovy
+
+/*
+ Copyright (C) 2019 Collabora Limited
+ Author: Guillaume Tucker <guillaume.tucker@collabora.com>
+
+ This module is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 2.1 of the License, or (at your option)
+ any later version.
+
+ This library 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 Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+/* ----------------------------------------------------------------------------
+ * Jenkins parameters
+
+LABS
+ Name of the labs where to submit tests
+TRIGGER_JOB_NAME
+ Name of the parent trigger job
+TRIGGER_JOB_NUMBER
+ Number of the parent trigger job
+BUILD_JOB_NAME
+ Name of the job that built the kernel
+BUILD_JOB_NUMBER
+ Number of the job that built the kernel
+KCI_CORE_URL (https://github.com/kernelci/kernelci-core.git)
+ URL of the kernelci-core repository
+KCI_CORE_BRANCH (master)
+ Name of the branch to use in the kernelci-core repository
+KCI_STORAGE_URL (https://storage.kernelci.org/)
+ URL of the KernelCI storage server
+DOCKER_BASE (kernelci/build-)
+ Dockerhub base address used for the build images
+CALLBACK_ID (kernel-ci-callback)
+ Identifier of the callback to look up an authentication token
+CALLBACK_URL (https://api.kernelci.org)
+ Base URL where to send the callbacks
+*/
+
+@Library('kernelci') _
+import org.kernelci.util.Job
+
+def getArtifacts(artifacts)
+{
+ dir(artifacts) {
+ copyArtifacts(
+ projectName: params.BUILD_JOB_NAME,
+ selector: specific("${params.BUILD_JOB_NUMBER}")
+ )
+
+ if (params.TRIGGER_JOB_NAME) {
+ copyArtifacts(
+ projectName: params.TRIGGER_JOB_NAME,
+ selector: specific("${params.TRIGGER_JOB_NUMBER}")
+ )
+ }
+ }
+}
+
+def generateJobs(kci_core, lab, artifacts, jobs_dir)
+{
+ def token = "${lab}-lava-api"
+
+ dir(kci_core) {
+ withCredentials([string(credentialsId: token, variable: 'SECRET')]) {
+ sh(script: """\
+./kci_test \
+generate \
+--bmeta-json=${artifacts}/bmeta.json \
+--dtbs-json=${artifacts}/dtbs.json \
+--lab-json=${artifacts}/${lab}.json \
+--storage=${params.KCI_STORAGE_URL} \
+--lab=${lab} \
+--user=kernel-ci \
+--token=${SECRET} \
+--output=${jobs_dir} \
+--callback-id=${params.CALLBACK_ID} \
+--callback-url=${params.CALLBACK_URL} \
+""")
+ }
+ }
+}
+
+def submitJobs(kci_core, lab, jobs_dir)
+{
+ def token = "${lab}-lava-api"
+
+ dir(kci_core) {
+ withCredentials([string(credentialsId: token, variable: 'SECRET')]) {
+ sh(script: """\
+./kci_test \
+submit \
+--lab=${lab} \
+--user=kernel-ci \
+--token=${SECRET} \
+--jobs=${jobs_dir}/* \
+""")
+ }
+ }
+}
+
+node("docker && test-runner") {
+ def j = new Job()
+ def kci_core = "${env.WORKSPACE}/kernelci-core"
+ def jobs_dir = "${env.WORKSPACE}/jobs"
+ def artifacts = "${env.WORKSPACE}/artifacts"
+ def docker_image = "${params.DOCKER_BASE}base"
+ def labs = params.LABS.tokenize(' ')
+ def labs_submit = []
+
+ print("""\
+ Labs: ${params.LABS}
+ Container: ${docker_image}""")
+
+ j.dockerPullWithRetry(docker_image).inside() {
+ stage("Init") {
+ sh(script: "rm -rf ${artifacts}")
+ sh(script: "rm -rf ${jobs_dir}")
+
+ timeout(time: 15, unit: 'MINUTES') {
+ parallel(
+ kci_core: {
+ j.cloneKciCore(
+ kci_core,
+ params.KCI_CORE_URL, params.KCI_CORE_BRANCH)
+ },
+ artifacts: {
+ getArtifacts(artifacts)
+ },
+ )
+ }
+
+ print("Artifacts:")
+ sh(script: "ls -l ${artifacts}")
+
+ print("Build meta-data:")
+ sh(script: "cat ${artifacts}/bmeta.json")
+ }
+
+ stage("Generate") {
+ for (lab in labs) {
+ def lab_dir = "${jobs_dir}/${lab}"
+ generateJobs(kci_core, lab, artifacts, lab_dir)
+ labs_submit.add(lab)
+ }
+ }
+
+ stage("Submit") {
+ def steps = [:]
+ def i = 0
+
+ for (lab in labs_submit) {
+ def lab_name = "${lab}"
+ def lab_dir = "${jobs_dir}/${lab}"
+ def step_name = "${i} ${lab}"
+
+ print(step_name)
+
+ steps[step_name] = {
+ submitJobs(kci_core, lab_name, lab_dir)
+ }
+
+ i += 1
+ }
+
+ parallel(steps)
+ }
+ }
+}
diff --git a/kci_build b/kci_build
index 0d96fb0..d483ebe 100755
--- a/kci_build
+++ b/kci_build
@@ -17,159 +17,13 @@
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-import argparse
-import os
-import subprocess
import sys
-import time
+from kernelci.cli import Args, Command, parse_args
import kernelci.build
import kernelci.config.build
-# -----------------------------------------------------------------------------
-# Standard arguments that can be used in sub-commands
-#
-
-class Args(object):
- config= {
- 'name': '--config',
- 'help': "Build config name",
- }
-
- variant = {
- 'name': '--variant',
- 'help': "Build config variant name",
- }
-
- build_env = {
- 'name': '--build-env',
- 'help': "Build environment name",
- }
-
- storage = {
- 'name': '--storage',
- 'help': "Storage URL",
- 'default': "https://storage.kernelci.org",
- 'required': False,
- }
-
- api = {
- 'name': '--api',
- 'help': "Backend API URL",
- 'default': "https://api.kernelci.org",
- 'required': False,
- }
-
- token = {
- 'name': '--token',
- 'help': "Backend API token",
- }
-
- commit = {
- 'name': '--commit',
- 'help': "Git commit checksum",
- }
-
- describe = {
- 'name': '--describe',
- 'help': "Git describe",
- }
-
- describe_verbose = {
- 'name': '--describe-verbose',
- 'help': "Verbose version of git describe",
- }
-
- tree_name = {
- 'name': '--tree-name',
- 'help': "Name of a kernel tree",
- }
-
- tree_url = {
- 'name': '--tree-url',
- 'help': "URL of a kernel tree",
- }
-
- branch = {
- 'name': '--branch',
- 'help': "Name of a kernel branch in a tree",
- }
-
- mirror = {
- 'name': '--mirror',
- 'help': "Path to the local kernel git mirror",
- }
-
- kdir = {
- 'name': '--kdir',
- 'help': "Path to the kernel checkout directory",
- }
-
- arch = {
- 'name': '--arch',
- 'help': "CPU architecture name",
- }
-
- defconfig = {
- 'name': '--defconfig',
- 'help': "Kernel defconfig name",
- }
-
- j = {
- 'name': '-j',
- 'help': "Number of parallel build processes",
- }
-
- verbose = {
- 'name': '--verbose',
- 'help': "Verbose output",
- 'action': 'store_true',
- }
-
- output = {
- 'name': '--output',
- 'help': "Path the output directory",
- }
-
- json_path = {
- 'name': '--json-path',
- 'help': "Path to the JSON file",
- }
-
-
-# -----------------------------------------------------------------------------
-# Commands
-#
-
-class Command(object):
- help = None
- args = None
- opt_args = None
-
- def __init__(self, sub_parser, name):
- if not self.help:
- raise AttributeError("Missing help message for {}".format(name))
- self._parser = sub_parser.add_parser(name, help=self.help)
- if self.args:
- for arg in self.args:
- self._add_arg(arg, True)
- if self.opt_args:
- for arg in self.opt_args:
- self._add_arg(arg, False)
- self._parser.set_defaults(func=self)
-
- def __call__(self, *args, **kw):
- raise NotImplementedError("Command not implemented")
-
- def _add_arg(self, arg, required=True):
- kw = dict(arg)
- arg_name = kw.pop('name')
- if required:
- kw.setdefault('required', True)
- self._parser.add_argument(arg_name, **kw)
-
-
class cmd_list_configs(Command):
help = "List the build configurations"
@@ -235,7 +89,6 @@ class cmd_update_repo(Command):
return True
-
class cmd_describe(Command):
help = "Print the git commit, describe and verbose describe from kdir"
args = [Args.config, Args.kdir]
@@ -357,6 +210,21 @@ class cmd_get_build_env(Command):
return True
+class cmd_get_reference(Command):
+ help = "Print reference tree and branch for bisections"
+ args = [Args.tree_name, Args.branch]
+
+ def __call__(self, configs, args):
+ for conf in configs['build_configs'].itervalues():
+ if conf.tree.name == args.tree_name and conf.branch == args.branch:
+ if conf.reference:
+ print(conf.reference.tree.url)
+ print(conf.reference.tree.name)
+ print(conf.reference.branch)
+ return True
+ return False
+
+
class cmd_show_build_env(Command):
help = "Show parameters of a given build environment"
args = [Args.build_env]
@@ -395,7 +263,7 @@ class cmd_build_kernel(Command):
class cmd_install_kernel(Command):
- help = "Install the kernel binaries and build.json locally"
+ help = "Install the kernel binaries and bmeta.json locally"
args = [Args.kdir]
opt_args = [Args.config, Args.tree_name, Args.tree_url, Args.branch,
Args.commit, Args.describe, Args.describe_verbose,
@@ -449,27 +317,19 @@ Invalid arguments, please provide at least one of these sets of options:
args.kdir, api=args.api, token=args.token,
json_path=args.json_path)
-# -----------------------------------------------------------------------------
-# Main
-#
+
+class cmd_pull_tarball(Command):
+ help = "Downloads and untars kernel sources"
+ args = [Args.kdir, Args.url]
+ opt_args = [Args.filename, Args.retries]
+
+ def __call__(self, configs, args):
+ return kernelci.build.pull_tarball(args.kdir, args.url,
+ args.filename, args.retries)
+
if __name__ == '__main__':
- parser = argparse.ArgumentParser("kci_build")
- parser.add_argument("--build-configs", default="build-configs.yaml",
- help="Path to build configs file")
- sub_parser = parser.add_subparsers(title="Commands",
- help="List of available commands")
-
- commands = dict()
- for k in globals().keys():
- split = k.split('cmd_')
- if len(split) == 2:
- obj = globals().get(k)
- if issubclass(obj, Command):
- cmd_name = split[1]
- commands[cmd_name] = obj(sub_parser, cmd_name)
-
- args = parser.parse_args()
- configs = kernelci.config.build.from_yaml(args.build_configs)
+ args = parse_args("kci_build", "build-configs.yaml", globals())
+ configs = kernelci.config.build.from_yaml(args.yaml_configs)
status = args.func(configs, args)
sys.exit(0 if status is True else 1)
diff --git a/kci_test b/kci_test
new file mode 100755
index 0000000..e10f07c
--- /dev/null
+++ b/kci_test
@@ -0,0 +1,204 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2019 Collabora Limited
+# Author: Guillaume Tucker <guillaume.tucker@collabora.com>
+#
+# This module is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This library 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import argparse
+import glob
+import json
+import os
+import sys
+
+from kernelci.cli import Args, Command, parse_args
+import kernelci.config.lab
+import kernelci.config.test
+import kernelci.build
+import kernelci.lab
+import kernelci.test
+
+
+# -----------------------------------------------------------------------------
+# Commands
+#
+
+class cmd_list_jobs(Command):
+ help = "List all the jobs that need to be run for a given build and lab"
+ args = [Args.bmeta_json, Args.dtbs_json, Args.lab]
+ opt_args = [Args.user, Args.token, Args.lab_json]
+
+ def __call__(self, test_configs, lab_configs, args):
+ bmeta, dtbs = kernelci.build.load_json(args.bmeta_json, args.dtbs_json)
+
+ if bmeta['status'] != "PASS":
+ return True
+
+ lab = lab_configs['labs'][args.lab]
+ api = kernelci.lab.get_api(lab, args.user, args.token, args.lab_json)
+
+ configs = kernelci.test.match_configs(
+ test_configs['test_configs'], bmeta, dtbs, lab)
+ for device_type, plan in configs:
+ if not api.device_type_online(device_type):
+ continue
+ print(' '.join([device_type.name, plan.name]))
+
+ return True
+
+
+class cmd_list_plans(Command):
+ help = "List all the existing test plan names"
+
+ def __call__(self, test_configs, lab_configs, args):
+ plans = set(plan.name for plan in test_configs['test_plans'].values())
+ for plan in sorted(plans):
+ print(plan)
+ return True
+
+
+class cmd_list_labs(Command):
+ help = "List all the existing lab names"
+
+ def __call__(self, test_configs, lab_configs, args):
+ for lab in sorted(lab_configs['labs'].keys()):
+ print(lab)
+ return True
+
+
+class cmd_get_lab_info(Command):
+ help = "Get the information about a lab into a JSON file"
+ args = [Args.lab, Args.lab_json]
+ opt_args = [Args.user, Args.token]
+
+ def __call__(self, test_configs, lab_configs, args):
+ lab = lab_configs['labs'][args.lab]
+ lab_api = kernelci.lab.get_api(lab, args.user, args.token)
+ data = {
+ 'lab': lab.name,
+ 'lab_type': lab.lab_type,
+ 'url': lab.url,
+ 'devices': lab_api.devices,
+ }
+ with open(args.lab_json, 'w') as json_file:
+ json.dump(data, json_file, indent=4, sort_keys=True)
+ return True
+
+
+class cmd_generate(Command):
+ help = "Generate the job definition for a given build"
+ args = [Args.bmeta_json, Args.dtbs_json, Args.storage, Args.lab]
+ opt_args = [Args.plan, Args.target, Args.output,
+ Args.lab_json, Args.user, Args.token,
+ Args.callback_id, Args.callback_dataset,
+ Args.callback_type, Args.callback_url]
+
+ def __call__(self, test_configs, lab_configs, args):
+ if args.callback_id and not args.callback_url:
+ print("--callback-url is required with --callback-id")
+ return False
+
+ bmeta, dtbs = kernelci.build.load_json(args.bmeta_json, args.dtbs_json)
+
+ if bmeta['status'] != "PASS":
+ return True
+
+ lab = lab_configs['labs'][args.lab]
+ api = kernelci.lab.get_api(lab, args.user, args.token, args.lab_json)
+
+ if args.target and args.plan:
+ target = test_configs['device_types'][args.target]
+ plan = test_configs['test_plans'][args.plan]
+ jobs_list = [(target, plan)]
+ else:
+ jobs_list = []
+ configs = kernelci.test.match_configs(
+ test_configs['test_configs'], bmeta, dtbs, lab)
+ for device_type, plan in configs:
+ if not api.device_type_online(device_type):
+ continue
+ if args.target and device_type.name != args.target:
+ continue
+ if args.plan and plan.name != args.plan:
+ continue
+ jobs_list.append((device_type, plan))
+
+ # ToDo: deal with a JSON file containing a list of builds to iterate
+ # over, such as the one produced by "kci_build publish" or saved as a
+ # result of a new command "kci_build get_meta" to download meta-data
+ # from the backend API.
+ callback_opts = {
+ 'id': args.callback_id,
+ 'dataset': args.callback_dataset,
+ 'type': args.callback_type,
+ 'url': args.callback_url,
+ }
+ if args.output and not os.path.exists(args.output):
+ os.makedirs(args.output)
+ for target, plan in jobs_list:
+ params = kernelci.test.get_params(
+ bmeta, target, plan, args.storage)
+ job = api.generate(params, target, plan, callback_opts)
+ if args.output:
+ file_name = api.job_file_name(params)
+ output_file = os.path.join(args.output, file_name)
+ print(output_file)
+ with open(output_file, 'wb') as output:
+ output.write(job)
+ else:
+ print("# Job: {}".format(params['name']))
+ print(job)
+ return True
+
+
+class cmd_submit(Command):
+ help = "Submit job definitions to a lab"
+ args = [Args.lab, Args.user, Args.token, Args.jobs]
+
+ def __call__(self, test_configs, lab_configs, args):
+ lab = lab_configs['labs'][args.lab]
+ lab_api = kernelci.lab.get_api(lab, args.user, args.token)
+ job_paths = glob.glob(args.jobs)
+ res = True
+ for path in job_paths:
+ if not os.path.isfile(path):
+ continue
+ with open(path, 'rb') as job_file:
+ job = job_file.read()
+ try:
+ job_id = lab_api.submit(job)
+ print("{} {}".format(job_id, path))
+ except Exception as e:
+ print("ERROR {}: {}".format(path, e))
+ res = False
+ return res
+
+
+# -----------------------------------------------------------------------------
+# Main
+#
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser("kci_test")
+ parser.add_argument("--yaml-test-configs", default="test-configs.yaml",
+ help="Path to the YAML test configs file")
+ parser.add_argument("--yaml-lab-configs", default="lab-configs.yaml",
+ help="Path to the YAML lab configs file")
+ kernelci.cli.add_subparser(parser, globals())
+ args = parser.parse_args()
+ test_configs = kernelci.config.test.from_yaml(args.yaml_test_configs)
+ lab_configs = kernelci.config.lab.from_yaml(args.yaml_lab_configs)
+ status = args.func(test_configs, lab_configs, args)
+ sys.exit(0 if status is True else 1)
diff --git a/kernelci/build.py b/kernelci/build.py
index 598786f..969b548 100644
--- a/kernelci/build.py
+++ b/kernelci/build.py
@@ -16,13 +16,14 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import fnmatch
+import itertools
import json
import os
import platform
import requests
import shutil
import stat
-import subprocess
+import tarfile
import tempfile
import time
import urlparse
@@ -141,7 +142,8 @@ def check_new_commit(config, storage):
def _update_remote(config, path):
- shell_cmd("""
+ shell_cmd("""
+set -e
cd {path}
if git remote | grep -e '^{remote}$'; then
git remote set-url {remote} {url}
@@ -156,6 +158,7 @@ fi
def _fetch_tags(path, url=TORVALDS_GIT_URL):
shell_cmd("""
+set -e
cd {path}
git fetch --tags {url}
""".format(path=path, url=url))
@@ -169,6 +172,7 @@ def update_mirror(config, path):
"""
if not os.path.exists(path):
shell_cmd("""
+set -e
mkdir -p {path}
cd {path}
git init --bare
@@ -186,19 +190,19 @@ def update_repo(config, path, ref=None):
"""
if not os.path.exists(path):
ref_opt = '--reference={ref}'.format(ref=ref) if ref else ''
- shell_cmd("""
-git clone {ref} -o {remote} {url} {path}
-""".format(ref=ref_opt, remote=config.tree.name,
- url=config.tree.url, path=path))
+ shell_cmd("git clone {ref} -o {remote} {url} {path}".format(
+ ref=ref_opt, remote=config.tree.name,
+ url=config.tree.url, path=path))
_update_remote(config, path)
- _fetch_tags(path)
+ _fetch_tags(path, config.tree.url)
+ _fetch_tags(path, TORVALDS_GIT_URL)
shell_cmd("""
+set -e
cd {path}
git reset --hard
git clean -fd
-git fetch --tags {remote}
git checkout --detach {remote}/{branch}
""".format(path=path, remote=config.tree.name, branch=config.branch))
@@ -211,8 +215,9 @@ def head_commit(path):
The returned value is the git SHA of the current HEAD of the branch checked
out in the local git repository.
"""
- cmd = """\
-cd {path} &&
+ cmd = """
+set -e
+cd {path}
git log --pretty=format:%H -n1
""".format(path=path)
commit = shell_cmd(cmd)
@@ -229,9 +234,10 @@ def git_describe(tree_name, path):
currently checked out in the local git repository.
"""
describe_args = r"--match=v\*" if tree_name == "soc" else ""
- cmd = """\
-cd {path} && \
-git describe {describe_args} \
+ cmd = """
+set -e
+cd {path}
+git describe {describe_args}
""".format(path=path, describe_args=describe_args)
describe = shell_cmd(cmd)
return describe.strip().replace('/', '_')
@@ -246,9 +252,10 @@ def git_describe_verbose(path):
the commit currently checked out in the local git repository. This is
typically based on a mainline kernel version tag.
"""
- cmd = r"""\
-cd {path} &&
-git describe --match=v[1-9]\* \
+ cmd = r"""
+set -e
+cd {path}
+git describe --match=v[1-9]\*
""".format(path=path)
describe = shell_cmd(cmd)
return describe.strip()
@@ -261,7 +268,8 @@ def add_kselftest_fragment(path, frag_path='kernel/configs/kselftest.config'):
*frag_path* is the path where to create the fragment within the repo
"""
shell_cmd(r"""
-cd {path} &&
+set -e
+cd {path}
find \
tools/testing/selftests \
-name config \
@@ -281,9 +289,13 @@ def make_tarball(kdir, tarball_name):
*kdir* is the path to the local kernel source directory
*tarball_name* is the name of the tarball file to create
"""
- cmd = "tar -czf {name} --exclude=.git -C {kdir} .".format(
- kdir=kdir, name=tarball_name)
- subprocess.check_output(cmd, shell=True)
+ cwd = os.getcwd()
+ os.chdir(kdir)
+ _, dirs, files = next(os.walk('.'))
+ with tarfile.open(os.path.join(cwd, tarball_name), "w:gz") as tarball:
+ for item in itertools.chain(dirs, files):
+ tarball.add(item, filter=lambda f: f if f.name != '.git' else None)
+ os.chdir(cwd)
def generate_config_fragment(frag, kdir):
@@ -341,6 +353,33 @@ def push_tarball(config, kdir, storage, api, token):
return tarball_url
+def _download_file(url, dest_filename, chunk_size=1024):
+ resp = requests.get(url, stream=True)
+ if resp.status_code == 200:
+ with open(dest_filename, 'wb') as out_file:
+ for chunk in resp.iter_content(chunk_size):
+ out_file.write(chunk)
+ return True
+ else:
+ return False
+
+
+def pull_tarball(kdir, url, dest_filename, retries):
+ if os.path.exists(kdir):
+ shutil.rmtree(kdir)
+ os.makedirs(kdir)
+ for i in range(1, retries + 1):
+ if _download_file(url, dest_filename):
+ break
+ if i < retries:
+ time.sleep(2 ** i)
+ else:
+ return False
+ with tarfile.open(dest_filename, 'r:*') as tarball:
+ tarball.extractall(kdir)
+ return True
+
+
def _add_frag_configs(kdir, frag_list, frag_paths, frag_configs):
for frag in frag_list:
if os.path.exists(os.path.join(kdir, frag.path)):
@@ -450,44 +489,58 @@ def _run_make(kdir, arch, target=None, jopt=None, silent=True, cc='gcc',
return shell_cmd(cmd, True)
-def _make_defconfig(defconfig, kwargs, fragments, verbose, log_file):
+def _make_defconfig(defconfig, kwargs, extras, verbose, log_file):
kdir, output_path = (kwargs.get(k) for k in ('kdir', 'output'))
result = True
+ defconfig_kwargs = dict(kwargs)
+ defconfig_opts = dict(defconfig_kwargs['opts'])
+ defconfig_kwargs['opts'] = defconfig_opts
tmpfile_fd, tmpfile_path = tempfile.mkstemp(prefix='kconfig-')
tmpfile = os.fdopen(tmpfile_fd, 'w')
+ tmpfile_used = False
defs = defconfig.split('+')
target = defs.pop(0)
for d in defs:
- if d.startswith('CONFIG_'):
+ if d.startswith('KCONFIG_'):
+ config, value = d.split('=')
+ defconfig_opts[config] = value
+ extras.append(d)
+ elif d.startswith('CONFIG_'):
tmpfile.write(d + '\n')
- fragments.append(d)
+ extras.append(d)
+ tmpfile_used = True
else:
frag_path = os.path.join(kdir, d)
if os.path.exists(frag_path):
with open(frag_path) as frag:
tmpfile.write("\n# fragment from : {}\n".format(d))
tmpfile.writelines(frag)
- fragments.append(os.path.basename(os.path.splitext(d)[0]))
+ tmpfile_used = True
+ extras.append(os.path.basename(os.path.splitext(d)[0]))
+ else:
+ print("Fragment not found: {}".format(frag_path))
+ result = False
tmpfile.flush()
- if not _run_make(target=target, **kwargs):
+ if not _run_make(target=target, **defconfig_kwargs):
result = False
- if result and fragments:
+ if result and tmpfile_used:
kconfig_frag_name = 'frag.config'
kconfig_frag = os.path.join(output_path, kconfig_frag_name)
shutil.copy(tmpfile_path, kconfig_frag)
os.chmod(kconfig_frag,
stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
rel_path = os.path.relpath(output_path, kdir)
- cmd = """\
+ cmd = """
+set -e
cd {kdir}
export ARCH={arch}
export HOSTCC={cc}
export CC={cc}
export CROSS_COMPILE={cross}
-scripts/kconfig/merge_config.sh -O {output} '{base}' '{frag}' {redir} \
+scripts/kconfig/merge_config.sh -O {output} '{base}' '{frag}' {redir}
""".format(kdir=kdir, arch=kwargs['arch'], cc=kwargs['cc'],
cross=kwargs['cross_compile'], output=rel_path,
base=os.path.join(rel_path, '.config'),
@@ -555,10 +608,10 @@ def build_kernel(build_env, kdir, arch, defconfig=None, jopt=None,
}
start_time = time.time()
- fragments = []
+ defconfig_extras = []
if defconfig:
result = _make_defconfig(
- defconfig, kwargs, fragments, verbose, log_file)
+ defconfig, kwargs, defconfig_extras, verbose, log_file)
elif os.path.exists(dot_config):
print("Re-using {}".format(dot_config))
result = True
@@ -599,7 +652,7 @@ def build_kernel(build_env, kdir, arch, defconfig=None, jopt=None,
bmeta = {
'build_threads': jopt,
'build_time': round(build_time, 2),
- 'build_result': 'PASS' if result is True else 'FAIL',
+ 'status': 'PASS' if result is True else 'FAIL',
'arch': arch,
'cross_compile': cross_compile,
'compiler': cc,
@@ -614,7 +667,12 @@ def build_kernel(build_env, kdir, arch, defconfig=None, jopt=None,
defconfig_target = defconfig.split('+')[0]
bmeta.update({
'defconfig': defconfig_target,
- 'defconfig_full': '+'.join([defconfig_target] + fragments),
+ 'defconfig_full': '+'.join([defconfig_target] + defconfig_extras),
+ })
+ else:
+ bmeta.update({
+ 'defconfig': 'none',
+ 'defconfig_full': 'none',
})
vmlinux_file = os.path.join(output_path, 'vmlinux')
@@ -710,15 +768,19 @@ def install_kernel(kdir, tree_name, tree_url, git_branch, git_commit=None,
dts_dir = os.path.join(boot_dir, 'dts')
dtbs = os.path.join(install_path, 'dtbs')
+ dtb_list = []
for root, _, files in os.walk(dts_dir):
for f in fnmatch.filter(files, '*.dtb'):
dtb_path = os.path.join(root, f)
dtb_rel = os.path.relpath(dtb_path, dts_dir)
+ dtb_list.append(dtb_rel)
dest_path = os.path.join(dtbs, dtb_rel)
dest_dir = os.path.dirname(dest_path)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
shutil.copy(dtb_path, dest_path)
+ with open(os.path.join(install_path, 'dtbs.json'), 'w') as json_file:
+ json.dump({'dtbs': sorted(dtb_list)}, json_file, indent=4)
modules_tarball = None
if mod_path:
@@ -731,8 +793,9 @@ def install_kernel(kdir, tree_name, tree_url, git_branch, git_commit=None,
build_env = bmeta['build_environment']
defconfig_full = bmeta['defconfig_full']
+ defconfig_dir = defconfig_full.replace('/', '-')
publish_path = '/'.join([
- tree_name, git_branch, describe, arch, defconfig_full, build_env,
+ tree_name, git_branch, describe, arch, defconfig_dir, build_env,
])
bmeta.update({
@@ -752,7 +815,7 @@ def install_kernel(kdir, tree_name, tree_url, git_branch, git_commit=None,
'file_server_resource': publish_path,
})
- with open(os.path.join(install_path, 'build.json'), 'w') as json_file:
+ with open(os.path.join(install_path, 'bmeta.json'), 'w') as json_file:
json.dump(bmeta, json_file, indent=4, sort_keys=True)
return True
@@ -774,7 +837,7 @@ def push_kernel(kdir, api, token, install='_install_'):
"""
install_path = os.path.join(kdir, install)
- with open(os.path.join(install_path, 'build.json')) as f:
+ with open(os.path.join(install_path, 'bmeta.json')) as f:
bmeta = json.load(f)
artifacts = {}
@@ -811,53 +874,56 @@ def publish_kernel(kdir, install='_install_', api=None, token=None,
"""
install_path = os.path.join(kdir, install)
- with open(os.path.join(install_path, 'build.json')) as f:
+ with open(os.path.join(install_path, 'bmeta.json')) as f:
bmeta = json.load(f)
- data = {k: bmeta[v] for k, v in {
- 'path': 'file_server_resource',
- 'file_server_resource': 'file_server_resource',
- 'job': 'job',
- 'git_branch': 'git_branch',
- 'arch': 'arch',
- 'kernel': 'git_describe',
- 'build_environment': 'build_environment',
- 'defconfig': 'defconfig',
- 'defconfig_full': 'defconfig_full',
- }.iteritems()}
-
if json_path:
- json_data = dict(data)
- for k in ['kernel_image', 'modules', 'git_commit', 'git_url']:
- json_data[k] = bmeta[k]
- json_data['status'] = bmeta['build_result']
- dtb_data = []
- if bmeta['dtb_dir']:
- dtb_dir = os.path.join(install_path, bmeta['dtb_dir'])
- for root, dirs, files in os.walk(dtb_dir):
- if root != dtb_dir:
- rel = os.path.relpath(root, dtb_dir)
- files = list(os.path.join(rel, dtb) for dtb in files)
- dtb_data += files
- json_data['dtb_dir_data'] = dtb_data
+ with open(os.path.join(install_path, 'dtbs.json')) as f:
+ dtbs = json.load(f)['dtbs']
+ bmeta['dtb_dir_data'] = dtbs
try:
with open(json_path, 'r') as json_file:
full_json = json.load(json_file)
- full_json.append(json_data)
+ full_json.append(bmeta)
except Exception as e:
- full_json = [json_data]
+ full_json = [bmeta]
with open(json_path, 'w') as json_file:
json.dump(full_json, json_file)
if api and token:
+ data = {k: bmeta[v] for k, v in {
+ 'path': 'file_server_resource',
+ 'file_server_resource': 'file_server_resource',
+ 'job': 'job',
+ 'git_branch': 'git_branch',
+ 'arch': 'arch',
+ 'kernel': 'git_describe',
+ 'build_environment': 'build_environment',
+ 'defconfig': 'defconfig',
+ 'defconfig_full': 'defconfig_full',
+ }.iteritems()}
headers = {
'Authorization': token,
'Content-Type': 'application/json',
}
-
url = urlparse.urljoin(api, '/build')
- json_data = json.dumps(data)
- resp = requests.post(url, headers=headers, data=json_data)
+ data_json = json.dumps(data)
+ resp = requests.post(url, headers=headers, data=data_json)
resp.raise_for_status()
return True
+
+
+def load_json(bmeta_json, dtbs_json):
+ """Load the build meta-data from JSON files and return dictionaries
+
+ *bmeta_json* is the path to a kernel build meta-data JSON file
+ *dtbs_json* is the path to a kernel dtbs JSON file
+
+ The returned value is a 2-tuple with the bmeta and dtbs data.
+ """
+ with open(bmeta_json) as json_file:
+ bmeta = json.load(json_file)
+ with open(dtbs_json) as json_file:
+ dtbs = json.load(json_file)['dtbs']
+ return bmeta, dtbs
diff --git a/kernelci/cli.py b/kernelci/cli.py
new file mode 100644
index 0000000..af43525
--- /dev/null
+++ b/kernelci/cli.py
@@ -0,0 +1,321 @@
+# Copyright (C) 2018, 2019 Collabora Limited
+# Author: Guillaume Tucker <guillaume.tucker@collabora.com>
+#
+# This module is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This library 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import argparse
+
+
+# -----------------------------------------------------------------------------
+# Standard arguments that can be used in sub-commands
+#
+
+class Args(object):
+ """A list of all the common command line argument options
+
+ All the members of this class are arguments that can be reused in various
+ command line tools. They are dictionaries with at least a `name`
+ attribute, and all the other ones are passed as keyword arguments to the
+ add_argument() method of the parser object from argparse. There should
+ also always be a `help` attribute, as this is needed by the Command class.
+ """
+
+ config = {
+ 'name': '--config',
+ 'help': "Build config name",
+ }
+
+ variant = {
+ 'name': '--variant',
+ 'help': "Build config variant name",
+ }
+
+ build_env = {
+ 'name': '--build-env',
+ 'help': "Build environment name",
+ }
+
+ storage = {
+ 'name': '--storage',
+ 'help': "Storage URL",
+ 'default': "https://storage.kernelci.org",
+ 'required': False,
+ }
+
+ api = {
+ 'name': '--api',
+ 'help': "Backend API URL",
+ 'default': "https://api.kernelci.org",
+ 'required': False,
+ }
+
+ user = {
+ 'name': '--user',
+ 'help': "User name",
+ }
+
+ token = {
+ 'name': '--token',
+ 'help': "Backend API token",
+ }
+
+ callback_id = {
+ 'name': '--callback-id',
+ 'help': "Callback identifier used to look up an authentication token",
+ }
+
+ callback_dataset = {
+ 'name': '--callback-dataset',
+ 'help': "Dataset to include in a lab callback",
+ 'default': 'all',
+ }
+
+ callback_type = {
+ 'name': '--callback-type',
+ 'help': "Type of callback URL",
+ 'default': 'kernelci',
+ }
+
+ callback_url = {
+ 'name': '--callback-url',
+ 'help': "Base URL for the callback",
+ }
+
+ jobs = {
+ 'name': '--jobs',
+ 'help': "File pattern with jobs to submit",
+ }
+
+ commit = {
+ 'name': '--commit',
+ 'help': "Git commit checksum",
+ }
+
+ describe = {
+ 'name': '--describe',
+ 'help': "Git describe",
+ }
+
+ describe_verbose = {
+ 'name': '--describe-verbose',
+ 'help': "Verbose version of git describe",
+ }
+
+ tree_name = {
+ 'name': '--tree-name',
+ 'help': "Name of a kernel tree",
+ }
+
+ tree_url = {
+ 'name': '--tree-url',
+ 'help': "URL of a kernel tree",
+ }
+
+ branch = {
+ 'name': '--branch',
+ 'help': "Name of a kernel branch in a tree",
+ }
+
+ mirror = {
+ 'name': '--mirror',
+ 'help': "Path to the local kernel git mirror",
+ }
+
+ kdir = {
+ 'name': '--kdir',
+ 'help': "Path to the kernel checkout directory",
+ }
+
+ arch = {
+ 'name': '--arch',
+ 'help': "CPU architecture name",
+ }
+
+ bmeta_json = {
+ 'name': '--bmeta-json',
+ 'help': "Path to the build.json file",
+ }
+
+ dtbs_json = {
+ 'name': '--dtbs-json',
+ 'help': "Path to the dtbs.json file",
+ }
+
+ lab_json = {
+ 'name': '--lab-json',
+ 'help': "Path to a JSON file with lab-specific info",
+ }
+
+ lab = {
+ 'name': '--lab',
+ 'help': "Name of a test lab",
+ }
+
+ target = {
+ 'name': '--target',
+ 'help': "Name of a target platform",
+ }
+
+ defconfig = {
+ 'name': '--defconfig',
+ 'help': "Kernel defconfig name",
+ }
+
+ j = {
+ 'name': '-j',
+ 'help': "Number of parallel build processes",
+ }
+
+ verbose = {
+ 'name': '--verbose',
+ 'help': "Verbose output",
+ 'action': 'store_true',
+ }
+
+ output = {
+ 'name': '--output',
+ 'help': "Path the output directory",
+ }
+
+ json_path = {
+ 'name': '--json-path',
+ 'help': "Path to the JSON file",
+ }
+
+ plan = {
+ 'name': '--plan',
+ 'help': "Test plan name",
+ }
+
+ url = {
+ 'name': '--url',
+ 'help': "Kernel sources download URL",
+ }
+
+ filename = {
+ 'name': '--filename',
+ 'help': "Kernel sources destination filename",
+ 'required': False,
+ 'default': 'linux-src.tar.gz',
+ }
+
+ retries = {
+ 'name': '--retries',
+ 'help': 'Number of retries before download fails',
+ 'required': False,
+ 'default': 1,
+ 'type': int,
+ }
+
+
+class Command(object):
+ """A command helper class.
+
+ It contains several class attributes:
+
+ *help* is the help message passed to tbe sub-parser
+ *args* is a list of required arguments dictionaries to add to the parser
+ *opt_args* is a list of optional arguments to add to the parser
+ """
+
+ help = None
+ args = None
+ opt_args = None
+
+ def __init__(self, sub_parser, name):
+ """This class is to facilitate creating command line utilities
+
+ Each command uses a separate sub-parser to be able to have a different
+ set of arguments. A Command object is callable like a function, so it
+ is also possible to simply have a function in the command line tool
+ instead.
+
+ *sub_parser* is a sub-parser from argparse for this particular command.
+ *name* is the name of the command as used on the command line.
+
+ """
+ if not self.help:
+ raise AttributeError("Missing help message for {}".format(name))
+ self._parser = sub_parser.add_parser(name, help=self.help)
+ if self.args:
+ for arg in self.args:
+ self._add_arg(arg, True)
+ if self.opt_args:
+ for arg in self.opt_args:
+ self._add_arg(arg, False)
+ self._parser.set_defaults(func=self)
+
+ def __call__(self, *args, **kw):
+ raise NotImplementedError("Command not implemented")
+
+ def _add_arg(self, arg, required=True):
+ kw = dict(arg)
+ arg_name = kw.pop('name')
+ if required:
+ kw.setdefault('required', True)
+ self._parser.add_argument(arg_name, **kw)
+
+
+def make_parser(title, default_yaml):
+ """Helper to make a parser object from argparse.
+
+ *title* is the title of the parser
+ *default_yaml* is the default YAML config file name to use
+ """
+ parser = argparse.ArgumentParser(title)
+ parser.add_argument("--yaml-configs", default=default_yaml,
+ help="Path to the YAML configs file")
+ return parser
+
+
+def add_subparser(parser, glob):
+ """Helper to add a sub-parser to add sub-commands
+
+ All the global attributes from `glob` starting with `cmd_` are added as
+ sub-commands to the parser.
+
+ *parser* is the main parser object from argparse
+ *glob* is the globals dictionary
+ """
+ sub_parser = parser.add_subparsers(title="Commands",
+ help="List of available commands")
+ commands = dict()
+ for k in glob.keys():
+ split = k.split('cmd_')
+ if len(split) == 2:
+ obj = glob.get(k)
+ if issubclass(obj, Command):
+ cmd_name = split[1]
+ commands[cmd_name] = obj(sub_parser, cmd_name)
+
+
+def parse_args(title, default_yaml, glob):
+ """Helper function to parse the command line arguments
+
+ This will create a parser and automatically add the sub-commands from the
+ global attributes `glob` and return the parsed arguments.
+
+ *title* is the parser title
+
+ *default_yaml* is the name of the default YAML configuration file to use
+ with the command line utility
+
+ *glob* is the dictionary with all the global attributes where to look for
+ commands starting with `cmd_`
+ """
+ parser = make_parser(title, default_yaml)
+ add_subparser(parser, glob)
+ args = parser.parse_args()
+ return args
diff --git a/kernelci/config/build.py b/kernelci/config/build.py
index 9a7a686..daeb5f0 100644
--- a/kernelci/config/build.py
+++ b/kernelci/config/build.py
@@ -49,6 +49,33 @@ class Tree(YAMLObject):
return self._url
+class Reference(YAMLObject):
+ """Kernel reference tree and branch model."""
+
+ def __init__(self, tree, branch):
+ """Reference is a tree and branch used for bisections
+
+ *tree* is a Tree object
+ *branch* is the branch name to be used from the tree
+ """
+ self._tree = tree
+ self._branch = branch
+
+ @classmethod
+ def from_yaml(cls, reference, trees):
+ kw = cls._kw_from_yaml(reference, ['tree', 'branch'])
+ kw['tree'] = trees[kw['tree']]
+ return cls(**kw)
+
+ @property
+ def tree(self):
+ return self._tree
+
+ @property
+ def branch(self):
+ return self._branch
+
+
class Fragment(YAMLObject):
"""Kernel config fragment model."""
@@ -290,7 +317,7 @@ class BuildVariant(YAMLObject):
class BuildConfig(YAMLObject):
"""Build configuration model."""
- def __init__(self, name, tree, branch, variants):
+ def __init__(self, name, tree, branch, variants, reference=None):
"""A build configuration defines the actual kernels to be built.
*name* is the name of the build configuration. It is arbitrary and
@@ -304,11 +331,17 @@ class BuildConfig(YAMLObject):
*variants* is a list of BuildVariant objects, to define all the
variants to build for this tree / branch combination.
+
+ *reference* is a Reference object which defines the tree and branch for
+ bisections when no base commit is found for the good and
+ bad revisions. It can also be None if no reference branch
+ can be used with this build configuration.
"""
self._name = name
self._tree = tree
self._branch = branch
self._variants = variants
+ self._reference = reference
@classmethod
def from_yaml(cls, config, name, trees, fragments, build_envs, defaults):
@@ -318,12 +351,16 @@ class BuildConfig(YAMLObject):
kw.update(cls._kw_from_yaml(
config, ['name', 'tree', 'branch']))
kw['tree'] = trees[kw['tree']]
- config_variants = config.get('variants', defaults)
+ default_variants = defaults.get('variants', {})
+ config_variants = config.get('variants', default_variants)
variants = [
BuildVariant.from_yaml(variant, name, fragments, build_envs)
for name, variant in config_variants.iteritems()
]
kw['variants'] = {v.name: v for v in variants}
+ reference = config.get('reference', defaults.get('reference'))
+ if reference:
+ kw['reference'] = Reference.from_yaml(reference, trees)
return cls(**kw)
@property
@@ -345,6 +382,10 @@ class BuildConfig(YAMLObject):
def get_variant(self, name):
return self._variants[name]
+ @property
+ def reference(self):
+ return self._reference
+
def from_yaml(yaml_path):
with open(yaml_path) as f:
diff --git a/kernelci/config/lab.py b/kernelci/config/lab.py
new file mode 100644
index 0000000..91c0267
--- /dev/null
+++ b/kernelci/config/lab.py
@@ -0,0 +1,111 @@
+# Copyright (C) 2019 Collabora Limited
+# Author: Guillaume Tucker <guillaume.tucker@collabora.com>
+#
+# This module is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This library 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import yaml
+
+from kernelci.config import FilterFactory, YAMLObject
+
+
+class Lab(YAMLObject):
+ """Test lab model."""
+
+ def __init__(self, name, lab_type, url, filters=None):
+ """A lab object contains all the information relative to a test lab.
+
+ *name* is the name used to refer to the lab in meta-data.
+ *lab_type* is the name of the type of lab, essentially indicating the
+ type of software used by the lab.
+ *url* is the URL to reach the lab API.
+ *filters* is a list of Filter objects associated with this lab.
+ """
+ self._name = name
+ self._lab_type = lab_type
+ self._url = url
+ self._filters = filters or list()
+
+ @classmethod
+ def from_yaml(cls, lab, kw):
+ return cls(**kw)
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def lab_type(self):
+ return self._lab_type
+
+ @property
+ def url(self):
+ return self._url
+
+ def match(self, data):
+ return all(f.match(**data) for f in self._filters)
+
+
+class Lab_LAVA(Lab):
+
+ def __init__(self, priority='medium', *args, **kwargs):
+ super(Lab_LAVA, self).__init__(*args, **kwargs)
+ self._priority = priority
+
+ @property
+ def priority(self):
+ return self._priority
+
+ @classmethod
+ def from_yaml(cls, lab, kw):
+ priority = lab.get('priority')
+ if priority:
+ kw['priority'] = priority
+ return cls(**kw)
+
+
+class LabFactory(YAMLObject):
+ """Factory to create lab objects from YAML data."""
+
+ _lab_types = {
+ 'lava': Lab_LAVA,
+ }
+
+ @classmethod
+ def from_yaml(cls, name, lab):
+ lab_type = lab.get('lab_type')
+ kw = cls._kw_from_yaml(lab, ['url'])
+ kw.update({
+ 'name': name,
+ 'lab_type': lab_type,
+ 'filters': FilterFactory.from_data(lab),
+ })
+ lab_cls = cls._lab_types[lab_type] if lab_type else Lab
+ return lab_cls.from_yaml(lab, kw)
+
+
+def from_yaml(yaml_path):
+ with open(yaml_path) as f:
+ data = yaml.load(f)
+
+ labs = {
+ name: LabFactory.from_yaml(name, lab)
+ for name, lab in data['labs'].iteritems()
+ }
+
+ config_data = {
+ 'labs': labs,
+ }
+
+ return config_data
diff --git a/kernelci/config/test.py b/kernelci/config/test.py
index b01c5e8..f21b578 100644
--- a/kernelci/config/test.py
+++ b/kernelci/config/test.py
@@ -128,6 +128,14 @@ class DeviceType_arm64(DeviceType):
super(DeviceType_arm64, self).__init__(name, mach, arch, *args, **kw)
+class DeviceType_riscv(DeviceType):
+
+ def __init__(self, name, mach, arch='riscv', *args, **kw):
+ """RISCV device type with a device tree."""
+ kw.setdefault('dtb', '{}/{}.dtb'.format(mach, name))
+ super(DeviceType_riscv, self).__init__(name, mach, arch, *args, **kw)
+
+
class DeviceTypeFactory(YAMLObject):
"""Factory to create device types from YAML data."""
@@ -136,6 +144,7 @@ class DeviceTypeFactory(YAMLObject):
'mips-dtb': DeviceType_mips,
'arm-dtb': DeviceType_arm,
'arm64-dtb': DeviceType_arm64,
+ 'riscv-dtb': DeviceType_riscv,
}
@classmethod
@@ -272,10 +281,11 @@ class RootFS(YAMLObject):
class TestPlan(YAMLObject):
"""Test plan model."""
- _pattern = '{plan}/{category}-{method}-{protocol}-{rootfs}-{plan}-template.jinja2'
+ _pattern = \
+ '{plan}/{category}-{method}-{protocol}-{rootfs}-{plan}-template.jinja2'
- def __init__(self, name, rootfs, params=None, category='generic',
- filters=None, pattern=None):
+ def __init__(self, name, rootfs, base_name=None, params=None,
+ category='generic', filters=None, pattern=None):
"""A test plan is an arbitrary group of test cases to be run.
*name* is the overall arbitrary test plan name, used when looking for
@@ -283,6 +293,9 @@ class TestPlan(YAMLObject):
*rootfs* is a RootFS object to be used to run this test plan.
+ *base_name* is the name of the base test plan which this test plan
+ configuration refers to.
+
*params" is a dictionary with parameters to pass to the test job
generator.
@@ -294,9 +307,11 @@ class TestPlan(YAMLObject):
*pattern* is a string pattern to create the path to the job template
file, see TestPlan._pattern for the default value with the
regular template file naming scheme.
+
"""
self._name = name
self._rootfs = rootfs
+ self._base_name = base_name or name
self._params = params or dict()
self._category = category
self._filters = filters or list()
@@ -308,6 +323,7 @@ class TestPlan(YAMLObject):
kw = {
'name': name,
'rootfs': file_systems[test_plan['rootfs']],
+ 'base_name': test_plan.get('base_name'),
'filters': FilterFactory.from_data(test_plan, default_filters),
}
kw.update(cls._kw_from_yaml(test_plan, [
@@ -323,6 +339,10 @@ class TestPlan(YAMLObject):
return self._rootfs
@property
+ def base_name(self):
+ return self._base_name
+
+ @property
def params(self):
return dict(self._params)
@@ -341,8 +361,6 @@ class TestPlan(YAMLObject):
plan=self.name)
def match(self, config):
- if self.name == 'boot':
- return True
return all(f.match(**config) for f in self._filters)
@@ -381,10 +399,12 @@ class TestConfig(YAMLObject):
def test_plans(self):
return self._test_plans
- def match(self, arch, plan, flags, config):
+ def match(self, arch, flags, config, plan=None):
return (
- plan in self._test_plans and
- self._test_plans[plan].match(config) and
+ (plan is None or (
+ plan in self._test_plans and
+ self._test_plans[plan].match(config)
+ )) and
self.device_type.arch == arch and
self.device_type.match(flags, config) and
all(f.match(**config) for f in self._filters)
diff --git a/kernelci/lab/__init__.py b/kernelci/lab/__init__.py
new file mode 100644
index 0000000..d70e44d
--- /dev/null
+++ b/kernelci/lab/__init__.py
@@ -0,0 +1,99 @@
+# Copyright (C) 2019 Collabora Limited
+# Author: Guillaume Tucker <guillaume.tucker@collabora.com>
+#
+# This module is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This library 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import importlib
+import json
+import urlparse
+import xmlrpclib
+
+
+class LabAPI(object):
+ """Remote API to a test lab"""
+
+ def __init__(self, config):
+ """A test lab API object can be used to remotely interact with a lab
+
+ *config* is a kernelci.config.lab.Lab object
+ """
+ self._config = config
+ self._server = None
+ self._devices = None
+
+ @property
+ def config(self):
+ return self._config
+
+ @property
+ def devices(self):
+ if self._devices is None:
+ self._devices = self._get_devices()
+ return self._devices
+
+ def _get_devices(self):
+ return list()
+
+ def connect(self, user=None, token=None):
+ """Connect to the remote server API
+
+ *user* is the name of the user to connect to the lab
+ *token* is the token associated with the user to connect to the lab
+ """
+ if user and token:
+ url = urlparse.urlparse(self.config.url)
+ api_url = "{scheme}://{user}:{token}@{loc}{path}".format(
+ scheme=url.scheme, user=user, token=token,
+ loc=url.netloc, path=url.path)
+ else:
+ api_url = self.config.url
+ self._server = xmlrpclib.ServerProxy(api_url)
+
+ def import_devices(self, data):
+ self._devices = data
+
+ def device_type_online(self, device_type_name):
+ return True
+
+ def job_file_name(self, params):
+ return params['name']
+
+ def match(self, filter_data):
+ return self.config.match(filter_data)
+
+ def generate(self, params, target, plan, callback_opts):
+ raise NotImplementedError("Lab.generate() is required")
+
+ def submit(self, job):
+ raise NotImplementedError("Lab.submit() is required")
+
+
+def get_api(lab, user=None, token=None, lab_json=None):
+ """Get the LabAPI object for a given lab config.
+
+ *lab* is a kernelci.config.lab.Lab object
+ *user* is the name of the user to connect to the remote lab
+ *token* is the associated token to connect to the remote lab
+ *lab_json* is the path to a JSON file with cached lab information
+ """
+ m = importlib.import_module('.'.join(['kernelci', 'lab', lab.lab_type]))
+ api = m.get_api(lab)
+ if lab_json:
+ with open(lab_json) as json_file:
+ devices = json.load(json_file)['devices']
+ api.import_devices(devices)
+ if user and token:
+ api.connect(user, token)
+ return api
diff --git a/kernelci/lab/lava.py b/kernelci/lab/lava.py
new file mode 100644
index 0000000..5f3df29
--- /dev/null
+++ b/kernelci/lab/lava.py
@@ -0,0 +1,146 @@
+# Copyright (C) 2019 Collabora Limited
+# Author: Guillaume Tucker <guillaume.tucker@collabora.com>
+#
+# Copyright (C) 2019 Linaro Limited
+# Author: Dan Rue <dan.rue@linaro.org>
+#
+# This module is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This library 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+from jinja2 import Environment, FileSystemLoader
+import os
+from kernelci.lab import LabAPI
+
+DEVICE_ONLINE_STATUS = ['idle', 'running', 'reserved']
+
+
+def get_device_type_by_name(name, device_types, aliases=[]):
+ """
+ Return a device type named name. In the case of an alias, resolve the
+ alias to a device_type
+
+ Example:
+ IN:
+ name = "x15"
+ device_types = ['x15', 'beaglebone-black'],
+ aliases = [
+ {'name': 'x15', 'device_type': 'am57xx-beagle-x15'}
+ ]
+ OUT:
+ 'am57xx-beagle-x15'
+
+ """
+ for device_type in device_types:
+ if device_type == name:
+ return device_type
+ for alias in aliases:
+ if alias["name"] == name:
+ for device_type in device_types:
+ if alias["device_type"] == device_type:
+ return device_type
+ return None
+
+
+class LAVA(LabAPI):
+ """Interface to a LAVA lab
+
+ This implementation of kernelci.lab.LabAPI is to communicate with LAVA
+ labs. It can retrieve some information such as the list of devices and
+ their online status, generate and submit jobs with callback parameters.
+ One special thing it can deal with is job priorities, which is only
+ available in kernelci.config.lab.lab_LAVA objects.
+ """
+
+ def _get_aliases(self):
+ aliases = []
+ for alias in self._server.scheduler.aliases.list():
+ aliases.append(self._server.scheduler.aliases.show(alias))
+ return aliases
+
+ def _get_devices(self):
+ all_devices = self._server.scheduler.all_devices()
+ all_aliases = []
+ for alias in self._server.scheduler.aliases.list():
+ all_aliases.append(self._server.scheduler.aliases.show(alias))
+ device_types = {}
+ for device in all_devices:
+ name, device_type, status, _, _ = device
+ device_list = device_types.setdefault(device_type, list())
+ device_list.append({
+ 'name': name,
+ 'online': status in DEVICE_ONLINE_STATUS,
+ })
+ device_type_online = {
+ device_type: any(device['online'] for device in devices)
+ for device_type, devices in device_types.iteritems()
+ }
+ return {
+ 'device_type_online': device_type_online,
+ 'aliases': all_aliases,
+ }
+
+ def _add_callback_params(self, params, opts):
+ callback_id = opts.get('id')
+ if not callback_id:
+ return
+ callback_type = opts.get('type')
+ if callback_type == 'kernelci':
+ lava_cb = 'boot' if params['plan'] == 'boot' else 'test'
+ # ToDo: consolidate this to just have to pass the callback_url
+ params['callback_name'] = '/'.join(['lava', lava_cb])
+ params.update({
+ 'callback': callback_id,
+ 'callback_url': opts['url'],
+ 'callback_dataset': opts['dataset'],
+ 'callback_type': callback_type,
+ })
+
+ def device_type_online(self, device_type):
+ devices = self.devices['device_type_online']
+ device_type_name = get_device_type_by_name(
+ device_type.base_name, devices.keys(), self.devices['aliases'])
+ return self.devices['device_type_online'].get(device_type_name, False)
+
+ def job_file_name(self, params):
+ return '.'.join([params['name'], 'yaml'])
+
+ def generate(self, params, target, plan, callback_opts):
+ short_template_file = plan.get_template_path(target.boot_method)
+ template_file = os.path.join('templates', short_template_file)
+ if not os.path.exists(template_file):
+ print("Template not found: {}".format(template_file))
+ return None
+ devices = self.devices['device_type_online']
+ base_name = params['base_device_type']
+ params.update({
+ 'template_file': template_file,
+ 'priority': self.config.priority,
+ 'lab_name': self.config.name,
+ 'base_device_type': get_device_type_by_name(
+ base_name, devices.keys(), self.devices['aliases']),
+ })
+ self._add_callback_params(params, callback_opts)
+ jinja2_env = Environment(loader=FileSystemLoader('templates'),
+ extensions=["jinja2.ext.do"])
+ template = jinja2_env.get_template(short_template_file)
+ data = template.render(params)
+ return data
+
+ def submit(self, job):
+ return self._server.scheduler.submit_job(job)
+
+
+def get_api(lab):
+ """Get a LAVA lab API object"""
+ return LAVA(lab)
diff --git a/kernelci/test.py b/kernelci/test.py
new file mode 100644
index 0000000..b3095af
--- /dev/null
+++ b/kernelci/test.py
@@ -0,0 +1,145 @@
+# Copyright (C) 2019 Collabora Limited
+# Author: Guillaume Tucker <guillaume.tucker@collabora.com>
+#
+# This module is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This library 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 Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os
+import urlparse
+
+
+def match_configs(configs, bmeta, dtbs, lab):
+ """Filter the test configs for a given kernel build and lab.
+
+ *configs* is a list of all the initial test configs
+ *bmeta* is a dictionary with the kernel build meta-data
+ *dtbs* is the list of dtb files included in the kernel build
+ *lab* is a Lab object instance
+
+ The returned value is a list with a subset of the configs that match the
+ provided kernel build meta-data and lab filters.
+ """
+ defconfig = bmeta['defconfig_full']
+ arch = bmeta['arch']
+
+ filters = {
+ 'arch': arch,
+ 'defconfig': defconfig,
+ 'kernel': bmeta['git_describe'],
+ 'build_environment': bmeta['build_environment'],
+ 'tree': bmeta['job'],
+ }
+
+ flags = {
+ 'big_endian': 'BIG_ENDIAN' in defconfig,
+ 'lpae': 'LPAE' in defconfig,
+ }
+
+ match = set()
+
+ for test_config in configs:
+ if not test_config.match(arch, flags, filters):
+ continue
+ dtb = test_config.device_type.dtb
+ if dtb and dtb not in dtbs:
+ continue
+ for plan_name, plan in test_config.test_plans.iteritems():
+ if not plan.match(filters):
+ continue
+ filters['plan'] = plan_name
+ if lab.match(filters):
+ match.add((test_config.device_type, plan))
+
+ return match
+
+
+def get_params(bmeta, target, plan_config, storage):
+ """Get a dictionary with all the test parameters to run a test job
+
+ *bmeta* is a dictionary with the kernel build meta-data
+ *target* is the name of the target platform to run the test
+ *plan_config* is a TestPlan object for the test plan to run
+ *storage* is the URL of the storage server
+ """
+ arch = target.arch
+ dtb = dtb_full = target.dtb
+ if dtb:
+ dtb = os.path.basename(dtb) # hack for dtbs in subfolders
+ file_server_resource = bmeta['file_server_resource']
+ job_px = file_server_resource.replace('/', '-')
+ url_px = file_server_resource
+ job_name = '-'.join([job_px, dtb or 'no-dtb',
+ target.name, plan_config.name])
+ base_url = urlparse.urljoin(storage, '/'.join([url_px, '']))
+ kernel_img = bmeta['kernel_image']
+ kernel_url = urlparse.urljoin(storage, '/'.join([url_px, kernel_img]))
+ if dtb_full and dtb_full.endswith('.dtb'):
+ dtb_url = urlparse.urljoin(
+ storage, '/'.join([url_px, 'dtbs', dtb_full]))
+ platform = dtb.split('.')[0]
+ else:
+ dtb_url = None
+ platform = target.name
+ modules = bmeta.get('modules')
+ modules_url = (
+ urlparse.urljoin(storage, '/'.join([url_px, modules]))
+ if modules else None
+ )
+ rootfs = plan_config.rootfs
+ defconfig = bmeta['defconfig_full']
+ defconfig_base = ''.join(defconfig.split('+')[:1])
+ endian = 'big' if 'BIG_ENDIAN' in defconfig else 'little'
+ describe = bmeta['git_describe']
+
+ params = {
+ 'name': job_name,
+ 'dtb_url': dtb_url,
+ 'dtb_short': dtb,
+ 'dtb_full': dtb_full,
+ 'platform': platform,
+ 'mach': target.mach,
+ 'kernel_url': kernel_url,
+ 'image_type': 'kernel-ci',
+ 'image_url': base_url,
+ 'modules_url': modules_url,
+ 'plan': plan_config.base_name,
+ 'plan_variant': plan_config.name,
+ 'kernel': describe,
+ 'tree': bmeta['job'],
+ 'defconfig': defconfig,
+ 'arch_defconfig': '-'.join([arch, defconfig]),
+ 'fastboot': str(target.get_flag('fastboot')).lower(),
+ 'device_type': target.name,
+ 'base_device_type': target.base_name,
+ 'base_url': base_url,
+ 'endian': endian,
+ 'arch': arch,
+ 'git_branch': bmeta['git_branch'],
+ 'git_commit': bmeta['git_commit'],
+ 'git_describe': describe,
+ 'git_url': bmeta['git_url'],
+ 'defconfig_base': defconfig_base,
+ 'initrd_url': rootfs.get_url('ramdisk', arch, endian),
+ 'kernel_image': kernel_img,
+ 'nfsrootfs_url': rootfs.get_url('nfs', arch, endian),
+ 'context': target.context,
+ 'rootfs_prompt': rootfs.prompt,
+ 'file_server_resource': file_server_resource,
+ 'build_environment': bmeta['build_environment'],
+ }
+
+ params.update(plan_config.params)
+ params.update(target.params)
+
+ return params
diff --git a/lab-configs.yaml b/lab-configs.yaml
new file mode 100644
index 0000000..0989808
--- /dev/null
+++ b/lab-configs.yaml
@@ -0,0 +1,124 @@
+labs:
+
+ # ToDo: also run jobs with callbacks sent to BayLibre's KernelCI backend
+ lab-baylibre:
+ lab_type: lava
+ url: 'http://lava.baylibre.com:10080/RPC2/'
+ filters:
+ - blacklist: {tree: [drm-tip]}
+ - whitelist:
+ plan:
+ - baseline
+ - baseline-fastboot
+ - boot
+ - kselftest
+
+ lab-clabbe:
+ lab_type: lava
+ url: 'https://lava.montjoie.ovh/RPC2/'
+ filters:
+ - whitelist:
+ plan:
+ - baseline
+ - boot
+ - boot-nfs
+ - simple
+ - sleep
+ tree:
+ - kernelci
+ - next
+ - stable-rc
+
+ lab-collabora:
+ lab_type: lava
+ url: 'https://lava.collabora.co.uk/RPC2/'
+ filters:
+ - blacklist: {tree: [android]}
+ - whitelist:
+ plan:
+ - baseline
+ - boot
+ - cros-ec
+ - igt-drm-kms
+ - sleep
+ - usb
+ - v4l2-compliance-uvc
+ - v4l2-compliance-vivid
+
+ lab-drue:
+ lab_type: lava
+ url: 'https://lava.therub.org/RPC2/'
+ filters:
+ - whitelist:
+ plan:
+ - baseline
+ - boot
+ - boot-nfs
+ - simple
+ - sleep
+
+ lab-free-electrons:
+ lab_type: lava
+ url: 'https://lab.free-electrons.com/RPC2/'
+ filters:
+ - blacklist: {tree: [drm-tip, linaro-android]}
+ - whitelist:
+ plan:
+ - baseline
+ - boot
+ - boot-nfs
+
+ lab-linaro-lkft:
+ lab_type: lava
+ url: 'https://lkft.validation.linaro.org/RPC2/'
+ priority: low
+ filters:
+ - combination:
+ keys: ['tree', 'branch']
+ values:
+ - ['stable', 'linux-4.4.y']
+ - ['stable', 'linux-4.9.y']
+ - ['stable', 'linux-4.14.y']
+ - ['stable-rc', 'linux-4.4.y']
+ - ['stable-rc', 'linux-4.9.y']
+ - ['stable-rc', 'linux-4.14.y']
+ - ['next', 'master']
+ - ['next', 'pending-fixes']
+ - ['kernelci', 'kernelci.org']
+ - ['kernelci', 'staging.kernelci.org']
+ - whitelist:
+ plan:
+ - baseline
+ - baseline-uefi
+ - boot
+
+ lab-mhart:
+ lab_type: lava
+ url: 'http://lava.streamtester.net/RPC2/'
+ filters:
+ - blacklist: {tree: ['android', 'drm-tip', 'linaro-android']}
+ - whitelist:
+ plan:
+ - baseline
+ - boot
+ - boot-nfs
+ - simple
+
+ lab-pengutronix:
+ lab_type: lava
+ url: 'https://hekla.openlab.pengutronix.de/RPC2/'
+ filters:
+ - whitelist:
+ plan:
+ - baseline
+ - boot
+
+ lab-theobroma-systems:
+ lab_type: lava
+ url: 'https://lava.theobroma-systems.com/RPC2/'
+ filters:
+ - whitelist:
+ plan:
+ - baseline
+ - boot
+ - kselftest
diff --git a/lava-v2-jobs-from-api.py b/lava-v2-jobs-from-api.py
index c28bdd7..c809901 100755
--- a/lava-v2-jobs-from-api.py
+++ b/lava-v2-jobs-from-api.py
@@ -72,7 +72,7 @@ def get_builds(api, token, config):
return builds
-def add_callback_params(params, config, plan):
+def add_callback_params(params, config, plan_config):
callback = config.get('callback')
if not callback:
return
@@ -80,7 +80,7 @@ def add_callback_params(params, config, plan):
callback_type = config.get('callback_type')
if callback_type == 'kernelci':
- lava_cb = 'boot' if plan == 'boot' else 'test'
+ lava_cb = 'boot' if plan_config.base_name == 'boot' else 'test'
params['callback_name'] = '/'.join(['lava', lava_cb])
params.update({
@@ -91,8 +91,8 @@ def add_callback_params(params, config, plan):
})
-def get_job_params(config, test_config, defconfig, opts, build, plan):
- short_template_file = test_config.get_template_path(plan)
+def get_job_params(config, test_config, defconfig, opts, build, plan_config):
+ short_template_file = test_config.get_template_path(plan_config.name)
template_file = os.path.join('templates', short_template_file)
if not os.path.exists(template_file):
print("Template not found: {}".format(template_file))
@@ -101,13 +101,14 @@ def get_job_params(config, test_config, defconfig, opts, build, plan):
arch = config.get('arch')
storage = config.get('storage')
device_type = test_config.device_type
- test_plan = test_config.test_plans[plan]
defconfig_base = ''.join(defconfig.split('+')[:1])
dtb = dtb_full = opts['dtb_full'] = opts['dtb'] = device_type.dtb
# hack for arm64 dtbs in subfolders
if arch == 'arm64' and dtb:
dtb = opts['dtb'] = os.path.basename(dtb)
+ if arch == 'riscv' and dtb:
+ dtb = opts['dtb'] = os.path.basename(dtb)
file_server_resource = build.get('file_server_resource')
if file_server_resource:
@@ -119,7 +120,7 @@ def get_job_params(config, test_config, defconfig, opts, build, plan):
url_px = '/'.join(parts)
job_name = '-'.join([job_name_prefix, dtb or 'no-dtb',
- device_type.name, plan])
+ device_type.name, plan_config.name])
base_url = urlparse.urljoin(storage, '/'.join([url_px, '']))
kernel_url = urlparse.urljoin(
@@ -137,7 +138,7 @@ def get_job_params(config, test_config, defconfig, opts, build, plan):
else:
modules_url = None
- rootfs = test_plan.rootfs
+ rootfs = plan_config.rootfs
job_params = {
'name': job_name,
@@ -150,7 +151,7 @@ def get_job_params(config, test_config, defconfig, opts, build, plan):
'image_type': 'kernel-ci',
'image_url': base_url,
'modules_url': modules_url,
- 'plan': plan,
+ 'plan': plan_config.base_name,
'kernel': config.get('describe'),
'tree': config.get('tree'),
'defconfig': defconfig,
@@ -175,19 +176,18 @@ def get_job_params(config, test_config, defconfig, opts, build, plan):
'lab_name': config.get('lab'),
'context': device_type.context,
'rootfs_prompt': rootfs.prompt,
- 'plan_name': test_plan.name,
'file_server_resource': file_server_resource,
'build_environment': build.get('build_environment'),
}
- job_params.update(test_plan.params)
+ job_params.update(plan_config.params)
job_params.update(device_type.params)
- add_callback_params(job_params, config, plan)
+ add_callback_params(job_params, config, plan_config)
return job_params
-def add_jobs(jobs, config, tests, opts, build, plan, arch, defconfig):
+def add_jobs(jobs, config, tests, opts, build, plan_config, arch, defconfig):
filters = {
'arch': arch,
'defconfig': defconfig,
@@ -207,7 +207,7 @@ def add_jobs(jobs, config, tests, opts, build, plan, arch, defconfig):
print("device not in targets: {}".format(
test_config.device_type, targets))
continue
- if not test_config.match(arch, plan, flags, filters):
+ if not test_config.match(arch, flags, filters, plan_config.name):
print("test config did not match: {}".format(
test_config.device_type))
continue
@@ -216,12 +216,12 @@ def add_jobs(jobs, config, tests, opts, build, plan, arch, defconfig):
print("dtb not in builds: {}".format(dtb))
continue
job_params = get_job_params(
- config, test_config, defconfig, opts, build, plan)
+ config, test_config, defconfig, opts, build, plan_config)
if job_params:
jobs.append(job_params)
-def get_jobs_from_builds(config, builds, tests):
+def get_jobs_from_builds(config, builds, tests, plans):
arch = config.get('arch')
cwd = os.getcwd()
jobs = []
@@ -233,7 +233,7 @@ def get_jobs_from_builds(config, builds, tests):
defconfig = build['defconfig_full']
print("Working on build: {}".format(build.get('file_server_resource')))
- for plan in config.get('plans'):
+ for plan in plans:
opts = {
'arch_defconfig': '-'.join([arch, defconfig]),
'endian': 'big' if 'BIG_ENDIAN' in defconfig else 'little',
@@ -284,10 +284,19 @@ def main(args):
print("Number of builds: {}".format(len(builds)))
config_data = kernelci.config.test.from_yaml(config.get('test_configs'))
+
+ plan_configs = config_data['test_plans']
+ base_plans = config.get('plans')
+ plans = list(
+ plan_config
+ for plan_config in plan_configs.values()
+ if plan_config.base_name in base_plans
+ )
+
tests = config_data['test_configs']
print("Number of test configs: {}".format(len(tests)))
- jobs = get_jobs_from_builds(config, builds, tests)
+ jobs = get_jobs_from_builds(config, builds, tests, plans)
print("Number of jobs: {}".format(len(jobs)))
write_jobs(config, jobs)
diff --git a/src/org/kernelci/build/Kernel.groovy b/src/org/kernelci/build/Kernel.groovy
deleted file mode 100644
index e156546..0000000
--- a/src/org/kernelci/build/Kernel.groovy
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- Copyright (C) 2018 Collabora Limited
- Author: Guillaume Tucker <guillaume.tucker@collabora.com>
-
- This module is free software; you can redistribute it and/or modify it under
- the terms of the GNU Lesser General Public License as published by the Free
- Software Foundation; either version 2.1 of the License, or (at your option)
- any later version.
-
- This library 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 Lesser General Public License for more
- details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this library; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-
-package org.kernelci.build
-
-def downloadTarball(kdir, url, filename="linux-src.tar.gz") {
- sh(script: "rm -rf ${kdir}")
- dir(kdir) {
- /* Storing the tarball is done asynchronously on the server, so it may
- * not be ready by the time we try to download it. Give it a
- * minute by retrying periodically. */
- def retry_sleep_s = 5
- def retries = 12
- def downloaded = false
-
- while (!downloaded) {
- def stat = sh(returnStatus: true,
- script: "\
-wget \
---no-hsts \
---progress=dot:giga \
---retry-connrefused \
---waitretry=5 \
---read-timeout=20 \
---timeout=15 \
---tries 20 \
---continue \
--O ${filename} \
-${url}")
-
- if (!stat) {
- downloaded = true
- } else {
- retries -= 1
-
- /* Only retry if server returned an HTTP error (status 8) */
- if (!retries || (stat != 8)) {
- throw new hudson.AbortException(
- "Failed to download tarball")
- }
-
- echo "retries: ${retries}"
- sleep(time: retry_sleep_s, unit: 'SECONDS')
- }
- }
-
- sh(script: "tar xzf ${filename}")
- }
-}
diff --git a/templates/base/kernel-ci-base.jinja2 b/templates/base/kernel-ci-base.jinja2
index 99babae..c6a08da 100644
--- a/templates/base/kernel-ci-base.jinja2
+++ b/templates/base/kernel-ci-base.jinja2
@@ -16,6 +16,7 @@ metadata:
platform.name: {{ platform }}
platform.mach: {{ mach }}
test.plan: {{ plan }}
+ test.plan_variant: {{ plan_variant }}
git.commit: {{ git_commit }}
git.describe: {{ git_describe }}
git.branch: {{ git_branch }}
diff --git a/templates/baseline/baseline.jinja2 b/templates/baseline/baseline.jinja2
index d514f28..e0b856a 100644
--- a/templates/baseline/baseline.jinja2
+++ b/templates/baseline/baseline.jinja2
@@ -1,6 +1,48 @@
- test:
+{%- if test_namespace %}
+ namespace: {{ test_namespace }}
+{%- endif %}
timeout:
- minutes: 10
+ minutes: 1
+ definitions:
+ - repository:
+ metadata:
+ format: Lava-Test Test Definition 1.0
+ name: baseline
+ description: "baseline test plan"
+ os:
+ - debian
+ scope:
+ - functional
+ environment:
+ - lava-test-shell
+ run:
+ steps:
+ - >
+ for level in warn err; do
+ dmesg --level=$level --notime -x -k > dmesg.$level
+ done
+ - >
+ for level in crit alert emerg; do
+ dmesg --level=$level --notime -x -k > dmesg.$level
+ test -s dmesg.$level && res=fail || res=pass
+ count=$(cat dmesg.$level | wc -l)
+ lava-test-case $level \
+ --result $res \
+ --measurement $count \
+ --units lines
+ done
+ - cat dmesg.emerg dmesg.alert dmesg.crit dmesg.err dmesg.warn
+ from: inline
+ name: dmesg
+ path: inline/dmesg.yaml
+
+- test:
+{%- if test_namespace %}
+ namespace: {{ test_namespace }}
+{%- endif %}
+ timeout:
+ minutes: 1
definitions:
- repository:
metadata:
diff --git a/templates/baseline/generic-fastboot-baseline-template.jinja2 b/templates/baseline/generic-fastboot-baseline-template.jinja2
new file mode 100644
index 0000000..691d33e
--- /dev/null
+++ b/templates/baseline/generic-fastboot-baseline-template.jinja2
@@ -0,0 +1,9 @@
+{% extends 'boot-fastboot/generic-fastboot-boot-template.jinja2' %}
+{% block actions %}
+{{ super () }}
+
+{% set test_namespace = "target" %}
+
+{% include 'baseline/baseline.jinja2' %}
+
+{% endblock %}
diff --git a/templates/boot-fastboot/generic-fastboot-boot-template.jinja2 b/templates/boot-fastboot/generic-fastboot-boot-template.jinja2
new file mode 100644
index 0000000..d91f925
--- /dev/null
+++ b/templates/boot-fastboot/generic-fastboot-boot-template.jinja2
@@ -0,0 +1,95 @@
+{%- extends 'base/kernel-ci-base.jinja2' %}
+{% block metadata %}
+{{ super() }}
+{% endblock %}
+{% block main %}
+{{ super() }}
+tags:
+ - fastboot
+protocols:
+ lava-lxc:
+ name: lxc-{{ platform }}-kernelci-fastboot
+ template: debian
+ distribution: debian
+ release: buster
+{% endblock %}
+{% block actions %}
+actions:
+{%- block deploy_lxc %}
+
+- deploy:
+ namespace: host
+ timeout:
+ minutes: 15
+ to: lxc
+ packages:
+ - android-tools-adb
+ - android-tools-fastboot
+ - cpio
+ - mkbootimg
+{%- endblock %}
+{%- block boot_lxc %}
+
+- boot:
+ namespace: host
+ prompts:
+ - 'root@(.*):/#'
+ timeout:
+ minutes: 5
+ method: lxc
+{%- endblock %}
+{%- block deploy_url %}
+
+- deploy:
+ timeout:
+ minutes: 40
+ namespace: target
+ to: download
+ images:
+ kernel:
+ url: {{ kernel_url }}
+{%- block kernel_image_type %}
+ type: {{ kernel_image.lower() }}
+{%- endblock %}
+{%- if initrd_url %}
+ ramdisk:
+ url: {{ initrd_url }}
+{%- endif %}
+{%- if modules_url %}
+ modules:
+ url: {{ modules_url }}
+{%- endif %}
+{%- if dtb_url %}
+ dtb:
+ url: {{ dtb_url }}
+{%- endif %}
+{%- endblock %}
+{%- block test_lxc %}
+
+{% include "/boot-fastboot/mkbootimg.jinja2" %}
+{%- endblock %}
+{%- block deploy_boot %}
+
+- deploy:
+ timeout:
+ minutes: 40
+ to: fastboot
+ namespace: target
+ images:
+ boot:
+ url: lxc:///boot.img
+{%- endblock %}
+{%- block boot %}
+
+- boot:
+ namespace: target
+ prompts:
+ - '/ #'
+ timeout:
+ minutes: 15
+ method: fastboot
+ transfer_overlay:
+ download_command: udhcpc ; ip addr show ; wget
+ unpack_command: tar -C / -zxvpf
+{%- endblock %}
+{% endblock %}
diff --git a/templates/boot-fastboot/mkbootimg.jinja2 b/templates/boot-fastboot/mkbootimg.jinja2
new file mode 100644
index 0000000..988f04b
--- /dev/null
+++ b/templates/boot-fastboot/mkbootimg.jinja2
@@ -0,0 +1,20 @@
+- test:
+ namespace: host
+ timeout:
+ minutes: 30
+ definitions:
+ - from: inline
+ name: {{ device_type }}-images
+ path: inline/{{ device_type }}-images.yaml
+ repository:
+ metadata:
+ description: {{ device_type }} images
+ format: Lava-Test Test Definition 1.0
+ name: {{ device_type }}-images
+ run:
+ steps:
+ - cd /lava-lxc
+ - tar xf modules.tar.xz
+ - gunzip rootfs.cpio.gz
+ - find lib/ | cpio -o --format=newc --append -F rootfs.cpio
+ - mkbootimg --kernel {{ kernel_image }} --second {{ dtb_short }} --ramdisk rootfs.cpio --cmdline {{ cmdline }} --kernel_offset {{ kernel_addr }} --ramdisk_offset {{ ramdisk_addr }} --second_offset {{ dtb_addr }} -o boot.img
diff --git a/templates/igt/igt.jinja2 b/templates/igt/igt.jinja2
index 67cef60..f9a0eb9 100644
--- a/templates/igt/igt.jinja2
+++ b/templates/igt/igt.jinja2
@@ -5,7 +5,7 @@
- repository:
metadata:
format: Lava-Test Test Definition 1.0
- name: {{ plan_name }}
+ name: {{ plan }}
description: "IGT test plan"
os:
- oe
@@ -17,6 +17,6 @@
/usr/bin/igt-parser.sh
{{ tests|wordwrap(1, False, "\n ") }}
from: inline
- name: {{ plan_name }}
- path: inline/{{ plan_name }}.yaml
+ name: {{ plan }}
+ path: inline/{{ plan }}.yaml
lava-signal: kmsg
diff --git a/templates/v4l2-compliance/v4l2-compliance.jinja2 b/templates/v4l2-compliance/v4l2-compliance.jinja2
index 2260aeb..ec521ca 100644
--- a/templates/v4l2-compliance/v4l2-compliance.jinja2
+++ b/templates/v4l2-compliance/v4l2-compliance.jinja2
@@ -5,7 +5,7 @@
- repository:
metadata:
format: Lava-Test Test Definition 1.0
- name: v4l2
+ name: {{ plan }}
description: "v4l2 test plan"
os:
- debian
@@ -15,5 +15,5 @@
steps:
- /usr/bin/v4l2-parser.sh {{ v4l2_driver }}
from: inline
- name: {{ plan_name }}
- path: inline/v4l2.yaml
+ name: {{ plan }}
+ path: inline/{{ plan }}.yaml
diff --git a/test-configs.yaml b/test-configs.yaml
index cd01e99..7683b1c 100644
--- a/test-configs.yaml
+++ b/test-configs.yaml
@@ -5,7 +5,7 @@
file_system_types:
buildroot:
- url: 'https://storage.kernelci.org/images/rootfs/buildroot/kci-2019.02-2-gefc755ba4a02'
+ url: 'https://storage.kernelci.org/images/rootfs/buildroot/kci-2019.02-8-gd700ebb99e8f'
arch_map:
arm64be: [{arch: arm64, endian: big}]
@@ -41,15 +41,15 @@ file_systems:
debian_buster_ramdisk:
type: debian
- ramdisk: 'buster/20190830.0/{arch}/rootfs.cpio.gz'
+ ramdisk: 'buster/20191115.0/{arch}/rootfs.cpio.gz'
debian_buster-igt_ramdisk:
type: debian
- ramdisk: 'buster-igt/20190830.0/{arch}/rootfs.cpio.gz'
+ ramdisk: 'buster-igt/20191025.0/{arch}/rootfs.cpio.gz'
- debian_stretch-v4l2_ramdisk:
+ debian_buster-v4l2_ramdisk:
type: debian
- ramdisk: 'stretch-v4l2/20190830.0/{arch}/rootfs.cpio.gz'
+ ramdisk: 'buster-v4l2/20191115.0/{arch}/rootfs.cpio.gz'
test_plan_default_filters:
@@ -79,13 +79,60 @@ test_plans:
filters:
- blacklist: *kselftest_defconfig_clang_environment_filter
+ baseline_qemu:
+ base_name: baseline
+ rootfs: buildroot_baseline_ramdisk
+ pattern: 'baseline/generic-qemu-baseline-template.jinja2'
+ filters:
+ - blacklist: *kselftest_defconfig_clang_environment_filter
+
+ baseline-fastboot:
+ rootfs: buildroot_baseline_ramdisk
+ pattern: 'baseline/generic-fastboot-baseline-template.jinja2'
+ params:
+ job_timeout: '50'
+
+ baseline-uefi_arm:
+ base_name: baseline-uefi
+ rootfs: buildroot_baseline_ramdisk
+ pattern: 'baseline/generic-qemu-baseline-template.jinja2'
+ params:
+ bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/QEMU_EFI.fd-ARM-RELEASE-111bbcf87621'
+
+ baseline-uefi_arm64:
+ base_name: baseline-uefi
+ rootfs: buildroot_baseline_ramdisk
+ pattern: 'baseline/generic-qemu-baseline-template.jinja2'
+ params:
+ bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/QEMU_EFI.fd-AARCH64-RELEASE-111bbcf87621'
+
+ baseline-uefi_x86_64:
+ base_name: baseline-uefi
+ rootfs: buildroot_baseline_ramdisk
+ pattern: 'baseline/generic-qemu-baseline-template.jinja2'
+ params:
+ bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/OVMF.fd-X64-RELEASE-111bbcf87621'
+
+ baseline-uefi_i386:
+ base_name: baseline-uefi
+ rootfs: buildroot_baseline_ramdisk
+ pattern: 'baseline/generic-qemu-baseline-template.jinja2'
+ params:
+ bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/OVMF.fd-IA32-RELEASE-111bbcf87621'
+
+ baseline-uefi_x86-mixed:
+ base_name: baseline-uefi
+ rootfs: buildroot_baseline_ramdisk
+ pattern: 'baseline/generic-qemu-baseline-template.jinja2'
+ params:
+ bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/OVMF.fd-IA32X64-RELEASE-111bbcf87621'
+
boot:
rootfs: buildroot_ramdisk
filters:
- blacklist: *kselftest_defconfig_clang_environment_filter
- boot_nfs:
- name: 'boot-nfs'
+ boot-nfs:
rootfs: buildroot_nfs
pattern: 'boot-nfs/{category}-{method}-{protocol}-nfs-template.jinja2'
filters:
@@ -108,7 +155,7 @@ test_plans:
- blacklist: *clang_environment_filter
boot_qemu:
- name: boot
+ base_name: boot
rootfs: buildroot_ramdisk
pattern: 'boot/generic-qemu-boot-template.jinja2'
filters:
@@ -117,7 +164,7 @@ test_plans:
cros-ec:
rootfs: debian_buster_ramdisk
- igt_drm_kms:
+ igt-drm-kms:
rootfs: debian_buster-igt_ramdisk
pattern: 'igt/{category}-{method}-{protocol}-{rootfs}-igt.jinja2'
params:
@@ -143,56 +190,24 @@ test_plans:
rootfs: debian_buster_ramdisk
simple_qemu:
- name: simple
+ base_name: simple
rootfs: debian_buster_ramdisk
pattern: 'simple/generic-qemu-simple-template.jinja2'
sleep:
rootfs: debian_buster_ramdisk
- uefi_arm:
- rootfs: buildroot_ramdisk
- pattern: 'boot/generic-qemu-boot-template.jinja2'
- params:
- bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/QEMU_EFI.fd-ARM-RELEASE-111bbcf87621'
-
- uefi_arm64:
- rootfs: buildroot_ramdisk
- pattern: 'boot/generic-qemu-boot-template.jinja2'
- params:
- bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/QEMU_EFI.fd-AARCH64-RELEASE-111bbcf87621'
-
- uefi_x86_64:
- rootfs: buildroot_ramdisk
- pattern: 'boot/generic-qemu-boot-template.jinja2'
- params:
- bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/OVMF.fd-X64-RELEASE-111bbcf87621'
-
- uefi_i386:
- rootfs: buildroot_ramdisk
- pattern: 'boot/generic-qemu-boot-template.jinja2'
- params:
- bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/OVMF.fd-IA32-RELEASE-111bbcf87621'
-
- uefi_x86-mixed:
- rootfs: buildroot_ramdisk
- pattern: 'boot/generic-qemu-boot-template.jinja2'
- params:
- bios_url: 'https://storage.kernelci.org/images/uefi/111bbcf87621/OVMF.fd-IA32X64-RELEASE-111bbcf87621'
-
usb:
rootfs: debian_buster_ramdisk
- v4l2_compliance_uvc:
- name: v4l2-compliance-uvc
- rootfs: debian_stretch-v4l2_ramdisk
+ v4l2-compliance-uvc:
+ rootfs: debian_buster-v4l2_ramdisk
# FIXME - this is not very sustainable, improve template naming scheme
pattern: 'v4l2-compliance/{category}-{method}-{protocol}-{rootfs}-v4l2-compliance-template.jinja2'
params: {v4l2_driver: "uvcvideo"}
- v4l2_compliance_qemu_vivid:
- name: v4l2-compliance-vivid
- rootfs: debian_stretch-v4l2_ramdisk
+ v4l2-compliance-vivid:
+ rootfs: debian_buster-v4l2_ramdisk
pattern: 'v4l2-compliance/generic-qemu-v4l2-compliance-template.jinja2'
params: {v4l2_driver: "vivid"}
filters:
@@ -437,6 +452,16 @@ device_types:
class: arm64-dtb
boot_method: uboot
+ hifive-unleashed-a00:
+ mach: sifive
+ class: riscv-dtb
+ boot_method: uboot
+ filters:
+ # no console in tinyconfig
+ - blacklist:
+ defconfig: ['tinyconfig']
+ kernel: ['v4.', 'v5.1', 'v5.2']
+
hsdk:
mach: arc
class: arc-dtb
@@ -532,6 +557,11 @@ device_types:
- 'multi_v7_defconfig+kselftest'
kernel: ['v3.18']
+ imx8mn-ddr4-evk:
+ mach: freescale
+ class: arm64-dtb
+ boot_method: uboot
+
jetson-tk1:
mach: tegra
class: arm-dtb
@@ -578,6 +608,12 @@ device_types:
boot_method: uboot
filters:
- blacklist: {defconfig: ['allnoconfig', 'allmodconfig']}
+ flags: ['fastboot']
+ params:
+ kernel_addr: '0x01080000'
+ dtb_addr: '0x1000000'
+ ramdisk_addr: '0x6000000'
+ cmdline: '"console=ttyAML0,115200 consoleblank=0 earlycon"'
meson-g12a-u200:
mach: amlogic
@@ -590,6 +626,7 @@ device_types:
mach: amlogic
class: arm64-dtb
boot_method: uboot
+ flags: ['fastboot']
filters:
- blacklist: {defconfig: ['allnoconfig', 'allmodconfig']}
@@ -600,6 +637,13 @@ device_types:
filters:
- blacklist: {defconfig: ['allnoconfig', 'allmodconfig']}
+ meson-g12b-a311d-khadas-vim3:
+ mach: amlogic
+ class: arm64-dtb
+ boot_method: uboot
+ filters:
+ - blacklist: {defconfig: ['allnoconfig', 'allmodconfig']}
+
meson-gxbb-nanopi-k2:
mach: amlogic
class: arm64-dtb
@@ -672,6 +716,14 @@ device_types:
filters:
- blacklist: {defconfig: ['allnoconfig', 'allmodconfig']}
+ meson-gxm-q200:
+ mach: amlogic
+ class: arm64-dtb
+ boot_method: uboot
+ flags: ['big_endian']
+ filters:
+ - blacklist: {defconfig: ['allnoconfig', 'allmodconfig']}
+
minnowboard-turbot-E3826:
mach: x86
arch: x86_64
@@ -767,7 +819,7 @@ device_types:
guestfs_interface: 'virtio'
machine: 'virt,gic-version=2'
filters:
- - whitelist: {defconfig: ['multi_v7_defconfig', 'vexpress_defconfig']}
+ - whitelist: {defconfig: ['multi_v7_defconfig']}
qemu_arm-virt-gicv3:
base_name: qemu
@@ -780,7 +832,7 @@ device_types:
guestfs_interface: 'virtio'
machine: 'virt,gic-version=3'
filters:
- - whitelist: {defconfig: ['multi_v7_defconfig', 'vexpress_defconfig']}
+ - whitelist: {defconfig: ['multi_v7_defconfig']}
qemu_arm64-virt-gicv2:
base_name: qemu
@@ -900,6 +952,11 @@ device_types:
- blacklist: *allmodconfig_filter
- blacklist: {defconfig: ['multi_v7_defconfig+CONFIG_SMP=n']}
+ sun4i-a10-olinuxino-lime:
+ mach: allwinner
+ class: arm-dtb
+ boot_method: uboot
+
sun50i-a64-bananapi-m64:
mach: allwinner
class: arm64-dtb
@@ -943,6 +1000,11 @@ device_types:
class: arm-dtb
boot_method: uboot
+ sun7i-a20-olinuxino-lime2:
+ mach: allwinner
+ class: arm-dtb
+ boot_method: uboot
+
sun8i-a23-evb:
mach: allwinner
class: arm-dtb
@@ -1072,86 +1134,125 @@ device_types:
test_configs:
- device_type: alpine-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: am57xx-beagle-x15
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- simple
- sleep
- device_type: apq8016-sbc
test_plans:
+ - baseline
- boot
- kselftest
- device_type: ar9331-dpt-module
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: armada-370-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-370-rd
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-375-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-385-db-ap
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-388-clearfog
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-388-gp
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-398-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-3720-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-7040-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-8040-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-xp-db
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-xp-gp
- test_plans: [boot_nfs]
+ test_plans:
+ - baseline
+ - boot-nfs
- device_type: armada-xp-linksys-mamba
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: armada-xp-openblocks-ax3-4
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: arndale
test_plans: [boot, kselftest]
- device_type: at91-sama5d2-xplained
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: at91-sama5d4-xplained
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: bcm2836-rpi-2-b
test_plans:
+ - baseline
- boot
- sleep
- usb
- device_type: bcm2837-rpi-3-b
test_plans:
+ - baseline
- boot
- kselftest
- simple
@@ -1159,218 +1260,332 @@ test_configs:
- device_type: bcm2837-rpi-3-b-32
test_plans:
+ - baseline
- boot
- kselftest
- simple
- device_type: beaglebone-black
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- simple
- device_type: beagle-xm
- test_plans: [boot, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
- device_type: cubietruck
- test_plans: [boot, boot_nfs]
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
- device_type: d03
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: da850-lcdk
- test_plans: [boot]
-
- - device_type: dra7-evm
test_plans:
+ - baseline
- boot
- - kselftest
- - simple
- device_type: dove-cubox
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
+ - device_type: dra7-evm
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
+ - simple
+
- device_type: hi6220-hikey
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- simple
- device_type: hip07-d05
- test_plans: [boot, boot_nfs]
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+
+ - device_type: hifive-unleashed-a00
+ test_plans:
+ - baseline
+ - boot
- device_type: hsdk
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: imx23-olinuxino
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: imx27-phytec-phycard-s-rdk
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: imx28-duckbill
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: imx53-qsrb
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: imx6dl-riotboard
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: imx6q-nitrogen6x
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: imx6ul-pico-hobbit
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: imx6q-sabrelite
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- usb
+ - device_type: imx8mn-ddr4-evk
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+ - kselftest
+
- device_type: jetson-tk1
- test_plans: [boot, boot_nfs, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+ - kselftest
- device_type: kirkwood-db-88f6282
- test_plans: [boot_nfs]
+ test_plans:
+ - baseline
+ - boot-nfs
- device_type: kirkwood-openblocks_a7
- test_plans: [boot, boot_nfs]
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
- device_type: meson8b-odroidc1
- test_plans: [boot, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
- device_type: meson-g12a-sei510
- test_plans: [boot, simple]
+ test_plans:
+ - baseline
+ - baseline-fastboot
+ - boot
+ - simple
- device_type: meson-g12a-u200
- test_plans: [boot, simple]
+ test_plans:
+ - baseline
+ - boot
+ - simple
- device_type: meson-g12a-x96-max
- test_plans: [boot, simple]
+ test_plans:
+ - baseline
+ - boot
+ - simple
- device_type: meson-g12b-odroid-n2
- test_plans: [boot, simple]
+ test_plans:
+ - baseline
+ - boot
+ - simple
+
+ - device_type: meson-g12b-a311d-khadas-vim3
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+ - kselftest
+ - simple
- device_type: meson-gxbb-nanopi-k2
test_plans:
+ - baseline
- boot
- kselftest
- simple
- device_type: meson-gxbb-odroidc2
- test_plans: [boot, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
- device_type: meson-gxbb-p200
- test_plans: [boot, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
- device_type: meson-gxl-s805x-libretech-ac
test_plans:
+ - baseline
- boot
- kselftest
- simple
- device_type: meson-gxl-s905d-p230
test_plans:
+ - baseline
- boot
- kselftest
- simple
- device_type: meson-gxl-s805x-p241
test_plans:
+ - baseline
- boot
- kselftest
- simple
- device_type: meson-gxl-s905x-khadas-vim
test_plans:
+ - baseline
- boot
- kselftest
- simple
- device_type: meson-gxl-s905x-libretech-cc
test_plans:
+ - baseline
- boot
- kselftest
- simple
- device_type: meson-gxm-khadas-vim2
test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+ - kselftest
+ - simple
+
+ - device_type: meson-gxm-q200
+ test_plans:
+ - baseline
- boot
+ - boot-nfs
- kselftest
- simple
- - boot_nfs
- device_type: minnowboard-turbot-E3826
test_plans:
+ - baseline
- boot
- simple
- device_type: mustang
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- device_type: odroid-x2
- test_plans: [boot, boot_nfs, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+ - kselftest
- device_type: odroid-xu3
test_plans:
+ - baseline
- boot
- - boot_nfs
- - igt_drm_kms
+ - boot-nfs
+ - igt-drm-kms
- kselftest
- sleep
- usb
- device_type: orion5x-rd88f5182-nas
- test_plans: [boot_nfs]
+ test_plans:
+ - baseline
+ - boot-nfs
- device_type: ox820-cloudengines-pogoplug-series-3
- test_plans: [boot, boot_nfs]
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
- device_type: panda
- test_plans: [boot, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
- device_type: panda-es
- test_plans: [boot, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
- device_type: peach-pi
test_plans:
+ - baseline
- boot
- cros-ec
- kselftest
@@ -1378,58 +1593,70 @@ test_configs:
- usb
- device_type: qcom-qdf2400
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: qemu_arm-virt-gicv2
test_plans:
+ - baseline_qemu
+ - baseline-uefi_arm
- boot_qemu
- - uefi_arm
- device_type: qemu_arm-virt-gicv3
test_plans:
+ - baseline_qemu
+ - baseline-uefi_arm
- boot_qemu
- simple_qemu
- - uefi_arm
- - v4l2_compliance_qemu_vivid
+ - v4l2-compliance-vivid
- device_type: qemu_arm64-virt-gicv2
test_plans:
+ - baseline_qemu
+ - baseline-uefi_arm64
- boot_qemu
- - uefi_arm64
- device_type: qemu_arm64-virt-gicv3
test_plans:
+ - baseline_qemu
+ - baseline-uefi_arm64
- boot_qemu
- simple_qemu
- - uefi_arm64
- - v4l2_compliance_qemu_vivid
+ - v4l2-compliance-vivid
- device_type: qemu_i386
test_plans:
- - boot
- - uefi_i386
+ - baseline_qemu
+ - baseline-uefi_i386
+ - boot_qemu
- simple_qemu
- device_type: qemu_x86_64
test_plans:
+ - baseline_qemu
+ - baseline-uefi_x86_64
+ - baseline-uefi_x86-mixed
- boot_qemu
- simple_qemu
- - uefi_x86_64
- - uefi_x86-mixed
- - v4l2_compliance_qemu_vivid
+ - v4l2-compliance-vivid
- device_type: r8a7791-porter
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: r8a7795-salvator-x
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- simple
- device_type: r8a7796-m3ulcb
test_plans:
+ - baseline
- boot
- simple
- usb
@@ -1439,140 +1666,214 @@ test_configs:
- baseline
- boot
- cros-ec
- - v4l2_compliance_uvc
+ - sleep
+ - v4l2-compliance-uvc
- device_type: rk3399-gru-kevin
- test_plans: [igt_drm_kms]
+ test_plans: [igt-drm-kms]
filters:
- blacklist: {kernel: ['v3.', 'v4.4', 'v4.9', 'v4.14']}
- device_type: rk3399-puma-haikou
- test_plans: [boot, kselftest]
+ test_plans:
+ - baseline
+ - boot
+ - kselftest
- device_type: rk3288-rock2-square
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- usb
- device_type: rk3328-rock64
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: rk3288-veyron-jaq
test_plans:
- baseline
- boot
- - boot_nfs
+ - boot-nfs
- cros-ec
- - igt_drm_kms
+ - igt-drm-kms
- sleep
- usb
- - v4l2_compliance_uvc
+ - v4l2-compliance-uvc
- device_type: socfpga-cyclone5-socrates
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- sleep
- device_type: snow
test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+ - kselftest
+
+ - device_type: sun4i-a10-olinuxino-lime
+ test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
+ - simple
- device_type: sun50i-a64-bananapi-m64
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun50i-h5-libretech-all-h3-cc
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun50i-h6-orangepi-one-plus
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun50i-h6-pine-h64
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun5i-a13-olinuxino-micro
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun5i-gr8-chip
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun5i-gr8-chip-pro
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun7i-a20-cubieboard2
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
+
+ - device_type: sun7i-a20-olinuxino-lime2
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
+ - kselftest
+ - simple
- device_type: sun8i-a23-evb
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-a33-sinlinx-sina33
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-a33-olinuxino
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-a83t-bananapi-m3
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-a83t-allwinner-h8homlet-v2
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-h2-plus-orangepi-zero
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-h2-plus-orangepi-r1
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-h2-plus-libretech-all-h3-cc
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-h3-libretech-all-h3-cc
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: sun8i-h3-orangepi-pc
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: synquacer-acpi
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: synquacer-dtb
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot
- device_type: tegra124-nyan-big
test_plans:
+ - baseline
- boot
- cros-ec
- - igt_drm_kms
+ - igt-drm-kms
- sleep
- usb
- device_type: x86-atom330
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- kselftest
- simple
- device_type: x86-celeron
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- simple
- device_type: x86-pentium4
test_plans:
+ - baseline
- boot
- - boot_nfs
+ - boot-nfs
- simple
- device_type: x86-x5-z8350
- test_plans: [boot, boot_nfs]
+ test_plans:
+ - baseline
+ - boot
+ - boot-nfs
- device_type: zynq-zc702
- test_plans: [boot]
+ test_plans:
+ - baseline
+ - boot