Skip to content

Instantly share code, notes, and snippets.

@GTRekter
Created April 13, 2023 14:45
Show Gist options
  • Save GTRekter/e30cdd1db5fd2f5da2c938ec2d4ad492 to your computer and use it in GitHub Desktop.
Save GTRekter/e30cdd1db5fd2f5da2c938ec2d4ad492 to your computer and use it in GitHub Desktop.
The script is designed to automate the creation of Azure DevOps agent pools. It will process both self-hosted and Azure-hosted pools.
PAT=""
ORG_NAME="ivanporta"
PROJECT_NAME="Sample"
DEFAULT_JSON='{
"agent_pools":
[
{
"self_hosted":[
{
"name": "Default",
"authorize_pipelines": false
},
{
"name": "On-Premises",
"authorize_pipelines": false
}
],
"azure_virtual_machine_scale_sets": [
{
"name":"Sample",
"authorize_pipelines": false,
"auto_provision_project_pools": true,
"azure_resource_group_name": "rg-sample-dev",
"azure_virtual_machine_scale_set_name": "vmss-sample-dev-02",
"desired_idle": 1,
"max_capacity": 2,
"os_type": 1,
"max_saved_node_count": 0,
"recycle_after_each_use": true,
"time_to_live_minutes": 30,
"service_endpoint_name": "Azure"
}
]
}
]
}'
echo "Creating agent pools in $PROJECT_NAME project"
echo "Read organization ID by $ORG_NAME. This property is needed to get a list of service endpoints"
RESPONSE=$(curl --silent \
--write-out "\n%{http_code}" \
--header "Authorization: Basic $(echo -n :$PAT | base64)" \
--header "Content-Type: application/json" \
--data-raw '{"contributionIds": ["ms.vss-features.my-organizations-data-provider"],"dataProviderContext":{"properties":{}}}' \
"https://dev.azure.com/$ORG_NAME/_apis/Contribution/HierarchyQuery?api-version=5.0-preview.1")
HTTP_STATUS=$(tail -n1 <<< "$RESPONSE")
RESPONSE_BODY=$(sed '$ d' <<< "$RESPONSE")
if [ $HTTP_STATUS != 200 ]; then
echo "Failed to get the list of existing service endpoints. $RESPONSE"
exit 1;
else
echo "The list of existing service endpoints was succesfully retrieved"
fi
ORG_ID=$(echo "$RESPONSE_BODY" | jq '.dataProviders."ms.vss-features.my-organizations-data-provider".organizations[] | select(.name == "'"$ORG_NAME"'") | .id' | tr -d '"')
echo "The ID of the $ORG_NAME organization is $ORG_ID"
echo "Get project ID by $PROJECT_NAME"
PROJECT_ID=$(az devops project show --project $PROJECT_NAME | jq -r '.id')
if [ $? -eq 0 ]; then
echo "The ID of the $PROJECT_NAME project is $PROJECT_ID"
else
echo "Error during the reading of the property ID of the $PROJECT_ID"
exit 1
fi
echo "Get the list of agent pools"
RESPONSE=$(curl --silent \
--write-out "\n%{http_code}" \
--header "Authorization: Basic $(echo -n :$PAT | base64)" \
--header "Content-Type: application/json" \
"https://dev.azure.com/$ORG_NAME/$PROJECT_NAME/_apis/distributedtask/queues?api-version=5.0-preview.1")
HTTP_STATUS=$(tail -n1 <<< "$RESPONSE")
AGENT_POOL_LIST_RESPONSE_BODY=$(sed '$ d' <<< "$RESPONSE")
if [ $HTTP_STATUS != 200 ]; then
echo "Failed to get the list of existing pools. $RESPONSE"
exit 1;
else
echo "The list of existing pools was succesfully retrieved"
fi
for AGENT_POOL in $(echo "$DEFAULT_JSON" | jq -r '.pipeline.agent_pools[] | @base64'); do
AGENT_POOL_JSON=$(echo "$AGENT_POOL" | base64 --decode | jq -r '.')
echo "Creating self-hosted agents"
for SELF_HOSTED_AGENT_POOL in $(echo "$AGENT_POOL_JSON" | jq -r '.self_hosted[] | @base64'); do
SELF_HOSTED_AGENT_POOL_JSON=$(echo "$SELF_HOSTED_AGENT_POOL" | base64 --decode | jq -r '.')
NAME=$(echo "$SELF_HOSTED_AGENT_POOL_JSON" | jq -r '.name')
AUTH_PIPELINES=$(echo "$AGENT_POOL_JSON" | jq -r '.authorize_pipelines')
echo "Check if the $NAME agent pool already exists"
if [[ $(echo "$AGENT_POOL_LIST_RESPONSE_BODY" | jq '.value[] | select(.name == "'"$NAME"'") | length') -gt 0 ]]; then
echo "$NAME agent pool already exists. Skipping..."
continue
else
echo "$NAME agent pool does not exist."
fi
echo "Create $NAME self-hosted agent pool"
RESPONSE=$(curl --silent \
--write-out "\n%{http_code}" \
--header "Authorization: Basic $(echo -n :$PAT | base64)" \
--header "Content-Type: application/json" \
--data-raw '{"name": "'"$NAME"'"}' \
"https://dev.azure.com/$ORG_NAME/$PROJECT_NAME/_apis/distributedtask/queues?authorizePipelines=$AUTH_PIPELINES&api-version=5.0-preview.1")
HTTP_STATUS=$(tail -n1 <<< "$RESPONSE")
RESPONSE_BODY=$(sed '$ d' <<< "$RESPONSE")
if [ $HTTP_STATUS != 200 ]; then
echo "Failed to create the $NAME agent pool. $RESPONSE"
exit 1;
else
echo "The $NAME agent pool was successfully created"
fi
done
echo "Creating azure virtual machine scale set agents"
for AZURE_HOSTED_AGENT_POOL in $(echo "$AGENT_POOL_JSON" | jq -r '.azure_virtual_machine_scale_sets[] | @base64'); do
AZURE_HOSTED_AGENT_POOL_JSON=$(echo "$AZURE_HOSTED_AGENT_POOL" | base64 --decode | jq -r '.')
NAME=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.name')
AUTH_PIPELINES=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.authorize_pipelines')
SERVICE_ENDPOINT_NAME=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.service_endpoint_name')
AUTO_PROVISIONING_PROJECT_POOLS=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.auto_provision_project_pools')
AZURE_RESOURCE_GROUP_NAME=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.azure_resource_group_name')
AZURE_VIRTUAL_MACHINE_SCALE_SET_NAME=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.azure_virtual_machine_scale_set_name')
DESIRED_IDLE=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.desired_idle')
MAX_CAPACITY=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.max_capacity')
OS_TYPE=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.os_type')
MAX_SAVED_NODE_COUNT=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.max_saved_node_count')
RECYCLE_AFTER_EACH_USE=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.recycle_after_each_use')
TIME_TO_LIVE_MINUTES=$(echo "$AZURE_HOSTED_AGENT_POOL_JSON" | jq -r '.time_to_live_minutes')
echo "Check if the $NAME agent pool already exists"
if [[ $(echo "$AGENT_POOL_LIST_RESPONSE_BODY" | jq '.value[] | select(.name == "'"$NAME"'") | length') -gt 0 ]]; then
echo "$NAME agent pool already exists. Skipping..."
continue
else
echo "$NAME agent pool does not exist."
fi
echo "Read the list of existing service endpoints. Needed to configure the VMSS."
RESPONSE=$(curl --silent \
--write-out "\n%{http_code}" \
--header "Authorization: Basic $(echo -n :$PAT | base64)" \
--header "Content-Type: application/json" \
"https://dev.azure.com/$ORG_NAME/$PROJECT_ID/_apis/serviceendpoint/endpoints?type=azurerm&api-version=6.0-preview.4")
HTTP_STATUS=$(tail -n1 <<< "$RESPONSE")
RESPONSE_BODY=$(sed '$ d' <<< "$RESPONSE")
if [ $HTTP_STATUS != 200 ]; then
echo "Failed to get the list of existing service endpoints. $RESPONSE"
exit 1;
else
echo "The list of existing service endpoints was succesfully retrieved"
fi
SERVICE_ENDPOINT=$(echo "$RESPONSE_BODY" | jq -r '.value[] | select(.name == "'"$SERVICE_ENDPOINT_NAME"'")')
SERVICE_ENDPOINT_ID=$(echo "$SERVICE_ENDPOINT" | jq -r '.id')
SERVICE_ENDPOINT_TENANT_ID=$(echo "$SERVICE_ENDPOINT" | jq -r '.authorization.parameters.tenantid')
SERVICE_ENDPOINT_SCOPE=$(echo "$SERVICE_ENDPOINT" | jq -r '.serviceEndpointProjectReferences[] | select(.projectReference.name == "'"$PROJECT_NAME"'") | .projectReference.id')
SERVICE_ENDPOINT_SUBSCRIPTION_ID=$(echo "$SERVICE_ENDPOINT" | jq -r '.data.subscriptionId')
echo "Create $NAME virtual machine scale set agent pool"
RESPONSE=$(curl --silent \
--request POST \
--write-out "\n%{http_code}" \
--header "Authorization: Basic $(echo -n :$PAT | base64)" \
--header "Content-Type: application/json" \
--data-raw '{"agentInteractiveUI":false,"azureId":"/subscriptions/'$SERVICE_ENDPOINT_SUBSCRIPTION_ID'/resourceGroups/'$AZURE_RESOURCE_GROUP_NAME'/providers/Microsoft.Compute/virtualMachineScaleSets/'$AZURE_VIRTUAL_MACHINE_SCALE_SET_NAME'","desiredIdle":'$DESIRED_IDLE',"maxCapacity":'$MAX_CAPACITY',"osType":'$OS_TYPE',"maxSavedNodeCount":'$MAX_SAVED_NODE_COUNT',"recycleAfterEachUse":'$RECYCLE_AFTER_EACH_USE',"serviceEndpointId":"'$SERVICE_ENDPOINT_ID'","serviceEndpointScope":"'$SERVICE_ENDPOINT_SCOPE'","timeToLiveMinutes":'$TIME_TO_LIVE_MINUTES'}' \
"https://dev.azure.com/$ORG_NAME/_apis/distributedtask/elasticpools?poolName=$NAME&authorizeAllPipelines=$AUTH_PIPELINES&autoProvisionProjectPools=$AUTO_PROVISIONING_PROJECT_POOLS&projectId=$PROJECT_ID&api-version=6.1-preview.1")
HTTP_STATUS=$(tail -n1 <<< "$RESPONSE")
RESPONSE_BODY=$(sed '$ d' <<< "$RESPONSE")
if [ $HTTP_STATUS != 200 ]; then
echo "Failed to create the $NAME agent pool. $RESPONSE"
exit 1;
else
echo "The $NAME agent pool was successfully created"
fi
done
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment