Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AzureRMWebAppTask migrated to nodejs (#2506)
* Migrating from Powershell to Node.js * Made Change to Friendly Name * Additional Changes * Additional Changes * Made changes to RMUtil * Made change to Rest Call * Added Q * Added Q Library * Rearranged module headers * Made changes to task.json * Redefining error message * Removing PS Files * MSDEPloyexePath Function added * MSDEPloyexePath Function added * Changed then with await, package.json updated * Removing .taskkey * Run MSDeploycommand function updated * Async await changes * Handling files with spaces * CheckFile Function added * Fix for task not failing in case of error * Fixed review comments * Destination output url Fix * Publishing profile Fix * SetParamFile find Fix * SetParam File Fix * File supplied Fix * Fixing few formatting issues * Users/ajya/node js folder support to task (#2328) * Removing PS Fies * Added support for folder and optinal parameters.xml in package * Changes after conflicts * Indentation changes * correction * Indentation correction * Corrected review comments * PR Review Fix (MSDeploy return code Fix) * Added WebDeploy Function * Added Comments at Method Level * AzureRMUtil Update Deployment History Fix * Fixing Formatting issues * Destination URL Fix * common part moved to main * Deployment of webapplication using KUDU service * Indentation correction of deferred statement * added messages that will be help for debugging. * Adding unit test for AzureRMWebAppDeployment Task (#2386) * Adding unit test for AzureRMWebAppDeployment Task * Made changes according to PR comments * Made changes according to PR comments * Azure RM Upgrade scenario handling in task * Review comment fixes * Changed Request to HttpClient * Changes Reqyest to HttpClient * Changed Error to defer(reject) * Changed tl to defer(resolve) * SetParamFile issue fix * msDepoyBatchFIle Path FIx * Conditional selection of deployment tool and check for param file on … (#2451) * Conditional selection of deployment tool and check for param file on linux plat * PR review correction and few fixes for linux agent. * check of Parameter.xml * Added unit test (#2444) * Task upgrade fix for not reading right inputs * Reverting compact changes handling in UI * Path Issue & Bug Bash Fix (#2512) * Path with '&' issue Fix * Using Local MSDeploy Fix * Resource File Updated * L0 Tests Updated (Ashish) * Gulp Test Fix * TypoError Fix * enabling appoffline feature by default (#2555) * Parameter Content Fix (#2557) * Help mark down corrected
- Loading branch information
Ajay Kumar Yadav
committed
Sep 19, 2016
1 parent
6b049da
commit 7b4575c
Showing
31 changed files
with
2,181 additions
and
1,419 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
/// <reference path="../../definitions/node.d.ts" /> | ||
/// <reference path="../../definitions/q.d.ts" /> | ||
/// <reference path="../../definitions/vsts-task-lib.d.ts" /> | ||
/// <reference path="../../definitions/vso-node-api.d.ts" /> | ||
|
||
var adal = require ('adal-node'); | ||
var parseString = require('xml2js').parseString; | ||
|
||
import tl = require('vsts-task-lib/task'); | ||
import Q = require('q'); | ||
import httpClient = require('vso-node-api/HttpClient'); | ||
import restClient = require('vso-node-api/RestClient'); | ||
|
||
var httpObj = new httpClient.HttpClient(tl.getVariable("AZURE_HTTP_USER_AGENT")); | ||
var restObj = new restClient.RestClient(httpObj); | ||
|
||
var AuthenticationContext = adal.AuthenticationContext; | ||
var authUrl = 'https://login.windows.net/'; | ||
var armUrl = 'https://management.azure.com/'; | ||
var azureApiVersion = 'api-version=2015-08-01'; | ||
|
||
/** | ||
* updates the deployment status in kudu service | ||
* | ||
* @param publishingProfile Publish Profile details | ||
* @param isDeploymentSuccess Status of Deployment | ||
* | ||
* @returns promise with string | ||
*/ | ||
export function updateDeploymentStatus(publishingProfile, isDeploymentSuccess: boolean): Q.Promise<string> { | ||
var deferred = Q.defer<string>(); | ||
|
||
var webAppPublishKuduUrl = publishingProfile.publishUrl; | ||
if(webAppPublishKuduUrl) { | ||
var requestDetails = getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); | ||
var accessToken = 'Basic ' + (new Buffer(publishingProfile.userName + ':' + publishingProfile.userPWD).toString('base64')); | ||
var headers = { | ||
authorization: accessToken | ||
}; | ||
|
||
restObj.replace(requestDetails['requestUrl'], null, requestDetails['requestBody'], headers, null, | ||
(error, response, body) => { | ||
if(error) { | ||
deferred.reject(error); | ||
} | ||
else if(response === 200) { | ||
deferred.resolve(tl.loc("Successfullyupdateddeploymenthistory", body.url)); | ||
} | ||
else { | ||
tl.warning(body); | ||
deferred.reject(tl.loc("Failedtoupdatedeploymenthistory")); | ||
} | ||
}); | ||
} | ||
else { | ||
deferred.reject(tl.loc('WARNINGCannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite')); | ||
} | ||
|
||
return deferred.promise; | ||
} | ||
|
||
/** | ||
* Gets the Azure RM Web App Connections details from SPN | ||
* | ||
* @param SPN Service Principal Name | ||
* @param webAppName Name of the web App | ||
* @param resourceGroupName Resource Group Name | ||
* @param deployToSlotFlag Flag to check slot deployment | ||
* @param slotName Name of the slot | ||
* | ||
* @returns (JSON) | ||
*/ | ||
export async function getAzureRMWebAppPublishProfile(SPN, webAppName: string, resourceGroupName: string, deployToSlotFlag: boolean, slotName: string) { | ||
if(!deployToSlotFlag) { | ||
var webAppID = await getAzureRMWebAppID(SPN, webAppName, 'Microsoft.Web/Sites'); | ||
// webAppID Format ==> /subscriptions/<subscriptionId>/resourceGroups/<resource_grp_name>/providers/Microsoft.Web/sites/<webAppName> | ||
resourceGroupName = webAppID.id.split ('/')[4]; | ||
} | ||
var publishProfile = await getWebAppPublishProfile(SPN, webAppName, resourceGroupName, deployToSlotFlag, slotName); | ||
return publishProfile; | ||
} | ||
|
||
function getAuthorizationToken(SPN): Q.Promise<string> { | ||
|
||
var deferred = Q.defer<string>(); | ||
var authorityUrl = authUrl + SPN.tenantID; | ||
|
||
var context = new AuthenticationContext(authorityUrl); | ||
context.acquireTokenWithClientCredentials(armUrl, SPN.servicePrincipalClientID, SPN.servicePrincipalKey, (error, tokenResponse) => { | ||
if(error) { | ||
deferred.reject(error); | ||
} | ||
else { | ||
deferred.resolve(tokenResponse.accessToken); | ||
} | ||
}); | ||
|
||
return deferred.promise; | ||
} | ||
|
||
function getDeploymentAuthor(): string { | ||
var author = tl.getVariable('build.sourceVersionAuthor'); | ||
|
||
if(author === undefined) { | ||
author = tl.getVariable('build.requestedfor'); | ||
} | ||
|
||
if(author === undefined) { | ||
author = tl.getVariable('release.requestedfor'); | ||
} | ||
|
||
if(author === undefined) { | ||
author = tl.getVariable('agent.name'); | ||
} | ||
|
||
return author; | ||
} | ||
|
||
function getUpdateHistoryRequest(webAppPublishKuduUrl: string, isDeploymentSuccess: boolean): any { | ||
|
||
var status = isDeploymentSuccess ? 4 : 3; | ||
var status_text = (status == 4) ? "success" : "failed"; | ||
var author = getDeploymentAuthor(); | ||
|
||
var buildUrl = tl.getVariable('build.buildUri'); | ||
var releaseUrl = tl.getVariable('release.releaseUri'); | ||
|
||
var buildId = tl.getVariable('build.buildId'); | ||
var releaseId = tl.getVariable('release.releaseId'); | ||
|
||
var collectionUrl = tl.getVariable('system.TeamFoundationCollectionUri'); | ||
var teamProject = tl.getVariable('system.teamProject'); | ||
|
||
var buildOrReleaseUrl = "" ; | ||
var deploymentId = ""; | ||
|
||
if(releaseUrl !== undefined) { | ||
deploymentId = releaseId + Date.now(); | ||
buildOrReleaseUrl = collectionUrl + teamProject + "/_apps/hub/ms.vss-releaseManagement-web.hub-explorer?releaseId=" + releaseId + "&_a=release-summary"; | ||
} | ||
else if(buildUrl !== undefined) { | ||
deploymentId = buildId + Date.now(); | ||
buildOrReleaseUrl = collectionUrl + teamProject + "/_build?buildId=" + buildId + "&_a=summary"; | ||
} | ||
else { | ||
throw new Error(tl.loc('CannotupdatedeploymentstatusuniquedeploymentIdCannotBeRetrieved')); | ||
} | ||
|
||
var message = "Updating Deployment History For Deployment " + buildOrReleaseUrl; | ||
var requestBody = { | ||
status : status, | ||
status_text : status_text, | ||
message : message, | ||
author : author, | ||
deployer : 'VSTS', | ||
details : buildOrReleaseUrl | ||
}; | ||
|
||
var webAppHostUrl = webAppPublishKuduUrl.split(':')[0]; | ||
var requestUrl = "https://" + encodeURIComponent(webAppHostUrl) + "/deployments/" + encodeURIComponent(deploymentId); | ||
|
||
var requestDetails = new Array<string>(); | ||
requestDetails["requestBody"] = requestBody; | ||
requestDetails["requestUrl"] = requestUrl; | ||
return requestDetails; | ||
} | ||
|
||
async function getWebAppPublishProfile(SPN, webAppName: string, resourceGroupName: string, deployToSlotFlag: boolean, slotName: string ) { | ||
|
||
var deferred = Q.defer(); | ||
var slotUrl = deployToSlotFlag ? "/slots/" + slotName : ""; | ||
var accessToken = await getAuthorizationToken(SPN); | ||
|
||
var url = armUrl + 'subscriptions/' + SPN.subscriptionId + '/resourceGroups/' + resourceGroupName + | ||
'/providers/Microsoft.Web/sites/' + webAppName + slotUrl + '/publishxml?' + azureApiVersion; | ||
var headers = { | ||
authorization: 'Bearer '+ accessToken | ||
|
||
}; | ||
|
||
httpObj.get('POST', url, headers, (error, response, body) => { | ||
if(error) { | ||
deferred.reject(error); | ||
} | ||
else if(response.statusCode === 200) { | ||
parseString(body, (error, result) => { | ||
for (var index in result.publishData.publishProfile) { | ||
if (result.publishData.publishProfile[index].$.publishMethod === "MSDeploy") | ||
deferred.resolve(result.publishData.publishProfile[index].$); | ||
} | ||
deferred.reject(tl.loc('ErrorNoSuchDeployingMethodExists')); | ||
}); | ||
} | ||
else { | ||
tl.error(response.statusMessage); | ||
deferred.reject(tl.loc('UnabletoretrieveconnectiondetailsforazureRMWebApp0StatusCode1', webAppName, response.statusCode)); | ||
} | ||
}); | ||
|
||
return deferred.promise; | ||
} | ||
|
||
async function getAzureRMWebAppID(SPN, webAppName: string, resourceType: string) { | ||
|
||
var deferred = Q.defer<any>(); | ||
var accessToken = await getAuthorizationToken(SPN); | ||
|
||
var url = armUrl + 'subscriptions/' + SPN.subscriptionId + '/resources?$filter=resourceType EQ \'' + resourceType + | ||
'\' AND name EQ \'' + webAppName + '\'&api-version=2016-07-01'; | ||
var headers = { | ||
authorization: 'Bearer '+ accessToken | ||
}; | ||
|
||
httpObj.get('GET', url, headers, (error, response, body) => { | ||
if(error) { | ||
deferred.reject(error); | ||
} | ||
else if(response.statusCode === 200) { | ||
var webAppIDDetails = JSON.parse(body); | ||
deferred.resolve(webAppIDDetails.value[0]); | ||
} | ||
else { | ||
tl.error(response.statusMessage); | ||
deferred.reject(tl.loc('UnabletoretrieveWebAppIDforazureRMWebApp0StatusCode1', webAppName, response.statusCode)); | ||
} | ||
}); | ||
|
||
return deferred.promise; | ||
} | ||
|
||
/** | ||
* REST request for azure webapp config details. Config details contains virtual application mappings. | ||
* | ||
* @param SPN Subscription details | ||
* @param webAppName Web application name | ||
* @param deployToSlotFlag Should deploy to slot | ||
* @param slotName Slot for deployment | ||
*/ | ||
export async function getAzureRMWebAppConfigDetails(SPN, webAppName: string, resourceGroupName: string, deployToSlotFlag: boolean, slotName: string) { | ||
|
||
if(!deployToSlotFlag) { | ||
var webAppID = await getAzureRMWebAppID(SPN, webAppName, 'Microsoft.Web/Sites'); | ||
resourceGroupName = webAppID.id.split ('/')[4]; | ||
} | ||
|
||
var deferred = Q.defer<any>(); | ||
var accessToken = await getAuthorizationToken(SPN); | ||
var headers = { | ||
authorization: 'Bearer '+ accessToken | ||
}; | ||
|
||
var slotUrl = deployToSlotFlag ? "/slots/" + slotName : ""; | ||
var configUrl = armUrl + 'subscriptions/' + SPN.subscriptionId + '/resourceGroups/' + resourceGroupName + | ||
'/providers/Microsoft.Web/sites/' + webAppName + slotUrl + '/config/web?' + azureApiVersion; | ||
tl.debug(tl.loc("Requestingconfigdetails", configUrl)); | ||
|
||
httpObj.get('GET', configUrl, headers, (error, response, body) => { | ||
if( error ) { | ||
deferred.reject(error); | ||
} | ||
else if(response.statusCode === 200) { | ||
var obj = JSON.parse(body); | ||
deferred.resolve(obj); | ||
} | ||
else { | ||
tl.error(response.statusMessage); | ||
deferred.reject(tl.loc('ErrorOccurredStausCode0',response.statusCode)); | ||
} | ||
}); | ||
|
||
return deferred.promise; | ||
} |
Oops, something went wrong.