build #1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: build | |
on: | |
workflow_dispatch: | |
inputs: | |
build_boxes: | |
type: choice | |
description: Build box name | |
default: "all" | |
options: | |
- "all" | |
- "my_windows-10-enterprise-x64-eval" | |
- "ubuntu-18.04-server-amd64" | |
- "ubuntu-20.04-desktop-amd64" | |
- "ubuntu-20.04-server-amd64" | |
- "windows-10-enterprise-x64-eval" | |
- "windows-server-2019-standard-x64-eval" | |
- "windows-server-2022-standard-x64-eval" | |
required: false | |
build_box_providers: | |
type: choice | |
description: Packer provider | |
default: "all" | |
options: | |
- "all" | |
- "libvirt" | |
- "virtualbox" | |
required: false | |
PACKER_LOG: | |
type: choice | |
description: PACKER_LOG (0, 1) | |
default: "0" | |
options: | |
- "0" | |
- "1" | |
required: false | |
ANSIBLE_DEBUG: | |
type: choice | |
description: ANSIBLE_DEBUG (true, false) | |
options: | |
- "false" | |
- "true" | |
required: false | |
VAGRANT_LOG: | |
type: choice | |
description: VAGRANT_LOG (debug, info, warn) | |
default: "warn" | |
options: | |
- "warn" | |
- "info" | |
- "debug" | |
required: false | |
build_upload: | |
type: choice | |
description: Upload release to Vagrant Cloud | |
options: | |
- "false" | |
- "true" | |
required: false | |
schedule: | |
- cron: "0 1 1 * *" | |
env: | |
PACKER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
PACKER_IMAGES_OUTPUT_DIR: /var/tmp/packer-templates-images | |
PACKER_CACHE_DIR: /var/tmp/packer_cache | |
LOGDIR: /var/tmp/packer-templates-logs | |
VAGRANT_CLOUD_USER: peru | |
VAGRANT_CLOUD_TOKEN: ${{ secrets.VAGRANT_CLOUD_TOKEN }} | |
# Needed for Packer when calling ansible (https://github.com/ansible/ansible/issues/32499) | |
OBJC_DISABLE_INITIALIZE_FORK_SAFETY: YES | |
# Note: windows-server-2016-standard-x64-eval was disabled because it take more than 6 hour to build the image - which is above the GH Action limit | |
BUILD_BOX_LIST: | | |
( | |
"my_windows-10-enterprise-x64-eval" | |
"ubuntu-18.04-server-amd64" | |
"ubuntu-20.04-desktop-amd64" | |
"ubuntu-20.04-server-amd64" | |
"windows-10-enterprise-x64-eval" | |
"windows-server-2019-standard-x64-eval" | |
"windows-server-2022-standard-x64-eval" | |
) | |
BUILD_BOX_PROVIDER_LIST: | | |
( | |
"libvirt" | |
"virtualbox" | |
) | |
permissions: read-all | |
jobs: | |
generate-matrix: | |
name: "Generate matrix" | |
runs-on: ubuntu-latest | |
outputs: | |
MATRIX: ${{ steps.set-matrix.outputs.MATRIX }} | |
steps: | |
- name: Get Matrix Builds | |
id: set-matrix | |
run: | | |
set -euxo pipefail | |
if [[ "${{ github.event.inputs.build_boxes }}" = "all" || "${{ github.event_name }}" == 'schedule' ]]; then | |
declare -a BUILD_BOXES=${{ env.BUILD_BOX_LIST }} | |
else | |
declare -a BUILD_BOXES=( "${{ github.event.inputs.build_boxes }}" ) | |
fi | |
if [[ "${{ github.event.inputs.build_box_providers }}" = "all" || "${{ github.event_name }}" == 'schedule' ]]; then | |
declare -a BUILD_BOX_PROVIDERS=${{ env.BUILD_BOX_PROVIDER_LIST }} | |
else | |
declare -a BUILD_BOX_PROVIDERS=( "${{ github.event.inputs.build_box_providers }}" ) | |
fi | |
for BUILD_BOX in "${BUILD_BOXES[@]}" ; do | |
NAME="${BUILD_BOX}" | |
for BUILD_BOX_PROVIDER in "${BUILD_BOX_PROVIDERS[@]}" ; do | |
PACKER_VAGRANT_PROVIDER="${BUILD_BOX_PROVIDER}" | |
# Check if the boxes (virtualbox/libvirt) with the same git hash already exists | |
if curl -s "https://app.vagrantup.com/${VAGRANT_CLOUD_USER}/boxes/${NAME}" | grep -q "Not found" ; then | |
CURRENT_VERSION_DESCRIPTION_MARKDOWN="Box doesn't exist" | |
else | |
CURRENT_VERSION_DESCRIPTION_MARKDOWN="$(curl -L --silent "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}" | jq '.current_version.version as $current_version | .versions[] | select (.version == $current_version) .description_markdown')" | |
fi | |
if [[ "${CURRENT_VERSION_DESCRIPTION_MARKDOWN}" =~ ${GITHUB_SHA} ]] ; then | |
echo "*** Git hash \"${GITHUB_SHA}\" found in current markdown description" | |
# Skip build if the box already exists | |
CURRENT_VERSION_PROVIDER_URL="$(curl -L --silent "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}" | jq -r ".current_version.version as \$current_version | .versions[] | select (.version == \$current_version) .providers[] | select (.name == \"${PACKER_VAGRANT_PROVIDER}\") .download_url")" | |
if [ -n "${CURRENT_VERSION_PROVIDER_URL}" ]; then | |
echo "*** Found already build image \"${BUILD_BOX}-${PACKER_VAGRANT_PROVIDER}\" with hash \"${GITHUB_SHA}\": ${CURRENT_VERSION_PROVIDER_URL}" | |
echo "*** This build will be skipped..." | |
else | |
# Set BOX_VERSION variable from existing provider (if exists) or from "date" | |
BOX_VERSION="$(curl -L --silent "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}" | jq -r ".current_version.version")" | |
echo "*** Using previously defined box version \"${BOX_VERSION}\", because there is already builded box with git hash \"${GITHUB_SHA}\"" | |
BUILDS_MATRIX+=("${BUILD_BOX}-${PACKER_VAGRANT_PROVIDER}@${BOX_VERSION}") | |
fi | |
else | |
BOX_VERSION="$(date +%Y%m%d).01" | |
echo "*** Using new box version based on current date: ${BOX_VERSION}" | |
BUILDS_MATRIX+=("${BUILD_BOX}-${PACKER_VAGRANT_PROVIDER}@${BOX_VERSION}") | |
fi | |
done | |
done | |
jq --compact-output --null-input '$ARGS.positional' --args "${BUILDS_MATRIX[@]}" | |
echo "MATRIX=$( jq --compact-output --null-input '$ARGS.positional' --args "${BUILDS_MATRIX[@]}" )" | tee -a "${GITHUB_OUTPUT}" | |
build-boxes: | |
name: "*" | |
runs-on: macos-13 | |
needs: generate-matrix | |
if: ${{ needs.generate-matrix.outputs.MATRIX != '[]' && needs.generate-matrix.outputs.MATRIX != '' }} | |
concurrency: | |
group: build-boxes-${{ matrix.stage }} | |
strategy: | |
# Do not cancel matrix jobs if one of them fails | |
fail-fast: false | |
matrix: | |
stage: ${{ fromJSON(needs.generate-matrix.outputs.MATRIX) }} | |
steps: | |
- name: Set PACKER_LOG, ANSIBLE_DEBUG, VAGRANT_LOG variables when using workflow_dispatch | |
if: ${{ github.event_name == 'workflow_dispatch' }} | |
run: | | |
set -euo pipefail | |
cat << EOF | tee -a "${GITHUB_ENV}" | |
PACKER_LOG=${{ github.event.inputs.PACKER_LOG }} | |
ANSIBLE_DEBUG=${{ github.event.inputs.ANSIBLE_DEBUG }} | |
VAGRANT_LOG=${{ github.event.inputs.VAGRANT_LOG }} | |
EOF | |
- name: Set global environment variables like BOX_VERSION, BUILD, NAME, PACKER_VAGRANT_PROVIDER | |
run: | | |
set -euo pipefail | |
STAGE="${{ matrix.stage }}" | |
echo "*** STAGE: ${STAGE}" | |
# shellcheck disable=SC2001 | |
cat << EOF | tee -a "${GITHUB_ENV}" | |
BOX_VERSION=${STAGE##*@} | |
BUILD=${STAGE%@*} | |
NAME=${STAGE%-*} | |
PACKER_VAGRANT_PROVIDER=$(echo "${STAGE}" | sed 's/.*-\([^@]*\).*/\1/') | |
EOF | |
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
with: | |
submodules: true | |
- name: Install packages | |
run: | | |
set -euxo pipefail | |
brew install ansible bash coreutils gnu-sed jq packer hudochenkov/sshpass/sshpass hashicorp/tap/hashicorp-vagrant | |
if [[ "${PACKER_VAGRANT_PROVIDER}" = "libvirt" ]]; then | |
brew install qemu xorriso | |
qemu-system-x86_64 --version | |
fi | |
if [[ "${PACKER_VAGRANT_PROVIDER}" = "virtualbox" ]]; then | |
brew install virtualbox | |
vboxmanage --version | |
fi | |
packer plugins install github.com/hashicorp/ansible | |
packer plugins install github.com/hashicorp/qemu | |
packer plugins install github.com/hashicorp/vagrant | |
packer plugins install github.com/hashicorp/virtualbox | |
vagrant --version | |
packer --version | |
ansible --version | |
if [[ "${BUILD}" =~ windows ]]; then | |
# renovate: datasource=pypi depName=pywinrm | |
PYWINRM_VERSION="0.4.3" | |
pip3 install pywinrm=="${PYWINRM_VERSION}" | |
ansible-galaxy collection install --force -r ansible/requirements.yml | |
fi | |
echo "/usr/local/bin:/usr/local/opt/gnu-sed/libexec/gnubin:/usr/local/opt/coreutils/libexec/gnubin" >> "${GITHUB_PATH}" | |
# Remove unused packages to save some disk space | |
rm -rf /Users/runner/Library/Developer /Users/runner/Library/Android /Users/runner/hostedtoolcache /Users/runner/.dotnet | |
# Used by mxschmitt/action-tmate | |
touch continue | |
# - name: Setup tmate session | |
# uses: mxschmitt/action-tmate@v3 | |
# with: | |
# limit-access-to-actor: true | |
- name: Build image | |
id: build_image | |
run: | | |
./build.sh "${BUILD}" | |
- name: Upload logs to GitHub artifact store in case of VirtualBox failure | |
uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 | |
if: ${{ always() && contains(matrix.stage, 'virtualbox') }} | |
with: | |
name: ${{ matrix.stage }} | |
path: ${{ env.LOGDIR }}/* | |
retention-days: 3 | |
- name: Check the created box image | |
run: | | |
if [[ "${PACKER_VAGRANT_PROVIDER}" = "virtualbox" ]] ; then | |
./vagrant_init_destroy_boxes.sh "${PACKER_IMAGES_OUTPUT_DIR}/${BUILD}.box" | |
else | |
echo "*** Skipping the checks..." | |
fi | |
- name: Upload box to Vagrant Cloud | |
if: ${{ github.event_name == 'schedule' || github.event.inputs.build_upload == 'true' }} | |
run: | | |
./upload_box_to_vagrantcloud.sh "${VAGRANT_CLOUD_USER}@${PACKER_IMAGES_OUTPUT_DIR}/${BUILD}.box" | |
clean_check_versions: | |
needs: build-boxes | |
if: ${{ always() }} | |
runs-on: ubuntu-latest | |
steps: | |
- name: Remove old versions | |
run: | | |
set -euxo pipefail | |
declare -a BUILD_BOXES=${{ env.BUILD_BOX_LIST }} | |
for NAME in "${BUILD_BOXES[@]}"; do | |
while read -r VERSION ; do | |
echo "*** Removing box version: https://vagrantcloud.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}/version/${VERSION}" | |
curl -s "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}/version/${VERSION}" -X DELETE -d "access_token=${VAGRANT_CLOUD_TOKEN}" -o /dev/null | |
done < <( curl -s "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}" | jq -r '.current_version.version as $current_version | .versions[] | select (.version != $current_version) .version' ) | |
# Verify if current version of the box has both boxes (virtualbox + libvirt) | |
CURRENT_VERSION_PROVIDERS=$(curl -s "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}"| jq -r ".current_version.providers|length") | |
if [[ ${CURRENT_VERSION_PROVIDERS} -ne 2 ]]; then | |
echo "*** Current version of ${VAGRANT_CLOUD_USER}/${NAME} does not contain both box versions (virtualbox + libvirt) !" | |
continue | |
fi | |
done | |
- name: Verify if the boxes are available on the Vagrant Cloud | |
run: | | |
set -euxo pipefail | |
declare -a BUILD_BOXES=${{ env.BUILD_BOX_LIST }} | |
declare -a BUILD_BOX_PROVIDERS=${{ env.BUILD_BOX_PROVIDER_LIST }} | |
for NAME in "${BUILD_BOXES[@]}"; do | |
for VAGRANT_PROVIDER in "${BUILD_BOX_PROVIDERS[@]}"; do | |
CURRENT_VERSION=$(curl -s "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}" | jq -r ".current_version.version") | |
CHECKSUM=$(curl -s "https://app.vagrantup.com/api/v1/box/${VAGRANT_CLOUD_USER}/${NAME}" | jq -r ".current_version.providers[] | select (.name == \"${VAGRANT_PROVIDER}\") .checksum") | |
URL="https://app.vagrantup.com/${VAGRANT_CLOUD_USER}/boxes/${NAME}/versions/${CURRENT_VERSION}/providers/${VAGRANT_PROVIDER}.box" | |
echo "*** ${URL} | ${CHECKSUM}" | |
if ! curl -L --fail --silent --head --output /dev/null "${URL}"; then | |
echo "* URL \"${URL}\" is not accessible !" | |
exit 1 | |
fi | |
if [ "$(curl -s "https://app.vagrantup.com/${VAGRANT_CLOUD_USER}/boxes/${NAME}" | jq '.versions | length')" != "1" ]; then | |
echo "* Too many versions for: https://app.vagrantup.com/${VAGRANT_CLOUD_USER}/boxes/${NAME} !" | |
exit 2 | |
fi | |
done | |
done |