How can I know if the pipeline is using a Microsoft-hosted agent or self-hosted agent - azure

While running an azure build pipeline (yml version) is there any programmatic way (inside the pipeline itself) to know if the current pipeline is running on the ms-hosted agent or self-hosted agent?
We have one pre-defined variable called 'Agent.Name' which gives the agent name.
But it keeps changing the agent name (Hosted, Azure)
Agent.Name=Hosted, Agent.Name=Azure
Is there any way to determine the type of agent at the pipeline run time.
- task: Bash#3
displayName: Show Agent Name
inputs:
targetType: 'inline'
script: |
echo $(Agent.Name)

No built-in feature to achieve your requirements.
But we can 'for-each' the 'azure pipeline agent pool' to get all of the Microsoft-agent names in it. And then compare.
trigger:
- none
# pool:
# name: VMAS
# 1
stages:
- stage: s1
displayName: get the Microsoft host agents' names
jobs:
- job: testJob
steps:
- task: PowerShell#2
name: setvar
inputs:
targetType: 'inline'
script: |
# logic here. For example you get the vars and put it into this format:
$PAT = "<Your Personal Access Token>"
$org_name = "<Your Organization Name>"
$pool_id = <The microsoft hosted agent pool id>
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic "+$PAT)
$url = "https://dev.azure.com/"+$org_name+"/_apis/distributedtask/pools/"+$pool_id+"/agents?api-version=6.0"
$response = Invoke-RestMethod $url -Method 'GET' -Headers $headers
$response | ConvertTo-Json
$str = "";
foreach ($item in $response.value) {
$str += $item.name
$str += ","
}
Write-Host $str
Write-Host "##vso[task.setvariable variable=outputvars;isOutput=true]$str"
# 2
- stage: s2
displayName: check whether current agent name is one of the above
dependsOn: s1
variables:
vars: $[ stageDependencies.s1.testJob.outputs['setvar.outputvars'] ]
jobs:
- job:
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
$varsArr = "$(vars)".Split(',')
$microsofthostagent = 0
foreach ($var in $varsArr)
{
if ($var -eq "$(Agent.Name)")
{
$microsofthostagent = 1
}
else
{
}
}
if( $microsofthostagent -eq 1){
Write-Host "This pipeline is based on Microsoft Host Agent."
}else{
Write-Host "This pipeline is based on Self Host Agent."
}
By default, the self host agent will not have the same name as the Microsoft host agent.
You just need to be careful not to name the self host agent the same as the agent in the Microsoft agent pool (eg "Hosted Agent", "Azure Pipelines ")
On my side, it works:
Microsoft hosted agent
Self hosted agent

As we are using both the ms-hosted & self-hosted so as a solution I started verifying the names of my self-hosted agents (these names are already known to us) & based on this I am able to pick the MS-hosted agents

Related

How to pass KeyVault secrets to a template or a script file in Azure Pipelines?

I have this YAML file:
steps:
- task: AzureKeyVault#2
displayName: Get secret from AzureVault
inputs:
azureSubscription: 'subName'
KeyVaultName: 'vaultName'
SecretsFilter: 'mySecret'
RunAsPreJob: true
- template: \pipelines\templates\vm_setup.yml
parameters:
os_pass: $(mySecret)
How do I use mySecret inside myScript.ps1 or inside myTemplate.yml?
I tried to pass it as an argument, or map it to an env variable then pass that env variable as an argument but neither worked!
My myTemplate.yml looks like this:
parameters:
- name: os_pass
type: string
steps:
- task: PowerShell#2
displayName: Trial
inputs:
targetType: 'filepath'
filePath: '${{ parameters.workingDirectory }}\myScript.ps1'
arguments: >-
- OS_Pass ${{ parameters.os_pass }}
And this is myScript.ps1
param (
[Parameter(Mandatory = $true)]
[string]$OS_Pass
)
$password = ConvertTo-SecureString -String $OS_Pass -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'admin', $password
Write-Host '---------'
Write-Host $OS_Pass
Doing so the secret is now a string! How do I pass it without changing its type?
Take a look at the official documentation here: https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-secret-variables?view=azure-devops&tabs=yaml%2Cbash.
There are a few different ways to accomplish what you want to do. Without knowing exactly what you want to do, it is hard to recommend a specific method to use. Take a look above and let us know if that resolves your issue.

Only SPN credential auth scheme is supported for non windows agent

I have a linux agent where I want to run a PowerShell script with an azcli command, using Azure Resource Manager service connection.
This is the task I am using :
- task: AzurePowerShell#5
displayName: 'Add webapp OutboundIPs into SA FW'
inputs:
azureSubscription: ${{ parameters.serviceConnection }}
ScriptType: 'FilePath'
ScriptPath: '$(path)/update-SA-firewall.ps1'
ScriptArguments: '-webappOutboundIPs "$(webappOutboundIPs)" -SAName $(SAName) -RG ${{ parameters.resourceGroupName }}'
azurePowerShellVersion: 'LatestVersion'
And this is the script:
Param(
[string] [Parameter(Mandatory=$true)] $webappOutboundIPs,
[string] [Parameter(Mandatory=$true)] $SAName,
[string] [Parameter(Mandatory=$true)] $RG
)
# get the Array of IPs from the given string
$IPs = $webappOutboundIPs.Split(",")
# Add these IPs into the SA Firewall
foreach ($ip in $IPs) {
az storage account network-rule add -g $RG --account-name $SAName --ip-address $ip | out-null
}
The error I get is :
Line | 106 | throw ("Only SPN credential auth scheme is
supported for non wind …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Only SPN credential auth scheme is supported for non windows
| agent.
##[error]PowerShell exited with code '1'.
Am I missing something here :/ ?

How to get build name on Azure?

My goal is to get the build name from Azure YAML pipeline code.
For example, here it is #20220803.9 JBS-2413 Do not approve yet, this is an experiment of automating the tra...
I looked here but no luck
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
I tried Build.DefinitionName it returns PR
I tried Build.BuildNumber it returns 20220803.9 only
I tried Build.SourceVersionMessage it returns Merge
No built-in predefined variables or other things to get the "build name" you want. If you intercept the network traffic analysis, you will also find that the "build name" you want is not a whole, it is a combination of two data.
You need to design your own code to get it. For example, if you are based on Azure Git Repo, below pipeline YAML can help you get the "build name" you want when creating a pull request to trigger the pipeline:
trigger:
- none
# 1
stages:
- stage: s1
displayName: Get the lastest comment
jobs:
- job: testJob
steps:
- task: PowerShell#2
name: setvar
inputs:
targetType: 'inline'
script: |
$PAT = "<Your Personal Access Token>"
$org_name = "<Organization Name>"
$project_name = "<Project Name>"
$branch_name = "<Current Branch Name>"
$def_id = "<Pipeline definition ID>"
$run_id = "$(Build.BuildId)"
Write-Host $run_id
if("$(Build.Reason)" -eq "PullRequest") {
$headers_run = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers_run.Add("Authorization", "Basic "+$PAT)
$run_url = "https://dev.azure.com/"+$org_name+"/"+$project_name+"/_apis/pipelines/"+$def_id+"/runs/"+$run_id+"?api-version=6.0-preview.1"
$response_run = Invoke-RestMethod $run_url -Method 'GET' -Headers $headers_run
$response_run | ConvertTo-Json
$pull_request_id = $response_run.variables."system.pullRequest.pullRequestId".value
$headers_pr = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers_pr.Add("Authorization", "Basic "+$PAT)
$pr_url = "https://dev.azure.com/"+$org_name+"/"+$project_name+"/_apis/git/repositories/ShowBuildName/pullrequests/"+$pull_request_id+"?api-version=6.0"
$response_pr = Invoke-RestMethod $pr_url -Method 'GET' -Headers $headers_pr
$response_pr | ConvertTo-Json
Write-Host $response_pr.title
$str = $response_pr.title
Write-Host "##vso[task.setvariable variable=outputvars;isOutput=true]$str"
}
else {
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic "+$PAT)
$url = "https://dev.azure.com/"+$org_name+"/"+$project_name+"/_apis/git/repositories/ShowBuildName/commits?searchCriteria.itemVersion.version="+$branch_name+"&api-version=6.0"
$response = Invoke-RestMethod $url -Method 'GET' -Headers $headers
$response | ConvertTo-Json
$str = $response.value[0].comment
Write-Host "##vso[task.setvariable variable=outputvars;isOutput=true]$str"
}
# 2
- stage: s2
displayName: Get the "build name"
dependsOn: s1
variables:
vars: $[ stageDependencies.s1.testJob.outputs['setvar.outputvars'] ]
jobs:
- job:
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
Write-Host "$(Build.BuildNumber) $(vars)"
Pipeline run:
Successfully get the "build name":

Integrate CI and CD together Azure Devops

we need your support on enabling continues deployment on our release pipeline .
Environment :
CI or Build Pipeline is on Azure Devops Services
CD or Release pipeline is on Azure Devops Server
We want to Integrate CI and CD together right now after Build release is not kicking automatically.(I have to manually execute the release )
[![enter image description here][1]][1]
[![enter image description here][2]][2]
[![enter image description here][3]][3]
Service connection between azure devops service and azure devops server
[![enter image description here][4]][4]
# Trigger Release pipeline
- task: PowerShell#2
displayName: 'Trigger Release pipeline'
inputs:
targetType: 'inline'
powershell: |
$url = "https://vsrm.dev.azure.com/{OrganizationName}/{ProjectName}/_apis/release/releases?api-version=6.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($env:TOKEN)"))
$JSON = #'
{
"definitionId": 38,
"variables": {
"Version": {
"value": "$(build.buildnumber)"
}
}
}
'#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON
displayName: 'PowerShell Script'
env:
TOKEN: $(token)```
[1]: https://i.stack.imgur.com/g4J8I.png
[2]: https://i.stack.imgur.com/njsVU.png
[3]: https://i.stack.imgur.com/MIaJJ.png
[4]: https://i.stack.imgur.com/20wk9.png
We want to Integrate CI and CD together right now after Build release is not kicking automatically.
Since the azure devops service is on the cloud side and the azure devops server is local, there is no out-of-the-box feature that can Integrate CI/CD.
But you could use PowerShell task to run the Rest API in Azure Devops Service to trigger the Release on Azure Devops Server . Releases - Create
Here is an example:
You can add the Powershell Task to the end of the build, then you could add the following script in the powershell task:
$token = "PAT"
$url = "https://{instance}/{collection}/{project}/_apis/release/releases?api-version=5.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = #'
{
"definitionId": DefinitionID(e.g. 15),
"description": "Creating Sample release",
"artifacts": [],
"isDraft": false,
"reason": "none",
"manualEnvironments": null
}
'#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON
If your CI/Build pipeline is running on self-hosted agent, you can directly add the powershell task at the same agent job.
If your build pipeline is running on Microsoft-hosted agent, you need to create a self-hosted agent and add additional agent job to run powershell script.
In this case, you also need to set the Dependencies.
Note: When running the rest api to trigger the azure devops server release, you need to ensure that they are in the same network range. So it needs self-hosted agent.
Update:
To define a stage, you could refer to the following doc and sample:
stages:
- stage: A
jobs:
- job: A1
pool:
name: Default
steps:
- script: echo
- stage: B
pool:
name: Default
jobs:
- job: B1
steps:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
$token = "PAT"
$url = "https://{instance}/{collection}/{project}/_apis/release/releases?api-version=5.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
$JSON = #'
{
"definitionId": ID,
"variables": {
"Version": {
"value": "$(Build.buildnumber)"
}
}
}
'#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON
Update2:
In order to achieve a function similar to the system.accesstoken variable, you can try the following settings.
Step1: Create a variable in Azure Devops Service Build Pipeline and set it as variable:
Step2: PowerShell Task script:
- powershell: |
$url = "https://{instance}/{collection}/{project}/_apis/release/releases?api-version=5.0"
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($env:TOKEN)"))
$JSON = #'
{
"definitionId": 38,
"variables": {
"Version": {
"value": "$(build.buildnumber)"
}
}
}
'#
$response = Invoke-RestMethod -Uri $url -Headers #{Authorization = "Basic $token"} -Method Post -ContentType application/json -body $JSON
displayName: 'PowerShell Script'
env:
TOKEN: $(token)

How to get the unit test results in variables in Azure DevOps Pipelines?

I have a build pipeline in Azure DevOps and I'm using the .NET Core task for applying unit testing.
I need to get the result of the unit tests in variables. For example, if there are 10 tests cases and two failed, I need to get something like:
failedTestCases = 2
succeededTestCases = 8
This is because I need those values in the next tasks. Is there a way to do that?
To be clear, I don't need to publish the results, they are already being published, I need to get those values in execution time.
Yes, this is possible but in my opinion you need to use REST API. Below you will find part of build definition. There are three steps:
test app
get test details
display test details
For you very important part is to figure out which log id you have for your test. Bascially if your test task is on 5th position on this list (including Initialize job):
You need to add 3 and you have your logId. In my case this is 8.
variables:
devopsAccount : 'thecodemanual'
projectName : 'DevOps Manual'
logId: "8"
- task: DotNetCoreCLI#2
displayName: Test
inputs:
command: test
projects: 'dotnet-core-on-windows/*Tests/*.csproj'
arguments: '--configuration $(buildConfiguration) --collect:"XPlat Code Coverage" -- RunConfiguration.DisableAppDomain=true'
workingDirectory: $(rootDirectory)
- task: PowerShell#2
condition: always()
name: testDetails
inputs:
targetType: 'inline'
script: |
# Encode the Personal Access Token (PAT)
$AzureDevOpsAuthenicationHeader = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$(System.AccessToken)")) }
# Get a list of releases
$uri = "https://dev.azure.com/$(devopsAccount)/$(projectName)/_apis/build/builds/$(Build.BuildId)/logs/$(logId)?api-version=5.1"
Write-Host $uri
# Invoke the REST call
$result = Invoke-RestMethod -Uri $uri -Method Get -Headers $AzureDevOpsAuthenicationHeader
Write-Host $result
$lines = $result.Split([Environment]::NewLine)
$passed = 0;
$failed = 0;
foreach($line in $lines) {
if ($line -match "Passed:.(\d+)") {
$passed = $matches[1]
}
if ($line -match "Failed:.(\d+)") {
$failed = $matches[1]
}
}
echo $passed
echo $failed
Write-Host "##vso[task.setvariable variable=passed]$passed"
Write-Host "##vso[task.setvariable variable=failed]$failed"
- script: |
echo $(passed)
echo $(failed)
condition: always()
And for this I got:
So it means we have number of passed and failed tests in variables ready to use.

Resources