Skip to content

Commit

Permalink
fix: github workflows
Browse files Browse the repository at this point in the history
Signed-off-by: Oleksii Orel <[email protected]>
  • Loading branch information
olexii4 committed May 11, 2024
1 parent da6f498 commit 6bbc2b9
Show file tree
Hide file tree
Showing 4 changed files with 320 additions and 27 deletions.
78 changes: 53 additions & 25 deletions .devfile.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,40 +1,68 @@
FROM quay.io/devfile/universal-developer-image:ubi8-6eb0041
FROM docker.io/debian:buster

# Switching to root user (setting UID to 0) because next
# commands require root privileges. Universal Developer
# Image default user has UID set to 10001.
USER 0
USER root
# Install openwrt build dependencies
RUN apt-get update &&\
apt-get install -y \
sudo ccache time git-core subversion build-essential g++ bash make \
libssl-dev patch libncurses5 libncurses5-dev zlib1g-dev gawk \
flex gettext wget zip unzip xz-utils python python-distutils-extra \
python3 python3-distutils-extra rsync curl libsnmp-dev liblzma-dev \
libpam0g-dev cpio rsync re2c && \
wget https://github.com/cli/cli/releases/download/v2.39.2/gh_2.39.2_linux_amd64.deb && \
apt-get install -f ./gh_2.39.2_linux_amd64.deb && \
rm -f ./gh_2.39.2_linux_amd64.deb && \
apt-get clean && \
useradd -m user && \
echo 'user ALL=NOPASSWD: ALL' > /etc/sudoers.d/user

RUN dnf -y update && dnf -y install \
gcc gcc-c++ make ncurses-devel patch rsync tar unzip bzip2 wget which diffutils python2 python3 perl &&\
dnf -y clean all --enablerepo='*'
# Install Node.js for che-code editor
ARG NODE_VERSION=v20.12.2
ARG NODE_DISTRO=linux-x64
ARG NODE_BASE_URL=https://nodejs.org/dist/${NODE_VERSION}

RUN npm install -g http-server
# Switch back to default user
USER 10001
RUN curl -fsSL ${NODE_BASE_URL}/node-${NODE_VERSION}-${NODE_DISTRO}.tar.gz -o node-${NODE_VERSION}-${NODE_DISTRO}.tar.gz \
&& mkdir -p /usr/local/lib/nodejs \
&& tar -xzf node-${NODE_VERSION}-${NODE_DISTRO}.tar.gz -C /usr/local/lib/nodejs \
&& rm node-${NODE_VERSION}-${NODE_DISTRO}.tar.gz

ENV VSCODE_NODEJS_RUNTIME_DIR=/usr/local/lib/nodejs/node-${NODE_VERSION}-${NODE_DISTRO}/bin
ENV PATH=${VSCODE_NODEJS_RUNTIME_DIR}:$PATH

RUN apt-get install -y npm \
&& npm install -g http-server

USER user

# Install OpenWRT build dependencies
ARG OPENWRT_BASE_URL='https://github.com/openwrt/openwrt'
ARG OPENWRT_VERSION='23.05.0-rc1'
ARG OPENWRT_VERSION='21.02.3'

RUN mkdir -p /tmp/pre-install /tmp/pre-install/openwrt /tmp/pre-install/openwrt/package

COPY ${PWD}/package/helloworld /tmp/helloworld
COPY ${PWD}/configs/.x86-generic.config /tmp/.config
COPY ${PWD}/package/helloworld /tmp/pre-install/openwrt/package/helloworld
COPY ${PWD}/configs/.x86-generic.config /tmp/pre-install/openwrt/.config

RUN mkdir -p /tmp/pre-install /tmp/pre-install/openwrt /tmp/pre-install/openwrt/${OPENWRT_VERSION} \
RUN cd /tmp/pre-install \
&& curl "${OPENWRT_BASE_URL}/archive/refs/tags/v${OPENWRT_VERSION}.zip" -L -o "/tmp/pre-install/openwrt-${OPENWRT_VERSION}.zip" \
&& unzip "/tmp/pre-install/openwrt-${OPENWRT_VERSION}.zip" -d /tmp/pre-install \
&& rm -rf /tmp/pre-install/openwrt-${OPENWRT_VERSION}.zip \
&& cd /tmp/pre-install/openwrt-${OPENWRT_VERSION} \
&& cp /tmp/pre-install/openwrt/.config /tmp/pre-install/openwrt-${OPENWRT_VERSION}/.config \
&& cp -r /tmp/pre-install/openwrt/package /tmp/pre-install/openwrt-${OPENWRT_VERSION}/package \
&& cd /tmp/pre-install/openwrt-${OPENWRT_VERSION} \
&& scripts/feeds update -a -f \
&& scripts/feeds install -a -f \
&& cp /tmp/.config /tmp/pre-install/openwrt-${OPENWRT_VERSION}/.config \
&& cp -r /tmp/helloworld /tmp/pre-install/openwrt-${OPENWRT_VERSION}/package/helloworld \
&& cd /tmp/pre-install/openwrt-${OPENWRT_VERSION} \
&& cp /tmp/pre-install/openwrt/.config /tmp/pre-install/openwrt-${OPENWRT_VERSION}/.config \
&& make defconfig \
&& make -j1 \
&& mv bin /tmp/pre-install/openwrt/${OPENWRT_VERSION}/bin \
&& mv build_dir /tmp/pre-install/openwrt/${OPENWRT_VERSION}/build_dir \
&& mv dl /tmp/pre-install/openwrt/${OPENWRT_VERSION}/dl \
&& mv feeds /tmp/pre-install/openwrt/${OPENWRT_VERSION}/feeds \
&& mv staging_dir /tmp/pre-install/openwrt/${OPENWRT_VERSION}/staging_dir \
&& mv tmp /tmp/pre-install/openwrt/${OPENWRT_VERSION}/tmp \
&& make -j$(nproc) \
&& zip -r bin.zip bin/* \
&& rm -r bin \
&& mv bin.zip ../openwrt \
&& zip -r feeds.zip feeds/* \
&& rm -r feeds \
&& mv feeds.zip ../openwrt \
&& cd /tmp/pre-install \
&& rm -rf /tmp/pre-install/openwrt-${OPENWRT_VERSION}

CMD ["tail", "-f", "/dev/null"]
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to quay.io
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/qemu-image-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Build of the QEMU container image

on:
push:
branches: [dockerfile]

jobs:
build_image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to quay.io
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Build and push image
uses: docker/build-push-action@v4
with:
context: .
file: dockerfiles/qemu.Dockerfile
push: true
tags: quay.io/che-incubator/openwrt-runner:latest
240 changes: 240 additions & 0 deletions dockerfiles/qemu.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
FROM docker.io/library/alpine:3.19.1

# Install QEMU, remove large unnecessary files
RUN apk add --no-cache \
curl \
make \
qemu-chardev-spice \
qemu-hw-display-virtio-vga \
qemu-hw-usb-redirect \
qemu-img \
qemu-system-x86_64 \
qemu-ui-spice-core \
socat \
perl \
openssh \
sshpass \
&& \
rm -f /usr/share/qemu/edk2-*

# Support Arbitrary User IDs in container
RUN echo -e '#!/bin/sh\n\
set -ex \n\
if ! whoami &> /dev/null; then \n\
if [ -w /etc/passwd ]; then \n\
echo "container:x:$(id -u):0:Container User:/tmp:/sbin/nologin" >> /etc/passwd \n\
echo "container:x:$(id -u):$(id -u)" >> /etc/group \n\
fi \n\
fi \n\
\n' > /usr/local/bin/create-container-user.sh && \
chmod +x /usr/local/bin/create-container-user.sh && \
chmod g=u /etc/passwd && \
chmod g=u /etc/group

# Provision VM disk image
RUN echo -e '#!/bin/sh\n\
set -ex \n\
if [ ! -f /projects/openwrt-helloworld/output/openwrt-*combined.img.gz ]; then \n\
echo "No /projects/openwrt-helloworld/output/openwrt-*combined.img.gz file." \n\
exit 1 \n\
fi \n\
if [ -f /var/lib/qemu/image.raw ]; then \n\
rm /var/lib/qemu/image.raw \n\
fi \n\
if [ -f /var/lib/qemu/image.qcow2 ]; then \n\
rm /var/lib/qemu/image.qcow2 \n\
fi \n\
gunzip --stdout /projects/openwrt-helloworld/output/openwrt-*combined.img.gz > /var/lib/qemu/image.raw || true \n\
qemu-img convert -f raw -O qcow2 /var/lib/qemu/image.raw /var/lib/qemu/image.qcow2 \n\
rm /var/lib/qemu/image.raw \n\
if [ -n "${QEMU_STORAGE}" ]; then \n\
qemu-img resize /var/lib/qemu/image.qcow2 "${QEMU_STORAGE}" \n\
fi \n\
\n' > /usr/local/bin/provision-image.sh && \
chmod +x /usr/local/bin/provision-image.sh

# Create default VM configuration scripts
RUN mkdir -p /usr/local/share/vmconfig/container.d /usr/local/share/vmconfig/vm.d

RUN echo -e '#!/bin/sh\n\
set -e \n\
cat > vm.d/20-hostname.sh <<EOF\n\
#!/bin/sh \n\
set -e \n\
uci set system.@system[0].hostname="$QEMU_HOSTNAME" \n\
uci commit system \n\
EOF\n\
chmod +x vm.d/20-hostname.sh \n\
\n\' > /usr/local/share/vmconfig/container.d/20-hostname.sh && \
chmod +x /usr/local/share/vmconfig/container.d/20-hostname.sh
RUN echo -e '#!/bin/sh\n\
set -e \n\
cat > vm.d/20-password.sh <<EOF\n\
#!/bin/sh \n\
set -e \n\
echo -e "$QEMU_PASSWORD\\n$QEMU_PASSWORD" | passwd \n\
EOF\n\
chmod +x vm.d/20-password.sh \n\
\n\' > /usr/local/share/vmconfig/container.d/20-password.sh && \
chmod +x /usr/local/share/vmconfig/container.d/20-password.sh

RUN echo -e '#!/bin/sh\n\
set -ex \n\
uci add firewall rule \n\
uci set firewall.@rule[-1].name="Allow-Admin" \n\
uci set firewall.@rule[-1].enabled="true" \n\
uci set firewall.@rule[-1].src="wan" \n\
uci set firewall.@rule[-1].proto="tcp" \n\
uci set firewall.@rule[-1].dest_port="22 80 443" \n\
uci set firewall.@rule[-1].target="ACCEPT" \n\
uci commit firewall \n\
\n\' > /usr/local/share/vmconfig/vm.d/20-firewall.sh && \
chmod +x /usr/local/share/vmconfig/vm.d/20-firewall.sh
RUN echo -e '#!/bin/sh\n\
set -ex \n\
ubus wait_for network.interface.wan \n\
sleep 3 \n\
opkg update \n\
\n\' > /usr/local/share/vmconfig/vm.d/30-wait-for-network.sh && \
chmod +x /usr/local/share/vmconfig/vm.d/30-wait-for-network.sh

RUN echo -e '#!/bin/sh\n\
set -ex \n\
opkg install partx-utils resize2fs sfdisk tune2fs \n\
echo "- +" | sfdisk --force -N 2 /dev/vda \n\
partx -u /dev/vda \n\
mount -o remount,ro / \n\
tune2fs -O^resize_inode /dev/vda2 \n\
e2fsck -y -f /dev/vda2 || true \n\
mount -o remount,rw / \n\
resize2fs /dev/vda2 \n\
\n\' > /usr/local/share/vmconfig/vm.d/40-resize-disk.sh && \
chmod +x /usr/local/share/vmconfig/vm.d/40-resize-disk.sh
# Write VM configuration archive as serial console commands to STDOUT
RUN echo -e '#!/bin/sh\n\
set -e \n\
cat <<EOF\n\
\n\
echo "require \\"nixio\\"; io.stdin:setvbuf \\"no\\"; io.write(nixio.bin.b64decode(io.read()));" > /tmp/base64_decode.lua \n\
lua /tmp/base64_decode.lua > /tmp/vmconfig.tgz \n\
EOF\n\
tar -zcv -C "$1" . | base64 -w0 \n\
cat <<EOF\n\
\n\
mkdir /tmp/vmconfig \n\
tar -zxvf /tmp/vmconfig.tgz -C /tmp/vmconfig \n\
sleep 5 \n\
(cd /tmp/vmconfig && (for f in \$(ls vm.d); do echo "Executing ./vm.d/\$f"; "./vm.d/\$f" || exit 1; done)) && echo -e "\\nVM configuration result: successful." || echo -e "\\nVM configuration result: failed." \n\
poweroff \n\
EOF\n\
\n' > /usr/local/bin/serialize-vm-config.sh && \
chmod +x /usr/local/bin/serialize-vm-config.sh
# Send configuration archive to VM using serial console
RUN echo -e '#!/bin/sh\n\
set -ex \n\
echo "Discovered vmconfig:" \n\
find /var/lib/vmconfig \n\
sleep 5 \n\
rm -rf /tmp/vmconfig \n\
cp -rv /var/lib/vmconfig /tmp/vmconfig \n\
mkdir -p /tmp/vmconfig/container.d /tmp/vmconfig/vm.d \n\
if [ -z "$QEMU_CONFIG_NO_DEFAULTS" ]; then \n\
cp /usr/local/share/vmconfig/container.d/* /tmp/vmconfig/container.d \n\
cp /usr/local/share/vmconfig/vm.d/* /tmp/vmconfig/vm.d \n\
fi \n\
(cd /tmp/vmconfig && (for f in $(ls container.d); do "./container.d/$f"; done)) \n\
run-vm.sh & \n\
QEMU_PID="$!" \n\
sleep 5 \n\
socat STDOUT unix-connect:/tmp/qemu-console.sock | grep -q "Please press Enter to activate this console." \n\
serialize-vm-config.sh /tmp/vmconfig | socat STDIN unix-connect:/tmp/qemu-console.sock \n\
VM_CONFIG_RESULT="$(socat STDOUT unix-connect:/tmp/qemu-console.sock | grep -m1 "^VM configuration result:")" \n\
if test "${VM_CONFIG_RESULT#*failed}" != "$VM_CONFIG_RESULT"; then \n\
exit 1 \n\
fi \n\
wait "$QEMU_PID" \n\
\n' > /usr/local/bin/send-config-to-vm.sh && \
chmod +x /usr/local/bin/send-config-to-vm.sh
# Start VM in QEMU
RUN echo -e '#!/bin/sh\n\
set -e \n\
printf "$QEMU_PASSWORD" > /tmp/qemu-password.txt \n\
set -x \n\
exec /usr/bin/qemu-system-x86_64 \\\n\
-nodefaults \\\n\
-smp ""${QEMU_SMP}"" \\\n\
-m "${QEMU_MEMORY}" \\\n\
-drive file=/var/lib/qemu/image.qcow2,if=virtio \\\n\
-chardev socket,id=chr0,path=/tmp/qemu-console.sock,mux=on,logfile=/dev/stdout,signal=off,server=on,wait=off \\\n\
-serial chardev:chr0 \\\n\
-monitor unix:/tmp/qemu-monitor.sock,server,nowait \\\n\
-nic "user,model=virtio,restrict=on,ipv6=off,net=192.168.1.0/24,host=192.168.1.2,${QEMU_LAN_OPTIONS}" \\\n\
-nic "user,model=virtio,net=${QEMU_WAN_NETWORK},${QEMU_WAN_OPTIONS}" \\\n\
-object secret,id=secvnc0,format=raw,file=/tmp/qemu-password.txt \\\n\
-display none \\\n\
-device virtio-vga \\\n\
-spice port=5900,password-secret=secvnc0 \\\n\
-device intel-hda \\\n\
-device hda-duplex \\\n\
-device ich9-usb-ehci1,id=usb \\\n\
-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,multifunction=on \\\n\
-device ich9-usb-uhci2,masterbus=usb.0,firstport=2 \\\n\
-chardev spicevmc,name=usbredir,id=usbredirchardev1 \\\n\
-device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \\\n\
-chardev spicevmc,name=usbredir,id=usbredirchardev2 \\\n\
-device usb-redir,chardev=usbredirchardev2,id=usbredirdev2 \\\n\
$QEMU_ARGS \\\n\
\n' > /usr/local/bin/run-vm.sh && \
chmod +x /usr/local/bin/run-vm.sh
# Healthcheck
RUN echo -e '#!/bin/sh\n\
set -ex \n\
[ -e /tmp/qemu-console.sock -a -f /var/lib/qemu/initialized ] \n\
curl -sSf -m 5 http://127.0.0.1:30080 > /dev/null \n\
\n' > /usr/local/bin/healthcheck-vm.sh && \
chmod +x /usr/local/bin/healthcheck-vm.sh
# Prepare and run the VM
RUN echo -e '#!/bin/sh\n\
set -ex \n\
create-container-user.sh \n\
provision-image.sh \n\
timeout -s SIGINT "$QEMU_CONFIG_TIMEOUT" send-config-to-vm.sh || (echo "VM config error or time out."; exit 1) \n\
touch /var/lib/qemu/initialized \n\
chmod g+rw /var/lib/qemu/* \n\
exec run-vm.sh \n\
\n' > /usr/local/bin/prepare-and-run-vm.sh && \
chmod +x /usr/local/bin/prepare-and-run-vm.sh
# Runtime configuration
ENV QEMU_MEMORY="256M"
ENV QEMU_STORAGE="1G"
ENV QEMU_SMP="2"
ENV QEMU_LAN_OPTIONS=""
ENV QEMU_WAN_NETWORK="172.16.0.0/24"
ENV QEMU_WAN_OPTIONS="hostfwd=tcp::39000-:9000,hostfwd=tcp::30022-:22,hostfwd=tcp::30080-:80,hostfwd=tcp::30443-:443,hostfwd=udp::51820-:51820"
ENV QEMU_PASSWORD="pass1234"
ENV QEMU_CONFIG_TIMEOUT="300"
ENV QEMU_CONFIG_NO_DEFAULTS=""
ENV QEMU_HOSTNAME="OpenWrtVM"
ENV QEMU_ARGS=""
EXPOSE 39000/tcp
EXPOSE 5900/tcp
EXPOSE 30022/tcp
EXPOSE 30080/tcp
EXPOSE 30443/tcp
EXPOSE 51820/udp
HEALTHCHECK --interval=30s --timeout=30s --start-period=120s --retries=3 CMD [ "/usr/local/bin/healthcheck-vm.sh" ]
VOLUME /var/lib/vmconfig
VOLUME /var/lib/qemu
WORKDIR /tmp
USER 1001
CMD ["tail", "-f", "/dev/null"]

0 comments on commit 6bbc2b9

Please sign in to comment.