Azure App Configuration is designed for managing application settings and feature flags. It supports easy retrieval and updates of values via the Azure CLI or SDKs.
Features:
- Centralized store for configuration settings.
- Supports labels for managing multiple environments (e.g., dev, prod).
- Easy integration with other Azure services.
Commands:
Create an App Configuration Store:
Add or Update a Value:
Retrieve a Value:
Azure App Configuration Costs:
Azure App Configuration is a managed service that helps developers centralize application and feature settings securely.
Pricing:
- Standard Tier:
- $1.20 per store per day.
- Includes the first 200,000 requests per day.
- Additional requests are charged at $0.06 per 10,000 requests.
Example Calculation:
For a single store with up to 200,000 requests per day:
- Daily Cost: $1.20
- Monthly Cost: $1.20 × 30 = $36
For 300,000 requests per day:
- Daily Cost: $1.20 + ($0.06 × 10) = $1.80
- Monthly Cost: $1.80 × 30 = $54
Note: The Free tier is available but has limitations on the number of requests and storage capacity.
Here's a GitHub Actions workflow that increments or decrements an integer value stored in Azure App Configuration. It ensures that the value does not go below zero when decrementing. The workflow uses Azure CLI for interaction with Azure App Configuration.
Pre-requisites
- Ensure you have an Azure App Configuration resource set up.
- Add the following secrets to your GitHub repository:
AZURE_CLIENT_ID
: Azure Service Principal Client ID.AZURE_CLIENT_SECRET
: Azure Service Principal Client Secret.AZURE_TENANT_ID
: Azure Tenant ID.APP_CONFIG_NAME
: The name of your Azure App Configuration instance.VARIABLE_KEY
: The key name of the integer variable in App Configuration.
GitHub Actions Workflow
Save the following YAML file as .github/workflows/app-config-variable.yml
in your repository:
How It Works
- Trigger: The workflow is triggered manually using
workflow_dispatch
with an input parameteraction
(increment
ordecrement
). - Fetch Current Value:
- Retrieves the current value of the variable from Azure App Configuration.
- Defaults to
0
if the key does not exist.
- Perform Action:
- If the action is
increment
, the value is increased by 1. - If the action is
decrement
, it ensures the value does not go below0
.
- If the action is
- Update in Azure App Configuration:
- Updates the new value back to Azure App Configuration.
Usage
- Go to the "Actions" tab in your GitHub repository.
- Select the workflow
Update Azure App Configuration Variable
. - Click Run workflow and choose either
increment
ordecrement
as the action. - The workflow will update the value in your Azure App Configuration instance.
Now, let's use this for start and stop of the azure vms:
Updated GitHub Actions Workflows
Here are the updated workflows incorporating these changes.
1. start-vms
Workflow:
2. stop-vms
Workflow:
Explanation of Changes
In
start-vms
Workflow:- We first retrieve the current value of
installshield_runner
from Azure App Configuration. - If the VM name is
DevBuild004
, we increment the value ofinstallshield_runner
and then update it back to Azure App Configuration.
- We first retrieve the current value of
In
stop-vms
Workflow:- We retrieve the current value of
installshield_runner
before stopping the VMs. - If the VM name is
DevBuild004
, we decrement theinstallshield_runner
value and check if it becomes0
. If it's0
, the VM will be stopped and deallocated. - If the value is greater than
0
, the VM will simply be stopped and deallocated without being affected by theinstallshield_runner
value.
- We retrieve the current value of
Notes:
- The
installshield_runner
value is updated only forDevBuild004
. Other VMs will be started or stopped normally without affecting the value. - Make sure to update the
VM_Mappings
input with the appropriate VM names and resource groups.
The issue you're experiencing is a classic race condition, where multiple pipelines (or jobs) are trying to read and write the installshield_runner
value concurrently. Because these pipelines are not aware of each other's actions, one pipeline might read the value before the other updates it, causing them to both update it based on the same value, leading to inconsistent results.
To fix this, you need to ensure that when one pipeline updates the value, others are aware of this update and base their actions on the most recent value. Here's how you can solve this problem:
1. Use a Locking Mechanism
One way to ensure consistency is to implement a locking mechanism in the pipeline that prevents multiple workflows from updating the value at the same time. Azure App Configuration does not provide native support for locks, but you can manage this by implementing a simple "lock" using a flag stored in Azure App Configuration itself or another service like Azure Blob Storage.
2. Implementing an Optimistic Locking Strategy
Alternatively, you can implement optimistic concurrency control to handle the value changes, where each pipeline reads the value, increments/decrements it, and tries to update it only if the value hasn't changed since it was read. If it has changed, the pipeline should retry the update.
Solution with Optimistic Locking
We'll update the workflow to:
- Retrieve the current value of
installshield_runner
. - Use an ETag (entity tag) to check if the value has been modified.
- If the value has changed since it was read, the pipeline will retry the operation with the latest value.
Updated Workflow using Optimistic Locking
Here’s an updated workflow for both start-vms
and stop-vms
using Optimistic Locking.
start-vm pipelines
jobs: start-vms: runs-on: ubuntu-latest steps: - name: Azure Login uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Control VMs run: | retries=5 success=false while [ $retries -gt 0 ]; do # Retrieve current value (no --if-match flag used here) response=$(az appconfig kv show --name erwinDMBuilds --key installshield_runner --query "{value: value, etag: etag}" -o json) current_value=$(echo $response | jq -r '.value') etag=$(echo $response | jq -r '.etag') echo "Current installshield_runner value: $current_value, ETag: $etag" updated_value=$((current_value + 1)) # Update the value without the --if-match flag and with --yes to avoid confirmation prompts update_response=$(az appconfig kv set --name erwinDMBuilds --key installshield_runner --value $updated_value --yes) if [[ $? -eq 0 ]]; then success=true echo "Updated installshield_runner value to: $updated_value" break else retries=$((retries - 1)) echo "Failed to update value, retrying... ($retries attempts left)" sleep 2 fi done if [ "$success" = false ]; then echo "Failed to update installshield_runner after multiple attempts." exit 1 fi # Start VMs IFS=',' read -r -a VM_ARRAY <<< "${{ inputs.VM_Mappings }}" for VM_RG in "${VM_ARRAY[@]}"; do IFS=':' read -r -a VM_RG_PAIR <<< "$VM_RG" VM=${VM_RG_PAIR[0]} RG=${VM_RG_PAIR[1]} az vm start --resource-group $RG --name $VM done
Explanation of start-vms
:
Azure Login:
The actionazure/login@v1
authenticates to Azure using the credentials stored in GitHub secrets (${{ secrets.AZURE_CREDENTIALS }}
).Retrieve Current
installshield_runner
Value:
The script fetches the current value of theinstallshield_runner
key from Azure App Configuration using theaz appconfig kv show
command. The response includes both the value and anetag
.Increment the Value:
Theinstallshield_runner
value is incremented by 1 (updated_value=$((current_value + 1))
).Update the Value in Azure App Configuration:
The script then attempts to update theinstallshield_runner
value in Azure App Configuration with the new incremented value. The commandaz appconfig kv set
is used, and the--yes
flag ensures no confirmation is needed.Retry Mechanism:
If the update fails, the job will retry up to 5 times (retries=5
). After each failure, it waits for 2 seconds before retrying. If all retries fail, the job will exit with a failure.Start the VMs:
It iterates through the list of VMs (defined by theVM_Mappings
input) and starts the VMs usingaz vm start
. If the VM name isDevBuild004
, it checks if theinstallshield_runner
value is greater than 0. If the value is greater than 0, the VM is not started, and the script skips it.
stop-vm pipeline
jobs: stop-vms: runs-on: ubuntu-latest needs: - start-vms steps: - name: Azure Login uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Control VMs run: | retries=5 success=false while [ $retries -gt 0 ]; do # Retrieve current value (no --if-match flag used here) response=$(az appconfig kv show --name erwinDMBuilds --key installshield_runner --query "{value: value, etag: etag}" -o json) current_value=$(echo $response | jq -r '.value') etag=$(echo $response | jq -r '.etag') echo "Current installshield_runner value: $current_value, ETag: $etag" # Decrement the value, but ensure it doesn't go below 0 if [ $current_value -gt 0 ]; then updated_value=$((current_value - 1)) else updated_value=0 fi # Update the value without the --if-match flag and with --yes to avoid confirmation prompts update_response=$(az appconfig kv set --name erwinDMBuilds --key installshield_runner --value $updated_value --yes) if [[ $? -eq 0 ]]; then success=true echo "Updated installshield_runner value to: $updated_value" break else retries=$((retries - 1)) echo "Failed to update value, retrying... ($retries attempts left)" sleep 2 fi done if [ "$success" = false ]; then echo "Failed to update installshield_runner after multiple attempts." exit 1 fi # Stop VMs IFS=',' read -r -a VM_ARRAY <<< "${{ inputs.VM_Mappings }}" for VM_RG in "${VM_ARRAY[@]}"; do IFS=':' read -r -a VM_RG_PAIR <<< "$VM_RG" VM=${VM_RG_PAIR[0]} RG=${VM_RG_PAIR[1]} if [[ "$VM" == "DevBuild004" && $updated_value -gt 0 ]]; then echo "installshield_runner is not zero, skipping stop for $VM." else # Only stop DevBuild004 if installshield_runner is 0 echo "Stopping VM $VM." az vm stop --resource-group $RG --name $VM az vm deallocate --resource-group $RG --name $VM fi done
Explanation of stop-vms
:
Azure Login:
The action azure/login@v1
authenticates to Azure using the credentials stored in GitHub secrets (${{ secrets.AZURE_CREDENTIALS }}
).
Retrieve Current installshield_runner
Value:
Similar to start-vms
, the current value of the installshield_runner
key is retrieved from Azure App Configuration.
Decrement the Value:
If the installshield_runner
value is greater than 0, it is decremented by 1. If the value is 0, it remains 0.
Update the Value in Azure App Configuration:
The updated value is saved back into Azure App Configuration using the az appconfig kv set
command.
Retry Mechanism:
Similar to the start-vms
job, a retry mechanism is used to ensure the value is updated successfully. If all retries fail, the job exits with a failure.
Stop the VMs:
The VMs are checked and stopped. If the VM is DevBuild004
and the installshield_runner
value is greater than 0, it skips stopping the VM. If the value is 0, the VM is stopped using az vm stop
and deallocated using az vm deallocate
.
Azure Login:
The action azure/login@v1
authenticates to Azure using the credentials stored in GitHub secrets (${{ secrets.AZURE_CREDENTIALS }}
).
Retrieve Current installshield_runner
Value:
Similar to start-vms
, the current value of the installshield_runner
key is retrieved from Azure App Configuration.
Decrement the Value:
If the installshield_runner
value is greater than 0, it is decremented by 1. If the value is 0, it remains 0.
Update the Value in Azure App Configuration:
The updated value is saved back into Azure App Configuration using the az appconfig kv set
command.
Retry Mechanism:
Similar to the start-vms
job, a retry mechanism is used to ensure the value is updated successfully. If all retries fail, the job exits with a failure.
Stop the VMs:
The VMs are checked and stopped. If the VM is DevBuild004
and the installshield_runner
value is greater than 0, it skips stopping the VM. If the value is 0, the VM is stopped using az vm stop
and deallocated using az vm deallocate
.
Summary:
start-vms
: Increments the value of installshield_runner
and starts the VMs, except DevBuild004
if the value is greater than 0.stop-vms
: Decrements the value of installshield_runner
and stops the VMs, except DevBuild004
if the value is greater than 0.
start-vms
: Increments the value of installshield_runner
and starts the VMs, except DevBuild004
if the value is greater than 0.stop-vms
: Decrements the value of installshield_runner
and stops the VMs, except DevBuild004
if the value is greater than 0.
No comments:
Post a Comment