From 0e88701a1da6aea242dc8ef2d76c1c16a5b75d04 Mon Sep 17 00:00:00 2001 From: Oleksii Orel Date: Tue, 30 Apr 2024 04:08:27 +0300 Subject: [PATCH] fix: github workflows Signed-off-by: Oleksii Orel --- .devfile.Dockerfile | 78 ++++-- ...{image-build.yaml => cde-image-build.yaml} | 2 - .github/workflows/qemu-image-build.yaml | 27 ++ dockerfiles/qemu.Dockerfile | 240 ++++++++++++++++++ 4 files changed, 320 insertions(+), 27 deletions(-) rename .github/workflows/{image-build.yaml => cde-image-build.yaml} (91%) create mode 100644 .github/workflows/qemu-image-build.yaml create mode 100644 dockerfiles/qemu.Dockerfile diff --git a/.devfile.Dockerfile b/.devfile.Dockerfile index aff2e7e..1d82bf0 100644 --- a/.devfile.Dockerfile +++ b/.devfile.Dockerfile @@ -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"] diff --git a/.github/workflows/image-build.yaml b/.github/workflows/cde-image-build.yaml similarity index 91% rename from .github/workflows/image-build.yaml rename to .github/workflows/cde-image-build.yaml index 97b0508..dc41668 100644 --- a/.github/workflows/image-build.yaml +++ b/.github/workflows/cde-image-build.yaml @@ -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 diff --git a/.github/workflows/qemu-image-build.yaml b/.github/workflows/qemu-image-build.yaml new file mode 100644 index 0000000..830d21e --- /dev/null +++ b/.github/workflows/qemu-image-build.yaml @@ -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 \ No newline at end of file diff --git a/dockerfiles/qemu.Dockerfile b/dockerfiles/qemu.Dockerfile new file mode 100644 index 0000000..dd43fa4 --- /dev/null +++ b/dockerfiles/qemu.Dockerfile @@ -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 < /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 < /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 < /tmp/base64_decode.lua \n\ +lua /tmp/base64_decode.lua > /tmp/vmconfig.tgz \n\ +EOF\n\ +tar -zcv -C "$1" . | base64 -w0 \n\ +cat < /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"] \ No newline at end of file