Skip to content

Commit f5be964

Browse files
akurmiHovsep
authored andcommitted
PowerShell cmdlets for swapping web app slots (Azure#2529)
* PowerShell cmdlets for swapping web app slots * Replacing 'Start-Sleep' with 'Wait-Seconds'
1 parent 6095e51 commit f5be964

File tree

15 files changed

+3304
-4
lines changed

15 files changed

+3304
-4
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
* Name, the name of the data source
2222
* IsDefault, set to true if this is the default data source for the account
2323
* Get-AzureRMDataLakeAnalyticsJob fixed for list for certain date time offset values when filtering on submittedBefore and submittedAfter.
24+
* Web Apps
25+
* Add Swap-AzureRmWebAppSlot cmdlet for regular swap and swap with preview
26+
* Extend Set-AzureRmWebAppSlot cmdlet to support auto swap
2427
##2016.06.23 version 1.5.1
2528
* Azure Resource Manager
2629
- Fix a bug in New-AzureRmResourceGroupDeployment. In some deployments the cmdlet throws an exception with "Deployment 'deploymentName' could not be found." and causes the cmdlet to fail. The fix makes sure the deployment is created before getting operations.

src/ResourceManager/Websites/Commands.Websites.Test/Commands.Websites.Test.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,18 @@
258258
<None Include="SessionRecords\Microsoft.Azure.Commands.Websites.Test.ScenarioTests.WebAppSlotTests\TestStartStopRestartWebAppSlot.json">
259259
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
260260
</None>
261+
<None Include="SessionRecords\Microsoft.Azure.Commands.Websites.Test.ScenarioTests.WebAppSlotTests\TestWebAppRegularSlotSwap.json">
262+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
263+
</None>
261264
<None Include="SessionRecords\Microsoft.Azure.Commands.Websites.Test.ScenarioTests.WebAppSlotTests\TestWebAppSlotPublishingProfile.json">
262265
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
263266
</None>
267+
<None Include="SessionRecords\Microsoft.Azure.Commands.Websites.Test.ScenarioTests.WebAppSlotTests\TestWebAppSwapWithPreviewCompleteSlotSwap.json">
268+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
269+
</None>
270+
<None Include="SessionRecords\Microsoft.Azure.Commands.Websites.Test.ScenarioTests.WebAppSlotTests\TestWebAppSwapWithPreviewResetSlotSwap.json">
271+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
272+
</None>
264273
<None Include="SessionRecords\Microsoft.Azure.Commands.Websites.Test.ScenarioTests.WebAppTests\TestCloneNewWebApp.json">
265274
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
266275
</None>

src/ResourceManager/Websites/Commands.Websites.Test/ScenarioTests/WebAppSlotTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,26 @@ public void TestManageSlotSlotConfigName()
9797
{
9898
WebsitesController.NewInstance.RunPsTest("Test-ManageSlotSlotConfigName");
9999
}
100+
101+
[Fact]
102+
[Trait(Category.AcceptanceType, Category.CheckIn)]
103+
public void TestWebAppRegularSlotSwap()
104+
{
105+
WebsitesController.NewInstance.RunPsTest("Test-WebAppRegularSlotSwap");
106+
}
107+
108+
[Fact]
109+
[Trait(Category.AcceptanceType, Category.CheckIn)]
110+
public void TestWebAppSwapWithPreviewResetSlotSwap()
111+
{
112+
WebsitesController.NewInstance.RunPsTest("Test-WebAppSwapWithPreviewResetSlotSwap");
113+
}
114+
115+
[Fact]
116+
[Trait(Category.AcceptanceType, Category.CheckIn)]
117+
public void TestWebAppSwapWithPreviewCompleteSlotSwap()
118+
{
119+
WebsitesController.NewInstance.RunPsTest("Test-WebAppSwapWithPreviewCompleteSlotSwap");
120+
}
100121
}
101122
}

src/ResourceManager/Websites/Commands.Websites.Test/ScenarioTests/WebAppSlotTests.ps1

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,3 +749,81 @@ function Test-ManageSlotSlotConfigName
749749
Assert-AreEqual 0 $slotConfigNames.AppSettingNames.Count
750750
Assert-AreEqual 0 $slotConfigNames.ConnectionStringNames.Count
751751
}
752+
753+
754+
<#
755+
.SYNOPSIS
756+
Tests regular web app slot swap
757+
#>
758+
function Test-WebAppRegularSlotSwap
759+
{
760+
$rgname = "Default-Web-EastAsia"
761+
$appname = "webappslottest"
762+
$sourceSlotName = "staging"
763+
$destinationSlotName = "production"
764+
765+
# Swap Web App slots
766+
$webApp = Swap-AzureRmWebAppSlot -ResourceGroupName $rgname -Name $appname -SourceSlotName $sourceSlotName -DestinationSlotName $destinationSlotName
767+
}
768+
769+
<#
770+
.SYNOPSIS
771+
Tests web app slot swap with preview: apply slot config followed by reset slot swap
772+
#>
773+
function Test-WebAppSwapWithPreviewResetSlotSwap
774+
{
775+
Test-SlotSwapWithPreview 'ResetSlotSwap'
776+
}
777+
778+
<#
779+
.SYNOPSIS
780+
Tests web app slot swap with preview: apply slot config followed by complete slot swap
781+
#>
782+
function Test-WebAppSwapWithPreviewCompleteSlotSwap
783+
{
784+
Test-SlotSwapWithPreview 'CompleteSlotSwap'
785+
}
786+
787+
<#
788+
.SYNOPSIS
789+
Test slot swap with preview feature
790+
#>
791+
function Test-SlotSwapWithPreview($swapWithPreviewAction)
792+
{
793+
$rgname = "Default-Web-EastAsia"
794+
$appname = "webappslottest"
795+
$sourceSlotName = "staging"
796+
$destinationSlotName = "production"
797+
$appSettingName = 'testappsetting'
798+
$originalSourceAppSettingValue = "staging"
799+
$originalDestinationAppSettingValue = "production"
800+
801+
# Let's retrieve slot configs and make sure that it contains initial values as expected
802+
$destinationWebApp = Get-AzureRmWebApp -ResourceGroupName $rgname -Name $appname
803+
Validate-SlotSwapAppSetting $destinationWebApp $appSettingName $originalDestinationAppSettingValue
804+
805+
$sourceWebApp = Get-AzureRmWebAppSlot -ResourceGroupName $rgname -Name $appname -Slot $sourceSlotName
806+
Validate-SlotSwapAppSetting $sourceWebApp $appSettingName $originalSourceAppSettingValue
807+
808+
# Let's apply slot config and make sure that app setting values have been swapped
809+
Swap-AzureRmWebAppSlot -ResourceGroupName $rgname -Name $appname -SourceSlotName $sourceSlotName -DestinationSlotName $destinationSlotName -SwapWithPreviewAction 'ApplySlotConfig'
810+
Wait-Seconds 30
811+
$sourceWebApp = Get-AzureRmWebAppSlot -ResourceGroupName $rgname -Name $appname -Slot $sourceSlotName
812+
Validate-SlotSwapAppSetting $sourceWebApp $appSettingName $originalDestinationAppSettingValue
813+
814+
# Let's finish the current slot swap operation (complete or reset)
815+
Swap-AzureRmWebAppSlot -ResourceGroupName $rgname -Name $appname -SourceSlotName $sourceSlotName -DestinationSlotName $destinationSlotName -SwapWithPreviewAction $swapWithPreviewAction
816+
Wait-Seconds 30
817+
$sourceWebApp = Get-AzureRmWebAppSlot -ResourceGroupName $rgname -Name $appname -Slot $sourceSlotName
818+
Validate-SlotSwapAppSetting $sourceWebApp $appSettingName $originalSourceAppSettingValue
819+
}
820+
821+
<#
822+
.SYNOPSIS
823+
Validates slot app setting for slot swap tests
824+
#>
825+
function Validate-SlotSwapAppSetting($webApp, $appSettingName, $expectedValue)
826+
{
827+
Assert-AreEqual $webApp.SiteConfig.AppSettings[0].Name $appSettingName
828+
Assert-AreEqual $webApp.SiteConfig.AppSettings[0].Value $expectedValue
829+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
{
2+
"Entries": [
3+
{
4+
"RequestUri": "/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/resourceGroups/Default-Web-EastAsia/providers/Microsoft.Web/sites/webappslottest/slots/staging/slotsswap?api-version=2015-08-01",
5+
"EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvZmIyYzI1ZGMtNmJhYi00NWM0LThjYzktY2VjZTdjNDJhOTVhL3Jlc291cmNlR3JvdXBzL0RlZmF1bHQtV2ViLUVhc3RBc2lhL3Byb3ZpZGVycy9NaWNyb3NvZnQuV2ViL3NpdGVzL3dlYmFwcHNsb3R0ZXN0L3Nsb3RzL3N0YWdpbmcvc2xvdHNzd2FwP2FwaS12ZXJzaW9uPTIwMTUtMDgtMDE=",
6+
"RequestMethod": "POST",
7+
"RequestBody": "{\r\n \"targetSlot\": \"production\"\r\n}",
8+
"RequestHeaders": {
9+
"Content-Type": [
10+
"application/json; charset=utf-8"
11+
],
12+
"Content-Length": [
13+
"34"
14+
],
15+
"x-ms-client-request-id": [
16+
"5e32b648-58ac-4609-8a9b-737d685fba2a"
17+
],
18+
"accept-language": [
19+
"en-US"
20+
],
21+
"User-Agent": [
22+
"Microsoft.Azure.Management.WebSites.WebSiteManagementClient/1.0.0.2"
23+
],
24+
"Accept": [
25+
"application/json"
26+
]
27+
},
28+
"ResponseBody": "",
29+
"ResponseHeaders": {
30+
"Content-Length": [
31+
"0"
32+
],
33+
"Expires": [
34+
"-1"
35+
],
36+
"Pragma": [
37+
"no-cache"
38+
],
39+
"Retry-After": [
40+
"15"
41+
],
42+
"Strict-Transport-Security": [
43+
"max-age=31536000; includeSubDomains"
44+
],
45+
"x-ms-ratelimit-remaining-subscription-writes": [
46+
"1199"
47+
],
48+
"x-ms-request-id": [
49+
"cb7e943b-964f-4623-8ada-7d445995c9d0"
50+
],
51+
"x-ms-correlation-request-id": [
52+
"cb7e943b-964f-4623-8ada-7d445995c9d0"
53+
],
54+
"x-ms-routing-request-id": [
55+
"WESTUS:20160622T010800Z:cb7e943b-964f-4623-8ada-7d445995c9d0"
56+
],
57+
"Cache-Control": [
58+
"no-cache"
59+
],
60+
"Date": [
61+
"Wed, 22 Jun 2016 01:08:00 GMT"
62+
],
63+
"ETag": [
64+
"\"1D1CC1143EBEB20\""
65+
],
66+
"Location": [
67+
"https://management.azure.com/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/resourceGroups/Default-Web-EastAsia/providers/Microsoft.Web/sites/webappslottest/slots/staging/operationresults/7df37e6b-4fac-4964-917b-09de6bb62d6b?api-version=2015-08-01"
68+
],
69+
"Server": [
70+
"Microsoft-IIS/8.0"
71+
],
72+
"X-AspNet-Version": [
73+
"4.0.30319"
74+
],
75+
"X-Powered-By": [
76+
"ASP.NET"
77+
]
78+
},
79+
"StatusCode": 202
80+
},
81+
{
82+
"RequestUri": "/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/resourceGroups/Default-Web-EastAsia/providers/Microsoft.Web/sites/webappslottest/slots/staging/operationresults/7df37e6b-4fac-4964-917b-09de6bb62d6b?api-version=2015-08-01",
83+
"EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvZmIyYzI1ZGMtNmJhYi00NWM0LThjYzktY2VjZTdjNDJhOTVhL3Jlc291cmNlR3JvdXBzL0RlZmF1bHQtV2ViLUVhc3RBc2lhL3Byb3ZpZGVycy9NaWNyb3NvZnQuV2ViL3NpdGVzL3dlYmFwcHNsb3R0ZXN0L3Nsb3RzL3N0YWdpbmcvb3BlcmF0aW9ucmVzdWx0cy83ZGYzN2U2Yi00ZmFjLTQ5NjQtOTE3Yi0wOWRlNmJiNjJkNmI/YXBpLXZlcnNpb249MjAxNS0wOC0wMQ==",
84+
"RequestMethod": "GET",
85+
"RequestBody": "",
86+
"RequestHeaders": {
87+
"User-Agent": [
88+
"Microsoft.Azure.Management.WebSites.WebSiteManagementClient/1.0.0.2"
89+
],
90+
"Accept": [
91+
"application/json"
92+
]
93+
},
94+
"ResponseBody": "",
95+
"ResponseHeaders": {
96+
"Content-Length": [
97+
"0"
98+
],
99+
"Expires": [
100+
"-1"
101+
],
102+
"Pragma": [
103+
"no-cache"
104+
],
105+
"Retry-After": [
106+
"15"
107+
],
108+
"Strict-Transport-Security": [
109+
"max-age=31536000; includeSubDomains"
110+
],
111+
"x-ms-ratelimit-remaining-subscription-reads": [
112+
"14930"
113+
],
114+
"x-ms-request-id": [
115+
"b5e1e34f-8899-4b32-9fa0-d04240f7c747"
116+
],
117+
"x-ms-correlation-request-id": [
118+
"b5e1e34f-8899-4b32-9fa0-d04240f7c747"
119+
],
120+
"x-ms-routing-request-id": [
121+
"WESTUS:20160622T010830Z:b5e1e34f-8899-4b32-9fa0-d04240f7c747"
122+
],
123+
"Cache-Control": [
124+
"no-cache"
125+
],
126+
"Date": [
127+
"Wed, 22 Jun 2016 01:08:30 GMT"
128+
],
129+
"Location": [
130+
"https://management.azure.com/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/resourceGroups/Default-Web-EastAsia/providers/Microsoft.Web/sites/webappslottest/slots/staging/operationresults/7df37e6b-4fac-4964-917b-09de6bb62d6b?api-version=2015-08-01"
131+
],
132+
"Server": [
133+
"Microsoft-IIS/8.0"
134+
],
135+
"X-AspNet-Version": [
136+
"4.0.30319"
137+
],
138+
"X-Powered-By": [
139+
"ASP.NET"
140+
]
141+
},
142+
"StatusCode": 202
143+
},
144+
{
145+
"RequestUri": "/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/resourceGroups/Default-Web-EastAsia/providers/Microsoft.Web/sites/webappslottest/slots/staging/operationresults/7df37e6b-4fac-4964-917b-09de6bb62d6b?api-version=2015-08-01",
146+
"EncodedRequestUri": "L3N1YnNjcmlwdGlvbnMvZmIyYzI1ZGMtNmJhYi00NWM0LThjYzktY2VjZTdjNDJhOTVhL3Jlc291cmNlR3JvdXBzL0RlZmF1bHQtV2ViLUVhc3RBc2lhL3Byb3ZpZGVycy9NaWNyb3NvZnQuV2ViL3NpdGVzL3dlYmFwcHNsb3R0ZXN0L3Nsb3RzL3N0YWdpbmcvb3BlcmF0aW9ucmVzdWx0cy83ZGYzN2U2Yi00ZmFjLTQ5NjQtOTE3Yi0wOWRlNmJiNjJkNmI/YXBpLXZlcnNpb249MjAxNS0wOC0wMQ==",
147+
"RequestMethod": "GET",
148+
"RequestBody": "",
149+
"RequestHeaders": {
150+
"User-Agent": [
151+
"Microsoft.Azure.Management.WebSites.WebSiteManagementClient/1.0.0.2"
152+
],
153+
"Accept": [
154+
"application/json"
155+
]
156+
},
157+
"ResponseBody": "{\r\n \"id\": \"/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/resourceGroups/Default-Web-EastAsia/providers/Microsoft.Web/sites/webappslottest/slots/staging\",\r\n \"name\": \"webappslottest/staging\",\r\n \"type\": \"Microsoft.Web/sites/slots\",\r\n \"location\": \"East Asia\",\r\n \"tags\": null,\r\n \"properties\": {\r\n \"name\": \"webappslottest(staging)\",\r\n \"state\": \"Running\",\r\n \"hostNames\": [\r\n \"webappslottest-staging.azurewebsites.net\"\r\n ],\r\n \"webSpace\": \"eastasiawebspace\",\r\n \"selfLink\": \"https://waws-prod-hk1-001.api.azurewebsites.windows.net:454/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/webspaces/eastasiawebspace/sites/webappslottest\",\r\n \"repositorySiteName\": \"webappslottest\",\r\n \"owner\": null,\r\n \"usageState\": 0,\r\n \"enabled\": true,\r\n \"adminEnabled\": true,\r\n \"enabledHostNames\": [\r\n \"webappslottest-staging.azurewebsites.net\",\r\n \"webappslottest-staging.scm.azurewebsites.net\"\r\n ],\r\n \"siteProperties\": {\r\n \"metadata\": null,\r\n \"properties\": [],\r\n \"appSettings\": null\r\n },\r\n \"availabilityState\": 0,\r\n \"sslCertificates\": null,\r\n \"csrs\": [],\r\n \"cers\": null,\r\n \"siteMode\": null,\r\n \"hostNameSslStates\": [\r\n {\r\n \"name\": \"webappslottest-staging.azurewebsites.net\",\r\n \"sslState\": 0,\r\n \"ipBasedSslResult\": null,\r\n \"virtualIP\": null,\r\n \"thumbprint\": null,\r\n \"toUpdate\": null,\r\n \"toUpdateIpBasedSsl\": null,\r\n \"ipBasedSslState\": 0,\r\n \"hostType\": 0\r\n },\r\n {\r\n \"name\": \"webappslottest-staging.scm.azurewebsites.net\",\r\n \"sslState\": 0,\r\n \"ipBasedSslResult\": null,\r\n \"virtualIP\": null,\r\n \"thumbprint\": null,\r\n \"toUpdate\": null,\r\n \"toUpdateIpBasedSsl\": null,\r\n \"ipBasedSslState\": 0,\r\n \"hostType\": 1\r\n }\r\n ],\r\n \"computeMode\": null,\r\n \"serverFarm\": null,\r\n \"serverFarmId\": \"/subscriptions/fb2c25dc-6bab-45c4-8cc9-cece7c42a95a/resourceGroups/Default-Web-EastAsia/providers/Microsoft.Web/serverfarms/appservicecertificatedemoplan\",\r\n \"lastModifiedTimeUtc\": \"2016-06-22T01:08:50.45\",\r\n \"storageRecoveryDefaultState\": \"Running\",\r\n \"contentAvailabilityState\": 0,\r\n \"runtimeAvailabilityState\": 0,\r\n \"siteConfig\": null,\r\n \"deploymentId\": \"webappslottest__44d9\",\r\n \"trafficManagerHostNames\": null,\r\n \"sku\": \"Standard\",\r\n \"premiumAppDeployed\": null,\r\n \"scmSiteAlsoStopped\": false,\r\n \"targetSwapSlot\": null,\r\n \"hostingEnvironment\": null,\r\n \"hostingEnvironmentProfile\": null,\r\n \"microService\": \"WebSites\",\r\n \"gatewaySiteName\": null,\r\n \"clientAffinityEnabled\": true,\r\n \"clientCertEnabled\": false,\r\n \"hostNamesDisabled\": false,\r\n \"domainVerificationIdentifiers\": null,\r\n \"kind\": null,\r\n \"outboundIpAddresses\": \"65.52.168.77,65.52.168.81,65.52.168.84,65.52.160.98\",\r\n \"containerSize\": 0,\r\n \"maxNumberOfWorkers\": null,\r\n \"homeStamp\": \"waws-prod-hk1-001\",\r\n \"cloningInfo\": null,\r\n \"hostingEnvironmentId\": null,\r\n \"tags\": null,\r\n \"resourceGroup\": \"Default-Web-EastAsia\",\r\n \"defaultHostName\": \"webappslottest-staging.azurewebsites.net\"\r\n }\r\n}",
158+
"ResponseHeaders": {
159+
"Content-Length": [
160+
"2452"
161+
],
162+
"Content-Type": [
163+
"application/json"
164+
],
165+
"Expires": [
166+
"-1"
167+
],
168+
"Pragma": [
169+
"no-cache"
170+
],
171+
"Strict-Transport-Security": [
172+
"max-age=31536000; includeSubDomains"
173+
],
174+
"x-ms-request-id": [
175+
"c11929cd-cdda-4623-b9c4-5cb9eb7fec07"
176+
],
177+
"x-ms-ratelimit-remaining-subscription-reads": [
178+
"14929"
179+
],
180+
"x-ms-correlation-request-id": [
181+
"9b1dd934-bd65-41e1-8387-791c012df2e3"
182+
],
183+
"x-ms-routing-request-id": [
184+
"WESTUS:20160622T010901Z:9b1dd934-bd65-41e1-8387-791c012df2e3"
185+
],
186+
"Cache-Control": [
187+
"no-cache"
188+
],
189+
"Date": [
190+
"Wed, 22 Jun 2016 01:09:00 GMT"
191+
],
192+
"ETag": [
193+
"\"1D1CC22A2E7A720\""
194+
],
195+
"Server": [
196+
"Microsoft-IIS/8.0"
197+
],
198+
"X-AspNet-Version": [
199+
"4.0.30319"
200+
],
201+
"X-Powered-By": [
202+
"ASP.NET"
203+
]
204+
},
205+
"StatusCode": 200
206+
}
207+
],
208+
"Names": {},
209+
"Variables": {
210+
"SubscriptionId": "fb2c25dc-6bab-45c4-8cc9-cece7c42a95a"
211+
}
212+
}

0 commit comments

Comments
 (0)