diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..9b3d078 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,33 @@ +name: build +run-name: Create patched ISO images + +on: + # allow the workflow to be called from another workflow + workflow_call: + # allow the workflow to be run from the Github Actions UI + workflow_dispatch: + # trigger the workflow when a 'push' event happens to any branch except the main branch + push: + branches: + - '**' + - '!main' + +jobs: + # the build job to run the build script + build: + runs-on: ubuntu-latest + steps: + - name: Check out the repository to the runner + uses: actions/checkout@v4 + - name: Make the build script executable + run: chmod u+x scripts/build.sh + - name: Install dependent packages + run: sudo apt install -y p7zip-full p7zip-rar genisoimage fakeroot xorriso isolinux binutils squashfs-tools + - name: Run the build script + run: scripts/build.sh + # one set of upload statements for each OS image artifact + - name: Upload the vault-ubuntu-minimal artifact + uses: actions/upload-artifact@v4 + with: + name: vault-ubuntu-minimal + path: vault-ubuntu-minimal.iso diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b2cab27 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,32 @@ +name: release +run-name: Create a new release + +on: + # allow the workflow to be run from the Github Actions UI + workflow_dispatch: + # trigger the workflow run when a 'push' event happens to a tag with semantic versioning + push: + tags: + - "v*.*.*" + +jobs: + # call the build job (reuse from earlier workflow) + build: + uses: ./.github/workflows/build.yml + # the release job that will create a new release of all built OS images + release: + needs: build + runs-on: ubuntu-latest + steps: + - name: Check out the repository to the runner + uses: actions/checkout@v4 + # one set of statements for each OS image that needs to be downloaded + # and included in the next release + - name: Download the vault-ubuntu-minimal artifact + uses: actions/download-artifact@v4 + with: + name: vault-ubuntu-minimal + - name: Create a new release with latest images for all OSes + uses: softprops/action-gh-release@v2 + with: + files: vault-ubuntu-minimal.iso diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100644 index 0000000..30b69fd --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,104 @@ +#! /bin/bash + +# function to detect the environment and return an appropriate file name +assign_file_name () { + # check if it is a CI/CD environment like Github Actions + if [ -v CI ]; then + FILENAME="$1.iso" + else + IS_GIT=$(git rev-parse --is-inside-work-tree 2>&1) + # check if it is a git repository like when in local development + if [ $IS_GIT ]; then + GIT_COMMIT=$(git rev-parse --short HEAD) + DATE=$(date -u '+%Y%m%d') + FILENAME="$1-$DATE.$GIT_COMMIT.iso" + fi + fi + echo $FILENAME +} + +# function to create builds for all linux operating systems in scope +build_linux_oses () { + # array of URLs pointing to the base images of the operating system being handled + # give official, downloadable URLs, preferably from the same source as provided in the README + declare -a LINUXIMAGES=( + "https://releases.ubuntu.com/22.04.5/ubuntu-22.04.5-live-server-amd64.iso" + ) + + # array of directory names as present in this project + # this is used to copy and use the cloud-init config data + declare -a LINUXOSDIRS=( + "ubuntu-server-22-04-5" + ) + + # array of patched operating system names + # preferably in the `vault-` format + declare -a VAULTLINUXOSES=( + "vault-ubuntu-minimal" + ) + + # get lengths of above mentioned arrays + IMAGESLENGTH=${#LINUXIMAGES[@]} + OSESLENGTH=${#LINUXOSDIRS[@]} + VAULTSLENGTH=${#VAULTLINUXOSES[@]} + + # perform a check to confirm that all arrays have equal lengths + # if not, exit with an appropriate message + if [ $IMAGESLENGTH -ne $OSESLENGTH ] || [ $OSESLENGTH -ne $VAULTLINUXOSES ] || [ $IMAGESLENGTH -ne $VAULTLINUXOSES ]; then + echo "IMAGESLENGTH, OSESLENGTH, VAULTLINUXOSES are not of equal lengths. Recheck array entries." + exit 1 + fi + + # iterate through the list of operating systems and patch them with data from the cloud-init config files + for (( i=0; i<${IMAGESLENGTH}; i++ )); + do + TARGETFILENAME=$(assign_file_name "${VAULTLINUXOSES[$i]}") + echo "Creating patched OS: $TARGETFILENAME..." + # download the base OS image + curl -X GET -OL ${LINUXIMAGES[$i]} + SOURCEISO=${LINUXIMAGES[$i]##*/} + # extract the downloaded ISO image to the iso/ directory + 7z x -y $SOURCEISO -oiso + + # copy the cloud-init configuration files into the iso/nocloud directory + mkdir -p iso/nocloud + cp "${LINUXOSDIRS[$i]}/meta-data" iso/nocloud/ + cp "${LINUXOSDIRS[$i]}/user-data" iso/nocloud/ + + ## TODO: think of how this can possibly be extended to + ## other OSes. Do the boot kernel parameters change the + ## same way? Will we need a if-else tree to do it? + + # modify boot related files + sed -i -e 's/---/ autoinstall ---/g' iso/boot/grub/grub.cfg + sed -i -e 's/---/ autoinstall ---/g' iso/boot/grub/loopback.cfg + # modify kernel boot parameters to insert path to cloud-init config + sed -i -e 's,---, ds=nocloud\\;s=/cdrom/nocloud/ ---,g' iso/boot/grub/grub.cfg + sed -i -e 's,---, ds=nocloud\\;s=/cdrom/nocloud/ ---,g' iso/boot/grub/loopback.cfg + + # create the final ISO image + xorriso -as mkisofs -r \ + -V ${LINUXOSDIRS[$i]} \ + -o $TARGETFILENAME \ + -J \ + -c '/boot.catalog' \ + -b '/boot/grub/i386-pc/eltorito.img' \ + -no-emul-boot -boot-load-size 4 -boot-info-table --grub2-boot-info \ + -eltorito-alt-boot \ + -isohybrid-gpt-basdat -isohybrid-apm-hfsplus \ + iso/boot iso + + FILESIZE=$(stat -c %s $TARGETFILENAME 2>&1) + # verify that the patched iso image file was created properly + if [[ $FILESIZE > 0 ]]; then + printf '%s (%d bytes) ... done!\n' $TARGETFILENAME $FILESIZE + else + printf 'Something went wrong while trying to build %s\n' $TARGETFILENAME + fi + + # remove the iso/ directory + sudo rm -rf iso + done +} + +build_linux_oses \ No newline at end of file