Skip to content

Commit c9fcb7e

Browse files
sredmanSimon Redmandingmeng-xue
authored
Fix Status and StatusMessage fields in Get-AzSqlDatabaseImportExportStatus to conform to documentation (#13751)
* Put the correct value into the StatusMessage field * Add parsing of the http return value to determine the operation status * Add ChangeLog.md entry * Re-add as much testing as possible and add commenting for why the rest is broken * Update ChangeLog.md Co-authored-by: Simon Redman <[email protected]> Co-authored-by: Dingmeng Xue <[email protected]>
1 parent 1115f68 commit c9fcb7e

File tree

5 files changed

+130
-52
lines changed

5 files changed

+130
-52
lines changed

src/Sql/Sql.Test/ScenarioTests/ImportExportTests.ps1

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
#>
2020
function Test-ExportDatabase
2121
{
22-
# Setup
22+
# Setup
2323
$testSuffix = 90070
2424
$createServer = $true
2525
$createDatabase = $true
2626
$createFirewallRule = $true
2727
$operationName = "Export"
2828
$succeeded = $true
2929
$useNetworkIsolation = $false
30-
30+
3131
Verify-ImportExport $testSuffix $createServer $createDatabase $createFirewallRule $operationName $succeeded $useNetworkIsolation
3232
}
3333

@@ -41,13 +41,13 @@ function Test-ExportDatabaseNetworkIsolation
4141
$operationName = "Export"
4242
$succeeded = $true
4343
$useNetworkIsolation = $true
44-
44+
4545
Verify-ImportExport $testSuffix $createServer $createDatabase $createFirewallRule $operationName $succeeded $useNetworkIsolation
4646
}
4747

4848
function Test-ImportNewDatabase
4949
{
50-
# Setup
50+
# Setup
5151
$testSuffix = 90071
5252
$createServer = $true
5353
$createDatabase = $false
@@ -56,7 +56,7 @@ function Test-ImportNewDatabase
5656
$succeeded = $true
5757
$useNetworkIsolation = $false
5858

59-
Verify-ImportExport $testSuffix $createServer $createDatabase $createFirewallRule $operationName $succeeded $useNetworkIsolation
59+
Verify-ImportExport $testSuffix $createServer $createDatabase $createFirewallRule $operationName $succeeded $useNetworkIsolation
6060
}
6161

6262
function Test-ImportNewDatabaseNetworkIsolation
@@ -70,39 +70,39 @@ function Test-ImportNewDatabaseNetworkIsolation
7070
$succeeded = $true
7171
$useNetworkIsolation = $true
7272

73-
Verify-ImportExport $testSuffix $createServer $createDatabase $createFirewallRule $operationName $succeeded $useNetworkIsolation
73+
Verify-ImportExport $testSuffix $createServer $createDatabase $createFirewallRule $operationName $succeeded $useNetworkIsolation
7474
}
7575

7676
function Verify-ImportExport($testSuffix, $createServer, $createDatabase, $createFirewallRule, $operationName, $succeeded, $useNetworkIsolation)
7777
{
78-
# Setup
78+
# Setup
7979
$params = Get-SqlDatabaseImportExportTestEnvironmentParameters $testSuffix
8080
$rg = New-AzResourceGroup -Name $params.rgname -Location $params.location
8181
$export = "Export"
8282
$importNew = "ImportNew"
8383

84-
try
85-
{
84+
try
85+
{
8686
Assert-NotNull $params.storageKey
8787
Assert-NotNull $params.importBacpacUri
8888
Assert-NotNull $params.exportBacpacUri
8989
Assert-NotNull $params.storageResourceId
9090

9191
$password = $params.password
92-
93-
$secureString = ($password | ConvertTo-SecureString -asPlainText -Force)
92+
93+
$secureString = ($password | ConvertTo-SecureString -asPlainText -Force)
9494
$credentials = new-object System.Management.Automation.PSCredential($params.userName, $secureString)
9595
$rgname = $params.rgname
9696
$serverName = $params.serverName
9797

9898
if($createServer -eq $true){
99-
$server = New-AzSqlServer -ResourceGroupName $rgname -ServerName $serverName -ServerVersion $params.version -Location $params.location -SqlAdministratorCredentials $credentials
99+
$server = New-AzSqlServer -ResourceGroupName $rgname -ServerName $serverName -ServerVersion $params.version -Location $params.location -SqlAdministratorCredentials $credentials
100100
}
101101

102102
if($createDatabase -eq $true){
103103
$standarddb = New-AzSqlDatabase -ResourceGroupName $rgname -ServerName $serverName -DatabaseName $params.databaseName
104104
}
105-
105+
106106
if($createFirewallRule -eq $true){
107107
New-AzSqlServerFirewallRule -ResourceGroupName $rgname -ServerName $serverName -AllowAllAzureIPs
108108
}
@@ -127,16 +127,16 @@ function Test-ImportNewDatabaseNetworkIsolation
127127
Write-Output "Assert-NotNull exportResponse"
128128
Assert-NotNull $exportResponse
129129
Write-Output (ConvertTo-Json $exportResponse)
130-
#$operationStatusLink = $exportResponse.OperationStatusLink
131-
#Assert-AreEqual $exportResponse.ResourceGroupName $params.rgname
132-
#Assert-AreEqual $exportResponse.ServerName $params.serverName
133-
#Assert-AreEqual $exportResponse.DatabaseName $params.databaseName
134-
#Assert-AreEqual $exportResponse.StorageKeyType $params.storageKeyType
135-
#Assert-Null $exportResponse.StorageKey
136-
#Assert-AreEqual $exportResponse.StorageUri $params.exportBacpacUri
137-
#Assert-AreEqual $exportResponse.AdministratorLogin $params.userName
138-
#Assert-Null $exportResponse.AdministratorLoginPassword
139-
#Assert-AreEqual $exportResponse.AuthenticationType $params.authType
130+
$operationStatusLink = $exportResponse.OperationStatusLink
131+
Assert-AreEqual $exportResponse.ResourceGroupName $params.rgname
132+
Assert-AreEqual $exportResponse.ServerName $params.serverName
133+
Assert-AreEqual $exportResponse.DatabaseName $params.databaseName
134+
Assert-AreEqual $exportResponse.StorageKeyType $params.storageKeyType
135+
Assert-Null $exportResponse.StorageKey
136+
Assert-AreEqual $exportResponse.StorageUri $params.exportBacpacUri
137+
Assert-AreEqual $exportResponse.AdministratorLogin $params.userName
138+
Assert-Null $exportResponse.AdministratorLoginPassword
139+
Assert-AreEqual $exportResponse.AuthenticationType $params.authType
140140
}
141141

142142
if($operationName -eq $importNew){
@@ -146,26 +146,58 @@ function Test-ImportNewDatabaseNetworkIsolation
146146
}
147147
else
148148
{
149-
$importResponse = New-AzSqlDatabaseImport -ResourceGroupName $params.rgname -ServerName $params.serverName -DatabaseName $params.databaseName -StorageKeyType $params.storageKeyType -StorageKey $params.storageKey -StorageUri $params.importBacpacUri -AdministratorLogin $params.userName -AdministratorLoginPassword $secureString -Edition $params.databaseEdition -ServiceObjectiveName $params.serviceObjectiveName -DatabaseMaxSizeBytes $params.databaseMaxSizeBytes -AuthenticationType $params.authType
149+
$importResponse = New-AzSqlDatabaseImport -ResourceGroupName $params.rgname -ServerName $params.serverName -DatabaseName $params.databaseName -StorageKeyType $params.storageKeyType -StorageKey $params.storageKey -StorageUri $params.importBacpacUri -AdministratorLogin $params.userName -AdministratorLoginPassword $secureString -Edition $params.databaseEdition -ServiceObjectiveName $params.serviceObjectiveName -DatabaseMaxSizeBytes $params.databaseMaxSizeBytes -AuthenticationType $params.authType
150150
}
151151

152152
Write-Output "Assert-NotNull importResponse"
153153
Assert-NotNull $importResponse
154154
Write-Output (ConvertTo-Json $importResponse)
155-
#$operationStatusLink = $importResponse.OperationStatusLink
156-
#Assert-AreEqual $importResponse.ResourceGroupName $params.rgname
157-
#Assert-AreEqual $importResponse.ServerName $params.serverName
158-
#Assert-AreEqual $importResponse.DatabaseName $params.databaseName
159-
#Assert-AreEqual $importResponse.StorageKeyType $params.storageKeyType
160-
#Assert-Null $importResponse.StorageKey
161-
#Assert-AreEqual $importResponse.StorageUri $params.importBacpacUri
162-
#Assert-AreEqual $importResponse.AdministratorLogin $params.userName
163-
#Assert-Null $importResponse.AdministratorLoginPassword
164-
#Assert-AreEqual $importResponse.AuthenticationType $params.authType
165-
#Assert-AreEqual $importResponse.Edition $params.databaseEdition
166-
#Assert-AreEqual $importResponse.ServiceObjectiveName $params.serviceObjectiveName
167-
#Assert-AreEqual $importResponse.DatabaseMaxSizeBytes $params.databaseMaxSizeBytes
155+
$operationStatusLink = $importResponse.OperationStatusLink
156+
Assert-AreEqual $importResponse.ResourceGroupName $params.rgname
157+
Assert-AreEqual $importResponse.ServerName $params.serverName
158+
Assert-AreEqual $importResponse.DatabaseName $params.databaseName
159+
Assert-AreEqual $importResponse.StorageKeyType $params.storageKeyType
160+
Assert-Null $importResponse.StorageKey
161+
Assert-AreEqual $importResponse.StorageUri $params.importBacpacUri
162+
Assert-AreEqual $importResponse.AdministratorLogin $params.userName
163+
Assert-Null $importResponse.AdministratorLoginPassword
164+
Assert-AreEqual $importResponse.AuthenticationType $params.authType
165+
Assert-AreEqual $importResponse.Edition $params.databaseEdition
166+
Assert-AreEqual $importResponse.ServiceObjectiveName $params.serviceObjectiveName
167+
Assert-AreEqual $importResponse.DatabaseMaxSizeBytes $params.databaseMaxSizeBytes
168168
}
169+
170+
# The following part of the test is broken for now because $operationStatusLink is always null
171+
# this does not reproduce when I run the commands manually, so I suspect a race condition in the
172+
# way the v2020-02-02 New-Import and New-Export commandlets fetch the Location header
173+
# That handling is necessary because the v2020-02-02 SDK is itself returning null instead of the
174+
# promised AzureSqlDatabaseImportExportModel
175+
# I am trying to solve an outage now, so leaving this test commented out, but I will create a work
176+
# item to fix the SDK
177+
<# TODO: Uncomment once the location header is returning correctly
178+
Assert-NotNull $operationStatusLink
179+
180+
#Get status
181+
$statusInProgress = "InProgress"
182+
$statusSucceeded = "Succeeded"
183+
$status = "InProgress"
184+
185+
if($succeeded -eq $true){
186+
Write-Output "Getting Status"
187+
while($status -eq $statusInProgress){
188+
$statusResponse = Get-AzSqlDatabaseImportExportStatus -OperationStatusLink $operationStatusLink
189+
Write-Output "Import Export Status Message:" + $statusResponse.StatusMessage
190+
Assert-AreEqual $statusResponse.OperationStatusLink $operationStatusLink
191+
$status = $statusResponse.Status
192+
if($status -eq $statusInProgress){
193+
Assert-NotNull $statusResponse.LastModifiedTime
194+
Assert-NotNull $statusResponse.QueuedTime
195+
Assert-NotNull $statusResponse.StatusMessage
196+
}
197+
}
198+
Assert-AreEqual $status $statusSucceeded
199+
Write-Output "ImportExportStatus:" + $status
200+
#>
169201
}
170202
finally
171203
{

src/Sql/Sql/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
-->
2020
## Upcoming Release
2121
* Fixed parameter description for `InstanceFailoverGroup` command.
22+
* Fixed Status and StatusMessage fields in `Get-AzSqlDatabaseImportExportStatus` to conform to documentation
2223

2324
## Version 2.13.0
2425
* Added SecondaryType to the following:

src/Sql/Sql/ImportExport/Model/AzureSqlDatabaseImportExportStatusModel.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ public string RequestType
6767

6868
/// <summary>
6969
/// Gets or sets the status message returned from the server.
70+
///
71+
/// Ensure that this retains compatibility with the old Powershell versions since lots of customers use this for
72+
/// their automation.
73+
/// Compare to <see cref="Azure.Management.Sql.LegacySdk.ImportExportOperations.GetImportExportOperationStatusAsync"/>
7074
/// </summary>
7175
public string Status
7276
{
@@ -84,7 +88,7 @@ public string StatusMessage
8488
}
8589

8690
/// <summary>
87-
/// Gets or sets the
91+
/// Gets or sets the private endpoint status(es)
8892
/// </summary>
8993
public PrivateEndpointRequestStatus[] PrivateEndpointRequestStatus
9094
{

src/Sql/Sql/ImportExport/Service/ImportExportDatabaseAdapter.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
using Microsoft.Azure.Management.Sql.Models;
2020
using System;
2121
using System.Linq;
22+
using System.Net;
23+
using System.Net.Http;
2224

2325
namespace Microsoft.Azure.Commands.Sql.ImportExport.Service
2426
{
@@ -138,14 +140,18 @@ public AzureSqlDatabaseImportExportBaseModel ImportNewDatabase(AzureSqlDatabaseI
138140
/// <returns>Operation status response</returns>
139141
public AzureSqlDatabaseImportExportStatusModel GetStatus(string operationStatusLink)
140142
{
141-
ImportExportOperationResult response = Communicator.GetOperationStatus(operationStatusLink);
143+
HttpResponseMessage rawHttpResponse;
144+
ImportExportOperationResult response = Communicator.GetOperationStatus(operationStatusLink, out rawHttpResponse);
145+
146+
OperationStatus? operationStatus = GetOperationStatusFromHttpStatus(rawHttpResponse.StatusCode);
142147

143148
AzureSqlDatabaseImportExportStatusModel status = new AzureSqlDatabaseImportExportStatusModel()
144149
{
145150
ErrorMessage = response.ErrorMessage,
146151
LastModifiedTime = response.LastModifiedTime,
147152
QueuedTime = response.QueuedTime,
148-
Status = response.Status,
153+
StatusMessage = response.Status, // in spite of the name, the field called "Status" is the correct one to put into the "StatusMessage" field
154+
Status = operationStatus.HasValue ? operationStatus.Value.ToString() : "",
149155
RequestType = response.RequestType,
150156
PrivateEndpointRequestStatus = response.PrivateEndpointConnections?.Select(pec => new PrivateEndpointRequestStatus()
151157
{
@@ -168,7 +174,39 @@ private AzureSqlDatabaseImportExportBaseModel CreateImportExportResponse(ImportE
168174
{
169175
AzureSqlDatabaseImportExportBaseModel model = originalModel == null ? new AzureSqlDatabaseImportExportBaseModel() : originalModel.Copy();
170176
model.OperationStatusLink = statusLink?.ToString();
177+
178+
// It looks like the ExportDatabase SDK call is currently broken (and returns "null" instead of the response object).
179+
// I need to check in a sev2 hotfix now. Once the SDK issue has been resolved, un-comment this and the asserts in
180+
// the test code
181+
// Also can probably remove the "LastLocationHeader" hack and just rely on the header in the returned results
182+
// model.Status = response.Status;
171183
return model;
172184
}
185+
186+
/// <summary>
187+
/// Get the "Status" value for the Import/Export request
188+
///
189+
/// This logic is copied verbatim from the (generated) legacy SDK:
190+
/// <see cref="Azure.Management.Sql.LegacySdk.ImportExportOperations.GetImportExportOperationStatusAsync"/>
191+
/// </summary>
192+
/// <param name="statusCode"></param>
193+
/// <returns></returns>
194+
protected OperationStatus? GetOperationStatusFromHttpStatus(HttpStatusCode statusCode)
195+
{
196+
OperationStatus? status = null;
197+
switch (statusCode)
198+
{
199+
// We expect this switch statement to cover all possible cases of return values from the service
200+
case HttpStatusCode.OK:
201+
case HttpStatusCode.Created:
202+
status = OperationStatus.Succeeded;
203+
break;
204+
case HttpStatusCode.Accepted:
205+
status = OperationStatus.InProgress;
206+
break;
207+
}
208+
209+
return status;
210+
}
173211
}
174212
}

src/Sql/Sql/ImportExport/Service/ImportExportDatabaseCommunicator.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,20 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15-
using Microsoft.Azure.Commands.Common.Authentication;
16-
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
17-
using Microsoft.Azure.Commands.Common.Authentication.Models;
18-
using Microsoft.Azure.Commands.Sql.Common;
19-
using Microsoft.Azure.Management.Sql;
20-
using Microsoft.Azure.Management.Sql.Models;
21-
using Microsoft.Rest.Azure;
22-
using Newtonsoft.Json;
23-
using Newtonsoft.Json.Serialization;
2415
using System;
2516
using System.Collections.Generic;
26-
using System.Linq;
2717
using System.Net.Http;
2818
using System.Net.Http.Headers;
29-
using System.Runtime.InteropServices;
3019
using System.Threading;
3120
using System.Threading.Tasks;
3221

22+
using Microsoft.Azure.Commands.Common.Authentication;
23+
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
24+
using Microsoft.Azure.Management.Sql;
25+
using Microsoft.Azure.Management.Sql.Models;
26+
27+
using Newtonsoft.Json;
28+
3329
namespace Microsoft.Azure.Commands.Sql.Database.Services
3430
{
3531
/// <summary>
@@ -114,7 +110,13 @@ public ImportExportOperationResult BeginImportNewDatabase(string resourceGroupNa
114110
return result;
115111
}
116112

117-
public ImportExportOperationResult GetOperationStatus(string operationStatusLink)
113+
/// <summary>
114+
/// Get the status of an operation given a raw Operation Status Link
115+
/// </summary>
116+
/// <param name="operationStatusLink">Status link as returned by the import or export commandlet</param>
117+
/// <param name="rawHttpResponse">Out parameter for the raw HTTP response for further inspection</param>
118+
/// <returns></returns>
119+
public ImportExportOperationResult GetOperationStatus(string operationStatusLink, out HttpResponseMessage rawHttpResponse)
118120
{
119121
var client = GetCurrentSqlClient();
120122

@@ -129,6 +131,7 @@ public ImportExportOperationResult GetOperationStatus(string operationStatusLink
129131

130132
response.EnsureSuccessStatusCode();
131133

134+
rawHttpResponse = response;
132135
string responseString = response.Content.ReadAsStringAsync().Result;
133136

134137
ImportExportOperationResult operationResult = JsonConvert.DeserializeObject<ImportExportOperationResult>(responseString, new JsonSerializerSettings

0 commit comments

Comments
 (0)