blob: 54b2c8a01d47cd3c27bacedee44bc1e123b1fc7c [file] [log] [blame] [view]
# Prow Presubmit for KUnit
KUnit uses Prow for presubmit and CI.
This repository contains all the code and instructions needed for generating a
docker container for building and running KUnit tests on Prow, and then using
that container with a Prow cluster.
The official repo for Prow is
[test-infra](https://github.com/kubernetes/test-infra), Kubernetes' test
infrastructure. It enables us to run presubmit jobs on changes to our gerrit
repo against an arbitrary docker container image. We have pushed the docker
image generated from here to gcr.io/kunit-presubmit/kunit. The image is pulled
and deployed by our prow cluster, source is pulled into working directory of
container from
[kunit source](https://kunit.googlesource.com/linux/kunit/alpha/master), and
entrypoint script (kunit.sh) is ran. The script copies kunitconfig to working
directory, runs kunit.py, and sends output to job artifacts that can be viewed
later. Prow will comment on the Gerrit change with the status of the job
(successful, a test failed, a test crashed, etc) and link to Prow URL for more
details. The container is currently configured to require the inclusion of
kunitconfig in repo. A convenience of this model is that updating the job image
can be done without change to ProwJob configuration.
## ProwJob Docker image
The docker image is configured in the
[Dockerfile](Dockerfile). It is
based off of Debian, with kernel build tools installed and the script ran by the
prowjob included. A couple peculiarities of building/running UML in a docker
container are solved in the deployment configuration discussed below under "Prow
Job Specification".
To build and push, you can either use Bazel or Docker:
### Bazel
Bazel allows building/pushing without dependence on docker and automates
using latest kunitconfig in build. As Bazel enforces deterministic
builds, all debian packages depended on are listed in [debs.bzl](debs.bzl), and
based off the snapshot specified in the *dpkg_src* rule in
[WORKSPACE](WORKSPACE).
#### Update
The direct dependencies needed are:
* build-essential
* bc
* m4
* flex
* bison
* python3
If recursive dependencies change in future snapshots, [debs.bzl](debs.bzl) must
be manually updated with a list of all dependencies.
A simple solution:
```shell
# run interactive shell in latest debian image
docker run -it --rm debian
# update list of available packages
apt update
# generate list of all required dependencies recursively
apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts \
--no-breaks --no-replaces --no-enhances --no-pre-depends \
build-essential bc m4 flex bison python3 | grep "^\w" | sort -u
```
The snapshot used can be updated as specified in the
[distroless package manager bazel rules](
https://github.com/GoogleContainerTools/distroless/tree/master/package_manager).
#### Use
```shell
# build prowjob image
bazel build :kunit
# push to configured repo
bazel run :push_kunit
# build test image with kunit source and add to local docker
bazel run :kunit_test
# need docker to run, results to stdout
docker run --privileged --tmpfs /dev/shm:exec kunit-presubmit/test:kunit_test
```
### Docker
You must have [Docker](https://docs.docker.com/install/linux/docker-ce/debian/)
Make sure to enable
[sudoless docker](https://docs.docker.com/install/linux/linux-postinstall/)
(fixes gcr push
authentication problems).
Now to build and push image :
```shell
# build image
docker build . gcr.io/kunit-presubmit/kunit
# confirm image is built
docker images
# push to gcr
docker push gcr.io/kunit-presubmit/kunit
```
To test the container locally:
```shell
# have tmp directory with source checked out to $TMP/linux
cp Dockerfile.test $TMP/Dockerfile
cd $TMP
# build test container which includes source
docker build . -t test
# run with args to handle issues with UML in Docker.
docker run --privileged --tmpfs /dev/shm:exec test
# extract log
RUN=$(docker container ls --last 1 -q)
docker cp $RUN:/artifacts/kunit.log .
cat kunit.log
# cleanup container
docker rm $RUN
```
Note: Testing with an interactive shell results in unexpected behaviour. Running
the UML Kernel in an entrypoint script works as intended but fails in an
interactive shell.
### Registry
By default, we have configured our install to use Google Container Registry.
This requires installing [Google Cloud SDK](
https://cloud.google.com/sdk/install) and configuring with project to push to.
If using docker to push, you will need to enable gcloud authentication first to
push with `gcloud auth configure-docker`.
## Prow Job Specification
Prow Jobs are detailed at
[testinfra/prow/jobs.md](https://github.com/kubernetes/test-infra/blob/master/prow/jobs.md).
The prow job specification is held in the
[config.yaml](config.yaml). It
specifies the gerrit repo for prow to poll and the specifications for the
container. We found that running the container privileged and mounting a
emptydir at /dev/shm fixed KUnit build errors. There may be more secure methods,
but as prow doesn't expose job containers to external resources, this solution
results in the cleanest Dockerfile. We are using the decorated prow job which is
recommended for all new prowjobs and detailed at
[test-infra/prow/pod-utilities.md](https://github.com/kubernetes/test-infra/blob/master/prow/pod-utilities.md).
## Job Script
The job script and kunitconfig stored inside in the docker image are
[kunit.sh](kunit.sh) and
[kunitconfig](kunitconfig).
Prow sets the environment variable ARTIFACTS to specify a directory that will be
exported to gcloud on job completion. It additionally sends all data send to
stdout/stderr to the reporting interface. Exit code of 0 signals success and 1
signals failure akin to regular shell scripts.
## Prow Cluster Deployment
To deploy in any Kubernetes environment, first read Prow deployment
documentation [here](https://github.com/kubernetes/test-infra/blob/master/prow/\
getting_started_deploy.md) and for further clarification, the Kubernetes
documentation [here](https://kubernetes.io/docs/setup/). Prow comes with several
[components](https://github.com/kubernetes/test-infra/blob/master/prow/cmd/README.md),
several of which are only necessary for interacting with github webhooks. We
have included here a [deployment.yaml](deployment.yaml) which includes just the
components needed to poll gerrit repos. For every new gerrit repo to run
presubmits on, you will need to update the
[Gerrit](https://github.com/kubernetes/test-infra/tree/master/prow/cmd/gerrit)
component in the deployment accordingly.
Checkout [prow/cluster/starter.yaml](
https://github.com/kubernetes/test-infra/blob/master/prow/cluster/starter.yaml)
for github presubmit instructions which requires oauth token authentication.
Job configuration in config.yaml does not need to change.
Succinctly, a Kubernetes deployment file specifies all the API objects needed
for deployment. Each prow component is a container pod that is described in
an object of kind *Deployment*, specifying a Docker image that the deployment
will launch. *Services* specify extra-pod communication and
*ServiceAccount*s provide an identity to the processes that run in these pods.
*Role*s and *RoleBinding*s provide RBAC authorization for components. Read this
[article](https://www.cncf.io/blog/2018/08/01/demystifying-rbac-in-kubernetes/)
on RBAC in Kubernetes if documentation is not sufficient.
*PersistentVolumeClaim* are a type of Volume used for maintaining state and
is used for gerrit to keep track of the latest synced commit. You may also need
to configure the *Ingress* depending on your network / deployment environment
for all external communication.
You will also need a git https cookie file to interact with your gerrit
instances as anonymous access is not currently supported. For a token
periodically authenticated with gcloud, see/deploy [grandmatriarch](
https://github.com/kubernetes/test-infra/blob/master/prow/cmd/grandmatriarch/bake.sh)
(TODO(avikr) BUG #120081009: change documentation upon gcr image update)