diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 04cf0d1e1a5a4..d89644133a0e8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,3 +10,14 @@ updates: labels: ["A2-insubstantial", "B0-silent", "C1-low", "E2-dependencies"] schedule: interval: daily + + # Python dependencies for Linode + - package-ecosystem: "pip" + directories: + - "/.github" + groups: + linode-dependencies: + dependency-type: "production" + applies-to: version-updates + schedule: + interval: "monthly" diff --git a/.github/install-docker-engine-from-upstream.sh b/.github/install-docker-engine-from-upstream.sh new file mode 100755 index 0000000000000..2baa37438532e --- /dev/null +++ b/.github/install-docker-engine-from-upstream.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +if [ ! -f "/etc/apt/sources.list.d/docker.list" ]; then + sudo apt-get remove -y docker docker-engine docker.io containerd runc || echo + sudo apt-get update + sudo apt-get install -y ca-certificates curl gnupg lsb-release + sudo mkdir -p /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + sudo apt-get update + sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin +fi diff --git a/.github/linode-cloud-init.template b/.github/linode-cloud-init.template new file mode 100644 index 0000000000000..d322c39177e81 --- /dev/null +++ b/.github/linode-cloud-init.template @@ -0,0 +1,14 @@ +#cloud-config + +users: + - default + - name: ubuntu + shell: /bin/bash + lock_passwd: true + groups: + - sudo + sudo: + - ALL=(ALL) NOPASSWD:ALL + # WARNING: always keep this line at the end + # b/c runner provisioning appends the actual keys + ssh_authorized_keys: diff --git a/.github/provision-github-runner.sh b/.github/provision-github-runner.sh index 54090a6593937..cfa614d5ba90d 100755 --- a/.github/provision-github-runner.sh +++ b/.github/provision-github-runner.sh @@ -3,13 +3,21 @@ mkdir actions-runner pushd actions-runner || exit 1 -curl -L https://github.com/actions/runner/releases/download/v2.302.1/actions-runner-linux-x64-2.302.1.tar.gz > runner.tar.gz +curl -L https://github.com/actions/runner/releases/download/v2.317.0/actions-runner-linux-x64-2.317.0.tar.gz > runner.tar.gz tar xzf ./runner.tar.gz sudo ./bin/installdependencies.sh -sudo apt install -y jq +# for 3rd party dependencies and building the code +sudo apt install curl gnupg -y +curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list +sudo apt-get update +sudo apt install -y build-essential \ + cmake clang libclang-dev llvm curl gcc git-lfs jq \ + libssl-dev pipx pkg-config protobuf-compiler \ + unzip yarn -OWNER_REPO_SLUG="gluwa/substrate" +OWNER_REPO_SLUG="${LC_OWNER_REPO_SLUG}" REPOSITORY_URL="https://github.com/$OWNER_REPO_SLUG" EPHEMERAL=${LC_RUNNER_EPHEMERAL:-true} @@ -20,7 +28,19 @@ REGISTRATION_TOKEN=$(curl --silent -X POST \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/repos/$OWNER_REPO_SLUG/actions/runners/registration-token" | jq -r '.token') +if [ "$REGISTRATION_TOKEN" == "null" ]; then + echo "ERROR: REGISTRATION_TOKEN is null" + exit 1 +fi + +if [ -z "$REGISTRATION_TOKEN" ]; then + echo "ERROR: REGISTRATION_TOKEN is empty" + exit 2 +fi + # Important: ephemeral runners are removed after a single job is executed on them # which is inline with the VM lifecycle -./config.sh --unattended --ephemeral "$EPHEMERAL" --url "$REPOSITORY_URL" --token "$REGISTRATION_TOKEN" --labels "$LC_RUNNER_VM_NAME" +./config.sh --unattended --ephemeral "$EPHEMERAL" --url "$REPOSITORY_URL" --token "$REGISTRATION_TOKEN" \ + --name "$LC_RUNNER_VM_NAME" \ + --labels "$LC_RUNNER_VM_NAME,workflow-$LC_WORKFLOW_ID,proxy-$LC_PROXY_ENABLED,secret-$LC_PROXY_SECRET_VARIANT,type-$LC_PROXY_TYPE" nohup ./run.sh >/dev/null 2>&1 > .github/authorized_keys + + +# Provision VM +echo "INFO: From ENVs: RUNNER_VM_NAME=$LC_RUNNER_VM_NAME" + +# inject authorized keys into cloud-init for the `ubuntu@` user +while read -r LINE; do + echo " - $LINE" >> .github/linode-cloud-init.template +done < .github/authorized_keys + +# retry until we get a VM +IP_ADDRESS="" +COUNTER=0 +while [ -z "$IP_ADDRESS" ]; do + # if all jobs retry rate-limited queries at the same time they still hit the limit + # and subsequently fail. Max number of retries is hard-coded to 3 in linodecli + # use up to 60 sec random delay to avoid everything being scheduled at once! + sleep $((RANDOM % 60)) + + # WARNING: we do not specify --authorized_keys for root b/c + # linode-cli expects each key as a separate argument and iteratively constructing + # the argument list hits issues with quoting the jey values b/c of white-space. + # All SSH logins should be via the `ubuntu@` user. For more info see: + # https://www.linode.com/community/questions/21290/how-to-pass-multiple-ssh-public-keys-with-linode-cli-linodes-create + linode-cli linodes create --json \ + --image 'linode/ubuntu24.04' --region "$LINODE_REGION" \ + --type "$LINODE_VM_SIZE" --label "$LC_RUNNER_VM_NAME" \ + --root_pass "$(uuidgen)" --backups_enabled false --booted true --private_ip false \ + --metadata.user_data "$(base64 --wrap 0 < .github/linode-cloud-init.template)" > "retry_$COUNTER.json" + + IP_ADDRESS=$(jq -r '.[0].ipv4[0]' < "retry_$COUNTER.json") + + (( COUNTER=COUNTER+1 )) +done + +# provision the GitHub Runner binary on the VM +# passing additional ENV values +SSH_USER_AT_HOSTNAME="ubuntu@$IP_ADDRESS" +echo "INFO: $SSH_USER_AT_HOSTNAME" + +until ssh -i ~/.ssh/id_rsa \ + -o StrictHostKeyChecking=no "$SSH_USER_AT_HOSTNAME" < .github/install-docker-engine-from-upstream.sh; do + echo "DEBUG: retrying ssh connection ..." + sleep 30 +done + +until ssh -i ~/.ssh/id_rsa \ + -o SendEnv=LC_GITHUB_REPO_ADMIN_TOKEN,LC_RUNNER_VM_NAME,LC_WORKFLOW_ID,LC_PROXY_ENABLED,LC_PROXY_SECRET_VARIANT,LC_PROXY_TYPE \ + -o StrictHostKeyChecking=no "$SSH_USER_AT_HOSTNAME" < .github/provision-github-runner.sh; do + echo "DEBUG: retrying ssh connection ..." + sleep 30 +done diff --git a/.github/remove-linode-vm.sh b/.github/remove-linode-vm.sh new file mode 100755 index 0000000000000..8110612de2197 --- /dev/null +++ b/.github/remove-linode-vm.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -x + +# Install linode-cli +python3 --version +pipx install linode-cli +export PATH="$PATH:~/.local/bin" +linode-cli --version + +# if a specific VM was not specified then remove all zombies +if [ -z "$LC_RUNNER_VM_NAME" ]; then + THRESHOLD=$(date --utc "+%Y-%m-%dT%H:%M:%S" -d "5 hours ago") + + for VM_ID in $(linode-cli linodes list --json | jq ".[] | select(.created <= \"$THRESHOLD\")" | jq -r '.id'); do + echo "INFO: going to remove expired VM $VM_ID" + linode-cli linodes delete "$VM_ID" + done +else + VM_ID=$(linode-cli linodes list --json --label "$LC_RUNNER_VM_NAME" | jq -r '.[0].id') + linode-cli linodes delete "$VM_ID" +fi diff --git a/.github/requirements.txt b/.github/requirements.txt new file mode 100644 index 0000000000000..ecd5f2d2b7e3d --- /dev/null +++ b/.github/requirements.txt @@ -0,0 +1 @@ +linode-cli==5.54.0 diff --git a/.github/runner.bicep b/.github/runner.bicep deleted file mode 100644 index bf12013c5fbe6..0000000000000 --- a/.github/runner.bicep +++ /dev/null @@ -1,868 +0,0 @@ -@description('The name of you Virtual Machine.') -param utcValue string = utcNow() -param vmName string = toLower('github-runner-${uniqueString(resourceGroup().id, utcValue)}') - -@description('Username for the Virtual Machine.') -param adminUsername string = 'ubuntu' - -var authenticationType = 'sshPublicKey' - -@description('SSH Key value for the Virtual Machine.') -@secure() -param adminPasswordOrKey string - -@description('The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version.') -param ubuntuOSVersion string = '22_04-lts' -param ubuntuOffer string = '0001-com-ubuntu-server-jammy' - -@description('Location for all resources.') -param location string = resourceGroup().location - -@description('The size of the VM') -@allowed([ - 'Standard_B1ls' - 'Standard_B1ms' - 'Standard_B1s' - 'Standard_B2ms' - 'Standard_B2s' - 'Standard_B4ms' - 'Standard_B8ms' - 'Standard_B12ms' - 'Standard_B16ms' - 'Standard_B20ms' - 'Standard_DS1_v2' - 'Standard_DS2_v2' - 'Standard_DS3_v2' - 'Standard_DS4_v2' - 'Standard_DS5_v2' - 'Standard_DS11-1_v2' - 'Standard_DS11_v2' - 'Standard_DS12-1_v2' - 'Standard_DS12-2_v2' - 'Standard_DS12_v2' - 'Standard_DS13-2_v2' - 'Standard_DS13-4_v2' - 'Standard_DS13_v2' - 'Standard_DS14-4_v2' - 'Standard_DS14-8_v2' - 'Standard_DS14_v2' - 'Standard_DS15_v2' - 'Standard_DS2_v2_Promo' - 'Standard_DS3_v2_Promo' - 'Standard_DS4_v2_Promo' - 'Standard_DS5_v2_Promo' - 'Standard_DS11_v2_Promo' - 'Standard_DS12_v2_Promo' - 'Standard_DS13_v2_Promo' - 'Standard_DS14_v2_Promo' - 'Standard_F1s' - 'Standard_F2s' - 'Standard_F4s' - 'Standard_F8s' - 'Standard_F16s' - 'Standard_D2s_v3' - 'Standard_D4s_v3' - 'Standard_D8s_v3' - 'Standard_D16s_v3' - 'Standard_D32s_v3' - 'Standard_E2_v4' - 'Standard_E4_v4' - 'Standard_E8_v4' - 'Standard_E16_v4' - 'Standard_E20_v4' - 'Standard_E32_v4' - 'Standard_E2d_v4' - 'Standard_E4d_v4' - 'Standard_E8d_v4' - 'Standard_E16d_v4' - 'Standard_E20d_v4' - 'Standard_E32d_v4' - 'Standard_E2s_v4' - 'Standard_E4-2s_v4' - 'Standard_E4s_v4' - 'Standard_E8-2s_v4' - 'Standard_E8-4s_v4' - 'Standard_E8s_v4' - 'Standard_E16-4s_v4' - 'Standard_E16-8s_v4' - 'Standard_E16s_v4' - 'Standard_E20s_v4' - 'Standard_E32-8s_v4' - 'Standard_E32-16s_v4' - 'Standard_E32s_v4' - 'Standard_E2ds_v4' - 'Standard_E4-2ds_v4' - 'Standard_E4ds_v4' - 'Standard_E8-2ds_v4' - 'Standard_E8-4ds_v4' - 'Standard_E8ds_v4' - 'Standard_E16-4ds_v4' - 'Standard_E16-8ds_v4' - 'Standard_E16ds_v4' - 'Standard_E20ds_v4' - 'Standard_E32-8ds_v4' - 'Standard_E32-16ds_v4' - 'Standard_E32ds_v4' - 'Standard_D2d_v4' - 'Standard_D4d_v4' - 'Standard_D8d_v4' - 'Standard_D16d_v4' - 'Standard_D32d_v4' - 'Standard_D48d_v4' - 'Standard_D64d_v4' - 'Standard_D2_v4' - 'Standard_D4_v4' - 'Standard_D8_v4' - 'Standard_D16_v4' - 'Standard_D32_v4' - 'Standard_D48_v4' - 'Standard_D64_v4' - 'Standard_D2ds_v4' - 'Standard_D4ds_v4' - 'Standard_D8ds_v4' - 'Standard_D16ds_v4' - 'Standard_D32ds_v4' - 'Standard_D48ds_v4' - 'Standard_D64ds_v4' - 'Standard_D2s_v4' - 'Standard_D4s_v4' - 'Standard_D8s_v4' - 'Standard_D16s_v4' - 'Standard_D32s_v4' - 'Standard_D48s_v4' - 'Standard_D64s_v4' - 'Standard_D1_v2' - 'Standard_D2_v2' - 'Standard_D3_v2' - 'Standard_D4_v2' - 'Standard_D5_v2' - 'Standard_D11_v2' - 'Standard_D12_v2' - 'Standard_D13_v2' - 'Standard_D14_v2' - 'Standard_D15_v2' - 'Standard_D2_v2_Promo' - 'Standard_D3_v2_Promo' - 'Standard_D4_v2_Promo' - 'Standard_D5_v2_Promo' - 'Standard_D11_v2_Promo' - 'Standard_D12_v2_Promo' - 'Standard_D13_v2_Promo' - 'Standard_D14_v2_Promo' - 'Standard_F1' - 'Standard_F2' - 'Standard_F4' - 'Standard_F8' - 'Standard_F16' - 'Standard_A1_v2' - 'Standard_A2m_v2' - 'Standard_A2_v2' - 'Standard_A4m_v2' - 'Standard_A4_v2' - 'Standard_A8m_v2' - 'Standard_A8_v2' - 'Standard_D2_v3' - 'Standard_D4_v3' - 'Standard_D8_v3' - 'Standard_D16_v3' - 'Standard_D32_v3' - 'Standard_D48_v3' - 'Standard_D64_v3' - 'Standard_D48s_v3' - 'Standard_D64s_v3' - 'Standard_E2_v3' - 'Standard_E4_v3' - 'Standard_E8_v3' - 'Standard_E16_v3' - 'Standard_E20_v3' - 'Standard_E32_v3' - 'Standard_E2s_v3' - 'Standard_E4-2s_v3' - 'Standard_E4s_v3' - 'Standard_E8-2s_v3' - 'Standard_E8-4s_v3' - 'Standard_E8s_v3' - 'Standard_E16-4s_v3' - 'Standard_E16-8s_v3' - 'Standard_E16s_v3' - 'Standard_E20s_v3' - 'Standard_E32-8s_v3' - 'Standard_E32-16s_v3' - 'Standard_E32s_v3' - 'Standard_F2s_v2' - 'Standard_F4s_v2' - 'Standard_F8s_v2' - 'Standard_F16s_v2' - 'Standard_F32s_v2' - 'Standard_F48s_v2' - 'Standard_F64s_v2' - 'Standard_F72s_v2' - 'Standard_DC2as_v5' - 'Standard_DC4as_v5' - 'Standard_DC8as_v5' - 'Standard_DC16as_v5' - 'Standard_DC32as_v5' - 'Standard_DC48as_v5' - 'Standard_DC64as_v5' - 'Standard_DC96as_v5' - 'Standard_DC2ads_v5' - 'Standard_DC4ads_v5' - 'Standard_DC8ads_v5' - 'Standard_DC16ads_v5' - 'Standard_DC32ads_v5' - 'Standard_DC48ads_v5' - 'Standard_DC64ads_v5' - 'Standard_DC96ads_v5' - 'Standard_EC2as_v5' - 'Standard_EC4as_v5' - 'Standard_EC8as_v5' - 'Standard_EC16as_v5' - 'Standard_EC20as_v5' - 'Standard_EC32as_v5' - 'Standard_EC48as_v5' - 'Standard_EC64as_v5' - 'Standard_EC96as_v5' - 'Standard_EC96ias_v5' - 'Standard_EC2ads_v5' - 'Standard_EC4ads_v5' - 'Standard_EC8ads_v5' - 'Standard_EC16ads_v5' - 'Standard_EC20ads_v5' - 'Standard_EC32ads_v5' - 'Standard_EC48ads_v5' - 'Standard_EC64ads_v5' - 'Standard_EC96ads_v5' - 'Standard_EC96iads_v5' - 'Standard_D2a_v4' - 'Standard_D4a_v4' - 'Standard_D8a_v4' - 'Standard_D16a_v4' - 'Standard_D32a_v4' - 'Standard_D48a_v4' - 'Standard_D64a_v4' - 'Standard_D96a_v4' - 'Standard_D2as_v4' - 'Standard_D4as_v4' - 'Standard_D8as_v4' - 'Standard_D16as_v4' - 'Standard_D32as_v4' - 'Standard_D48as_v4' - 'Standard_D64as_v4' - 'Standard_D96as_v4' - 'Standard_E2a_v4' - 'Standard_E4a_v4' - 'Standard_E8a_v4' - 'Standard_E16a_v4' - 'Standard_E20a_v4' - 'Standard_E32a_v4' - 'Standard_E48a_v4' - 'Standard_E64a_v4' - 'Standard_E96a_v4' - 'Standard_E2as_v4' - 'Standard_E4-2as_v4' - 'Standard_E4as_v4' - 'Standard_E8-2as_v4' - 'Standard_E8-4as_v4' - 'Standard_E8as_v4' - 'Standard_E16-4as_v4' - 'Standard_E16-8as_v4' - 'Standard_E16as_v4' - 'Standard_E20as_v4' - 'Standard_E32-8as_v4' - 'Standard_E32-16as_v4' - 'Standard_E32as_v4' - 'Standard_E48as_v4' - 'Standard_E64-16as_v4' - 'Standard_E64-32as_v4' - 'Standard_E64as_v4' - 'Standard_E96-24as_v4' - 'Standard_E96-48as_v4' - 'Standard_E96as_v4' - 'Standard_E96ias_v4' - 'Standard_E48_v3' - 'Standard_E64_v3' - 'Standard_E48s_v3' - 'Standard_E64-16s_v3' - 'Standard_E64-32s_v3' - 'Standard_E64s_v3' - 'Standard_A0' - 'Standard_A1' - 'Standard_A2' - 'Standard_A3' - 'Standard_A5' - 'Standard_A4' - 'Standard_A6' - 'Standard_A7' - 'Basic_A0' - 'Basic_A1' - 'Basic_A2' - 'Basic_A3' - 'Basic_A4' - 'Standard_D2ds_v5' - 'Standard_D4ds_v5' - 'Standard_D8ds_v5' - 'Standard_D16ds_v5' - 'Standard_D32ds_v5' - 'Standard_D48ds_v5' - 'Standard_D64ds_v5' - 'Standard_D96ds_v5' - 'Standard_D2d_v5' - 'Standard_D4d_v5' - 'Standard_D8d_v5' - 'Standard_D16d_v5' - 'Standard_D32d_v5' - 'Standard_D48d_v5' - 'Standard_D64d_v5' - 'Standard_D96d_v5' - 'Standard_D2s_v5' - 'Standard_D4s_v5' - 'Standard_D8s_v5' - 'Standard_D16s_v5' - 'Standard_D32s_v5' - 'Standard_D48s_v5' - 'Standard_D64s_v5' - 'Standard_D96s_v5' - 'Standard_D2_v5' - 'Standard_D4_v5' - 'Standard_D8_v5' - 'Standard_D16_v5' - 'Standard_D32_v5' - 'Standard_D48_v5' - 'Standard_D64_v5' - 'Standard_D96_v5' - 'Standard_E48ds_v4' - 'Standard_E64-16ds_v4' - 'Standard_E64-32ds_v4' - 'Standard_E64ds_v4' - 'Standard_E2ds_v5' - 'Standard_E4-2ds_v5' - 'Standard_E4ds_v5' - 'Standard_E8-2ds_v5' - 'Standard_E8-4ds_v5' - 'Standard_E8ds_v5' - 'Standard_E16-4ds_v5' - 'Standard_E16-8ds_v5' - 'Standard_E16ds_v5' - 'Standard_E20ds_v5' - 'Standard_E32-8ds_v5' - 'Standard_E32-16ds_v5' - 'Standard_E32ds_v5' - 'Standard_E48ds_v5' - 'Standard_E64-16ds_v5' - 'Standard_E64-32ds_v5' - 'Standard_E64ds_v5' - 'Standard_E96-24ds_v5' - 'Standard_E96-48ds_v5' - 'Standard_E96ds_v5' - 'Standard_E104ids_v5' - 'Standard_E48d_v4' - 'Standard_E64d_v4' - 'Standard_E2d_v5' - 'Standard_E4d_v5' - 'Standard_E8d_v5' - 'Standard_E16d_v5' - 'Standard_E20d_v5' - 'Standard_E32d_v5' - 'Standard_E48d_v5' - 'Standard_E64d_v5' - 'Standard_E96d_v5' - 'Standard_E104id_v5' - 'Standard_E48s_v4' - 'Standard_E64-16s_v4' - 'Standard_E64-32s_v4' - 'Standard_E64s_v4' - 'Standard_E2s_v5' - 'Standard_E4-2s_v5' - 'Standard_E4s_v5' - 'Standard_E8-2s_v5' - 'Standard_E8-4s_v5' - 'Standard_E8s_v5' - 'Standard_E16-4s_v5' - 'Standard_E16-8s_v5' - 'Standard_E16s_v5' - 'Standard_E20s_v5' - 'Standard_E32-8s_v5' - 'Standard_E32-16s_v5' - 'Standard_E32s_v5' - 'Standard_E48s_v5' - 'Standard_E64-16s_v5' - 'Standard_E64-32s_v5' - 'Standard_E64s_v5' - 'Standard_E96-24s_v5' - 'Standard_E96-48s_v5' - 'Standard_E96s_v5' - 'Standard_E104is_v5' - 'Standard_E48_v4' - 'Standard_E64_v4' - 'Standard_E2_v5' - 'Standard_E4_v5' - 'Standard_E8_v5' - 'Standard_E16_v5' - 'Standard_E20_v5' - 'Standard_E32_v5' - 'Standard_E48_v5' - 'Standard_E64_v5' - 'Standard_E96_v5' - 'Standard_E104i_v5' - 'Standard_E2bs_v5' - 'Standard_E4bs_v5' - 'Standard_E8bs_v5' - 'Standard_E16bs_v5' - 'Standard_E32bs_v5' - 'Standard_E48bs_v5' - 'Standard_E64bs_v5' - 'Standard_E2bds_v5' - 'Standard_E4bds_v5' - 'Standard_E8bds_v5' - 'Standard_E16bds_v5' - 'Standard_E32bds_v5' - 'Standard_E48bds_v5' - 'Standard_E64bds_v5' - 'Standard_D2as_v5' - 'Standard_D4as_v5' - 'Standard_D8as_v5' - 'Standard_D16as_v5' - 'Standard_D32as_v5' - 'Standard_D48as_v5' - 'Standard_D64as_v5' - 'Standard_D96as_v5' - 'Standard_D2ads_v5' - 'Standard_D4ads_v5' - 'Standard_D8ads_v5' - 'Standard_D16ads_v5' - 'Standard_D32ads_v5' - 'Standard_D48ads_v5' - 'Standard_D64ads_v5' - 'Standard_E64i_v3' - 'Standard_E64is_v3' - 'Standard_M208ms_v2' - 'Standard_M208s_v2' - 'Standard_M416-208s_v2' - 'Standard_M416s_v2' - 'Standard_M416-208ms_v2' - 'Standard_M416ms_v2' - 'Standard_D1' - 'Standard_D2' - 'Standard_D3' - 'Standard_D4' - 'Standard_D11' - 'Standard_D12' - 'Standard_D13' - 'Standard_D14' - 'Standard_NV6' - 'Standard_NV12' - 'Standard_NV24' - 'Standard_NV6_Promo' - 'Standard_NV12_Promo' - 'Standard_NV24_Promo' - 'Standard_L8s_v3' - 'Standard_L16s_v3' - 'Standard_L32s_v3' - 'Standard_L48s_v3' - 'Standard_L64s_v3' - 'Standard_L80s_v3' - 'Standard_NC4as_T4_v3' - 'Standard_NC8as_T4_v3' - 'Standard_NC16as_T4_v3' - 'Standard_NC64as_T4_v3' - 'Standard_NV6s_v2' - 'Standard_NV12s_v2' - 'Standard_NV24s_v2' - 'Standard_NV12s_v3' - 'Standard_NV24s_v3' - 'Standard_NV48s_v3' - 'Standard_M64' - 'Standard_M64m' - 'Standard_M128' - 'Standard_M128m' - 'Standard_M8-2ms' - 'Standard_M8-4ms' - 'Standard_M8ms' - 'Standard_M16-4ms' - 'Standard_M16-8ms' - 'Standard_M16ms' - 'Standard_M32-8ms' - 'Standard_M32-16ms' - 'Standard_M32ls' - 'Standard_M32ms' - 'Standard_M32ts' - 'Standard_M64-16ms' - 'Standard_M64-32ms' - 'Standard_M64ls' - 'Standard_M64ms' - 'Standard_M64s' - 'Standard_M128-32ms' - 'Standard_M128-64ms' - 'Standard_M128ms' - 'Standard_M128s' - 'Standard_M32ms_v2' - 'Standard_M64ms_v2' - 'Standard_M64s_v2' - 'Standard_M128ms_v2' - 'Standard_M128s_v2' - 'Standard_M192ims_v2' - 'Standard_M192is_v2' - 'Standard_M32dms_v2' - 'Standard_M64dms_v2' - 'Standard_M64ds_v2' - 'Standard_M128dms_v2' - 'Standard_M128ds_v2' - 'Standard_M192idms_v2' - 'Standard_M192ids_v2' - 'Standard_HB120-16rs_v2' - 'Standard_HB120-32rs_v2' - 'Standard_HB120-64rs_v2' - 'Standard_HB120-96rs_v2' - 'Standard_HB120rs_v2' - 'Standard_D2plds_v5' - 'Standard_D4plds_v5' - 'Standard_D8plds_v5' - 'Standard_D16plds_v5' - 'Standard_D32plds_v5' - 'Standard_D48plds_v5' - 'Standard_D64plds_v5' - 'Standard_D2pls_v5' - 'Standard_D4pls_v5' - 'Standard_D8pls_v5' - 'Standard_D16pls_v5' - 'Standard_D32pls_v5' - 'Standard_D48pls_v5' - 'Standard_D64pls_v5' - 'Standard_D2pds_v5' - 'Standard_D4pds_v5' - 'Standard_D8pds_v5' - 'Standard_D16pds_v5' - 'Standard_D32pds_v5' - 'Standard_D48pds_v5' - 'Standard_D64pds_v5' - 'Standard_D2ps_v5' - 'Standard_D4ps_v5' - 'Standard_D8ps_v5' - 'Standard_D16ps_v5' - 'Standard_D32ps_v5' - 'Standard_D48ps_v5' - 'Standard_D64ps_v5' - 'Standard_E2pds_v5' - 'Standard_E4pds_v5' - 'Standard_E8pds_v5' - 'Standard_E16pds_v5' - 'Standard_E20pds_v5' - 'Standard_E32pds_v5' - 'Standard_E2ps_v5' - 'Standard_E4ps_v5' - 'Standard_E8ps_v5' - 'Standard_E16ps_v5' - 'Standard_E20ps_v5' - 'Standard_E32ps_v5' - 'Standard_L8as_v3' - 'Standard_L16as_v3' - 'Standard_L32as_v3' - 'Standard_L48as_v3' - 'Standard_L64as_v3' - 'Standard_L80as_v3' - 'Standard_E2as_v5' - 'Standard_E4-2as_v5' - 'Standard_E4as_v5' - 'Standard_E8-2as_v5' - 'Standard_E8-4as_v5' - 'Standard_E8as_v5' - 'Standard_E16-4as_v5' - 'Standard_E16-8as_v5' - 'Standard_E16as_v5' - 'Standard_E20as_v5' - 'Standard_E32-8as_v5' - 'Standard_E32-16as_v5' - 'Standard_E32as_v5' - 'Standard_E48as_v5' - 'Standard_E64-16as_v5' - 'Standard_E64-32as_v5' - 'Standard_E64as_v5' - 'Standard_E96-24as_v5' - 'Standard_E96-48as_v5' - 'Standard_E96as_v5' - 'Standard_D96ads_v5' - 'Standard_E2ads_v5' - 'Standard_E4-2ads_v5' - 'Standard_E4ads_v5' - 'Standard_E8-2ads_v5' - 'Standard_E8-4ads_v5' - 'Standard_E8ads_v5' - 'Standard_E16-4ads_v5' - 'Standard_E16-8ads_v5' - 'Standard_E16ads_v5' - 'Standard_E20ads_v5' - 'Standard_E32-8ads_v5' - 'Standard_E32-16ads_v5' - 'Standard_E32ads_v5' - 'Standard_E48ads_v5' - 'Standard_E64-16ads_v5' - 'Standard_E64-32ads_v5' - 'Standard_E64ads_v5' - 'Standard_E96-24ads_v5' - 'Standard_E96-48ads_v5' - 'Standard_E96ads_v5' - 'Standard_NC6s_v2' - 'Standard_NC12s_v2' - 'Standard_NC24rs_v2' - 'Standard_NC24s_v2' - 'Standard_E80is_v4' - 'Standard_E80ids_v4' - 'Standard_NC6' - 'Standard_NC12' - 'Standard_NC24' - 'Standard_NC24r' - 'Standard_NC6_Promo' - 'Standard_NC12_Promo' - 'Standard_NC24_Promo' - 'Standard_NC24r_Promo' - 'Standard_DS1' - 'Standard_DS2' - 'Standard_DS3' - 'Standard_DS4' - 'Standard_DS11' - 'Standard_DS12' - 'Standard_DS13' - 'Standard_DS14' - 'Standard_L8s_v2' - 'Standard_L16s_v2' - 'Standard_L32s_v2' - 'Standard_L48s_v2' - 'Standard_L64s_v2' - 'Standard_L80s_v2' - 'Standard_DC8_v2' - 'Standard_DC1s_v2' - 'Standard_DC2s_v2' - 'Standard_DC4s_v2' - 'Standard_ND40rs_v2' - 'Standard_FX4mds' - 'Standard_FX12mds' - 'Standard_FX24mds' - 'Standard_FX36mds' - 'Standard_FX48mds' - 'Standard_E112ias_v5' - 'Standard_E112iads_v5' - 'Standard_NP10s' - 'Standard_NP20s' - 'Standard_NP40s' - 'Standard_NC6s_v3' - 'Standard_NC12s_v3' - 'Standard_NC24rs_v3' - 'Standard_NC24s_v3' - 'Standard_DC1s_v3' - 'Standard_DC2s_v3' - 'Standard_DC4s_v3' - 'Standard_DC8s_v3' - 'Standard_DC16s_v3' - 'Standard_DC24s_v3' - 'Standard_DC32s_v3' - 'Standard_DC48s_v3' - 'Standard_DC1ds_v3' - 'Standard_DC2ds_v3' - 'Standard_DC4ds_v3' - 'Standard_DC8ds_v3' - 'Standard_DC16ds_v3' - 'Standard_DC24ds_v3' - 'Standard_DC32ds_v3' - 'Standard_DC48ds_v3' - 'Standard_NV4as_v4' - 'Standard_NV8as_v4' - 'Standard_NV16as_v4' - 'Standard_NV32as_v4' - 'Standard_NC24ads_A100_v4' - 'Standard_NC48ads_A100_v4' - 'Standard_NC96ads_A100_v4' - 'Standard_ND96amsr_A100_v4' - 'Standard_HB120-16rs_v3' - 'Standard_HB120-32rs_v3' - 'Standard_HB120-64rs_v3' - 'Standard_HB120-96rs_v3' - 'Standard_HB120rs_v3' - 'Standard_H8' - 'Standard_H8_Promo' - 'Standard_H16' - 'Standard_H16_Promo' - 'Standard_H8m' - 'Standard_H8m_Promo' - 'Standard_H16m' - 'Standard_H16m_Promo' - 'Standard_H16r' - 'Standard_H16r_Promo' - 'Standard_H16mr' - 'Standard_H16mr_Promo' - 'Standard_HC44-16rs' - 'Standard_HC44-32rs' - 'Standard_HC44rs' - 'Standard_ND6s' - 'Standard_ND12s' - 'Standard_ND24rs' - 'Standard_ND24s' - 'Standard_NV6ads_A10_v5' - 'Standard_NV12ads_A10_v5' - 'Standard_NV18ads_A10_v5' - 'Standard_NV36adms_A10_v5' - 'Standard_NV36ads_A10_v5' - 'Standard_NV72ads_A10_v5' - 'Standard_DC2s' - 'Standard_DC4s' - 'Standard_PB6s' - 'Standard_HB60-15rs' - 'Standard_HB60-30rs' - 'Standard_HB60-45rs' - 'Standard_HB60rs' - 'Standard_ND96asr_v4' - 'Standard_ND40s_v3' -]) -// $0.252/hr in West US 3; 4 vCPU, 32 GiB RAM, Memory optimized -param vmSize string = 'Standard_E4as_v4' - -@description('Name of the VNET') -param virtualNetworkName string = '${vmName}-vNet' - -@description('Name of the subnet in the virtual network') -param subnetName string = '${vmName}-Subnet' - -@description('Name of the Network Security Group') -param networkSecurityGroupName string = '${vmName}-SecGroupNet' - -var publicIPAddressName = '${vmName}-PublicIP' -var networkInterfaceName = '${vmName}-NetInt' -var osDiskType = 'Premium_LRS' -var subnetAddressPrefix = '10.1.0.0/24' -var addressPrefix = '10.1.0.0/16' -var linuxConfiguration = { - disablePasswordAuthentication: true - ssh: { - publicKeys: [ - { - path: '/home/${adminUsername}/.ssh/authorized_keys' - keyData: adminPasswordOrKey - } - ] - } -} - -resource nic 'Microsoft.Network/networkInterfaces@2021-05-01' = { - name: networkInterfaceName - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - subnet: { - id: subnet.id - } - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: publicIP.id - } - } - } - ] - networkSecurityGroup: { - id: nsg.id - } - } -} - -resource nsg 'Microsoft.Network/networkSecurityGroups@2021-05-01' = { - name: networkSecurityGroupName - location: location - properties: { - securityRules: [ - { - name: 'SSH' - properties: { - priority: 1000 - protocol: 'Tcp' - access: 'Allow' - direction: 'Inbound' - sourceAddressPrefix: '*' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '22' - } - } - ] - } -} - -resource vnet 'Microsoft.Network/virtualNetworks@2021-05-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - } -} - -resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-05-01' = { - parent: vnet - name: subnetName - properties: { - addressPrefix: subnetAddressPrefix - privateEndpointNetworkPolicies: 'Enabled' - privateLinkServiceNetworkPolicies: 'Enabled' - } -} - -resource publicIP 'Microsoft.Network/publicIPAddresses@2021-05-01' = { - name: publicIPAddressName - location: location - sku: { - name: 'Basic' - } - properties: { - deleteOption: 'Delete' - publicIPAllocationMethod: 'Dynamic' - publicIPAddressVersion: 'IPv4' - dnsSettings: { - domainNameLabel: vmName - } - idleTimeoutInMinutes: 4 - } -} - -resource vm 'Microsoft.Compute/virtualMachines@2021-11-01' = { - name: vmName - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - storageProfile: { - osDisk: { - diskSizeGB: 256 - createOption: 'FromImage' - deleteOption: 'Delete' - managedDisk: { - storageAccountType: osDiskType - } - } - imageReference: { - publisher: 'Canonical' - offer: ubuntuOffer - sku: ubuntuOSVersion - version: 'latest' - } - } - networkProfile: { - networkInterfaces: [ - { - id: nic.id - } - ] - } - osProfile: { - computerName: vmName - adminUsername: adminUsername - adminPassword: adminPasswordOrKey - linuxConfiguration: ((authenticationType == 'password') ? null : linuxConfiguration) - } - } -} - -output sshUserAtHostname string = '${adminUsername}@${publicIP.properties.dnsSettings.fqdn}' diff --git a/.github/workflows/gluwa.yml b/.github/workflows/gluwa.yml index f322b2322c311..b40e13418d6b6 100644 --- a/.github/workflows/gluwa.yml +++ b/.github/workflows/gluwa.yml @@ -14,90 +14,72 @@ on: permissions: read-all env: - RUNNER_VM_NAME: "github-runner-$GITHUB_RUN_ID-attempt-$GITHUB_RUN_ATTEMPT" - RESOURCE_GROUP: "github-runner-$GITHUB_RUN_ID-attempt-$GITHUB_RUN_ATTEMPT" - AZ_LOCATION: "westus3" + RUNNER_VM_NAME: "${{ github.event.repository.name }}-$GITHUB_RUN_ID-attempt-$GITHUB_RUN_ATTEMPT" + LINODE_REGION: "nl-ams" + # Shared CPU, Linode 8 GB, 4 vCPU, 96 $/mo + LINODE_VM_SIZE: "g6-standard-4" # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: deploy-github-runner: + timeout-minutes: 15 runs-on: ubuntu-latest - outputs: - runner_vm_name: ${{ steps.get-env.outputs.runner_vm_name }} - resource_group: ${{ steps.get-env.outputs.resource_group }} + strategy: + fail-fast: false + matrix: + include: + - proxy_type: substrate steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Install azure-cli + # See https://github.com/actions/runner/issues/1879#issuecomment-1123196869 + - name: Create matrix.txt run: | - sudo apt remove azure-cli -y && sudo apt autoremove -y - curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - sudo apt install -y jq - az version - - - name: Authorize hosted-runner - run: | - mkdir -p ~/.ssh/ - ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa - cat ~/.ssh/id_rsa.pub >> .github/authorized_keys + echo "proxy=${{ matrix.proxy }} / ${{ matrix.secret }} / type=${{ matrix.proxy_type }}" > matrix.txt - name: Evaluate env vars id: get-env run: | + HASH_VALUE=$(echo "${{ hashFiles('matrix.txt') }}" | cut -c1-7) + rm matrix.txt + # WARNING: using env.RUNNER_VM_NAME directly in job outputs above # doesn't evaluate the $GITHUB_RUN_ID reference - echo "runner_vm_name=${{ env.RUNNER_VM_NAME }}" >> "$GITHUB_OUTPUT" - echo "resource_group=${{ env.RESOURCE_GROUP }}" >> "$GITHUB_OUTPUT" + echo "runner_vm_name=${{ env.RUNNER_VM_NAME }}-$HASH_VALUE" >> "$GITHUB_OUTPUT" - name: Provision VM if: env.LC_GITHUB_REPO_ADMIN_TOKEN run: | - echo "INFO: From ENVs: RUNNER_VM_NAME=${{ env.RUNNER_VM_NAME }}" - echo "INFO: From Step: RUNNER_VM_NAME=${{ steps.get-env.outputs.runner_vm_name }}" - - az login --service-principal --username "${{ secrets.AZURE_APP_ID }}" --password "${{ secrets.AZURE_APP_PASSWORD }}" --tenant "${{ secrets.AZURE_TENANT_ID }}" - az account set --subscription "Playground Subscription" - ## az account set -s "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - - - # create resource group - echo "INFO: ${{ steps.get-env.outputs.resource_group }}" - az group create -n "${{ steps.get-env.outputs.resource_group }}" --location "${{ env.AZ_LOCATION }}" - - # RG Creditcoin-Test is in WestUS and the CPU quota is already full - # that's why specify a different region here - az deployment group create -g "${{ steps.get-env.outputs.resource_group }}" -f .github/runner.bicep \ - --parameters location="${{ env.AZ_LOCATION }}" \ - --parameters vmName="${{ steps.get-env.outputs.runner_vm_name }}" \ - --parameters adminPasswordOrKey="$(cat .github/authorized_keys)" > output.json - - # provision the GitHub Runner binary on the VM - # passing additional ENV values - SSH_USER_AT_HOSTNAME=$(jq -r '.properties.outputs.sshUserAtHostname.value' < output.json) - echo "INFO: $SSH_USER_AT_HOSTNAME" - - export LC_RUNNER_VM_NAME="${{ env.RUNNER_VM_NAME }}" - until ssh -i ~/.ssh/id_rsa \ - -o SendEnv=LC_GITHUB_REPO_ADMIN_TOKEN,LC_RUNNER_VM_NAME \ - -o StrictHostKeyChecking=no "$SSH_USER_AT_HOSTNAME" < ./.github/provision-github-runner.sh; do - echo "DEBUG: retrying ssh connection ..." - sleep 30 - done + .github/provision-linode-vm.sh env: + LC_OWNER_REPO_SLUG: ${{ github.repository }} LC_GITHUB_REPO_ADMIN_TOKEN: ${{ secrets.GH_REPO_ADMIN_TOKEN }} LC_RUNNER_EPHEMERAL: false + LC_RUNNER_VM_NAME: ${{ steps.get-env.outputs.runner_vm_name }} + LC_PROXY_ENABLED: ${{ matrix.proxy }} + LC_PROXY_SECRET_VARIANT: ${{ matrix.secret }} + LC_PROXY_TYPE: ${{ matrix.proxy_type }} + LC_WORKFLOW_ID: ${{ github.run_id }} + LINODE_CLI_TOKEN: ${{ secrets.LINODE_CLI_TOKEN }} + + - name: Upload Linode logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: linode-${{ matrix.proxy }}-${{ matrix.secret }}-${{ matrix.proxy_type }}-logs + path: retry*.json cargo-check: needs: - deploy-github-runner runs-on: - [self-hosted, "${{ needs.deploy-github-runner.outputs.runner_vm_name }}"] + [self-hosted, "workflow-${{ github.run_id }}", "type-substrate"] # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Configure rustc version run: | @@ -106,7 +88,7 @@ jobs: echo "RUSTC_VERSION=$RUSTC_VERSION" >> "$GITHUB_ENV" - name: Install Rust toolchain - uses: actions-rs/toolchain@v1 + uses: gluwa/toolchain@dev with: toolchain: ${{ env.RUSTC_VERSION }} target: wasm32-unknown-unknown @@ -122,10 +104,10 @@ jobs: needs: - deploy-github-runner runs-on: - [self-hosted, "${{ needs.deploy-github-runner.outputs.runner_vm_name }}"] + [self-hosted, "workflow-${{ github.run_id }}", "type-substrate"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Configure rustc version run: | @@ -134,7 +116,7 @@ jobs: echo "RUSTC_VERSION=$RUSTC_VERSION" >> "$GITHUB_ENV" - name: Install Rust toolchain - uses: actions-rs/toolchain@v1 + uses: gluwa/toolchain@dev with: toolchain: ${{ env.RUSTC_VERSION }} target: wasm32-unknown-unknown @@ -156,33 +138,32 @@ jobs: - cargo-test if: ${{ always() && needs.deploy-github-runner.result != 'skipped' }} + strategy: + fail-fast: false + matrix: + include: + - proxy_type: substrate + steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + # See https://github.com/actions/runner/issues/1879#issuecomment-1123196869 + - name: Create matrix.txt + run: | + echo "proxy=${{ matrix.proxy }} / ${{ matrix.secret }} / type=${{ matrix.proxy_type }}" > matrix.txt - name: Evaluate env vars id: get-env run: | - # WARNING: using env.RUNNER_VM_NAME directly in job outputs above - # doesn't evaluate the $GITHUB_RUN_ID reference - echo "resource_group=${{ env.RESOURCE_GROUP }}" >> "$GITHUB_OUTPUT" + HASH_VALUE=$(echo "${{ hashFiles('matrix.txt') }}" | cut -c1-7) + rm matrix.txt - - name: Install azure-cli - run: | - sudo apt remove azure-cli -y && sudo apt autoremove -y - curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash - az version + echo "runner_vm_name=${{ env.RUNNER_VM_NAME }}-$HASH_VALUE" >> "$GITHUB_OUTPUT" - name: Remove VM + continue-on-error: true run: | - echo "INFO: RUNNER_VM_NAME=${{ env.RUNNER_VM_NAME }}" - - az login --service-principal --username "${{ secrets.AZURE_APP_ID }}" --password "${{ secrets.AZURE_APP_PASSWORD }}" --tenant "${{ secrets.AZURE_TENANT_ID }}" - az account set --subscription "Playground Subscription" - az group delete --yes -n "${{ steps.get-env.outputs.resource_group }}" - - - name: Upload logs - uses: actions/upload-artifact@v3 - if: always() - with: - name: "Azure resources" - path: azure_resource_list.json + .github/remove-linode-vm.sh + env: + LINODE_CLI_TOKEN: ${{ secrets.LINODE_CLI_TOKEN }} + LC_RUNNER_VM_NAME: ${{ steps.get-env.outputs.runner_vm_name }}