Created
April 13, 2023 14:45
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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