blob: 94baa671e5ae60b5d0ee8a1f48ca150d8d4812a3 [file] [log] [blame]
Patrick Williams02871c92021-02-01 20:57:19 -06001#!/usr/bin/env python3
2#
3# Build the required docker image to run package unit tests
4#
5# Script Variables:
6# DOCKER_IMG_NAME: <optional, the name of the docker image to generate>
7# default is openbmc/ubuntu-unit-test
8# DISTRO: <optional, the distro to build a docker image against>
9# default is ubuntu:eoan
10# BRANCH: <optional, branch to build from each of the openbmc/
11# repositories>
12# default is master, which will be used if input branch not
13# provided or not found
14# UBUNTU_MIRROR: <optional, the URL of a mirror of Ubuntu to override the
15# default ones in /etc/apt/sources.list>
16# default is empty, and no mirror is used.
17# http_proxy The HTTP address of the proxy server to connect to.
18# Default: "", proxy is not setup if this is not set
19
20import os
21import sys
22from sh import docker, git, nproc, uname
23
24# Read a bunch of environment variables.
25docker_image_name = os.environ.get("DOCKER_IMAGE_NAME", "openbmc/ubuntu-unit-test")
26distro = os.environ.get("DISTRO", "ubuntu:focal")
27branch = os.environ.get("BRANCH", "master")
28ubuntu_mirror = os.environ.get("UBUNTU_MIRROR")
29http_proxy = os.environ.get("http_proxy")
30
31# Set up some common variables.
32proc_count = nproc().strip()
33username = os.environ.get("USER")
34homedir = os.environ.get("HOME")
35gid = os.getgid()
36uid = os.getuid()
37
38# Determine the architecture for Docker.
39arch = uname("-m").strip()
40if arch == "ppc64le":
41 docker_base = "ppc64le/"
42elif arch == "x86_64":
43 docker_base = ""
44else:
45 print(f"Unsupported system architecture({arch}) found for docker image")
46 sys.exit(1)
47
48# These packages we use 'HEAD' for.
49head_pkgs = [
50 "openbmc/phosphor-objmgr",
51 "openbmc/sdbusplus",
52 "openbmc/sdeventplus",
53 "openbmc/stdplus",
54 "openbmc/gpioplus",
55 "openbmc/phosphor-logging",
56 "openbmc/phosphor-dbus-interfaces",
57 "open-power/pdbg",
58 "openbmc/pldm",
59]
60
61# Packages with fixed revisions.
62pkg_rev = {
63 "boost": "1.74.0",
64 "cereal": "v1.3.0",
65 "catch2": "v2.12.2",
66 "CLI11": "v1.9.0",
67 "fmt": "6.2.1",
68 # Snapshot from 2020-01-03
69 "function2": "3a0746bf5f601dfed05330aefcb6854354fce07d",
70 # Snapshot from 2020-02-13
71 "googletest": "23b2a3b1cf803999fb38175f6e9e038a4495c8a5",
72 # Release 2020-08-06
73 "json": "v3.9.1",
74 # Snapshot from 2019-05-24
75 "lcov": "75fbae1cfc5027f818a0bb865bf6f96fab3202da",
76 # dev-5.0 2019-05-03
77 "linux-headers": "8bf6567e77f7aa68975b7c9c6d044bba690bf327",
78 # Snapshot from 2019-09-03
79 "libvncserver": "1354f7f1bb6962dab209eddb9d6aac1f03408110",
80 "span-lite": "v0.7.0",
81 # version from meta-openembedded/meta-oe/recipes-support/libtinyxml2/libtinyxml2_5.0.1.bb
82 "tinyxml2": "37bc3aca429f0164adf68c23444540b4a24b5778",
83 # version from /meta-openembedded/meta-oe/recipes-devtools/boost-url/boost-url_git.bb
84 "boost-url": "a56ae0df6d3078319755fbaa67822b4fa7fd352b",
85 # version from meta-openembedded/meta-oe/recipes-devtools/valijson/valijson_git.bb
86 "valijson": "c2f22fddf599d04dc33fcd7ed257c698a05345d9",
87 # version from meta-openembedded/meta-oe/recipes-devtools/nlohmann-fifo/nlohmann-fifo_git.bb
88 "fifo_map": "0dfbf5dacbb15a32c43f912a7e66a54aae39d0f9",
89}
90
91# Look up the HEAD for 'head_pkgs' and insert them into 'pkg_rev'.
92pkg_lookups = {}
93for pkg in head_pkgs:
94 pkg_lookups[pkg] = git(
95 "ls-remote", "--heads", f"https://github.com/{pkg}", _bg=True
96 )
97for pkg, result in pkg_lookups.items():
98 for line in result.stdout.decode().split("\n"):
99 if f"refs/heads/{branch}" in line:
100 pkg_rev[pkg] = line.strip().split()[0]
101 elif "refs/heads/master" in line and p not in pkg_rev:
102 pkg_rev[pkg] = line.strip().split()[0]
103
104# Create the contents of the '/tmp/depcache'.
105# This needs to be sorted for consistency.
106depcache = ""
107for pkg in sorted(head_pkgs):
108 if pkg in pkg_rev:
109 depcache += "%s:%s," % (pkg, pkg_rev[pkg])
110
111# Define common flags used for builds
112prefix = "/usr/local"
113configure_flags = " ".join(
114 [
115 f"--prefix={prefix}",
116 ]
117)
118cmake_flags = " ".join(
119 [
120 "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
121 "-DBUILD_SHARED_LIBS=ON",
122 f"-DCMAKE_INSTALL_PREFIX:PATH={prefix}",
123 ]
124)
125meson_flags = " ".join(
126 [
127 "--wrap-mode=nodownload",
128 f"-Dprefix={prefix}",
129 ]
130)
131
132
133def stagename(name):
134 if not name.startswith("openbmc/"):
135 name = "openbmc/" + name
136 return name.replace("/", "-")
137
138
139# Build the commands needed to compose our final image
140# We must sort the packages, otherwise we might produce an unstable
141# docker file and rebuild the image unnecessarily
142copy_cmds = ""
143for pkg in sorted(pkg_rev.keys()):
144 copy_cmds += f"COPY --from={stagename(pkg)} {prefix} {prefix}\n"
145 # Workaround for upstream docker bug and multiple COPY cmds
146 # https://github.com/moby/moby/issues/37965
147 copy_cmds += "RUN true\n"
148
149# Special flags if setting up a deb mirror.
150mirror = ""
151if "ubuntu" in distro and ubuntu_mirror:
152 mirror = f"""
153RUN echo "deb {ubuntu_mirror} $(. /etc/os-release && echo $VERSION_CODENAME) main restricted universe multiverse" > /etc/apt/sources.list && \\
154 echo "deb {ubuntu_mirror} $(. /etc/os-release && echo $VERSION_CODENAME)-updates main restricted universe multiverse" >> /etc/apt/sources.list && \\
155 echo "deb {ubuntu_mirror} $(. /etc/os-release && echo $VERSION_CODENAME)-security main restricted universe multiverse" >> /etc/apt/sources.list && \\
156 echo "deb {ubuntu_mirror} $(. /etc/os-release && echo $VERSION_CODENAME)-proposed main restricted universe multiverse" >> /etc/apt/sources.list && \\
157 echo "deb {ubuntu_mirror} $(. /etc/os-release && echo $VERSION_CODENAME)-backports main restricted universe multiverse" >> /etc/apt/sources.list
158"""
159
160# Special flags for proxying.
161proxy_cmd = ""
162proxy_args = []
163if http_proxy:
164 proxy_cmd = f"""
165RUN echo "[http]" >> {homedir}/.gitconfig && \
166 echo "proxy = {http_proxy}" >> {homedir}/.gitconfig
167"""
168 proxy_args.extend(
169 [
170 "--build-arg",
171 f"http_proxy={http_proxy}",
172 "--build-arg",
173 "https_proxy={https_proxy}",
174 ]
175 )
176
177# Create docker image that can run package unit tests
178dockerfile = f"""
179FROM {docker_base}{distro} as openbmc-base
180
181{mirror}
182
183ENV DEBIAN_FRONTEND noninteractive
184
185ENV PYTHONPATH "/usr/local/lib/python3.8/site-packages/"
186
187# We need the keys to be imported for dbgsym repos
188# New releases have a package, older ones fall back to manual fetching
189# https://wiki.ubuntu.com/Debug%20Symbol%20Packages
190RUN apt-get update && ( apt-get install ubuntu-dbgsym-keyring || ( apt-get install -yy dirmngr && \
191 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F2EDC64DC5AEE1F6B9C621F0C8CAB6595FDFF622 ) )
192
193# Parse the current repo list into a debug repo list
194RUN sed -n '/^deb /s,^deb [^ ]* ,deb http://ddebs.ubuntu.com ,p' /etc/apt/sources.list >/etc/apt/sources.list.d/debug.list
195
196# Remove non-existent debug repos
197RUN sed -i '/-\(backports\|security\) /d' /etc/apt/sources.list.d/debug.list
198
199RUN cat /etc/apt/sources.list.d/debug.list
200
201RUN apt-get update && apt-get dist-upgrade -yy && apt-get install -yy \
202 gcc-10 \
203 g++-10 \
204 libc6-dbg \
205 libc6-dev \
206 libtool \
207 bison \
208 libdbus-1-dev \
209 flex \
210 cmake \
211 python3 \
212 python3-dev\
213 python3-yaml \
214 python3-mako \
215 python3-pip \
216 python3-setuptools \
217 python3-git \
218 python3-socks \
219 pkg-config \
220 autoconf \
221 autoconf-archive \
222 libsystemd-dev \
223 systemd \
224 libssl-dev \
225 libevdev-dev \
226 libevdev2-dbgsym \
227 libjpeg-dev \
228 libpng-dev \
229 ninja-build \
230 sudo \
231 curl \
232 git \
233 dbus \
234 iputils-ping \
235 clang-10 \
236 clang-format-10 \
237 clang-tidy-10 \
238 clang-tools-10 \
239 shellcheck \
240 npm \
241 iproute2 \
242 libnl-3-dev \
243 libnl-genl-3-dev \
244 libconfig++-dev \
245 libsnmp-dev \
246 valgrind \
247 valgrind-dbg \
248 libpam0g-dev \
249 xxd \
250 libi2c-dev \
251 wget \
252 libldap2-dev \
253 libprotobuf-dev \
254 libperlio-gzip-perl \
255 libjson-perl \
256 protobuf-compiler \
257 libgpiod-dev \
258 device-tree-compiler \
259 cppcheck \
260 libpciaccess-dev \
261 libmimetic-dev \
262 libxml2-utils \
263 libxml-simple-perl
264
265RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 1000 \
266 --slave /usr/bin/g++ g++ /usr/bin/g++-10 \
267 --slave /usr/bin/gcov gcov /usr/bin/gcov-10 \
268 --slave /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-dump-10 \
269 --slave /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-tool-10
270
271
272RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-10 1000 \
273 --slave /usr/bin/clang++ clang++ /usr/bin/clang++-10 \
274 --slave /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-10 \
275 --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-10 \
276 --slave /usr/bin/run-clang-tidy.py run-clang-tidy.py /usr/bin/run-clang-tidy-10.py
277
278RUN pip3 install inflection
279RUN pip3 install pycodestyle
280RUN pip3 install jsonschema
281RUN pip3 install meson==0.54.3
282RUN pip3 install protobuf
283
284FROM openbmc-base as openbmc-lcov
285RUN curl -L https://github.com/linux-test-project/lcov/archive/{pkg_rev['lcov']}.tar.gz | tar -xz && \
286cd lcov-* && \
287make -j{proc_count} && \
288make install
289
290FROM openbmc-base as openbmc-function2
291RUN mkdir {prefix}/include/function2 && \
292curl -L -o {prefix}/include/function2/function2.hpp https://raw.githubusercontent.com/Naios/function2/{pkg_rev['function2']}/include/function2/function2.hpp
293
294FROM openbmc-base as openbmc-googletest
295RUN curl -L https://github.com/google/googletest/archive/{pkg_rev['googletest']}.tar.gz | tar -xz && \
296cd googletest-* && \
297mkdir build && \
298cd build && \
299CXXFLAGS=-std=c++17 cmake {cmake_flags} -DTHREADS_PREFER_PTHREAD_FLAG=ON .. && \
300make -j{proc_count} && \
301make install
302
303FROM openbmc-base as openbmc-catch2
304RUN curl -L https://github.com/catchorg/Catch2/archive/{pkg_rev['catch2']}.tar.gz | tar -xz && \
305cd Catch2-* && \
306mkdir build && \
307cd build && \
308cmake {cmake_flags} -DBUILD_TESTING=OFF -DCATCH_INSTALL_DOCS=OFF .. && \
309make -j{proc_count} && \
310make install
311
312FROM openbmc-base as openbmc-cereal
313RUN curl -L https://github.com/USCiLab/cereal/archive/{pkg_rev['cereal']}.tar.gz | tar -xz && \
314cp -a cereal-*/include/cereal/ {prefix}/include/
315
316FROM openbmc-base as openbmc-CLI11
317RUN curl -L https://github.com/CLIUtils/CLI11/archive/{pkg_rev['CLI11']}.tar.gz | tar -xz && \
318cd CLI11-* && \
319mkdir build && \
320cd build && \
321cmake {cmake_flags} -DCLI11_BUILD_DOCS=OFF -DBUILD_TESTING=OFF -DCLI11_BUILD_EXAMPLES=OFF .. && \
322make -j{proc_count} && \
323make install
324
325FROM openbmc-base as openbmc-fmt
326RUN curl -L https://github.com/fmtlib/fmt/archive/{pkg_rev['fmt']}.tar.gz | tar -xz && \
327cd fmt-* && \
328mkdir build && \
329cd build && \
330cmake {cmake_flags} -DFMT_DOC=OFF -DFMT_TEST=OFF .. && \
331make -j{proc_count} && \
332make install
333
334FROM openbmc-base as openbmc-json
335RUN mkdir {prefix}/include/nlohmann/ && \
336curl -L -o {prefix}/include/nlohmann/json.hpp https://github.com/nlohmann/json/releases/download/{pkg_rev['json']}/json.hpp && \
337ln -s nlohmann/json.hpp {prefix}/include/json.hpp
338
339FROM openbmc-base as openbmc-fifo_map
340RUN curl -L https://github.com/nlohmann/fifo_map/archive/{pkg_rev['fifo_map']}.tar.gz | tar -xz && \
341cd fifo_map-*/src && cp fifo_map.hpp {prefix}/include/
342
343FROM openbmc-base as openbmc-span-lite
344RUN curl -L https://github.com/martinmoene/span-lite/archive/{pkg_rev['span-lite']}.tar.gz | tar -xz && \
345cd span-lite-* && \
346mkdir build && \
347cd build && \
348cmake {cmake_flags} -DSPAN_LITE_OPT_BUILD_TESTS=OFF .. && \
349make -j{proc_count} && \
350make install
351
352FROM openbmc-base as openbmc-linux-headers
353RUN curl -L https://github.com/openbmc/linux/archive/{pkg_rev['linux-headers']}.tar.gz | tar -xz && \
354cd linux-* && \
355make -j{proc_count} defconfig && \
356make INSTALL_HDR_PATH=/usr/local headers_install
357
358FROM openbmc-base as openbmc-boost
359RUN curl -L https://dl.bintray.com/boostorg/release/{pkg_rev['boost']}/source/boost_$(echo "{pkg_rev['boost']}" | tr '.' '_').tar.bz2 | tar -xj && \
360cd boost_*/ && \
361./bootstrap.sh --prefix={prefix} --with-libraries=context,coroutine && \
362./b2 && ./b2 install --prefix={prefix}
363
364FROM openbmc-base as openbmc-tinyxml2
365RUN curl -L https://github.com/leethomason/tinyxml2/archive/{pkg_rev['tinyxml2']}.tar.gz | tar -xz && \
366cd tinyxml2-* && \
367mkdir build && \
368cd build && \
369cmake {cmake_flags} .. && \
370make -j{proc_count} && \
371make install
372
373FROM openbmc-base as openbmc-boost-url
374RUN curl -L https://github.com/CPPAlliance/url/archive/{pkg_rev['boost-url']}.tar.gz | tar -xz && \
375cd url-* && \
376mkdir buildir && \
377cd buildir && \
378cmake {cmake_flags} -DBOOST_URL_STANDALONE=ON -DBOOST_URL_BUILD_TESTS=OFF -DBOOST_URL_BUILD_EXAMPLES=OFF .. && \
379make -j{proc_count} && \
380make install
381
382FROM openbmc-base as openbmc-valijson
383RUN curl -L https://github.com/tristanpenman/valijson/archive/{pkg_rev['valijson']}.tar.gz | tar -xz && \
384cd valijson-* && \
385mkdir build && \
386cd build && \
387cmake {cmake_flags} -DINSTALL_HEADERS=1 -DBUILD_TESTS=0 .. && \
388make -j{proc_count} && \
389make install
390
391FROM openbmc-base as openbmc-libvncserver
392RUN curl -L https://github.com/LibVNC/libvncserver/archive/{pkg_rev['libvncserver']}.tar.gz | tar -xz && \
393cd libvncserver-* && \
394mkdir build && \
395cd build && \
396cmake {cmake_flags} .. && \
397make -j{proc_count} && \
398make install
399
400FROM openbmc-base as openbmc-stdplus
401COPY --from=openbmc-fmt {prefix} {prefix}
402COPY --from=openbmc-span-lite {prefix} {prefix}
403RUN curl -L https://github.com/openbmc/stdplus/archive/{pkg_rev['openbmc/stdplus']}.tar.gz | tar -xz && \
404cd stdplus-* && \
405meson build {meson_flags} -Dtests=disabled -Dexamples=false && \
406ninja -C build && \
407ninja -C build install
408
409FROM openbmc-base as openbmc-sdbusplus
410RUN curl -L https://github.com/openbmc/sdbusplus/archive/{pkg_rev['openbmc/sdbusplus']}.tar.gz | tar -xz && \
411cd sdbusplus-* && \
412cd tools && ./setup.py install --root=/ --prefix={prefix} && \
413cd .. && meson build {meson_flags} -Dtests=disabled -Dexamples=disabled && \
414ninja -C build && \
415ninja -C build install
416
417FROM openbmc-base as openbmc-sdeventplus
418COPY --from=openbmc-function2 {prefix} {prefix}
419COPY --from=openbmc-stdplus {prefix} {prefix}
420RUN curl -L https://github.com/openbmc/sdeventplus/archive/{pkg_rev['openbmc/sdeventplus']}.tar.gz | tar -xz && \
421cd sdeventplus-* && \
422meson build {meson_flags} -Dtests=disabled -Dexamples=false && \
423ninja -C build && \
424ninja -C build install
425
426FROM openbmc-base as openbmc-gpioplus
427COPY --from=openbmc-stdplus {prefix} {prefix}
428RUN curl -L https://github.com/openbmc/gpioplus/archive/{pkg_rev['openbmc/gpioplus']}.tar.gz | tar -xz && \
429cd gpioplus-* && \
430meson build {meson_flags} -Dtests=disabled -Dexamples=false && \
431ninja -C build && \
432ninja -C build install
433
434FROM openbmc-base as openbmc-phosphor-dbus-interfaces
435COPY --from=openbmc-sdbusplus {prefix} {prefix}
436RUN curl -L https://github.com/openbmc/phosphor-dbus-interfaces/archive/{pkg_rev['openbmc/phosphor-dbus-interfaces']}.tar.gz | tar -xz && \
437cd phosphor-dbus-interfaces-* && \
438meson build {meson_flags} -Ddata_org_open_power=true -Ddata_com_ibm=true && \
439ninja -C build && \
440ninja -C build install
441
442FROM openbmc-base as openbmc-phosphor-logging
443COPY --from=openbmc-cereal {prefix} {prefix}
444COPY --from=openbmc-sdbusplus {prefix} {prefix}
445COPY --from=openbmc-sdeventplus {prefix} {prefix}
446COPY --from=openbmc-phosphor-dbus-interfaces {prefix} {prefix}
447COPY --from=openbmc-fifo_map {prefix} {prefix}
448RUN curl -L https://github.com/openbmc/phosphor-logging/archive/{pkg_rev['openbmc/phosphor-logging']}.tar.gz | tar -xz && \
449cd phosphor-logging-* && \
450./bootstrap.sh && \
451./configure {configure_flags} --enable-metadata-processing YAML_DIR={prefix}/share/phosphor-dbus-yaml/yaml && \
452make -j{proc_count} && \
453make install
454
455FROM openbmc-base as openbmc-phosphor-objmgr
456COPY --from=openbmc-boost {prefix} {prefix}
457COPY --from=openbmc-sdbusplus {prefix} {prefix}
458COPY --from=openbmc-tinyxml2 {prefix} {prefix}
459COPY --from=openbmc-phosphor-logging {prefix} {prefix}
460RUN curl -L https://github.com/openbmc/phosphor-objmgr/archive/{pkg_rev['openbmc/phosphor-objmgr']}.tar.gz | tar -xz && \
461cd phosphor-objmgr-* && \
462./bootstrap.sh && \
463./configure {configure_flags} && \
464make -j{proc_count} && \
465make install
466
467FROM openbmc-base as openbmc-open-power-pdbg
468RUN curl -L https://github.com/open-power/pdbg/archive/{pkg_rev['open-power/pdbg']}.tar.gz | tar -xz && \
469cd pdbg-* && \
470./bootstrap.sh && \
471./configure {configure_flags} && \
472make -j{proc_count} && \
473make install
474
475FROM openbmc-base as openbmc-pldm
476COPY --from=openbmc-sdbusplus {prefix} {prefix}
477COPY --from=openbmc-sdeventplus {prefix} {prefix}
478COPY --from=openbmc-boost {prefix} {prefix}
479COPY --from=openbmc-phosphor-dbus-interfaces {prefix} {prefix}
480COPY --from=openbmc-phosphor-logging {prefix} {prefix}
481COPY --from=openbmc-json {prefix} {prefix}
482COPY --from=openbmc-CLI11 {prefix} {prefix}
483RUN curl -L https://github.com/openbmc/pldm/archive/{pkg_rev['openbmc/pldm']}.tar.gz | tar -xz && \
484cd pldm-* && \
485meson build {meson_flags} -Dlibpldm-only=enabled -Doem-ibm=enabled -Dtests=disabled && \
486ninja -C build && \
487ninja -C build install
488
489# Build the final output image
490FROM openbmc-base
491{copy_cmds}
492
493# Some of our infrastructure still relies on the presence of this file
494# even though it is no longer needed to rebuild the docker environment
495# NOTE: The file is sorted to ensure the ordering is stable.
496RUN echo '{depcache}' > /tmp/depcache
497
498# Final configuration for the workspace
499RUN grep -q {gid} /etc/group || groupadd -g {gid} {username}
500RUN mkdir -p "{os.path.dirname(homedir)}"
501RUN grep -q {uid} /etc/passwd || useradd -d {homedir} -m -u {uid} -g {gid} {username}
502RUN sed -i '1iDefaults umask=000' /etc/sudoers
503RUN echo "{username} ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
504
505{proxy_cmd}
506
507RUN /bin/bash
508"""
509
510# Do the docker build.
511for line in docker.build(
512 proxy_args,
513 "--network=host",
514 "-t",
515 docker_image_name,
516 "-",
517 _in=dockerfile,
518 _iter=True,
519):
520 print(line, end="", flush=True)