Created
August 2, 2016 21:53
-
-
Save digitaldelirium/af098a2384ff29f48c04087105491576 to your computer and use it in GitHub Desktop.
Windows TFS Ansible Module
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
#!powershell | |
# | |
# | |
# Author: Ian Cornett | |
# Version: 0.1 | |
# Version History: | |
# | |
# Purpose: Queue TFS Build from Ansible and return workable JSON dictionary for polling | |
# | |
# | |
# WANT_JSON | |
# POWERSHELL_COMMON | |
[PSObject]$params = Parse-Args -arguments $args | |
[PSObject]$result = New-Object -TypeName PSObject -ArgumentList @{ | |
win_tfs_url = New-Object -TypeName PSObject | |
response = $null | |
changed = $false | |
log = $null | |
} | |
[Uri]$tfsUri = '' | |
#setup TFS Connection Properties | |
$url = Get-AnsibleParam -obj $params -name 'url' -failifempty $true | |
$skip_certificate_validation = Get-AnsibleParam -name 'skip_certificate_validation' -default $false | |
$skip_certificate_validation = $skip_certificate_validation | ConvertTo-Bool | |
# setup TFS build properties | |
$collectionName = Get-AnsibleParam -obj $params -name 'collection' -failifempty $false | |
$projectName = Get-AnsibleParam -obj $params -name 'project' -failifempty $true | |
$buildDef = Get-AnsibleParam -obj $params -name 'buildId' -failifempty $true | |
# setup authtentication if needed | |
$username = Get-AnsibleParam -obj $params -name 'username' -failifempty $false | |
$password = Get-AnsibleParam -obj $params -name 'password' -failifempty $false | |
# setup proxy if needed | |
$proxy_url = Get-AnsibleParam -obj $params -name 'proxy_url' -failifempty $false | |
$proxy_user = Get-AnsibleParam -obj $params -name 'proxy_user' -failifempty $false | |
$proxy_pass = Get-AnsibleParam -obj $params -name 'proxy_pass' -failifempty $false | |
if($skip_certificate_validation) | |
{ | |
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { | |
$true | |
} | |
} | |
[PSObject]$requestBody = @{ | |
definition = @{ | |
id = $buildDef | |
} | |
reason = 'Manual' | |
priority = 'Normal' | |
} | |
# Kick off TFS Build using REST | |
function Invoke-TfsBuild | |
{ | |
param | |
( | |
[Object] | |
[Parameter(Mandatory = $true)] | |
$url, | |
[Object] | |
[Parameter(Mandatory = $true)] | |
$projectName, | |
[Object] | |
[Parameter(Mandatory = $true)] | |
$result, | |
[Object] | |
[Parameter(Mandatory = $true)] | |
$requestBody, | |
[Object] | |
$username, | |
[Object] | |
$password, | |
[Object] | |
$collectionName, | |
[Object] | |
$proxy_url, | |
[Object] | |
$proxy_user, | |
[Object] | |
$proxy_pass | |
) | |
# Logging Passed Parameters | |
$results.log += "Entered Invoke-TfsBuild`r`n" | |
$results.log += "Passed Parameters:`nUrl:`t$($url.ToString())`nCollection:`t$($collectionName.ToString())`n Project:`t$($projectName.ToString())`n" | |
$results.log += "User:`t$($username.ToString())`nProxy Url:`t$($proxy_url.ToString())`nProxy User:`t$($proxy_user.ToString())`nRequest Params:`t$($requestBody.ToString())" | |
[Object]$proxyCreds = $null | |
[Object]$tfsCreds = $null | |
[Object]$response = $null | |
# Create HashTable variable to store request params | |
[hashtable]$requestParams = [ordered]@{ | |
Method = 'Post' | |
ContentType = 'application/json' | |
} | |
# If collectionName is null, set to DefaultCollection | |
if(-not $collectionName) | |
{ | |
$collectionName = 'DefaultCollection' | |
} | |
#Build up TFS URI | |
$tfsUri = "$($url.toString())/$($collectionName.ToString())/$($projectName.ToString())/_apis/build/builds?api-version=2.0" | |
$result.win_tfs_url = $tfsUri | |
# Set up request parameters to be passed to TFS | |
try | |
{ | |
# Content | |
$requestParams.Add('Uri', $tfsUri.ToString()) | |
# Check to see if we're using a proxy, if so set up any necessary creds. Do the same for user/pass for TFS | |
if ($proxy_url) | |
{ | |
$requestParams.Add('Proxy', $proxy_url) | |
if ($proxy_user -and $proxy_pass) | |
{ | |
# Cast password to Secure String | |
$sec_proxy_pass = $proxy_pass | ConvertTo-SecureString -AsPlainText -Force | |
# Instantiate proxyCreds | |
$proxyCreds = New-Object -TypeName PSCredential -ArgumentList ($proxy_user, $sec_proxy_pass) | |
$requestParams.Add('ProxyCredential', $proxyCreds) | |
} | |
} | |
if ($username -and $password) | |
{ | |
#Create secure string for creating PSCredential object | |
$sec_password = $password | ConvertTo-SecureString -Force -AsPlainText | |
$tfsCreds = New-Object -TypeName PSCredential -ArgumentList ($username, $sec_password) | |
$requestParams.Add('Credential', $tfsCreds) | |
} | |
else | |
{ | |
$requestParams.Add('UseDefaultCredential', $true) | |
} | |
$requestParams.Add('Body', $($requestBody | ConvertTo-Json)) | |
$result.Add('Args',$requestParams) | |
$result.log += "Build Request Parameters:`n$($requestParams.ToString())" | |
} | |
catch | |
{ | |
Fail-Json -obj $result -message "Error occurred while setting up request parameters! `r`nArgs: $($result.Args)" | |
} | |
# Attempt TFS Build | |
try | |
{ | |
$request.log += "Requesting Build...`r`n" | |
# Queue TFS Build | |
$result.response = Invoke-RestMethod @requestParams | |
$result.changed = $false | |
$result.log += "Build Successfully Submitted`n`r" | |
} | |
catch | |
{ | |
Fail-Json -obj $result -message "Error queueing build at: $($tfsUri.ToString()) `nUsing TFS Credential: $($username.ToString())" | |
} | |
} | |
# Monitor Build Progress | |
function Get-TfsBuildStatus | |
{ | |
param | |
( | |
[Object] | |
[Parameter(Mandatory = $true)] | |
$url, | |
[Object] | |
$username, | |
[Object] | |
$password, | |
[Object] | |
$collectionName, | |
[Object] | |
[Parameter(Mandatory = $true)] | |
$projectName, | |
[Object] | |
$proxy_url, | |
[Object] | |
$proxy_user, | |
[Object] | |
$proxy_pass, | |
[Object] | |
[Parameter(Mandatory = $true)] | |
$result | |
) | |
$results.log += "Entered Get-TfsBuildStatus`r`n" | |
$results.log += "Passed Parameters:`nUrl:`t$($url.ToString())`nCollection:`t$($collectionName.ToString())`n Project:`t$($projectName.ToString())`n" | |
$results.log += "User:`t$($username.ToString())`nProxy Url:`t$($proxy_url.ToString())`nProxy User:`t$($proxy_user.ToString())`nRequest Params:`t$($requestBody.ToString())" | |
#Create BuildId, BuildNumber, and ReleaseName hashtable for easy recall | |
[hashtable]$buildInfo = @{ | |
Id = $result.response.id | |
buildNumber = $result.response.buildNumber | |
releaseName = $result.response.definition.name | |
buildState = $null | |
buildResult = $null | |
} | |
# Build URI for Monitoring Build status and create buildStatus response object | |
[Uri]$buildUri = "$($url.toString())/$($collectionName.ToString())/$($projectName.ToString())/_apis/build/builds/$($buildId.ToString())/timeline?api-version=2.0" | |
[Object]$buildStatus = New-Object PSObject | |
# Create Hashtable for passing parameters as necessary | |
[Hashtable]$requestParams = @{} | |
$requestParams.Add('Method','Get') | |
$requestParams.Add('ContentType','application/json') | |
# If collectionName is null, set to DefaultCollection | |
if(-not $collectionName) | |
{ | |
$collectionName = 'DefaultCollection' | |
} | |
$requestParams.Add('Uri', $buildUri.ToString()) | |
# Check to see if we're using a proxy, if so set up any necessary creds. Do the same for user/pass for TFS | |
if ($proxy_url) | |
{ | |
$requestParams.Add('Proxy', $proxy_url) | |
if ($proxy_user -and $proxy_pass) | |
{ | |
# Cast password to Secure String | |
$sec_proxy_pass = $proxy_pass | ConvertTo-SecureString -AsPlainText -Force | |
# Instantiate proxyCreds | |
$proxyCreds = New-Object -TypeName PSCredential -ArgumentList ($proxy_user, $sec_proxy_pass) | |
$requestParams.Add('ProxyCredential', $proxyCreds) | |
} | |
} | |
if ($username -and $password) | |
{ | |
#Create secure string for creating PSCredential object | |
$sec_password = $password | ConvertTo-SecureString -Force -AsPlainText | |
$tfsCreds = New-Object -TypeName PSCredential -ArgumentList ($username, $sec_password) | |
$requestParams.Add('Credential', $tfsCreds) | |
} | |
else | |
{ | |
$requestParams.Add('UseDefaultCredential', $true) | |
} | |
# Get Build Status with REST Call | |
try | |
{ | |
$buildStatus = Invoke-RestMethod @requestParams | |
# Loop through REST calls | |
while ($buildStatus.records.state -ne 'completed') | |
{ | |
# Call REST method until state is completed, Sleep 10 seconds between calls | |
Start-Sleep -Seconds 10 | |
$buildStatus = Invoke-RestMethod @requestParams | |
} | |
$buildInfo.buildResult = $buildStatus.records[0].result | |
$buildInfo.buildState = $buildStatus.records[0].state | |
} | |
catch | |
{ | |
$result.changed = $false | |
Fail-Json -obj $result -message "Error while trying to monitor build status $($_.Exception.Message) `r`n$($_.Exception.StackTrace)" | |
} | |
finally | |
{ | |
# Add Build Information to result, to allow for recall | |
$result.Add('build_info',$buildInfo) | |
if ($buildInfo.buildResult -eq 'succeeded') | |
{ | |
$result.changed = $true | |
} | |
else | |
{ | |
$result.changed = $false | |
# Iterate through results object looking for failed and details | |
$failedTask = $buildStatus.records | | |
Where-Object { | |
$_.result -ne 'succeeded' | |
} | | |
Select-Object -Property name, result, resultCode, details | |
Fail-Json -obj $result -message "TFS Build process failed! `nTask Name: $($failedTask.name) `nTask Result: $($failedTask.result) Result Code: $($failedTask.resultCode) `nDetails: $($failedTask.details)" | |
} | |
} | |
Exit-Json -obj $result | |
} | |
# Kick off the TFS Build and Monitor Progress | |
try | |
{ | |
# Load buildParams with required params for execution | |
[hashtable]$buildParams = @{ | |
url = $url | |
projectName = $projectName | |
result = $result | |
requestBody = $requestBody | |
} | |
# Build Request optional Params | |
# Proxy Support | |
if ($proxy_url) | |
{ | |
$buildParams.Add('proxy_url',$proxy_url) | |
if ($proxy_user -and $proxy_pass) | |
{ | |
$buildParams.Add('proxy_user',$proxy_user) | |
$buildParams.Add('proxy_pass',$proxy_pass) | |
} | |
} | |
if ($collectionName) | |
{ | |
$buildParams.Add('collectionName',$collectionName) | |
} | |
if ($username -and $password) | |
{ | |
$buildParams.Add('username',$username) | |
$buildParams.Add('password',$password) | |
} | |
# Kick off build | |
$results.log += "`tQueueing Build`v`r`n" | |
Invoke-TfsBuild @buildParams | |
$results.log += "Build Successfully Queued`n" | |
} | |
catch | |
{ | |
Fail-Json -obj $result -message "Error when attempting to invoke TFS build $($result.log.ToString()) `n$($_.Exception.Message)`r`n$($_.Exception.StackTrace)" | |
} | |
try | |
{ | |
# Get TFS Build Status | |
Get-TfsBuildStatus -url $url -collectionName $collectionName -projectName $projectName -username $username -password $password -result $result -proxy_url $proxy_url -proxy_user $proxy_user -proxy_pass $proxy_pass | |
} | |
catch | |
{ | |
Fail-Json -obj $result -message "Error trying to monitor build status! Last known build state: $($result.build_info.buildState)`r`n$($_.Exception.StackTrace)" | |
} | |
Exit-Json -obj $result |
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
#!/usr/bin/python | |
# -*- coding: utf-8 -*- | |
DOCUMENTATION = ''' | |
--- | |
module: win_tfsbuild | |
version_added: "0.1" | |
short_description: Queue TFS Build via REST | |
description: | |
- The M(win_tfsbuild) module queues a build for TFS or Visual Studio Online builds via POST to REST endpoint. | |
options: | |
url: | |
description: | |
- The root URI of the TFS/VSO instance. In case of connecting to Visual Studio Online, the CollectionName | |
variable needs to be left blank to use the DefaultCollection. eg: http://tfs.yourdomain.com:8080/tfs or | |
https://<youraccount>.visualstudio.com. | |
required: true | |
default: null | |
username: | |
description: | |
- If authentication is required, the username required to authenticate. | |
required: false | |
default: null | |
password: | |
description: | |
- If username is provided, the password required to authenticate. | |
required: false | |
default: null | |
collection: | |
description: | |
- If your TFS instance is an On Prem instance, you need to specify a Collection name that will be hosting your | |
project. In an enterprise situation, you may have multiple collections. | |
required: false | |
default: null | |
project: | |
description: | |
- Enter the name of your TFS/VSO project which you wish to build. | |
required: true | |
default: null | |
buildId: | |
description: | |
- The id number of the build definition that you're trying to invoke | |
required: true | |
default: null | |
proxy_url: | |
description: | |
- Proxy URL to connect to external path, if required. | |
required: false | |
default: null | |
proxy_user: | |
description: | |
- User name to authenticate to the proxy, if required. | |
required: false | |
default: null | |
proxy_pass: | |
description: | |
- Password required to authenticate to the proxy, if required. | |
required: false | |
default: null | |
skip_certificate_validation: | |
description: | |
- Boolean value to skip validating the certificate in cases of self-signed certificate. | |
required: false | |
default: false | |
author: "Ian Cornett (@iancornett)" | |
''' | |
EXAMPLES = ''' | |
# Queue a build | |
- win_tfsbuild: url=https://foo.visualstudio.com [email protected] password=myPassword project=MyProject buildId=123 | |
''' | |
RETURN = ''' | |
win_tfs_url: | |
description: | |
- The URI of the initial build request | |
returned: success | |
build_info: | |
description: | |
- The resulting information from the build request | |
response: | |
description: | |
- The response of the initial build request | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment