From cc25df7206bf975aaa6cd2af1311826ff1c305dd Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 20:35:52 -0400 Subject: [PATCH 01/17] Apply Prettier --- .devcontainer/devcontainer.json | 2 +- .github/workflows/ci-dotnet.yml | 61 ++- .github/workflows/ci-scripted-strategy.json | 11 +- .github/workflows/ci-scripted.yml | 459 +++++++++--------- .github/workflows/ci-vanilla.yml | 386 +++++++-------- .github/workflows/test.json | 11 +- README.md | 18 +- functions/global.json | 8 +- functions/host.json | 18 +- minecraft/bstats/config.yml | 2 +- minecraft/log-filter/config.yml | 14 +- multi-instance.md | 11 +- terraform/arm/startstop-template.json | 107 ++-- .../arm/workflow-connection-template.json | 63 +-- 14 files changed, 589 insertions(+), 582 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 926f5b6..4b7642d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -17,4 +17,4 @@ // Run bash script in .devcontainer directory "postCreateCommand": "/usr/bin/pwsh -nop -f ./.devcontainer/createorupdate.ps1 > ~/post-create.log" -} \ No newline at end of file +} diff --git a/.github/workflows/ci-dotnet.yml b/.github/workflows/ci-dotnet.yml index 0c42b9a..f79845e 100644 --- a/.github/workflows/ci-dotnet.yml +++ b/.github/workflows/ci-dotnet.yml @@ -3,50 +3,49 @@ name: ci-dotnet on: push: branches: - - '**' + - "**" paths: - - '.github/workflows/ci-function.yml' - - 'functions/**' + - ".github/workflows/ci-function.yml" + - "functions/**" pull_request: - branches: [ main ] + branches: [main] paths-ignore: - - '**/README.md' - - '**/LICENSE' - - 'visuals/**' + - "**/README.md" + - "**/LICENSE" + - "visuals/**" schedule: - - cron: '0 2 * * *' + - cron: "0 2 * * *" # Allows you to run this workflow manually from the Actions tab workflow_dispatch: env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: './functions' - DOTNET_VERSION: '6.0.x' + AZURE_FUNCTIONAPP_PACKAGE_PATH: "./functions" + DOTNET_VERSION: "6.0.x" jobs: dotnet: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Restore dependencies - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet restore - popd - - name: Build - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet build --no-restore --output ./bin/publish - popd - - name: Test - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet test --no-build --verbosity normal - popd \ No newline at end of file + - uses: actions/checkout@v2 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Restore dependencies + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet restore + popd + - name: Build + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet build --no-restore --output ./bin/publish + popd + - name: Test + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet test --no-build --verbosity normal + popd diff --git a/.github/workflows/ci-scripted-strategy.json b/.github/workflows/ci-scripted-strategy.json index 5b75ee0..5c02d04 100644 --- a/.github/workflows/ci-scripted-strategy.json +++ b/.github/workflows/ci-scripted-strategy.json @@ -1,11 +1,6 @@ { - "os": [ - "ubuntu-latest" - ], - "compatible": [ - "backward", - "forward" - ], + "os": ["ubuntu-latest"], + "compatible": ["backward", "forward"], "include": [ { "compatible": "backward", @@ -28,4 +23,4 @@ "upgrade_azure_cli": true } ] -} \ No newline at end of file +} diff --git a/.github/workflows/ci-scripted.yml b/.github/workflows/ci-scripted.yml index 34ec55d..b018ae9 100644 --- a/.github/workflows/ci-scripted.yml +++ b/.github/workflows/ci-scripted.yml @@ -1,47 +1,47 @@ on: pull_request: - branches: [ main ] + branches: [main] paths-ignore: - - '**/README.md' - - '**/LICENSE' - - 'visuals/**' + - "**/README.md" + - "**/LICENSE" + - "visuals/**" schedule: - - cron: '0 2 * * Thu,Sat' + - cron: "0 2 * * Thu,Sat" # Allows you to run this workflow manually from the Actions tab workflow_dispatch: inputs: upgrade_provider_versions: - description: 'Upgrade Terraform provider versions' + description: "Upgrade Terraform provider versions" required: false type: boolean default: false upgrade_terraform_version: - description: 'Upgrade Terraform version' + description: "Upgrade Terraform version" required: false type: boolean default: false upgrade_azure_cli: - description: 'Upgrade Azure CLI to latest version' + description: "Upgrade Azure CLI to latest version" required: false type: boolean default: false destroy: - description: 'Destroy Infrastucture' + description: "Destroy Infrastucture" required: false type: boolean default: true workspace: type: choice required: true - description: 'Terraform Workspace' + description: "Terraform Workspace" default: ci - options: - - ci - - ci1 - - ci2 - - ci3 + options: + - ci + - ci1 + - ci2 + - ci3 env: ARM_SAS_TOKEN: ${{ secrets.ARM_SAS_TOKEN }} TF_IN_AUTOMATION: true @@ -63,38 +63,38 @@ jobs: working-directory: scripts runs-on: ubuntu-latest steps: - - name: Checkout source - uses: actions/checkout@v2 - - - name: Print environment variables - run: | - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name - shell: pwsh - - - name: Create matrix - id: create-matrix - run: | - ConvertTo-SecureString -AsPlainText -String '${{ secrets.GITHUB_TOKEN }}' | Set-Variable gitHubToken - ./create_workflow_strategy.ps1 -GitHubToken $gitHubToken ` - -DestroyInput "${{ github.event.inputs.destroy }}" ` - -UseLatestAzureCLIVersionInput "${{ github.event.inputs.upgrade_azure_cli }}" ` - -UseLatestTerraformProviderVersionsInput "${{ github.event.inputs.upgrade_provider_versions }}" ` - -UseLatestTerraformVersionInput "${{ github.event.inputs.upgrade_terraform_version }}" - - shell: pwsh - - - name: Install json2yaml - run: | - sudo npm install -g json2yaml - - - name: Display matrix - run: | - $matrixJSON = '${{ steps.create-matrix.outputs.matrix }}' - $matrixJSON - $matrixJSON | jq - $matrixJSON | ConvertFrom-Json - $matrixJSON | json2yaml - shell: pwsh + - name: Checkout source + uses: actions/checkout@v2 + + - name: Print environment variables + run: | + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name + shell: pwsh + + - name: Create matrix + id: create-matrix + run: | + ConvertTo-SecureString -AsPlainText -String '${{ secrets.GITHUB_TOKEN }}' | Set-Variable gitHubToken + ./create_workflow_strategy.ps1 -GitHubToken $gitHubToken ` + -DestroyInput "${{ github.event.inputs.destroy }}" ` + -UseLatestAzureCLIVersionInput "${{ github.event.inputs.upgrade_azure_cli }}" ` + -UseLatestTerraformProviderVersionsInput "${{ github.event.inputs.upgrade_provider_versions }}" ` + -UseLatestTerraformVersionInput "${{ github.event.inputs.upgrade_terraform_version }}" + + shell: pwsh + + - name: Install json2yaml + run: | + sudo npm install -g json2yaml + + - name: Display matrix + run: | + $matrixJSON = '${{ steps.create-matrix.outputs.matrix }}' + $matrixJSON + $matrixJSON | jq + $matrixJSON | ConvertFrom-Json + $matrixJSON | json2yaml + shell: pwsh outputs: matrix: ${{ steps.create-matrix.outputs.matrix }} @@ -115,188 +115,187 @@ jobs: runs-on: ${{ matrix.os }} steps: - - name: Checkout source - uses: actions/checkout@v2 - - - name: Dump strategy context - env: - MATRIX_CONTEXT: ${{ toJSON(matrix) }} - STRATEGY_CONTEXT: ${{ toJSON(strategy) }} - run: | - Write-Host "Strategy context:" - $env:STRATEGY_CONTEXT | ConvertFrom-Json | Format-List - Write-Host "Matrix context:" - $env:MATRIX_CONTEXT | ConvertFrom-Json | Format-List - shell: pwsh - - - name: Upgrade Azure CLI - id: az-upgrade - if: ${{ matrix.upgrade_azure_cli }} - run: | - # sudo az upgrade -y # not reliable - - curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null - echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list - sudo apt-get update - - $packageName = ($(apt-cache show azure-cli | Select-String 'Version: ${{ matrix.azure_cli_version }}.*$') -split ' ' | Select-Object -Last 1) - Write-Host "`nAzure CLI package: $packageName" - if ($packageName) { - sudo apt-get install --allow-downgrades azure-cli=$packageName - } else { - Write-Host "Azure CLI version ${{ matrix.azure_cli_version }} not found" - } - - az -v - continue-on-error: true - shell: pwsh - - - name: Use Azure CLI - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - enable-AzPSSession: false - - - name: Show Azure CLI version - run: | - az -v - - - name: Use Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_version: ${{matrix.terraform_version}} - terraform_wrapper: false - - - name: Show Terraform version - run: | - terraform -v - - - name: Unpin Terraform provider versions - id: terraform-version-check - if: ${{ !matrix.pin_provider_versions }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - (Get-Content ./provider.tf) -replace " = `" *= +",' = "~> ' | Out-File provider.tf - Get-Content ./provider.tf - if (Test-Path .terraform.lock.hcl) { - Remove-Item .terraform.lock.hcl -Force - } - shell: pwsh - - - name: Prepare environment variables - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - ENVIRONMENT_VARIABLES: ${{ secrets.ENVIRONMENT_VARIABLES }} - run: | - # Parse Azure secret into Terraform variables - $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) - $env:ARM_CLIENT_ID = $servicePrincipal.clientId - $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret - $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId - $env:ARM_TENANT_ID = $servicePrincipal.tenantId - - $env:TF_VAR_run_id=$env:GITHUB_RUN_ID - # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: - $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId - $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret - $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId - - # Save environment variable setup for subsequent steps - Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV - shell: pwsh - - - name: Show environment variables - run: | - Write-Host "Environment (sorted):" - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name - Write-Host "Environment (unsorted):" - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* - shell: pwsh - - - name: Terraform Init & Plan - run: ./deploy.ps1 -Init -Plan - shell: pwsh - - - name: Use Node.js - if: ${{ matrix.terraform_apply }} - uses: actions/setup-node@v1 - - name: Install Azure Functions Core Tools - if: ${{ matrix.terraform_apply }} - run: - npm i -g azure-functions-core-tools@3 --unsafe-perm true - - - name: Terraform Apply - id: terraform-apply - if: ${{ matrix.terraform_apply }} - run: ./deploy.ps1 -Apply -Force -NoCode - shell: pwsh - - - name: Deploy Azure Function - if: ${{ matrix.terraform_apply }} - run: ./deploy_functions.ps1 - shell: pwsh - - - name: Test connection to Minecraft Server - if: ${{ matrix.terraform_apply }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - $minecraftConfig = (terraform output -json minecraft_java | ConvertFrom-Json -AsHashtable) - foreach ($minecraftConfigName in $minecraftConfig.Keys) { - Write-Host "Processing configuration '{$minecraftConfigName}''..." - $containerGroupID = $minecraftConfig[$minecraftConfigName].container_group_id - $serverFQDN = $minecraftConfig[$minecraftConfigName].minecraft_server_fqdn - $serverPort = $minecraftConfig[$minecraftConfigName].minecraft_server_port - - # Wait for Minecraft socket to open - $connectionAttempts = 0 - do { - Start-Sleep -Seconds 10 - Write-Host "Pinging ${serverFQDN} on port ${serverPort}..." - try { - $connectionAttempts++ - $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($serverFQDN, $serverPort) -ErrorAction SilentlyContinue - } catch [System.Management.Automation.MethodInvocationException] { - Write-Warning $_ - } - } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) - if ($mineCraftConnection.Connected) { - Write-Host "Connected to ${serverFQDN}:${serverPort}" - $mineCraftConnection.Close() + - name: Checkout source + uses: actions/checkout@v2 + + - name: Dump strategy context + env: + MATRIX_CONTEXT: ${{ toJSON(matrix) }} + STRATEGY_CONTEXT: ${{ toJSON(strategy) }} + run: | + Write-Host "Strategy context:" + $env:STRATEGY_CONTEXT | ConvertFrom-Json | Format-List + Write-Host "Matrix context:" + $env:MATRIX_CONTEXT | ConvertFrom-Json | Format-List + shell: pwsh + + - name: Upgrade Azure CLI + id: az-upgrade + if: ${{ matrix.upgrade_azure_cli }} + run: | + # sudo az upgrade -y # not reliable + + curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null + echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list + sudo apt-get update + + $packageName = ($(apt-cache show azure-cli | Select-String 'Version: ${{ matrix.azure_cli_version }}.*$') -split ' ' | Select-Object -Last 1) + Write-Host "`nAzure CLI package: $packageName" + if ($packageName) { + sudo apt-get install --allow-downgrades azure-cli=$packageName } else { - Write-Warning "Could not connect to ${serverFQDN}:${serverPort}!" + Write-Host "Azure CLI version ${{ matrix.azure_cli_version }} not found" + } + + az -v + continue-on-error: true + shell: pwsh + + - name: Use Azure CLI + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + enable-AzPSSession: false + + - name: Show Azure CLI version + run: | + az -v + + - name: Use Terraform + uses: hashicorp/setup-terraform@v1 + with: + terraform_version: ${{matrix.terraform_version}} + terraform_wrapper: false + + - name: Show Terraform version + run: | + terraform -v + + - name: Unpin Terraform provider versions + id: terraform-version-check + if: ${{ !matrix.pin_provider_versions }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + (Get-Content ./provider.tf) -replace " = `" *= +",' = "~> ' | Out-File provider.tf + Get-Content ./provider.tf + if (Test-Path .terraform.lock.hcl) { + Remove-Item .terraform.lock.hcl -Force } - - # BUG: https://github.com/Azure/azure-cli/issues/13352 - # No tty / ioctl device - # az container exec --ids $containerGroupID --exec-command "/health.sh" --container-name minecraft - script --return --quiet -c "az container exec --ids $containerGroupID --exec-command '/health.sh' --container-name minecraft" /dev/null - - az container show --ids $containerGroupID --query instanceView - az container logs --ids $containerGroupID - } - shell: pwsh - - - name: Remove backup items & resource locks - if: ${{ matrix.destroy }} - run: | - . (Join-Path $env:GITHUB_WORKSPACE scripts functions.ps1) - TearDown-Resources -Backups -Locks - shell: pwsh - - - name: Terraform Destroy - if: ${{ matrix.destroy }} - run: ./deploy.ps1 -Destroy -Force - shell: pwsh - continue-on-error: ${{ matrix.ignore_destroy_failure }} - - - name: Upload artifacts - uses: actions/upload-artifact@v2 - if: ${{ matrix.terraform_apply }} - with: - name: terraform - path: 'terraform' - - - name: Teardown - if: ${{ matrix.destroy || failure() }} - run: ./deploy.ps1 -Init -Teardown - shell: pwsh + shell: pwsh + + - name: Prepare environment variables + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ENVIRONMENT_VARIABLES: ${{ secrets.ENVIRONMENT_VARIABLES }} + run: | + # Parse Azure secret into Terraform variables + $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) + $env:ARM_CLIENT_ID = $servicePrincipal.clientId + $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret + $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId + $env:ARM_TENANT_ID = $servicePrincipal.tenantId + + $env:TF_VAR_run_id=$env:GITHUB_RUN_ID + # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: + $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId + $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret + $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId + + # Save environment variable setup for subsequent steps + Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV + shell: pwsh + + - name: Show environment variables + run: | + Write-Host "Environment (sorted):" + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name + Write-Host "Environment (unsorted):" + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* + shell: pwsh + + - name: Terraform Init & Plan + run: ./deploy.ps1 -Init -Plan + shell: pwsh + + - name: Use Node.js + if: ${{ matrix.terraform_apply }} + uses: actions/setup-node@v1 + - name: Install Azure Functions Core Tools + if: ${{ matrix.terraform_apply }} + run: npm i -g azure-functions-core-tools@3 --unsafe-perm true + + - name: Terraform Apply + id: terraform-apply + if: ${{ matrix.terraform_apply }} + run: ./deploy.ps1 -Apply -Force -NoCode + shell: pwsh + + - name: Deploy Azure Function + if: ${{ matrix.terraform_apply }} + run: ./deploy_functions.ps1 + shell: pwsh + + - name: Test connection to Minecraft Server + if: ${{ matrix.terraform_apply }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + $minecraftConfig = (terraform output -json minecraft_java | ConvertFrom-Json -AsHashtable) + foreach ($minecraftConfigName in $minecraftConfig.Keys) { + Write-Host "Processing configuration '{$minecraftConfigName}''..." + $containerGroupID = $minecraftConfig[$minecraftConfigName].container_group_id + $serverFQDN = $minecraftConfig[$minecraftConfigName].minecraft_server_fqdn + $serverPort = $minecraftConfig[$minecraftConfigName].minecraft_server_port + + # Wait for Minecraft socket to open + $connectionAttempts = 0 + do { + Start-Sleep -Seconds 10 + Write-Host "Pinging ${serverFQDN} on port ${serverPort}..." + try { + $connectionAttempts++ + $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($serverFQDN, $serverPort) -ErrorAction SilentlyContinue + } catch [System.Management.Automation.MethodInvocationException] { + Write-Warning $_ + } + } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) + if ($mineCraftConnection.Connected) { + Write-Host "Connected to ${serverFQDN}:${serverPort}" + $mineCraftConnection.Close() + } else { + Write-Warning "Could not connect to ${serverFQDN}:${serverPort}!" + } + + # BUG: https://github.com/Azure/azure-cli/issues/13352 + # No tty / ioctl device + # az container exec --ids $containerGroupID --exec-command "/health.sh" --container-name minecraft + script --return --quiet -c "az container exec --ids $containerGroupID --exec-command '/health.sh' --container-name minecraft" /dev/null + + az container show --ids $containerGroupID --query instanceView + az container logs --ids $containerGroupID + } + shell: pwsh + + - name: Remove backup items & resource locks + if: ${{ matrix.destroy }} + run: | + . (Join-Path $env:GITHUB_WORKSPACE scripts functions.ps1) + TearDown-Resources -Backups -Locks + shell: pwsh + + - name: Terraform Destroy + if: ${{ matrix.destroy }} + run: ./deploy.ps1 -Destroy -Force + shell: pwsh + continue-on-error: ${{ matrix.ignore_destroy_failure }} + + - name: Upload artifacts + uses: actions/upload-artifact@v2 + if: ${{ matrix.terraform_apply }} + with: + name: terraform + path: "terraform" + + - name: Teardown + if: ${{ matrix.destroy || failure() }} + run: ./deploy.ps1 -Init -Teardown + shell: pwsh diff --git a/.github/workflows/ci-vanilla.yml b/.github/workflows/ci-vanilla.yml index 739ff1e..fe916f3 100644 --- a/.github/workflows/ci-vanilla.yml +++ b/.github/workflows/ci-vanilla.yml @@ -1,29 +1,29 @@ -# Controls when the action will run. +# Controls when the action will run. on: # Triggers the workflow on push or pull request events but only for the main branch push: - branches: [ main ] + branches: [main] paths-ignore: - - '**/README.md' - - '**/LICENSE' - - 'visuals/**' + - "**/README.md" + - "**/LICENSE" + - "visuals/**" pull_request: - branches: [ main ] + branches: [main] paths-ignore: - - '**/README.md' - - '**/LICENSE' - - 'visuals/**' + - "**/README.md" + - "**/LICENSE" + - "visuals/**" schedule: - - cron: '0 3 * * Fri,Sun' + - cron: "0 3 * * Fri,Sun" # Allows you to run this workflow manually from the Actions tab workflow_dispatch: env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: 'functions' - DOTNET_VERSION: '6.0.x' - FUNCTIONS_ARTIFACT_NAME: 'functions' + AZURE_FUNCTIONAPP_PACKAGE_PATH: "functions" + DOTNET_VERSION: "6.0.x" + FUNCTIONS_ARTIFACT_NAME: "functions" TF_IN_AUTOMATION: true TF_INPUT: 0 TF_VAR_location: ${{ secrets.TF_VAR_LOCATION }} @@ -38,31 +38,31 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Restore dependencies - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet restore - popd - - name: Build - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet build --no-restore --output ./bin/publish - popd - - name: Test - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet test --no-build --verbosity normal - popd - - name: Upload artifacts - uses: actions/upload-artifact@v2 - with: - name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} - path: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' + - uses: actions/checkout@v2 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Restore dependencies + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet restore + popd + - name: Build + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet build --no-restore --output ./bin/publish + popd + - name: Test + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet test --no-build --verbosity normal + popd + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} + path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" terraform: needs: dotnet @@ -72,159 +72,159 @@ jobs: working-directory: terraform runs-on: ubuntu-latest steps: - - name: Checkout source - uses: actions/checkout@v2 - - - name: Download artifacts from previous job - uses: actions/download-artifact@v2 - with: - name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} - path: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' - - - name: Use Azure CLI - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - - name: Detect desired Terraform version - id: terraform-version-check - run: | - $terraformVersion = (Get-Content .terraform-version) - Write-Output "TERRAFORM_VERSION=${terraformVersion}" >> $env:GITHUB_OUTPUT - shell: pwsh - - name: Use Terraform - uses: hashicorp/setup-terraform@v1 - with: - terraform_version: ${{ steps.terraform-version-check.outputs.TERRAFORM_VERSION }} - terraform_wrapper: false - - - name: Terraform Init - run: | - # Parse Azure secret into Terraform variables - $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) - $env:ARM_CLIENT_ID = $servicePrincipal.clientId - $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret - $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId - $env:ARM_TENANT_ID = $servicePrincipal.tenantId - - $env:TF_VAR_run_id=$env:GITHUB_RUN_ID - # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: - $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId - $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret - $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId - - # List environment variables - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,TF_* | Sort-Object -Property Name - # Save environment variable setup for subsequent steps - Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV - - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - Get-Location - terraform init - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - shell: pwsh - - - name: Terraform Plan - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform plan -out='ci.tfplan' - shell: pwsh - - - name: Terraform Apply - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - id: terraform-apply - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform apply -auto-approve 'ci.tfplan' - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - throw "'terraform apply' exited with status $exitCode" - } - - # Export Terraform output as step output - $terraformOutput = (terraform output -json | ConvertFrom-Json -AsHashtable) - foreach ($key in $terraformOutput.Keys) { - $outputVariableValue = $terraformOutput[$key].value - Write-Output "${key}=${outputVariableValue}" >> $env:GITHUB_OUTPUT - Write-Output "TF_OUT_${key}=${outputVariableValue}" >> $env:GITHUB_ENV - } - shell: pwsh - - - name: 'Publish Monitor Function' - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - uses: azure/functions-action@v1 - with: - app-name: ${{ steps.terraform-apply.outputs.function_name }} - package: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' - - - name: Test connection to Minecraft Server (pwsh) - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - run: | - # Wait for Minecraft to boot up - $connectionAttempts = 0 - do { - Start-Sleep -Seconds 10 - Write-Host "Pinging ${env:TF_OUT_minecraft_server_fqdn} on port ${env:TF_OUT_minecraft_server_port}..." - try { - $connectionAttempts++ - $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($env:TF_OUT_minecraft_server_fqdn, $env:TF_OUT_minecraft_server_port) -ErrorAction SilentlyContinue - } catch [System.Management.Automation.MethodInvocationException] { - Write-Warning $_ + - name: Checkout source + uses: actions/checkout@v2 + + - name: Download artifacts from previous job + uses: actions/download-artifact@v2 + with: + name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} + path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" + + - name: Use Azure CLI + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Detect desired Terraform version + id: terraform-version-check + run: | + $terraformVersion = (Get-Content .terraform-version) + Write-Output "TERRAFORM_VERSION=${terraformVersion}" >> $env:GITHUB_OUTPUT + shell: pwsh + - name: Use Terraform + uses: hashicorp/setup-terraform@v1 + with: + terraform_version: ${{ steps.terraform-version-check.outputs.TERRAFORM_VERSION }} + terraform_wrapper: false + + - name: Terraform Init + run: | + # Parse Azure secret into Terraform variables + $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) + $env:ARM_CLIENT_ID = $servicePrincipal.clientId + $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret + $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId + $env:ARM_TENANT_ID = $servicePrincipal.tenantId + + $env:TF_VAR_run_id=$env:GITHUB_RUN_ID + # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: + $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId + $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret + $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId + + # List environment variables + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,TF_* | Sort-Object -Property Name + # Save environment variable setup for subsequent steps + Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV + + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + Get-Location + terraform init + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + shell: pwsh + + - name: Terraform Plan + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform plan -out='ci.tfplan' + shell: pwsh + + - name: Terraform Apply + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + id: terraform-apply + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform apply -auto-approve 'ci.tfplan' + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { + throw "'terraform apply' exited with status $exitCode" + } + + # Export Terraform output as step output + $terraformOutput = (terraform output -json | ConvertFrom-Json -AsHashtable) + foreach ($key in $terraformOutput.Keys) { + $outputVariableValue = $terraformOutput[$key].value + Write-Output "${key}=${outputVariableValue}" >> $env:GITHUB_OUTPUT + Write-Output "TF_OUT_${key}=${outputVariableValue}" >> $env:GITHUB_ENV } - } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) - - # No tty - # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - shell: pwsh - - # - name: Test connection to Minecraft Server (bash) - # if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - # run: | - # # Wait for Minecraft to boot up - # while ! echo exit | nc $TF_OUT_minecraft_server_fqdn $TF_OUT_minecraft_server_port; do sleep 10; done - # # No tty - # # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft - # shell: bash - - - name: Terraform Destroy - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform destroy -auto-approve - shell: pwsh - - - name: Upload artifacts - uses: actions/upload-artifact@v2 - with: - name: terraform - path: 'terraform' - - - name: Clean Up - if: ${{ always() }} - run: | - $ErrorActionPreference = "Continue" - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - - # Remove resource locks first - $resourceLocksJSON = $(terraform output -json resource_locks 2>$null) - if ($resourceLocksJSON -and ($resourceLocksJSON -match "^\[.*\]$")) { - $resourceLocks = ($resourceLocksJSON | ConvertFrom-JSON) - az resource lock delete --ids $resourceLocks --verbose - } - - # Build JMESPath expression - $repository = ($env:GITHUB_REPOSITORY).Split("/")[-1] - $tagQuery = "[?tags.repository == '${repository}' && tags.workspace == '${env:TF_WORKSPACE}' && tags.runid == '${env:GITHUB_RUN_ID}' && properties.provisioningState != 'Deleting'].id" - - Write-Host "Removing resource group identified by `"$tagQuery`"..." - $resourceGroupIDs = $(az group list --query "$tagQuery" -o tsv) - if ($resourceGroupIDs) { - Write-Host "az resource delete --ids ${resourceGroupIDs}..." - az resource delete --ids $resourceGroupIDs --verbose - } else { - Write-Host "Nothing to remove" - } - shell: pwsh \ No newline at end of file + shell: pwsh + + - name: "Publish Monitor Function" + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + uses: azure/functions-action@v1 + with: + app-name: ${{ steps.terraform-apply.outputs.function_name }} + package: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" + + - name: Test connection to Minecraft Server (pwsh) + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + run: | + # Wait for Minecraft to boot up + $connectionAttempts = 0 + do { + Start-Sleep -Seconds 10 + Write-Host "Pinging ${env:TF_OUT_minecraft_server_fqdn} on port ${env:TF_OUT_minecraft_server_port}..." + try { + $connectionAttempts++ + $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($env:TF_OUT_minecraft_server_fqdn, $env:TF_OUT_minecraft_server_port) -ErrorAction SilentlyContinue + } catch [System.Management.Automation.MethodInvocationException] { + Write-Warning $_ + } + } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) + + # No tty + # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + shell: pwsh + + # - name: Test connection to Minecraft Server (bash) + # if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + # run: | + # # Wait for Minecraft to boot up + # while ! echo exit | nc $TF_OUT_minecraft_server_fqdn $TF_OUT_minecraft_server_port; do sleep 10; done + # # No tty + # # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft + # shell: bash + + - name: Terraform Destroy + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform destroy -auto-approve + shell: pwsh + + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: terraform + path: "terraform" + + - name: Clean Up + if: ${{ always() }} + run: | + $ErrorActionPreference = "Continue" + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + + # Remove resource locks first + $resourceLocksJSON = $(terraform output -json resource_locks 2>$null) + if ($resourceLocksJSON -and ($resourceLocksJSON -match "^\[.*\]$")) { + $resourceLocks = ($resourceLocksJSON | ConvertFrom-JSON) + az resource lock delete --ids $resourceLocks --verbose + } + + # Build JMESPath expression + $repository = ($env:GITHUB_REPOSITORY).Split("/")[-1] + $tagQuery = "[?tags.repository == '${repository}' && tags.workspace == '${env:TF_WORKSPACE}' && tags.runid == '${env:GITHUB_RUN_ID}' && properties.provisioningState != 'Deleting'].id" + + Write-Host "Removing resource group identified by `"$tagQuery`"..." + $resourceGroupIDs = $(az group list --query "$tagQuery" -o tsv) + if ($resourceGroupIDs) { + Write-Host "az resource delete --ids ${resourceGroupIDs}..." + az resource delete --ids $resourceGroupIDs --verbose + } else { + Write-Host "Nothing to remove" + } + shell: pwsh diff --git a/.github/workflows/test.json b/.github/workflows/test.json index f3769d1..c684010 100644 --- a/.github/workflows/test.json +++ b/.github/workflows/test.json @@ -1,11 +1,6 @@ { - "os": [ - "ubuntu-latest" - ], - "use_latest_versions": [ - false, - true - ], + "os": ["ubuntu-latest"], + "use_latest_versions": [false, true], "include": [ { "use_latest_versions": false, @@ -24,4 +19,4 @@ "upgrade_azure_cli": true } ] -} \ No newline at end of file +} diff --git a/README.md b/README.md index ac3ce8c..cc78597 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Minecraft Server powered by Docker & Azure Container Instance + This repo deploys [itzg/minecraft-server](https://hub.docker.com/r/itzg/minecraft-server) as [Azure Container Instance](https://azure.microsoft.com/en-us/services/container-instances/), using Terraform. [![ci-scripted](https://github.com/geekzter/azure-minecraft-docker/actions/workflows/ci-scripted.yml/badge.svg)](https://github.com/geekzter/azure-minecraft-docker/actions/workflows/ci-scripted.yml) @@ -8,19 +9,26 @@ This repo deploys [itzg/minecraft-server](https://hub.docker.com/r/itzg/minecraf ![alt text](./visuals/diagram.png "Diagram") ## Instructions + There are 2 ways to set this up: ### Codespace setup + The easiest method is to use a GitHub [Codespace](https://github.com/features/codespaces) (in beta). Just create a GitHub Codespace from the Code menu. Wait for the Codespace to complete provisioning. When the Codespace has completed provisioning and you open a terminal window (Ctrl-`, Control-backquote), you should see a message like this: + ``` To provision infrastructure, make sure you're logged in with Azure CLI e.g. run 'az login' and 'az account set --subscription 00000000-0000-0000-0000-000000000000'. Then, either: - change to the /home/codespace/workspace/azure-minecraft-docker/terraform directory and run 'terraform apply', or: - run /home/codespace/workspace/azure-minecraft-docker/scripts/deploy.ps1 -apply To destroy infrastructure, replace 'apply' with 'destroy' in above commands ``` + Just follow these steps to provision Minecraft on Azure. + ### Local setup + If you set this up locally, make sure you have the following pre-requisites: + - [Azure CLI](http://aka.ms/azure-cli) - [PowerShell](https://github.com/PowerShell/PowerShell#get-powershell) - [Terraform](https://www.terraform.io/downloads.html) (to get that you can use [tfenv](https://github.com/tfutils/tfenv) on Linux & macOS, [Homebrew](https://github.com/hashicorp/homebrew-tap) on macOS or [chocolatey](https://chocolatey.org/packages/terraform) on Windows) @@ -28,13 +36,16 @@ If you set this up locally, make sure you have the following pre-requisites: On macOS, you can run `brew bundle` to install the pre-requisites. Once you have those, you can go ahead and provision: + - Use Azure CLI for SSO with [Terraform](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/azure_cli): `az login` - Select subscription to use: `az account set --subscription 00000000-0000-0000-0000-000000000000` - Initialize terraform: `terraform init` - Provision cloud infrastructure: `terraform apply` ### Customization + You can customize the deployment by overriding defaults for Terraform [input variables](https://www.terraform.io/docs/configuration/variables.html). The easiest way to do this is to copy [config.auto.example.tfvars](./terraform/config.auto.example.tfvars) and save it as config.auto.tfvars. + - Use the `minecraft_users` array to define users allowed to log in - Use a custom DNS name with `vanity_dns_zone_id` and `vanity_hostname_prefix`, using an Azure DNS managed domain - Once things get serious, you may want to start backing up data with `enable_backup` @@ -42,14 +53,17 @@ You can customize the deployment by overriding defaults for Terraform [input var - Concerned about chat messages appearing in logs? `enable_log_filter` uses the [Console Spam Fix](https://dev.bukkit.org/projects/console-spam-fix) and [configures](./minecraft/log-filter/config.yml) it to hide chat messages from logs. This feature is dependent on [PowerShell](https://github.com/PowerShell/PowerShell) and is more brittle in automation, but satisfies a key privacy requirement. See [variables.tf](./terraform/variables.tf) for all input variables. + ## Dashboard -Once provisioned, a dashboard like this will be available in the Azure Portal: + +Once provisioned, a dashboard like this will be available in the Azure Portal: ![alt text](./visuals/dashboard.png "Dashboard") You can update the dashboard in the portal and re-generate the [template](./terraform/dashboard.tpl) using [templatize_dashboard.ps1](./scripts/templatize_dashboard.ps1). ## Resources + - [itzg/minecraft-server](https://hub.docker.com/r/itzg/minecraft-server) on Docker Hub - [docker-minecraft-server](https://github.com/itzg/docker-minecraft-server) on Github - [Minecraft on Azure Friday](https://www.youtube.com/watch?v=2D8FTi-Zvt0) (uses Docker CLI workflow) -- [Minecraft on Docker Blog](https://www.docker.com/blog/deploying-a-minecraft-docker-server-to-the-cloud/) (uses Docker CLI workflow) \ No newline at end of file +- [Minecraft on Docker Blog](https://www.docker.com/blog/deploying-a-minecraft-docker-server-to-the-cloud/) (uses Docker CLI workflow) diff --git a/functions/global.json b/functions/global.json index d832153..bfe82da 100644 --- a/functions/global.json +++ b/functions/global.json @@ -1,5 +1,5 @@ { - "sdk": { - "version": "6.0" - } -} \ No newline at end of file + "sdk": { + "version": "6.0" + } +} diff --git a/functions/host.json b/functions/host.json index bb3b8da..6a0819c 100644 --- a/functions/host.json +++ b/functions/host.json @@ -1,11 +1,11 @@ { - "version": "2.0", - "logging": { - "applicationInsights": { - "samplingExcludedTypes": "Request", - "samplingSettings": { - "isEnabled": true - } - } + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingExcludedTypes": "Request", + "samplingSettings": { + "isEnabled": true + } } -} \ No newline at end of file + } +} diff --git a/minecraft/bstats/config.yml b/minecraft/bstats/config.yml index 2d58242..2cc118e 100644 --- a/minecraft/bstats/config.yml +++ b/minecraft/bstats/config.yml @@ -1,4 +1,4 @@ # Hode stats enabled: false serverUuid: 00000000-0000-0000-0000-000000000000 -logFailedRequests: false \ No newline at end of file +logFailedRequests: false diff --git a/minecraft/log-filter/config.yml b/minecraft/log-filter/config.yml index e33104e..8f9dd69 100644 --- a/minecraft/log-filter/config.yml +++ b/minecraft/log-filter/config.yml @@ -3,13 +3,13 @@ # https://www.spigotmc.org/resources/console-spam-fix.18410 Messages-To-Hide-Filter: -# Chat messages from users -- '<' -- '>' + # Chat messages from users + - "<" + - ">" #Chat messages with color and format codes support. -#Minecraft Color and Format Codes: http://minecraft.gamepedia.com/Formatting_codes +#Minecraft Color and Format Codes: http://minecraft.gamepedia.com/Formatting_codes ChatMessages: - NoPermission: '&4[System] &cYou don''t have permission!' - CmdHelp: '&4[System] &cAvailable commands:&6 /csf reload' - CmdReload: '&2[System] &aConfig reload complete!' \ No newline at end of file + NoPermission: "&4[System] &cYou don't have permission!" + CmdHelp: "&4[System] &cAvailable commands:&6 /csf reload" + CmdReload: "&2[System] &aConfig reload complete!" diff --git a/multi-instance.md b/multi-instance.md index ca48ed1..aadb145 100644 --- a/multi-instance.md +++ b/multi-instance.md @@ -1,18 +1,23 @@ # Multi Instance -The Terraform code has been restructured to allow for multiple Minecraft instances e.g. 1.6.5 & 1.7, or different distributions. To allow this, a lot of resources have moved into Terraform modules. This includes Azure file shares, that have state (Minecraft world data). + +The Terraform code has been restructured to allow for multiple Minecraft instances e.g. 1.6.5 & 1.7, or different distributions. To allow this, a lot of resources have moved into Terraform modules. This includes Azure file shares, that have state (Minecraft world data). To reconcile Terraform state with the actual resources (without losing data!), there are 2 approaches: ## 1 - Scripted deployment + In the case Minecraft is deployed with [deploy.ps1](scripts/deploy.ps1), the script will take care of moving file shares within Terraform state prior to plan stage. The script will prompt for confirmation, as custom configuration applied e.g. via an [.auto.tfvars file](terraform/config.auto.example.tfvars) needs to be applied differently as [variables.tf](terraform/variables.tf) has changed significantly. You can also migrate file shares in Terraform state running [migrate_storage_share_state.ps1](scripts/migrate_storage_share_state.ps1) prior to running deploy.ps1. ## 2 - Plain 'terraform apply' + If Minecraft is deployed without using deploy.ps1, Terraform will attempt to destroy and recreate resources. In the case of file shares, which have purge protection enabled, nothing will get destroyed (rather flagged as deleted in a restorable state) and Terraform will run into an existing resource. These can than be restored and imported with [import_file_shares.ps1](scripts/import_file_shares.ps1). ## Known issues -There is a known [issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11184#issuecomment-870535683) with `azurerm_backup_protected_file_share` where an error is thrown under certain conditions: + +There is a known [issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11184#issuecomment-870535683) with `azurerm_backup_protected_file_share` where an error is thrown under certain conditions: + ``` [ERROR] fileshare 'minecraft-aci-experimental-data-xxxx' not found in protectable or protected fileshares, make sure Storage Account "minecraftstorxxxx" is registered with Recovery Service Vault "Minecraft-default-xxxx-backup" (Resource Group "Minecraft-default-xxxx") ``` -If this happens, running [manage_unprotected_shares.ps1](scripts/manage_unprotected_shares.ps1) with the `-ToggleUnprotectedItemState` switch will resolve the issue. \ No newline at end of file +If this happens, running [manage_unprotected_shares.ps1](scripts/manage_unprotected_shares.ps1) with the `-ToggleUnprotectedItemState` switch will resolve the issue. diff --git a/terraform/arm/startstop-template.json b/terraform/arm/startstop-template.json index a662172..5636e5d 100644 --- a/terraform/arm/startstop-template.json +++ b/terraform/arm/startstop-template.json @@ -1,59 +1,58 @@ { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - }, - "variables": {}, - "resources": [ - { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "${workflow_name}", - "location": "${location}", - "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "defaultValue": {}, - "type": "Object" - } - }, - "triggers": {}, - "actions": { - "${operation}_minecraft": { - "runAfter": {}, - "type": "ApiConnection", - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['${connection_name_json}']['connectionId']" - } - }, - "method": "post", - "path": "${container_group_id}/${operation}", - "queries": { - "x-ms-api-version": "2019-12-01" - } - } - } - }, - "outputs": {} + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "${workflow_name}", + "location": "${location}", + "properties": { + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "defaultValue": {}, + "type": "Object" + } + }, + "triggers": {}, + "actions": { + "${operation}_minecraft": { + "runAfter": {}, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['${connection_name_json}']['connectionId']" + } }, - "parameters": { - "$connections": { - "value": { - "${connection_name_json}": { - "connectionId": "${connection_id}", - "connectionName": "${connection_name}", - "id": "${api_id}" - } - } - } + "method": "post", + "path": "${container_group_id}/${operation}", + "queries": { + "x-ms-api-version": "2019-12-01" } + } + } + }, + "outputs": {} + }, + "parameters": { + "$connections": { + "value": { + "${connection_name_json}": { + "connectionId": "${connection_id}", + "connectionName": "${connection_name}", + "id": "${api_id}" + } } + } } - ] -} \ No newline at end of file + } + } + ] +} diff --git a/terraform/arm/workflow-connection-template.json b/terraform/arm/workflow-connection-template.json index e2a9af2..6db402d 100644 --- a/terraform/arm/workflow-connection-template.json +++ b/terraform/arm/workflow-connection-template.json @@ -1,33 +1,34 @@ { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - }, - "resources": [{ - "type": "Microsoft.Web/connections", - "name": "${connection_name}", - "apiVersion": "2016-06-01", - "location": "${location}", - "scale": null, - "properties": { - "displayName": "${connection_display_name}", - "api": { - "type": "Microsoft.Web/locations/managedApis", - "id": "${api_id}", - "name": "aci", - "displayName": "Azure Container Instance", - "description": "Easily run containers on Azure with a single command. Create container groups, get the logs of a container and more.", - "iconUri": "https://connectoricons-prod.azureedge.net/releases/v1.0.1385/1.0.1385.2110/aci/icon.png", - "brandColor": "#0089D0", - "category": "Standard" - }, - "parameterValues": { - "token:clientId": "${client_id}", - "token:clientSecret": "${client_secret}", - "token:tenantId": "${tenant_id}", - "token:grantType": "client_credentials" - } + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": {}, + "resources": [ + { + "type": "Microsoft.Web/connections", + "name": "${connection_name}", + "apiVersion": "2016-06-01", + "location": "${location}", + "scale": null, + "properties": { + "displayName": "${connection_display_name}", + "api": { + "type": "Microsoft.Web/locations/managedApis", + "id": "${api_id}", + "name": "aci", + "displayName": "Azure Container Instance", + "description": "Easily run containers on Azure with a single command. Create container groups, get the logs of a container and more.", + "iconUri": "https://connectoricons-prod.azureedge.net/releases/v1.0.1385/1.0.1385.2110/aci/icon.png", + "brandColor": "#0089D0", + "category": "Standard" }, - "dependsOn": [] - }] -} \ No newline at end of file + "parameterValues": { + "token:clientId": "${client_id}", + "token:clientSecret": "${client_secret}", + "token:tenantId": "${tenant_id}", + "token:grantType": "client_credentials" + } + }, + "dependsOn": [] + } + ] +} From b8f50c16924fac1c72835ed8ebf67f12eb7c7744 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 20:46:38 -0400 Subject: [PATCH 02/17] Package, SDK, and tooling updates --- .github/workflows/ci-dotnet.yml | 7 ++----- .github/workflows/ci-scripted.yml | 6 +++--- .github/workflows/ci-vanilla.yml | 15 ++++++--------- functions/functions.csproj | 6 +++--- functions/global.json | 3 ++- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci-dotnet.yml b/.github/workflows/ci-dotnet.yml index f79845e..dc99b82 100644 --- a/.github/workflows/ci-dotnet.yml +++ b/.github/workflows/ci-dotnet.yml @@ -22,18 +22,15 @@ on: env: AZURE_FUNCTIONAPP_PACKAGE_PATH: "./functions" - DOTNET_VERSION: "6.0.x" jobs: dotnet: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} + uses: actions/setup-dotnet@v4 - name: Restore dependencies run: | pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' diff --git a/.github/workflows/ci-scripted.yml b/.github/workflows/ci-scripted.yml index b018ae9..f05c911 100644 --- a/.github/workflows/ci-scripted.yml +++ b/.github/workflows/ci-scripted.yml @@ -64,7 +64,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Print environment variables run: | @@ -116,7 +116,7 @@ jobs: steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Dump strategy context env: @@ -289,7 +289,7 @@ jobs: continue-on-error: ${{ matrix.ignore_destroy_failure }} - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: ${{ matrix.terraform_apply }} with: name: terraform diff --git a/.github/workflows/ci-vanilla.yml b/.github/workflows/ci-vanilla.yml index fe916f3..b1bdabb 100644 --- a/.github/workflows/ci-vanilla.yml +++ b/.github/workflows/ci-vanilla.yml @@ -22,7 +22,6 @@ on: env: AZURE_FUNCTIONAPP_PACKAGE_PATH: "functions" - DOTNET_VERSION: "6.0.x" FUNCTIONS_ARTIFACT_NAME: "functions" TF_IN_AUTOMATION: true TF_INPUT: 0 @@ -38,11 +37,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} + uses: actions/setup-dotnet@v4 - name: Restore dependencies run: | pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' @@ -59,7 +56,7 @@ jobs: dotnet test --no-build --verbosity normal popd - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" @@ -73,10 +70,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Download artifacts from previous job - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" @@ -197,7 +194,7 @@ jobs: shell: pwsh - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: terraform path: "terraform" diff --git a/functions/functions.csproj b/functions/functions.csproj index fad39f2..8ae7540 100644 --- a/functions/functions.csproj +++ b/functions/functions.csproj @@ -1,11 +1,11 @@ - net6.0 + net8.0 v4 - - + + diff --git a/functions/global.json b/functions/global.json index bfe82da..391ba3c 100644 --- a/functions/global.json +++ b/functions/global.json @@ -1,5 +1,6 @@ { "sdk": { - "version": "6.0" + "version": "8.0.100", + "rollForward": "latestFeature" } } From 4aa0a009f5fad3ec3d62a7564931cafcf71acf29 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 20:53:25 -0400 Subject: [PATCH 03/17] Add generated solution file --- azure-minecraft-docker.sln | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 azure-minecraft-docker.sln diff --git a/azure-minecraft-docker.sln b/azure-minecraft-docker.sln new file mode 100644 index 0000000..1d7edcf --- /dev/null +++ b/azure-minecraft-docker.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "functions", "functions\functions.csproj", "{864DEE18-2785-48AE-AA34-EAF7C183EADA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {864DEE18-2785-48AE-AA34-EAF7C183EADA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {864DEE18-2785-48AE-AA34-EAF7C183EADA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {864DEE18-2785-48AE-AA34-EAF7C183EADA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {864DEE18-2785-48AE-AA34-EAF7C183EADA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {943984F9-29C4-4669-9565-E56B8B6BF142} + EndGlobalSection +EndGlobal From aca1887708890f230dc4a4ffcc2e69d0a1d0236f Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 20:56:26 -0400 Subject: [PATCH 04/17] Use .NET 8 SDK with Brewfile --- Brewfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Brewfile b/Brewfile index 592678f..da61bcb 100644 --- a/Brewfile +++ b/Brewfile @@ -1,5 +1,4 @@ tap "azure/functions" -tap "isen-ng/dotnet-sdk-versions" brew "azure-cli" brew "azure-functions-core-tools@3" @@ -7,6 +6,5 @@ brew "hashicorp/tap/terraform" brew "jq" brew "tfenv" -# cask "dotnet-sdk6" -cask "dotnet-sdk6-0-400" +cask "dotnet-sdk" cask "powershell" \ No newline at end of file From d58ef5bffe1de7b6b08835e1db643f26e5fb5fda Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 21:01:29 -0400 Subject: [PATCH 05/17] Move SDK configuration --- functions/global.json => global.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename functions/global.json => global.json (100%) diff --git a/functions/global.json b/global.json similarity index 100% rename from functions/global.json rename to global.json From 87c4b713d968e20271809d4a15b285c26de3fcba Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 21:08:18 -0400 Subject: [PATCH 06/17] Bump a few more CI Actions --- .github/workflows/ci-scripted.yml | 6 +++--- .github/workflows/ci-vanilla.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-scripted.yml b/.github/workflows/ci-scripted.yml index f05c911..82bf45d 100644 --- a/.github/workflows/ci-scripted.yml +++ b/.github/workflows/ci-scripted.yml @@ -152,7 +152,7 @@ jobs: shell: pwsh - name: Use Azure CLI - uses: azure/login@v1 + uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} enable-AzPSSession: false @@ -162,7 +162,7 @@ jobs: az -v - name: Use Terraform - uses: hashicorp/setup-terraform@v1 + uses: hashicorp/setup-terraform@v3 with: terraform_version: ${{matrix.terraform_version}} terraform_wrapper: false @@ -219,7 +219,7 @@ jobs: - name: Use Node.js if: ${{ matrix.terraform_apply }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 - name: Install Azure Functions Core Tools if: ${{ matrix.terraform_apply }} run: npm i -g azure-functions-core-tools@3 --unsafe-perm true diff --git a/.github/workflows/ci-vanilla.yml b/.github/workflows/ci-vanilla.yml index b1bdabb..c09ec51 100644 --- a/.github/workflows/ci-vanilla.yml +++ b/.github/workflows/ci-vanilla.yml @@ -79,7 +79,7 @@ jobs: path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" - name: Use Azure CLI - uses: azure/login@v1 + uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} @@ -90,7 +90,7 @@ jobs: Write-Output "TERRAFORM_VERSION=${terraformVersion}" >> $env:GITHUB_OUTPUT shell: pwsh - name: Use Terraform - uses: hashicorp/setup-terraform@v1 + uses: hashicorp/setup-terraform@v3 with: terraform_version: ${{ steps.terraform-version-check.outputs.TERRAFORM_VERSION }} terraform_wrapper: false From 40a3b5d15501b12c1ce8dc2a32bb73127f40b118 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 21:17:20 -0400 Subject: [PATCH 07/17] Use latest DevContainer configuration --- .devcontainer/createorupdate.ps1 | 6 ++++-- .devcontainer/devcontainer.json | 29 +++++++++++++++-------------- .devcontainer/profile.ps1 | 2 +- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/.devcontainer/createorupdate.ps1 b/.devcontainer/createorupdate.ps1 index 243948a..18e8326 100755 --- a/.devcontainer/createorupdate.ps1 +++ b/.devcontainer/createorupdate.ps1 @@ -28,7 +28,8 @@ if (!(Get-Command tfenv -ErrorAction SilentlyContinue)) { Write-Host 'Installing tfenv...' git clone https://github.com/tfutils/tfenv.git ~/.tfenv sudo ln -s ~/.tfenv/bin/* /usr/local/bin -} else { +} +else { Write-Host 'Upgrading tfenv...' git -C ~/.tfenv pull } @@ -46,7 +47,8 @@ Pop-Location if (Test-Path ~/bootstrap-os) { # This has been run before, upgrade packages sudo apt-get upgrade -y -} else { +} +else { git clone https://github.com/geekzter/bootstrap-os.git ~/bootstrap-os } Push-Location ~/bootstrap-os/linux diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4b7642d..377d745 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,20 +1,21 @@ { // Install extensions - "extensions": [ - "4ops.terraform", - "ms-azuretools.vscode-azurefunctions", - "ms-azuretools.vscode-azureterraform", - "ms-dotnettools.csharp", - "ms-vscode.azurecli", - "ms-vscode.PowerShell" - ], - - // VSCode settings - "settings": { - // "terminal.integrated.cwd": "/home/codespace/workspace, - "terminal.integrated.shell.linux": "/usr/bin/pwsh" + "customizations": { + "vscode": { + "extensions": [ + "4ops.terraform", + "ms-azuretools.vscode-azurefunctions", + "ms-azuretools.vscode-azureterraform", + "ms-dotnettools.csharp", + "ms-vscode.azurecli", + "ms-vscode.PowerShell" + ], + "settings": { + // "terminal.integrated.cwd": "/home/codespace/workspace, + "terminal.integrated.shell.linux": "/usr/bin/pwsh" + } + } }, - // Run bash script in .devcontainer directory "postCreateCommand": "/usr/bin/pwsh -nop -f ./.devcontainer/createorupdate.ps1 > ~/post-create.log" } diff --git a/.devcontainer/profile.ps1 b/.devcontainer/profile.ps1 index 1bd5436..fc63048 100644 --- a/.devcontainer/profile.ps1 +++ b/.devcontainer/profile.ps1 @@ -8,7 +8,7 @@ $scriptDirectory = (Join-Path $repoDirectory "scripts") [System.Collections.ArrayList]$pathList = $env:PATH.Split(":") # Insert script path into PATH, so scripts can be called from anywhere if (!$pathList.Contains($scriptDirectory)) { - $pathList.Insert(1,$scriptDirectory) + $pathList.Insert(1, $scriptDirectory) } $env:PATH = $pathList -Join ":" From c950fbe335f5d05f3e5d3813062073ac776fa33c Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 21:20:11 -0400 Subject: [PATCH 08/17] Use latest Azure Functions tools --- Brewfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Brewfile b/Brewfile index da61bcb..04bfcfb 100644 --- a/Brewfile +++ b/Brewfile @@ -1,7 +1,7 @@ tap "azure/functions" brew "azure-cli" -brew "azure-functions-core-tools@3" +brew "azure-functions-core-tools@4" brew "hashicorp/tap/terraform" brew "jq" brew "tfenv" From 2e519f050d605db950446f925e7f645d99a7a2be Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 21:34:39 -0400 Subject: [PATCH 09/17] Add Powershell feature --- .devcontainer/devcontainer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 377d745..7914e94 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,4 +1,7 @@ { + "features": { + "ghcr.io/devcontainers/features/powershell:1": {} + }, // Install extensions "customizations": { "vscode": { From 1524a1694cc8b3d4416814dc370508660e1b6244 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 22:06:14 -0400 Subject: [PATCH 10/17] Use features entirely instead of extensions --- .devcontainer/devcontainer.json | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7914e94..0ef896d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,18 +1,13 @@ { "features": { - "ghcr.io/devcontainers/features/powershell:1": {} + "ghcr.io/devcontainers/features/azure-cli:1": {}, + "ghcr.io/devcontainers/features/dotnet:1": {}, + "ghcr.io/devcontainers/features/powershell:1": {}, + "ghcr.io/devcontainers/features/terraform:1": {} }, // Install extensions "customizations": { "vscode": { - "extensions": [ - "4ops.terraform", - "ms-azuretools.vscode-azurefunctions", - "ms-azuretools.vscode-azureterraform", - "ms-dotnettools.csharp", - "ms-vscode.azurecli", - "ms-vscode.PowerShell" - ], "settings": { // "terminal.integrated.cwd": "/home/codespace/workspace, "terminal.integrated.shell.linux": "/usr/bin/pwsh" From bd9f55cc381182ac8b393506549168d31157180f Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 4 Sep 2024 22:22:04 -0400 Subject: [PATCH 11/17] Rewrite installer script and remove unneeded setup --- .devcontainer/createorupdate.ps1 | 41 +++++++++++--------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/.devcontainer/createorupdate.ps1 b/.devcontainer/createorupdate.ps1 index 18e8326..47c6dea 100755 --- a/.devcontainer/createorupdate.ps1 +++ b/.devcontainer/createorupdate.ps1 @@ -3,19 +3,20 @@ # Update relevant packages sudo apt-get update -#sudo apt-get install --only-upgrade -y azure-cli powershell -if (!(Get-Command func -ErrorAction SilentlyContinue)) { - sudo apt-get install -y azure-functions-core-tools -} -if (!(Get-Content /etc/apt/sources.list | Select-String "^deb.*hashicorp" )) { - sudo apt-get install -y lsb-release - curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - - sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" - sudo apt-get install -y terraform -} -if (!(Get-Command tmux -ErrorAction SilentlyContinue)) { - sudo apt-get install -y tmux -} + +# Install Azure Functions Core Tools +curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg +sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg +sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/debian/$(lsb_release -rs 2>/dev/null | cut -d'.' -f 1)/prod $(lsb_release -cs 2>/dev/null) main" > /etc/apt/sources.list.d/dotnetdev.list' +sudo apt-get install -y azure-functions-core-tools-4 + +# Install Terraform +wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null +sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" > /etc/apt/sources.list.d/hashicorp.list' +sudo apt-get install -y terraform + +# Install tfenv dependencies +sudo apt-get install -y tmux # Determine directory locations (may vary based on what branch has been cloned initially) $repoDirectory = (Split-Path $PSScriptRoot -Parent) @@ -43,20 +44,6 @@ tfenv use latest terraform init -upgrade Pop-Location -# Use geekzter/bootstrap-os for PowerShell setup -if (Test-Path ~/bootstrap-os) { - # This has been run before, upgrade packages - sudo apt-get upgrade -y -} -else { - git clone https://github.com/geekzter/bootstrap-os.git ~/bootstrap-os -} -Push-Location ~/bootstrap-os/linux -./bootstrap_linux.sh --skip-packages -Pop-Location -. ~/bootstrap-os/common/functions/functions.ps1 -AddorUpdateModule Posh-Git - # Link PowerShell Profile if (!(Test-Path $Profile)) { New-Item -ItemType symboliclink -Path $Profile -Target $profileTemplate -Force | Select-Object -ExpandProperty Name From 4a6ea6161984ca2324d1687c60b420644eec711f Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Sun, 8 Sep 2024 17:03:56 -0400 Subject: [PATCH 12/17] Remove Terraform installation as it's already a feature --- .devcontainer/createorupdate.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.devcontainer/createorupdate.ps1 b/.devcontainer/createorupdate.ps1 index 47c6dea..f536f29 100755 --- a/.devcontainer/createorupdate.ps1 +++ b/.devcontainer/createorupdate.ps1 @@ -10,11 +10,6 @@ sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/debian/$(lsb_release -rs 2>/dev/null | cut -d'.' -f 1)/prod $(lsb_release -cs 2>/dev/null) main" > /etc/apt/sources.list.d/dotnetdev.list' sudo apt-get install -y azure-functions-core-tools-4 -# Install Terraform -wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null -sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" > /etc/apt/sources.list.d/hashicorp.list' -sudo apt-get install -y terraform - # Install tfenv dependencies sudo apt-get install -y tmux From e71682ab348553c7627a58216c6cbe4b64c46790 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Sun, 8 Sep 2024 17:05:21 -0400 Subject: [PATCH 13/17] Use latest .NET feature --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0ef896d..0db6853 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ { "features": { "ghcr.io/devcontainers/features/azure-cli:1": {}, - "ghcr.io/devcontainers/features/dotnet:1": {}, + "ghcr.io/devcontainers/features/dotnet:2": {}, "ghcr.io/devcontainers/features/powershell:1": {}, "ghcr.io/devcontainers/features/terraform:1": {} }, From 4d6e2fc5cd3e34e71f3214dd14c939f41a665d83 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Sun, 8 Sep 2024 17:06:42 -0400 Subject: [PATCH 14/17] Use feature for Azure Functions tools too --- .devcontainer/createorupdate.ps1 | 8 +------- .devcontainer/devcontainer.json | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.devcontainer/createorupdate.ps1 b/.devcontainer/createorupdate.ps1 index f536f29..10a775b 100755 --- a/.devcontainer/createorupdate.ps1 +++ b/.devcontainer/createorupdate.ps1 @@ -1,15 +1,9 @@ #!/usr/bin/env pwsh # Runs post create commands to prep Codespace for project -# Update relevant packages +# Get latest package information sudo apt-get update -# Install Azure Functions Core Tools -curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg -sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg -sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/debian/$(lsb_release -rs 2>/dev/null | cut -d'.' -f 1)/prod $(lsb_release -cs 2>/dev/null) main" > /etc/apt/sources.list.d/dotnetdev.list' -sudo apt-get install -y azure-functions-core-tools-4 - # Install tfenv dependencies sudo apt-get install -y tmux diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0db6853..6ae1445 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,7 @@ { "features": { "ghcr.io/devcontainers/features/azure-cli:1": {}, + "ghcr.io/devcontainers/features/azure-functions-core-tools:1": {}, "ghcr.io/devcontainers/features/dotnet:2": {}, "ghcr.io/devcontainers/features/powershell:1": {}, "ghcr.io/devcontainers/features/terraform:1": {} From c72aa2c3aaca485b6eb5a352b2e2e5929a9f5bf3 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Tue, 10 Sep 2024 19:13:50 -0400 Subject: [PATCH 15/17] Use the maintained Azure Functions feature --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6ae1445..a7973e5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,7 +1,7 @@ { "features": { "ghcr.io/devcontainers/features/azure-cli:1": {}, - "ghcr.io/devcontainers/features/azure-functions-core-tools:1": {}, + "ghcr.io/jlaundry/devcontainer-features/azure-functions-core-tools:1": {}, "ghcr.io/devcontainers/features/dotnet:2": {}, "ghcr.io/devcontainers/features/powershell:1": {}, "ghcr.io/devcontainers/features/terraform:1": {} From e65c1709508703ce767267f877552ab336a8e211 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Sun, 19 Jan 2025 16:48:00 -0500 Subject: [PATCH 16/17] Temporarily undo changes --- .github/workflows/ci-scripted.yml | 459 +++++++++++++++--------------- .github/workflows/ci-vanilla.yml | 384 ++++++++++++------------- 2 files changed, 424 insertions(+), 419 deletions(-) diff --git a/.github/workflows/ci-scripted.yml b/.github/workflows/ci-scripted.yml index 82bf45d..55f09aa 100644 --- a/.github/workflows/ci-scripted.yml +++ b/.github/workflows/ci-scripted.yml @@ -1,47 +1,47 @@ on: pull_request: - branches: [main] + branches: [ main ] paths-ignore: - - "**/README.md" - - "**/LICENSE" - - "visuals/**" + - '**/README.md' + - '**/LICENSE' + - 'visuals/**' schedule: - - cron: "0 2 * * Thu,Sat" + - cron: '0 2 * * Thu,Sat' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: inputs: upgrade_provider_versions: - description: "Upgrade Terraform provider versions" + description: 'Upgrade Terraform provider versions' required: false type: boolean default: false upgrade_terraform_version: - description: "Upgrade Terraform version" + description: 'Upgrade Terraform version' required: false type: boolean default: false upgrade_azure_cli: - description: "Upgrade Azure CLI to latest version" + description: 'Upgrade Azure CLI to latest version' required: false type: boolean default: false destroy: - description: "Destroy Infrastucture" + description: 'Destroy Infrastucture' required: false type: boolean default: true workspace: type: choice required: true - description: "Terraform Workspace" + description: 'Terraform Workspace' default: ci - options: - - ci - - ci1 - - ci2 - - ci3 + options: + - ci + - ci1 + - ci2 + - ci3 env: ARM_SAS_TOKEN: ${{ secrets.ARM_SAS_TOKEN }} TF_IN_AUTOMATION: true @@ -63,38 +63,38 @@ jobs: working-directory: scripts runs-on: ubuntu-latest steps: - - name: Checkout source - uses: actions/checkout@v4 - - - name: Print environment variables - run: | - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name - shell: pwsh - - - name: Create matrix - id: create-matrix - run: | - ConvertTo-SecureString -AsPlainText -String '${{ secrets.GITHUB_TOKEN }}' | Set-Variable gitHubToken - ./create_workflow_strategy.ps1 -GitHubToken $gitHubToken ` - -DestroyInput "${{ github.event.inputs.destroy }}" ` - -UseLatestAzureCLIVersionInput "${{ github.event.inputs.upgrade_azure_cli }}" ` - -UseLatestTerraformProviderVersionsInput "${{ github.event.inputs.upgrade_provider_versions }}" ` - -UseLatestTerraformVersionInput "${{ github.event.inputs.upgrade_terraform_version }}" - - shell: pwsh - - - name: Install json2yaml - run: | - sudo npm install -g json2yaml - - - name: Display matrix - run: | - $matrixJSON = '${{ steps.create-matrix.outputs.matrix }}' - $matrixJSON - $matrixJSON | jq - $matrixJSON | ConvertFrom-Json - $matrixJSON | json2yaml - shell: pwsh + - name: Checkout source + uses: actions/checkout@v4 + + - name: Print environment variables + run: | + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name + shell: pwsh + + - name: Create matrix + id: create-matrix + run: | + ConvertTo-SecureString -AsPlainText -String '${{ secrets.GITHUB_TOKEN }}' | Set-Variable gitHubToken + ./create_workflow_strategy.ps1 -GitHubToken $gitHubToken ` + -DestroyInput "${{ github.event.inputs.destroy }}" ` + -UseLatestAzureCLIVersionInput "${{ github.event.inputs.upgrade_azure_cli }}" ` + -UseLatestTerraformProviderVersionsInput "${{ github.event.inputs.upgrade_provider_versions }}" ` + -UseLatestTerraformVersionInput "${{ github.event.inputs.upgrade_terraform_version }}" + + shell: pwsh + + - name: Install json2yaml + run: | + sudo npm install -g json2yaml + + - name: Display matrix + run: | + $matrixJSON = '${{ steps.create-matrix.outputs.matrix }}' + $matrixJSON + $matrixJSON | jq + $matrixJSON | ConvertFrom-Json + $matrixJSON | json2yaml + shell: pwsh outputs: matrix: ${{ steps.create-matrix.outputs.matrix }} @@ -115,187 +115,188 @@ jobs: runs-on: ${{ matrix.os }} steps: - - name: Checkout source - uses: actions/checkout@v4 - - - name: Dump strategy context - env: - MATRIX_CONTEXT: ${{ toJSON(matrix) }} - STRATEGY_CONTEXT: ${{ toJSON(strategy) }} - run: | - Write-Host "Strategy context:" - $env:STRATEGY_CONTEXT | ConvertFrom-Json | Format-List - Write-Host "Matrix context:" - $env:MATRIX_CONTEXT | ConvertFrom-Json | Format-List - shell: pwsh - - - name: Upgrade Azure CLI - id: az-upgrade - if: ${{ matrix.upgrade_azure_cli }} - run: | - # sudo az upgrade -y # not reliable - - curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null - echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list - sudo apt-get update - - $packageName = ($(apt-cache show azure-cli | Select-String 'Version: ${{ matrix.azure_cli_version }}.*$') -split ' ' | Select-Object -Last 1) - Write-Host "`nAzure CLI package: $packageName" - if ($packageName) { - sudo apt-get install --allow-downgrades azure-cli=$packageName - } else { - Write-Host "Azure CLI version ${{ matrix.azure_cli_version }} not found" - } - - az -v - continue-on-error: true - shell: pwsh - - - name: Use Azure CLI - uses: azure/login@v2 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - enable-AzPSSession: false - - - name: Show Azure CLI version - run: | - az -v - - - name: Use Terraform - uses: hashicorp/setup-terraform@v3 - with: - terraform_version: ${{matrix.terraform_version}} - terraform_wrapper: false - - - name: Show Terraform version - run: | - terraform -v - - - name: Unpin Terraform provider versions - id: terraform-version-check - if: ${{ !matrix.pin_provider_versions }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - (Get-Content ./provider.tf) -replace " = `" *= +",' = "~> ' | Out-File provider.tf - Get-Content ./provider.tf - if (Test-Path .terraform.lock.hcl) { - Remove-Item .terraform.lock.hcl -Force - } - shell: pwsh - - - name: Prepare environment variables - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - ENVIRONMENT_VARIABLES: ${{ secrets.ENVIRONMENT_VARIABLES }} - run: | - # Parse Azure secret into Terraform variables - $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) - $env:ARM_CLIENT_ID = $servicePrincipal.clientId - $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret - $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId - $env:ARM_TENANT_ID = $servicePrincipal.tenantId - - $env:TF_VAR_run_id=$env:GITHUB_RUN_ID - # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: - $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId - $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret - $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId - - # Save environment variable setup for subsequent steps - Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV - shell: pwsh - - - name: Show environment variables - run: | - Write-Host "Environment (sorted):" - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name - Write-Host "Environment (unsorted):" - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* - shell: pwsh - - - name: Terraform Init & Plan - run: ./deploy.ps1 -Init -Plan - shell: pwsh - - - name: Use Node.js - if: ${{ matrix.terraform_apply }} - uses: actions/setup-node@v4 - - name: Install Azure Functions Core Tools - if: ${{ matrix.terraform_apply }} - run: npm i -g azure-functions-core-tools@3 --unsafe-perm true - - - name: Terraform Apply - id: terraform-apply - if: ${{ matrix.terraform_apply }} - run: ./deploy.ps1 -Apply -Force -NoCode - shell: pwsh - - - name: Deploy Azure Function - if: ${{ matrix.terraform_apply }} - run: ./deploy_functions.ps1 - shell: pwsh - - - name: Test connection to Minecraft Server - if: ${{ matrix.terraform_apply }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - $minecraftConfig = (terraform output -json minecraft_java | ConvertFrom-Json -AsHashtable) - foreach ($minecraftConfigName in $minecraftConfig.Keys) { - Write-Host "Processing configuration '{$minecraftConfigName}''..." - $containerGroupID = $minecraftConfig[$minecraftConfigName].container_group_id - $serverFQDN = $minecraftConfig[$minecraftConfigName].minecraft_server_fqdn - $serverPort = $minecraftConfig[$minecraftConfigName].minecraft_server_port - - # Wait for Minecraft socket to open - $connectionAttempts = 0 - do { - Start-Sleep -Seconds 10 - Write-Host "Pinging ${serverFQDN} on port ${serverPort}..." - try { - $connectionAttempts++ - $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($serverFQDN, $serverPort) -ErrorAction SilentlyContinue - } catch [System.Management.Automation.MethodInvocationException] { - Write-Warning $_ - } - } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) - if ($mineCraftConnection.Connected) { - Write-Host "Connected to ${serverFQDN}:${serverPort}" - $mineCraftConnection.Close() - } else { - Write-Warning "Could not connect to ${serverFQDN}:${serverPort}!" + - name: Checkout source + uses: actions/checkout@v4 + + - name: Dump strategy context + env: + MATRIX_CONTEXT: ${{ toJSON(matrix) }} + STRATEGY_CONTEXT: ${{ toJSON(strategy) }} + run: | + Write-Host "Strategy context:" + $env:STRATEGY_CONTEXT | ConvertFrom-Json | Format-List + Write-Host "Matrix context:" + $env:MATRIX_CONTEXT | ConvertFrom-Json | Format-List + shell: pwsh + + - name: Upgrade Azure CLI + id: az-upgrade + if: ${{ matrix.upgrade_azure_cli }} + run: | + # sudo az upgrade -y # not reliable + + curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null + echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list + sudo apt-get update + + $packageName = ($(apt-cache show azure-cli | Select-String 'Version: ${{ matrix.azure_cli_version }}.*$') -split ' ' | Select-Object -Last 1) + Write-Host "`nAzure CLI package: $packageName" + if ($packageName) { + sudo apt-get install --allow-downgrades azure-cli=$packageName + } else { + Write-Host "Azure CLI version ${{ matrix.azure_cli_version }} not found" + } + + az -v + continue-on-error: true + shell: pwsh + + - name: Use Azure CLI + uses: azure/login@v2 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + enable-AzPSSession: false + + - name: Show Azure CLI version + run: | + az -v + + - name: Use Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: ${{matrix.terraform_version}} + terraform_wrapper: false + + - name: Show Terraform version + run: | + terraform -v + + - name: Unpin Terraform provider versions + id: terraform-version-check + if: ${{ !matrix.pin_provider_versions }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + (Get-Content ./provider.tf) -replace " = `" *= +",' = "~> ' | Out-File provider.tf + Get-Content ./provider.tf + if (Test-Path .terraform.lock.hcl) { + Remove-Item .terraform.lock.hcl -Force + } + shell: pwsh + + - name: Prepare environment variables + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ENVIRONMENT_VARIABLES: ${{ secrets.ENVIRONMENT_VARIABLES }} + run: | + # Parse Azure secret into Terraform variables + $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) + $env:ARM_CLIENT_ID = $servicePrincipal.clientId + $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret + $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId + $env:ARM_TENANT_ID = $servicePrincipal.tenantId + + $env:TF_VAR_run_id=$env:GITHUB_RUN_ID + # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: + $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId + $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret + $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId + + # Save environment variable setup for subsequent steps + Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV + shell: pwsh + + - name: Show environment variables + run: | + Write-Host "Environment (sorted):" + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name + Write-Host "Environment (unsorted):" + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* + shell: pwsh + + - name: Terraform Init & Plan + run: ./deploy.ps1 -Init -Plan + shell: pwsh + + - name: Use Node.js + if: ${{ matrix.terraform_apply }} + uses: actions/setup-node@v4 + - name: Install Azure Functions Core Tools + if: ${{ matrix.terraform_apply }} + run: + npm i -g azure-functions-core-tools@3 --unsafe-perm true + + - name: Terraform Apply + id: terraform-apply + if: ${{ matrix.terraform_apply }} + run: ./deploy.ps1 -Apply -Force -NoCode + shell: pwsh + + - name: Deploy Azure Function + if: ${{ matrix.terraform_apply }} + run: ./deploy_functions.ps1 + shell: pwsh + + - name: Test connection to Minecraft Server + if: ${{ matrix.terraform_apply }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + $minecraftConfig = (terraform output -json minecraft_java | ConvertFrom-Json -AsHashtable) + foreach ($minecraftConfigName in $minecraftConfig.Keys) { + Write-Host "Processing configuration '{$minecraftConfigName}''..." + $containerGroupID = $minecraftConfig[$minecraftConfigName].container_group_id + $serverFQDN = $minecraftConfig[$minecraftConfigName].minecraft_server_fqdn + $serverPort = $minecraftConfig[$minecraftConfigName].minecraft_server_port + + # Wait for Minecraft socket to open + $connectionAttempts = 0 + do { + Start-Sleep -Seconds 10 + Write-Host "Pinging ${serverFQDN} on port ${serverPort}..." + try { + $connectionAttempts++ + $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($serverFQDN, $serverPort) -ErrorAction SilentlyContinue + } catch [System.Management.Automation.MethodInvocationException] { + Write-Warning $_ } - - # BUG: https://github.com/Azure/azure-cli/issues/13352 - # No tty / ioctl device - # az container exec --ids $containerGroupID --exec-command "/health.sh" --container-name minecraft - script --return --quiet -c "az container exec --ids $containerGroupID --exec-command '/health.sh' --container-name minecraft" /dev/null - - az container show --ids $containerGroupID --query instanceView - az container logs --ids $containerGroupID + } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) + if ($mineCraftConnection.Connected) { + Write-Host "Connected to ${serverFQDN}:${serverPort}" + $mineCraftConnection.Close() + } else { + Write-Warning "Could not connect to ${serverFQDN}:${serverPort}!" } - shell: pwsh - - - name: Remove backup items & resource locks - if: ${{ matrix.destroy }} - run: | - . (Join-Path $env:GITHUB_WORKSPACE scripts functions.ps1) - TearDown-Resources -Backups -Locks - shell: pwsh - - - name: Terraform Destroy - if: ${{ matrix.destroy }} - run: ./deploy.ps1 -Destroy -Force - shell: pwsh - continue-on-error: ${{ matrix.ignore_destroy_failure }} - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - if: ${{ matrix.terraform_apply }} - with: - name: terraform - path: "terraform" - - - name: Teardown - if: ${{ matrix.destroy || failure() }} - run: ./deploy.ps1 -Init -Teardown - shell: pwsh + + # BUG: https://github.com/Azure/azure-cli/issues/13352 + # No tty / ioctl device + # az container exec --ids $containerGroupID --exec-command "/health.sh" --container-name minecraft + script --return --quiet -c "az container exec --ids $containerGroupID --exec-command '/health.sh' --container-name minecraft" /dev/null + + az container show --ids $containerGroupID --query instanceView + az container logs --ids $containerGroupID + } + shell: pwsh + + - name: Remove backup items & resource locks + if: ${{ matrix.destroy }} + run: | + . (Join-Path $env:GITHUB_WORKSPACE scripts functions.ps1) + TearDown-Resources -Backups -Locks + shell: pwsh + + - name: Terraform Destroy + if: ${{ matrix.destroy }} + run: ./deploy.ps1 -Destroy -Force + shell: pwsh + continue-on-error: ${{ matrix.ignore_destroy_failure }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + if: ${{ matrix.terraform_apply }} + with: + name: terraform${{ matrix.name }} + path: 'terraform' + + - name: Teardown + if: ${{ matrix.destroy || failure() }} + run: ./deploy.ps1 -Init -Teardown + shell: pwsh diff --git a/.github/workflows/ci-vanilla.yml b/.github/workflows/ci-vanilla.yml index c09ec51..e6fdaed 100644 --- a/.github/workflows/ci-vanilla.yml +++ b/.github/workflows/ci-vanilla.yml @@ -1,28 +1,29 @@ -# Controls when the action will run. +# Controls when the action will run. on: # Triggers the workflow on push or pull request events but only for the main branch push: - branches: [main] + branches: [ main ] paths-ignore: - - "**/README.md" - - "**/LICENSE" - - "visuals/**" + - '**/README.md' + - '**/LICENSE' + - 'visuals/**' pull_request: - branches: [main] + branches: [ main ] paths-ignore: - - "**/README.md" - - "**/LICENSE" - - "visuals/**" + - '**/README.md' + - '**/LICENSE' + - 'visuals/**' schedule: - - cron: "0 3 * * Fri,Sun" + - cron: '0 3 * * Fri,Sun' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: "functions" - FUNCTIONS_ARTIFACT_NAME: "functions" + AZURE_FUNCTIONAPP_PACKAGE_PATH: 'functions' + DOTNET_VERSION: '6.0.x' + FUNCTIONS_ARTIFACT_NAME: 'functions' TF_IN_AUTOMATION: true TF_INPUT: 0 TF_VAR_location: ${{ secrets.TF_VAR_LOCATION }} @@ -37,29 +38,32 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - - name: Restore dependencies - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet restore - popd - - name: Build - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet build --no-restore --output ./bin/publish - popd - - name: Test - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet test --no-build --verbosity normal - popd - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} - path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" + - uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Restore dependencies + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet restore + popd + - name: Build + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet build --no-restore --output ./bin/publish + popd + - name: Test + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet test --no-build --verbosity normal + popd + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} + path: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' terraform: needs: dotnet @@ -69,159 +73,159 @@ jobs: working-directory: terraform runs-on: ubuntu-latest steps: - - name: Checkout source - uses: actions/checkout@v4 - - - name: Download artifacts from previous job - uses: actions/download-artifact@v4 - with: - name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} - path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" - - - name: Use Azure CLI - uses: azure/login@v2 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - - name: Detect desired Terraform version - id: terraform-version-check - run: | - $terraformVersion = (Get-Content .terraform-version) - Write-Output "TERRAFORM_VERSION=${terraformVersion}" >> $env:GITHUB_OUTPUT - shell: pwsh - - name: Use Terraform - uses: hashicorp/setup-terraform@v3 - with: - terraform_version: ${{ steps.terraform-version-check.outputs.TERRAFORM_VERSION }} - terraform_wrapper: false - - - name: Terraform Init - run: | - # Parse Azure secret into Terraform variables - $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) - $env:ARM_CLIENT_ID = $servicePrincipal.clientId - $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret - $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId - $env:ARM_TENANT_ID = $servicePrincipal.tenantId - - $env:TF_VAR_run_id=$env:GITHUB_RUN_ID - # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: - $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId - $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret - $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId - - # List environment variables - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,TF_* | Sort-Object -Property Name - # Save environment variable setup for subsequent steps - Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV - - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - Get-Location - terraform init - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - shell: pwsh - - - name: Terraform Plan - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform plan -out='ci.tfplan' - shell: pwsh - - - name: Terraform Apply - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - id: terraform-apply - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform apply -auto-approve 'ci.tfplan' - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - throw "'terraform apply' exited with status $exitCode" - } - - # Export Terraform output as step output - $terraformOutput = (terraform output -json | ConvertFrom-Json -AsHashtable) - foreach ($key in $terraformOutput.Keys) { - $outputVariableValue = $terraformOutput[$key].value - Write-Output "${key}=${outputVariableValue}" >> $env:GITHUB_OUTPUT - Write-Output "TF_OUT_${key}=${outputVariableValue}" >> $env:GITHUB_ENV + - name: Checkout source + uses: actions/checkout@v4 + + - name: Download artifacts from previous job + uses: actions/download-artifact@v4 + with: + name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} + path: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' + + - name: Use Azure CLI + uses: azure/login@v2 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Detect desired Terraform version + id: terraform-version-check + run: | + $terraformVersion = (Get-Content .terraform-version) + Write-Output "TERRAFORM_VERSION=${terraformVersion}" >> $env:GITHUB_OUTPUT + shell: pwsh + - name: Use Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_version: ${{ steps.terraform-version-check.outputs.TERRAFORM_VERSION }} + terraform_wrapper: false + + - name: Terraform Init + run: | + # Parse Azure secret into Terraform variables + $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) + $env:ARM_CLIENT_ID = $servicePrincipal.clientId + $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret + $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId + $env:ARM_TENANT_ID = $servicePrincipal.tenantId + + $env:TF_VAR_run_id=$env:GITHUB_RUN_ID + # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: + $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId + $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret + $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId + + # List environment variables + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,TF_* | Sort-Object -Property Name + # Save environment variable setup for subsequent steps + Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV + + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + Get-Location + terraform init + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + shell: pwsh + + - name: Terraform Plan + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform plan -out='ci.tfplan' + shell: pwsh + + - name: Terraform Apply + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + id: terraform-apply + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform apply -auto-approve 'ci.tfplan' + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { + throw "'terraform apply' exited with status $exitCode" + } + + # Export Terraform output as step output + $terraformOutput = (terraform output -json | ConvertFrom-Json -AsHashtable) + foreach ($key in $terraformOutput.Keys) { + $outputVariableValue = $terraformOutput[$key].value + Write-Output "${key}=${outputVariableValue}" >> $env:GITHUB_OUTPUT + Write-Output "TF_OUT_${key}=${outputVariableValue}" >> $env:GITHUB_ENV + } + shell: pwsh + + - name: 'Publish Monitor Function' + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + uses: azure/functions-action@v1 + with: + app-name: ${{ steps.terraform-apply.outputs.function_name }} + package: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' + + - name: Test connection to Minecraft Server (pwsh) + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + run: | + # Wait for Minecraft to boot up + $connectionAttempts = 0 + do { + Start-Sleep -Seconds 10 + Write-Host "Pinging ${env:TF_OUT_minecraft_server_fqdn} on port ${env:TF_OUT_minecraft_server_port}..." + try { + $connectionAttempts++ + $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($env:TF_OUT_minecraft_server_fqdn, $env:TF_OUT_minecraft_server_port) -ErrorAction SilentlyContinue + } catch [System.Management.Automation.MethodInvocationException] { + Write-Warning $_ } - shell: pwsh - - - name: "Publish Monitor Function" - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - uses: azure/functions-action@v1 - with: - app-name: ${{ steps.terraform-apply.outputs.function_name }} - package: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" - - - name: Test connection to Minecraft Server (pwsh) - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - run: | - # Wait for Minecraft to boot up - $connectionAttempts = 0 - do { - Start-Sleep -Seconds 10 - Write-Host "Pinging ${env:TF_OUT_minecraft_server_fqdn} on port ${env:TF_OUT_minecraft_server_port}..." - try { - $connectionAttempts++ - $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($env:TF_OUT_minecraft_server_fqdn, $env:TF_OUT_minecraft_server_port) -ErrorAction SilentlyContinue - } catch [System.Management.Automation.MethodInvocationException] { - Write-Warning $_ - } - } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) - - # No tty - # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - shell: pwsh - - # - name: Test connection to Minecraft Server (bash) - # if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - # run: | - # # Wait for Minecraft to boot up - # while ! echo exit | nc $TF_OUT_minecraft_server_fqdn $TF_OUT_minecraft_server_port; do sleep 10; done - # # No tty - # # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft - # shell: bash - - - name: Terraform Destroy - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform destroy -auto-approve - shell: pwsh - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: terraform - path: "terraform" - - - name: Clean Up - if: ${{ always() }} - run: | - $ErrorActionPreference = "Continue" - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - - # Remove resource locks first - $resourceLocksJSON = $(terraform output -json resource_locks 2>$null) - if ($resourceLocksJSON -and ($resourceLocksJSON -match "^\[.*\]$")) { - $resourceLocks = ($resourceLocksJSON | ConvertFrom-JSON) - az resource lock delete --ids $resourceLocks --verbose - } - - # Build JMESPath expression - $repository = ($env:GITHUB_REPOSITORY).Split("/")[-1] - $tagQuery = "[?tags.repository == '${repository}' && tags.workspace == '${env:TF_WORKSPACE}' && tags.runid == '${env:GITHUB_RUN_ID}' && properties.provisioningState != 'Deleting'].id" - - Write-Host "Removing resource group identified by `"$tagQuery`"..." - $resourceGroupIDs = $(az group list --query "$tagQuery" -o tsv) - if ($resourceGroupIDs) { - Write-Host "az resource delete --ids ${resourceGroupIDs}..." - az resource delete --ids $resourceGroupIDs --verbose - } else { - Write-Host "Nothing to remove" - } - shell: pwsh + } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) + + # No tty + # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + shell: pwsh + + # - name: Test connection to Minecraft Server (bash) + # if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + # run: | + # # Wait for Minecraft to boot up + # while ! echo exit | nc $TF_OUT_minecraft_server_fqdn $TF_OUT_minecraft_server_port; do sleep 10; done + # # No tty + # # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft + # shell: bash + + - name: Terraform Destroy + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform destroy -auto-approve + shell: pwsh + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: terraform + path: 'terraform' + + - name: Clean Up + if: ${{ always() }} + run: | + $ErrorActionPreference = "Continue" + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + + # Remove resource locks first + $resourceLocksJSON = $(terraform output -json resource_locks 2>$null) + if ($resourceLocksJSON -and ($resourceLocksJSON -match "^\[.*\]$")) { + $resourceLocks = ($resourceLocksJSON | ConvertFrom-JSON) + az resource lock delete --ids $resourceLocks --verbose + } + + # Build JMESPath expression + $repository = ($env:GITHUB_REPOSITORY).Split("/")[-1] + $tagQuery = "[?tags.repository == '${repository}' && tags.workspace == '${env:TF_WORKSPACE}' && tags.runid == '${env:GITHUB_RUN_ID}' && properties.provisioningState != 'Deleting'].id" + + Write-Host "Removing resource group identified by `"$tagQuery`"..." + $resourceGroupIDs = $(az group list --query "$tagQuery" -o tsv) + if ($resourceGroupIDs) { + Write-Host "az resource delete --ids ${resourceGroupIDs}..." + az resource delete --ids $resourceGroupIDs --verbose + } else { + Write-Host "Nothing to remove" + } + shell: pwsh From 420dc2991ca0b7b5acd904be3a543ffcb1ca4b13 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Sun, 19 Jan 2025 16:48:54 -0500 Subject: [PATCH 17/17] Reapply changes --- .github/workflows/ci-scripted.yml | 459 +++++++++++++++--------------- .github/workflows/ci-vanilla.yml | 388 ++++++++++++------------- 2 files changed, 423 insertions(+), 424 deletions(-) diff --git a/.github/workflows/ci-scripted.yml b/.github/workflows/ci-scripted.yml index 55f09aa..2e1d927 100644 --- a/.github/workflows/ci-scripted.yml +++ b/.github/workflows/ci-scripted.yml @@ -1,47 +1,47 @@ on: pull_request: - branches: [ main ] + branches: [main] paths-ignore: - - '**/README.md' - - '**/LICENSE' - - 'visuals/**' + - "**/README.md" + - "**/LICENSE" + - "visuals/**" schedule: - - cron: '0 2 * * Thu,Sat' + - cron: "0 2 * * Thu,Sat" # Allows you to run this workflow manually from the Actions tab workflow_dispatch: inputs: upgrade_provider_versions: - description: 'Upgrade Terraform provider versions' + description: "Upgrade Terraform provider versions" required: false type: boolean default: false upgrade_terraform_version: - description: 'Upgrade Terraform version' + description: "Upgrade Terraform version" required: false type: boolean default: false upgrade_azure_cli: - description: 'Upgrade Azure CLI to latest version' + description: "Upgrade Azure CLI to latest version" required: false type: boolean default: false destroy: - description: 'Destroy Infrastucture' + description: "Destroy Infrastucture" required: false type: boolean default: true workspace: type: choice required: true - description: 'Terraform Workspace' + description: "Terraform Workspace" default: ci - options: - - ci - - ci1 - - ci2 - - ci3 + options: + - ci + - ci1 + - ci2 + - ci3 env: ARM_SAS_TOKEN: ${{ secrets.ARM_SAS_TOKEN }} TF_IN_AUTOMATION: true @@ -63,38 +63,38 @@ jobs: working-directory: scripts runs-on: ubuntu-latest steps: - - name: Checkout source - uses: actions/checkout@v4 - - - name: Print environment variables - run: | - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name - shell: pwsh - - - name: Create matrix - id: create-matrix - run: | - ConvertTo-SecureString -AsPlainText -String '${{ secrets.GITHUB_TOKEN }}' | Set-Variable gitHubToken - ./create_workflow_strategy.ps1 -GitHubToken $gitHubToken ` - -DestroyInput "${{ github.event.inputs.destroy }}" ` - -UseLatestAzureCLIVersionInput "${{ github.event.inputs.upgrade_azure_cli }}" ` - -UseLatestTerraformProviderVersionsInput "${{ github.event.inputs.upgrade_provider_versions }}" ` - -UseLatestTerraformVersionInput "${{ github.event.inputs.upgrade_terraform_version }}" - - shell: pwsh - - - name: Install json2yaml - run: | - sudo npm install -g json2yaml - - - name: Display matrix - run: | - $matrixJSON = '${{ steps.create-matrix.outputs.matrix }}' - $matrixJSON - $matrixJSON | jq - $matrixJSON | ConvertFrom-Json - $matrixJSON | json2yaml - shell: pwsh + - name: Checkout source + uses: actions/checkout@v4 + + - name: Print environment variables + run: | + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name + shell: pwsh + + - name: Create matrix + id: create-matrix + run: | + ConvertTo-SecureString -AsPlainText -String '${{ secrets.GITHUB_TOKEN }}' | Set-Variable gitHubToken + ./create_workflow_strategy.ps1 -GitHubToken $gitHubToken ` + -DestroyInput "${{ github.event.inputs.destroy }}" ` + -UseLatestAzureCLIVersionInput "${{ github.event.inputs.upgrade_azure_cli }}" ` + -UseLatestTerraformProviderVersionsInput "${{ github.event.inputs.upgrade_provider_versions }}" ` + -UseLatestTerraformVersionInput "${{ github.event.inputs.upgrade_terraform_version }}" + + shell: pwsh + + - name: Install json2yaml + run: | + sudo npm install -g json2yaml + + - name: Display matrix + run: | + $matrixJSON = '${{ steps.create-matrix.outputs.matrix }}' + $matrixJSON + $matrixJSON | jq + $matrixJSON | ConvertFrom-Json + $matrixJSON | json2yaml + shell: pwsh outputs: matrix: ${{ steps.create-matrix.outputs.matrix }} @@ -115,188 +115,187 @@ jobs: runs-on: ${{ matrix.os }} steps: - - name: Checkout source - uses: actions/checkout@v4 - - - name: Dump strategy context - env: - MATRIX_CONTEXT: ${{ toJSON(matrix) }} - STRATEGY_CONTEXT: ${{ toJSON(strategy) }} - run: | - Write-Host "Strategy context:" - $env:STRATEGY_CONTEXT | ConvertFrom-Json | Format-List - Write-Host "Matrix context:" - $env:MATRIX_CONTEXT | ConvertFrom-Json | Format-List - shell: pwsh - - - name: Upgrade Azure CLI - id: az-upgrade - if: ${{ matrix.upgrade_azure_cli }} - run: | - # sudo az upgrade -y # not reliable - - curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null - echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list - sudo apt-get update - - $packageName = ($(apt-cache show azure-cli | Select-String 'Version: ${{ matrix.azure_cli_version }}.*$') -split ' ' | Select-Object -Last 1) - Write-Host "`nAzure CLI package: $packageName" - if ($packageName) { - sudo apt-get install --allow-downgrades azure-cli=$packageName - } else { - Write-Host "Azure CLI version ${{ matrix.azure_cli_version }} not found" - } - - az -v - continue-on-error: true - shell: pwsh - - - name: Use Azure CLI - uses: azure/login@v2 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - enable-AzPSSession: false - - - name: Show Azure CLI version - run: | - az -v - - - name: Use Terraform - uses: hashicorp/setup-terraform@v3 - with: - terraform_version: ${{matrix.terraform_version}} - terraform_wrapper: false - - - name: Show Terraform version - run: | - terraform -v - - - name: Unpin Terraform provider versions - id: terraform-version-check - if: ${{ !matrix.pin_provider_versions }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - (Get-Content ./provider.tf) -replace " = `" *= +",' = "~> ' | Out-File provider.tf - Get-Content ./provider.tf - if (Test-Path .terraform.lock.hcl) { - Remove-Item .terraform.lock.hcl -Force - } - shell: pwsh - - - name: Prepare environment variables - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - ENVIRONMENT_VARIABLES: ${{ secrets.ENVIRONMENT_VARIABLES }} - run: | - # Parse Azure secret into Terraform variables - $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) - $env:ARM_CLIENT_ID = $servicePrincipal.clientId - $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret - $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId - $env:ARM_TENANT_ID = $servicePrincipal.tenantId - - $env:TF_VAR_run_id=$env:GITHUB_RUN_ID - # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: - $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId - $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret - $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId - - # Save environment variable setup for subsequent steps - Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV - shell: pwsh - - - name: Show environment variables - run: | - Write-Host "Environment (sorted):" - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name - Write-Host "Environment (unsorted):" - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* - shell: pwsh - - - name: Terraform Init & Plan - run: ./deploy.ps1 -Init -Plan - shell: pwsh - - - name: Use Node.js - if: ${{ matrix.terraform_apply }} - uses: actions/setup-node@v4 - - name: Install Azure Functions Core Tools - if: ${{ matrix.terraform_apply }} - run: - npm i -g azure-functions-core-tools@3 --unsafe-perm true - - - name: Terraform Apply - id: terraform-apply - if: ${{ matrix.terraform_apply }} - run: ./deploy.ps1 -Apply -Force -NoCode - shell: pwsh - - - name: Deploy Azure Function - if: ${{ matrix.terraform_apply }} - run: ./deploy_functions.ps1 - shell: pwsh - - - name: Test connection to Minecraft Server - if: ${{ matrix.terraform_apply }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - $minecraftConfig = (terraform output -json minecraft_java | ConvertFrom-Json -AsHashtable) - foreach ($minecraftConfigName in $minecraftConfig.Keys) { - Write-Host "Processing configuration '{$minecraftConfigName}''..." - $containerGroupID = $minecraftConfig[$minecraftConfigName].container_group_id - $serverFQDN = $minecraftConfig[$minecraftConfigName].minecraft_server_fqdn - $serverPort = $minecraftConfig[$minecraftConfigName].minecraft_server_port - - # Wait for Minecraft socket to open - $connectionAttempts = 0 - do { - Start-Sleep -Seconds 10 - Write-Host "Pinging ${serverFQDN} on port ${serverPort}..." - try { - $connectionAttempts++ - $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($serverFQDN, $serverPort) -ErrorAction SilentlyContinue - } catch [System.Management.Automation.MethodInvocationException] { - Write-Warning $_ - } - } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) - if ($mineCraftConnection.Connected) { - Write-Host "Connected to ${serverFQDN}:${serverPort}" - $mineCraftConnection.Close() + - name: Checkout source + uses: actions/checkout@v4 + + - name: Dump strategy context + env: + MATRIX_CONTEXT: ${{ toJSON(matrix) }} + STRATEGY_CONTEXT: ${{ toJSON(strategy) }} + run: | + Write-Host "Strategy context:" + $env:STRATEGY_CONTEXT | ConvertFrom-Json | Format-List + Write-Host "Matrix context:" + $env:MATRIX_CONTEXT | ConvertFrom-Json | Format-List + shell: pwsh + + - name: Upgrade Azure CLI + id: az-upgrade + if: ${{ matrix.upgrade_azure_cli }} + run: | + # sudo az upgrade -y # not reliable + + curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null + echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/azure-cli.list + sudo apt-get update + + $packageName = ($(apt-cache show azure-cli | Select-String 'Version: ${{ matrix.azure_cli_version }}.*$') -split ' ' | Select-Object -Last 1) + Write-Host "`nAzure CLI package: $packageName" + if ($packageName) { + sudo apt-get install --allow-downgrades azure-cli=$packageName } else { - Write-Warning "Could not connect to ${serverFQDN}:${serverPort}!" + Write-Host "Azure CLI version ${{ matrix.azure_cli_version }} not found" + } + + az -v + continue-on-error: true + shell: pwsh + + - name: Use Azure CLI + uses: azure/login@v2 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + enable-AzPSSession: false + + - name: Show Azure CLI version + run: | + az -v + + - name: Use Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: ${{matrix.terraform_version}} + terraform_wrapper: false + + - name: Show Terraform version + run: | + terraform -v + + - name: Unpin Terraform provider versions + id: terraform-version-check + if: ${{ !matrix.pin_provider_versions }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + (Get-Content ./provider.tf) -replace " = `" *= +",' = "~> ' | Out-File provider.tf + Get-Content ./provider.tf + if (Test-Path .terraform.lock.hcl) { + Remove-Item .terraform.lock.hcl -Force } - - # BUG: https://github.com/Azure/azure-cli/issues/13352 - # No tty / ioctl device - # az container exec --ids $containerGroupID --exec-command "/health.sh" --container-name minecraft - script --return --quiet -c "az container exec --ids $containerGroupID --exec-command '/health.sh' --container-name minecraft" /dev/null - - az container show --ids $containerGroupID --query instanceView - az container logs --ids $containerGroupID - } - shell: pwsh - - - name: Remove backup items & resource locks - if: ${{ matrix.destroy }} - run: | - . (Join-Path $env:GITHUB_WORKSPACE scripts functions.ps1) - TearDown-Resources -Backups -Locks - shell: pwsh - - - name: Terraform Destroy - if: ${{ matrix.destroy }} - run: ./deploy.ps1 -Destroy -Force - shell: pwsh - continue-on-error: ${{ matrix.ignore_destroy_failure }} - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - if: ${{ matrix.terraform_apply }} - with: - name: terraform${{ matrix.name }} - path: 'terraform' - - - name: Teardown - if: ${{ matrix.destroy || failure() }} - run: ./deploy.ps1 -Init -Teardown - shell: pwsh + shell: pwsh + + - name: Prepare environment variables + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ENVIRONMENT_VARIABLES: ${{ secrets.ENVIRONMENT_VARIABLES }} + run: | + # Parse Azure secret into Terraform variables + $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) + $env:ARM_CLIENT_ID = $servicePrincipal.clientId + $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret + $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId + $env:ARM_TENANT_ID = $servicePrincipal.tenantId + + $env:TF_VAR_run_id=$env:GITHUB_RUN_ID + # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: + $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId + $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret + $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId + + # Save environment variable setup for subsequent steps + Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV + shell: pwsh + + - name: Show environment variables + run: | + Write-Host "Environment (sorted):" + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* | Sort-Object -Property Name + Write-Host "Environment (unsorted):" + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,INPUT_*,TF_* + shell: pwsh + + - name: Terraform Init & Plan + run: ./deploy.ps1 -Init -Plan + shell: pwsh + + - name: Use Node.js + if: ${{ matrix.terraform_apply }} + uses: actions/setup-node@v4 + - name: Install Azure Functions Core Tools + if: ${{ matrix.terraform_apply }} + run: npm i -g azure-functions-core-tools@3 --unsafe-perm true + + - name: Terraform Apply + id: terraform-apply + if: ${{ matrix.terraform_apply }} + run: ./deploy.ps1 -Apply -Force -NoCode + shell: pwsh + + - name: Deploy Azure Function + if: ${{ matrix.terraform_apply }} + run: ./deploy_functions.ps1 + shell: pwsh + + - name: Test connection to Minecraft Server + if: ${{ matrix.terraform_apply }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + $minecraftConfig = (terraform output -json minecraft_java | ConvertFrom-Json -AsHashtable) + foreach ($minecraftConfigName in $minecraftConfig.Keys) { + Write-Host "Processing configuration '{$minecraftConfigName}''..." + $containerGroupID = $minecraftConfig[$minecraftConfigName].container_group_id + $serverFQDN = $minecraftConfig[$minecraftConfigName].minecraft_server_fqdn + $serverPort = $minecraftConfig[$minecraftConfigName].minecraft_server_port + + # Wait for Minecraft socket to open + $connectionAttempts = 0 + do { + Start-Sleep -Seconds 10 + Write-Host "Pinging ${serverFQDN} on port ${serverPort}..." + try { + $connectionAttempts++ + $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($serverFQDN, $serverPort) -ErrorAction SilentlyContinue + } catch [System.Management.Automation.MethodInvocationException] { + Write-Warning $_ + } + } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) + if ($mineCraftConnection.Connected) { + Write-Host "Connected to ${serverFQDN}:${serverPort}" + $mineCraftConnection.Close() + } else { + Write-Warning "Could not connect to ${serverFQDN}:${serverPort}!" + } + + # BUG: https://github.com/Azure/azure-cli/issues/13352 + # No tty / ioctl device + # az container exec --ids $containerGroupID --exec-command "/health.sh" --container-name minecraft + script --return --quiet -c "az container exec --ids $containerGroupID --exec-command '/health.sh' --container-name minecraft" /dev/null + + az container show --ids $containerGroupID --query instanceView + az container logs --ids $containerGroupID + } + shell: pwsh + + - name: Remove backup items & resource locks + if: ${{ matrix.destroy }} + run: | + . (Join-Path $env:GITHUB_WORKSPACE scripts functions.ps1) + TearDown-Resources -Backups -Locks + shell: pwsh + + - name: Terraform Destroy + if: ${{ matrix.destroy }} + run: ./deploy.ps1 -Destroy -Force + shell: pwsh + continue-on-error: ${{ matrix.ignore_destroy_failure }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + if: ${{ matrix.terraform_apply }} + with: + name: terraform${{ matrix.name }} + path: "terraform" + + - name: Teardown + if: ${{ matrix.destroy || failure() }} + run: ./deploy.ps1 -Init -Teardown + shell: pwsh diff --git a/.github/workflows/ci-vanilla.yml b/.github/workflows/ci-vanilla.yml index e6fdaed..c7bd22c 100644 --- a/.github/workflows/ci-vanilla.yml +++ b/.github/workflows/ci-vanilla.yml @@ -1,29 +1,29 @@ -# Controls when the action will run. +# Controls when the action will run. on: # Triggers the workflow on push or pull request events but only for the main branch push: - branches: [ main ] + branches: [main] paths-ignore: - - '**/README.md' - - '**/LICENSE' - - 'visuals/**' + - "**/README.md" + - "**/LICENSE" + - "visuals/**" pull_request: - branches: [ main ] + branches: [main] paths-ignore: - - '**/README.md' - - '**/LICENSE' - - 'visuals/**' + - "**/README.md" + - "**/LICENSE" + - "visuals/**" schedule: - - cron: '0 3 * * Fri,Sun' + - cron: "0 3 * * Fri,Sun" # Allows you to run this workflow manually from the Actions tab workflow_dispatch: env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: 'functions' - DOTNET_VERSION: '6.0.x' - FUNCTIONS_ARTIFACT_NAME: 'functions' + AZURE_FUNCTIONAPP_PACKAGE_PATH: "functions" + DOTNET_VERSION: "6.0.x" + FUNCTIONS_ARTIFACT_NAME: "functions" TF_IN_AUTOMATION: true TF_INPUT: 0 TF_VAR_location: ${{ secrets.TF_VAR_LOCATION }} @@ -38,32 +38,32 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: hashicorp/setup-terraform@v3 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Restore dependencies - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet restore - popd - - name: Build - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet build --no-restore --output ./bin/publish - popd - - name: Test - run: | - pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' - dotnet test --no-build --verbosity normal - popd - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} - path: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' + - uses: actions/checkout@v4 + - uses: hashicorp/setup-terraform@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Restore dependencies + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet restore + popd + - name: Build + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet build --no-restore --output ./bin/publish + popd + - name: Test + run: | + pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}' + dotnet test --no-build --verbosity normal + popd + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} + path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" terraform: needs: dotnet @@ -73,159 +73,159 @@ jobs: working-directory: terraform runs-on: ubuntu-latest steps: - - name: Checkout source - uses: actions/checkout@v4 - - - name: Download artifacts from previous job - uses: actions/download-artifact@v4 - with: - name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} - path: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' - - - name: Use Azure CLI - uses: azure/login@v2 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - - name: Detect desired Terraform version - id: terraform-version-check - run: | - $terraformVersion = (Get-Content .terraform-version) - Write-Output "TERRAFORM_VERSION=${terraformVersion}" >> $env:GITHUB_OUTPUT - shell: pwsh - - name: Use Terraform - uses: hashicorp/setup-terraform@v2 - with: - terraform_version: ${{ steps.terraform-version-check.outputs.TERRAFORM_VERSION }} - terraform_wrapper: false - - - name: Terraform Init - run: | - # Parse Azure secret into Terraform variables - $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) - $env:ARM_CLIENT_ID = $servicePrincipal.clientId - $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret - $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId - $env:ARM_TENANT_ID = $servicePrincipal.tenantId - - $env:TF_VAR_run_id=$env:GITHUB_RUN_ID - # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: - $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId - $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret - $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId - - # List environment variables - Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,TF_* | Sort-Object -Property Name - # Save environment variable setup for subsequent steps - Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV - - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - Get-Location - terraform init - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - shell: pwsh - - - name: Terraform Plan - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform plan -out='ci.tfplan' - shell: pwsh - - - name: Terraform Apply - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - id: terraform-apply - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform apply -auto-approve 'ci.tfplan' - $exitCode = $LASTEXITCODE - if ($exitCode -ne 0) { - throw "'terraform apply' exited with status $exitCode" - } - - # Export Terraform output as step output - $terraformOutput = (terraform output -json | ConvertFrom-Json -AsHashtable) - foreach ($key in $terraformOutput.Keys) { - $outputVariableValue = $terraformOutput[$key].value - Write-Output "${key}=${outputVariableValue}" >> $env:GITHUB_OUTPUT - Write-Output "TF_OUT_${key}=${outputVariableValue}" >> $env:GITHUB_ENV - } - shell: pwsh - - - name: 'Publish Monitor Function' - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - uses: azure/functions-action@v1 - with: - app-name: ${{ steps.terraform-apply.outputs.function_name }} - package: '${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish' - - - name: Test connection to Minecraft Server (pwsh) - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - run: | - # Wait for Minecraft to boot up - $connectionAttempts = 0 - do { - Start-Sleep -Seconds 10 - Write-Host "Pinging ${env:TF_OUT_minecraft_server_fqdn} on port ${env:TF_OUT_minecraft_server_port}..." - try { - $connectionAttempts++ - $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($env:TF_OUT_minecraft_server_fqdn, $env:TF_OUT_minecraft_server_port) -ErrorAction SilentlyContinue - } catch [System.Management.Automation.MethodInvocationException] { - Write-Warning $_ + - name: Checkout source + uses: actions/checkout@v4 + + - name: Download artifacts from previous job + uses: actions/download-artifact@v4 + with: + name: ${{ env.FUNCTIONS_ARTIFACT_NAME }} + path: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" + + - name: Use Azure CLI + uses: azure/login@v2 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Detect desired Terraform version + id: terraform-version-check + run: | + $terraformVersion = (Get-Content .terraform-version) + Write-Output "TERRAFORM_VERSION=${terraformVersion}" >> $env:GITHUB_OUTPUT + shell: pwsh + - name: Use Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_version: ${{ steps.terraform-version-check.outputs.TERRAFORM_VERSION }} + terraform_wrapper: false + + - name: Terraform Init + run: | + # Parse Azure secret into Terraform variables + $servicePrincipal = ($env:AZURE_CREDENTIALS | ConvertFrom-Json) + $env:ARM_CLIENT_ID = $servicePrincipal.clientId + $env:ARM_CLIENT_SECRET = $servicePrincipal.clientSecret + $env:ARM_SUBSCRIPTION_ID = $servicePrincipal.subscriptionId + $env:ARM_TENANT_ID = $servicePrincipal.tenantId + + $env:TF_VAR_run_id=$env:GITHUB_RUN_ID + # We may not be able to create a Service Principal with a Service Principal, reuse Terraform SP for Logic App: + $env:TF_VAR_workflow_sp_application_id = $servicePrincipal.clientId + $env:TF_VAR_workflow_sp_application_secret = $servicePrincipal.clientSecret + $env:TF_VAR_workflow_sp_object_id = $servicePrincipal.objectId + + # List environment variables + Get-ChildItem -Path Env: -Recurse -Include ARM_*,AZURE_*,GITHUB_*,TF_* | Sort-Object -Property Name + # Save environment variable setup for subsequent steps + Get-ChildItem -Path Env: -Recurse -Include ARM_*,TF_VAR_* | ForEach-Object {Write-Output "$($_.Name)=$($_.Value)"} >> $env:GITHUB_ENV + + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + Get-Location + terraform init + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + shell: pwsh + + - name: Terraform Plan + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform plan -out='ci.tfplan' + shell: pwsh + + - name: Terraform Apply + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + id: terraform-apply + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform apply -auto-approve 'ci.tfplan' + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { + throw "'terraform apply' exited with status $exitCode" + } + + # Export Terraform output as step output + $terraformOutput = (terraform output -json | ConvertFrom-Json -AsHashtable) + foreach ($key in $terraformOutput.Keys) { + $outputVariableValue = $terraformOutput[$key].value + Write-Output "${key}=${outputVariableValue}" >> $env:GITHUB_OUTPUT + Write-Output "TF_OUT_${key}=${outputVariableValue}" >> $env:GITHUB_ENV } - } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) - - # No tty - # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft - env: - AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} - shell: pwsh - - # - name: Test connection to Minecraft Server (bash) - # if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - # run: | - # # Wait for Minecraft to boot up - # while ! echo exit | nc $TF_OUT_minecraft_server_fqdn $TF_OUT_minecraft_server_port; do sleep 10; done - # # No tty - # # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft - # shell: bash - - - name: Terraform Destroy - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - run: | - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - terraform destroy -auto-approve - shell: pwsh - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: terraform - path: 'terraform' - - - name: Clean Up - if: ${{ always() }} - run: | - $ErrorActionPreference = "Continue" - Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property - - # Remove resource locks first - $resourceLocksJSON = $(terraform output -json resource_locks 2>$null) - if ($resourceLocksJSON -and ($resourceLocksJSON -match "^\[.*\]$")) { - $resourceLocks = ($resourceLocksJSON | ConvertFrom-JSON) - az resource lock delete --ids $resourceLocks --verbose - } - - # Build JMESPath expression - $repository = ($env:GITHUB_REPOSITORY).Split("/")[-1] - $tagQuery = "[?tags.repository == '${repository}' && tags.workspace == '${env:TF_WORKSPACE}' && tags.runid == '${env:GITHUB_RUN_ID}' && properties.provisioningState != 'Deleting'].id" - - Write-Host "Removing resource group identified by `"$tagQuery`"..." - $resourceGroupIDs = $(az group list --query "$tagQuery" -o tsv) - if ($resourceGroupIDs) { - Write-Host "az resource delete --ids ${resourceGroupIDs}..." - az resource delete --ids $resourceGroupIDs --verbose - } else { - Write-Host "Nothing to remove" - } - shell: pwsh + shell: pwsh + + - name: "Publish Monitor Function" + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + uses: azure/functions-action@v1 + with: + app-name: ${{ steps.terraform-apply.outputs.function_name }} + package: "${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/bin/publish" + + - name: Test connection to Minecraft Server (pwsh) + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + run: | + # Wait for Minecraft to boot up + $connectionAttempts = 0 + do { + Start-Sleep -Seconds 10 + Write-Host "Pinging ${env:TF_OUT_minecraft_server_fqdn} on port ${env:TF_OUT_minecraft_server_port}..." + try { + $connectionAttempts++ + $mineCraftConnection = New-Object System.Net.Sockets.TcpClient($env:TF_OUT_minecraft_server_fqdn, $env:TF_OUT_minecraft_server_port) -ErrorAction SilentlyContinue + } catch [System.Management.Automation.MethodInvocationException] { + Write-Warning $_ + } + } while ((!$mineCraftConnection || !$mineCraftConnection.Connected) -and ($connectionAttempts -le 10)) + + # No tty + # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft + env: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + shell: pwsh + + # - name: Test connection to Minecraft Server (bash) + # if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + # run: | + # # Wait for Minecraft to boot up + # while ! echo exit | nc $TF_OUT_minecraft_server_fqdn $TF_OUT_minecraft_server_port; do sleep 10; done + # # No tty + # # az container exec --ids ${{ steps.terraform-apply.outputs.container_group_id }} --exec-command "/health.sh" --container-name minecraft + # shell: bash + + - name: Terraform Destroy + if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} + run: | + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + terraform destroy -auto-approve + shell: pwsh + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: terraform + path: "terraform" + + - name: Clean Up + if: ${{ always() }} + run: | + $ErrorActionPreference = "Continue" + Set-Location (Join-Path $env:GITHUB_WORKSPACE terraform) # Task does not support 'working-directory' property + + # Remove resource locks first + $resourceLocksJSON = $(terraform output -json resource_locks 2>$null) + if ($resourceLocksJSON -and ($resourceLocksJSON -match "^\[.*\]$")) { + $resourceLocks = ($resourceLocksJSON | ConvertFrom-JSON) + az resource lock delete --ids $resourceLocks --verbose + } + + # Build JMESPath expression + $repository = ($env:GITHUB_REPOSITORY).Split("/")[-1] + $tagQuery = "[?tags.repository == '${repository}' && tags.workspace == '${env:TF_WORKSPACE}' && tags.runid == '${env:GITHUB_RUN_ID}' && properties.provisioningState != 'Deleting'].id" + + Write-Host "Removing resource group identified by `"$tagQuery`"..." + $resourceGroupIDs = $(az group list --query "$tagQuery" -o tsv) + if ($resourceGroupIDs) { + Write-Host "az resource delete --ids ${resourceGroupIDs}..." + az resource delete --ids $resourceGroupIDs --verbose + } else { + Write-Host "Nothing to remove" + } + shell: pwsh