Move SQL database deletion to ARM (#126)

This commit is contained in:
Steve Faulkner 2020-08-04 18:03:14 -05:00 committed by GitHub
parent e6acf6686f
commit f132a8546c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 74 additions and 60 deletions

View File

@ -377,15 +377,6 @@ export function deleteConflict(
); );
} }
export function deleteDatabase(database: ViewModels.Database, options: any): Q.Promise<any> {
return Q(
CosmosClient.client()
.database(database.id())
.delete()
.then(() => refreshCachedResources())
);
}
export function deleteStoredProcedure( export function deleteStoredProcedure(
collection: ViewModels.Collection, collection: ViewModels.Collection,
storedProcedure: DataModels.StoredProcedure, storedProcedure: DataModels.StoredProcedure,

View File

@ -7,14 +7,13 @@ import { ConflictDefinition, ItemDefinition, QueryIterator, Resource } from "@az
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent"; import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
import * as DataAccessUtilityBase from "./DataAccessUtilityBase"; import * as DataAccessUtilityBase from "./DataAccessUtilityBase";
import * as Logger from "./Logger"; import * as Logger from "./Logger";
import { sendMessage } from "./MessageHandler";
import { MessageTypes } from "../Contracts/ExplorerContracts";
import { MinimalQueryIterator, nextPage } from "./IteratorUtilities"; import { MinimalQueryIterator, nextPage } from "./IteratorUtilities";
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils"; import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
import { RequestOptions } from "@azure/cosmos/dist-esm"; import { RequestOptions } from "@azure/cosmos/dist-esm";
import StoredProcedure from "../Explorer/Tree/StoredProcedure"; import StoredProcedure from "../Explorer/Tree/StoredProcedure";
import ConflictId from "../Explorer/Tree/ConflictId"; import ConflictId from "../Explorer/Tree/ConflictId";
import DocumentId from "../Explorer/Tree/DocumentId"; import DocumentId from "../Explorer/Tree/DocumentId";
import { sendNotificationForError } from "./dataAccess/sendNotificationForError";
// TODO: Log all promise resolutions and errors with verbosity levels // TODO: Log all promise resolutions and errors with verbosity levels
export function queryDocuments( export function queryDocuments(
@ -730,39 +729,6 @@ export function deleteConflict(
return deferred.promise; return deferred.promise;
} }
export function deleteDatabase(database: ViewModels.Database, options: any = {}): Q.Promise<any> {
var deferred = Q.defer<any>();
const id = NotificationConsoleUtils.logConsoleMessage(
ConsoleDataType.InProgress,
`Deleting database ${database.id()}`
);
DataAccessUtilityBase.deleteDatabase(database, options)
.then(
(response: any) => {
NotificationConsoleUtils.logConsoleMessage(
ConsoleDataType.Info,
`Successfully deleted database ${database.id()}`
);
deferred.resolve(response);
},
(error: any) => {
NotificationConsoleUtils.logConsoleMessage(
ConsoleDataType.Error,
`Error while deleting database ${database.id()}:\n ${JSON.stringify(error)}`
);
Logger.logError(JSON.stringify(error), "DeleteDatabase", error.code);
sendNotificationForError(error);
deferred.reject(error);
}
)
.finally(() => {
NotificationConsoleUtils.clearInProgressMessageWithId(id);
});
return deferred.promise;
}
export function deleteStoredProcedure( export function deleteStoredProcedure(
collection: ViewModels.Collection, collection: ViewModels.Collection,
storedProcedure: DataModels.StoredProcedure, storedProcedure: DataModels.StoredProcedure,
@ -1109,15 +1075,3 @@ export function createDatabase(
return deferred.promise; return deferred.promise;
} }
export function sendNotificationForError(error: any) {
if (error && error.code === Constants.HttpStatusCodes.Forbidden) {
if (error.message && error.message.toLowerCase().indexOf("sharedoffer is disabled for your account") > 0) {
return;
}
sendMessage({
type: MessageTypes.ForbiddenError,
reason: error && error.message ? error.message : error
});
}
}

View File

@ -0,0 +1,13 @@
jest.mock("../../Utils/arm/request");
import { deleteDatabase } from "./deleteDatabase";
import { armRequest } from "../../Utils/arm/request";
import { AuthType } from "../../AuthType";
describe("deleteDatabase", () => {
it("should call ARM if logged in with AAD", async () => {
window.authType = AuthType.AAD;
await deleteDatabase("database");
expect(armRequest).toHaveBeenCalled();
});
// TODO: Test non-AAD case
});

View File

@ -0,0 +1,34 @@
import { CosmosClient } from "../CosmosClient";
import { refreshCachedResources } from "../DataAccessUtilityBase";
import { logConsoleProgress, logConsoleError, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
import { AuthType } from "../../AuthType";
import { logError } from "../Logger";
import { sendNotificationForError } from "./sendNotificationForError";
export async function deleteDatabase(databaseId: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
try {
if (window.authType === AuthType.AAD) {
await deleteSqlDatabase(
CosmosClient.subscriptionId(),
CosmosClient.resourceGroup(),
CosmosClient.databaseAccount().name,
databaseId
);
} else {
await CosmosClient.client()
.database(databaseId)
.delete();
}
} catch (error) {
logConsoleError(`Error while deleting database ${databaseId}:\n ${JSON.stringify(error)}`);
logError(JSON.stringify(error), "DeleteDatabase", error.code);
sendNotificationForError(error);
throw error;
}
logConsoleInfo(`Successfully deleted database ${databaseId}`);
clearMessage();
await refreshCachedResources();
}

View File

@ -0,0 +1,20 @@
import * as Constants from "../Constants";
import { sendMessage } from "../MessageHandler";
import { MessageTypes } from "../../Contracts/ExplorerContracts";
interface CosmosError {
code: number;
message?: string;
}
export function sendNotificationForError(error: CosmosError): void {
if (error && error.code === Constants.HttpStatusCodes.Forbidden) {
if (error.message && error.message.toLowerCase().indexOf("sharedoffer is disabled for your account") > 0) {
return;
}
sendMessage({
type: MessageTypes.ForbiddenError,
reason: error && error.message ? error.message : error
});
}
}

View File

@ -1,4 +1,4 @@
jest.mock("../../Common/DocumentClientUtilityBase"); jest.mock("../../Common/dataAccess/deleteDatabase");
jest.mock("../../Shared/Telemetry/TelemetryProcessor"); jest.mock("../../Shared/Telemetry/TelemetryProcessor");
import * as ko from "knockout"; import * as ko from "knockout";
import Q from "q"; import Q from "q";
@ -11,7 +11,7 @@ import Explorer from "../Explorer";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { TreeNode } from "../../Contracts/ViewModels"; import { TreeNode } from "../../Contracts/ViewModels";
import { TabsManager } from "../Tabs/TabsManager"; import { TabsManager } from "../Tabs/TabsManager";
import { deleteDatabase } from "../../Common/DocumentClientUtilityBase"; import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
describe("Delete Database Confirmation Pane", () => { describe("Delete Database Confirmation Pane", () => {
describe("Explorer.isLastDatabase() and Explorer.isLastNonEmptyDatabase()", () => { describe("Explorer.isLastDatabase() and Explorer.isLastNonEmptyDatabase()", () => {

View File

@ -12,7 +12,7 @@ import DeleteFeedback from "../../Common/DeleteFeedback";
import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils"; import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils";
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { deleteDatabase } from "../../Common/DocumentClientUtilityBase"; import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase { export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
public databaseIdConfirmationText: ko.Observable<string>; public databaseIdConfirmationText: ko.Observable<string>;
@ -51,6 +51,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
dataExplorerArea: Constants.Areas.ContextualPane, dataExplorerArea: Constants.Areas.ContextualPane,
paneTitle: this.title() paneTitle: this.title()
}); });
// TODO: Should not be a Q promise anymore, but the Cassandra code requires it
let promise: Q.Promise<any>; let promise: Q.Promise<any>;
if (this.container.isPreferredApiCassandra()) { if (this.container.isPreferredApiCassandra()) {
promise = (<CassandraAPIDataClient>this.container.tableDataClient).deleteTableOrKeyspace( promise = (<CassandraAPIDataClient>this.container.tableDataClient).deleteTableOrKeyspace(
@ -60,7 +61,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
this.container this.container
); );
} else { } else {
promise = deleteDatabase(selectedDatabase); promise = Q(deleteDatabase(selectedDatabase.id()));
} }
return promise.then( return promise.then(
() => { () => {

View File

@ -21,6 +21,7 @@
"./src/Common/ObjectCache.ts", "./src/Common/ObjectCache.ts",
"./src/Common/ThemeUtility.ts", "./src/Common/ThemeUtility.ts",
"./src/Common/UrlUtility.ts", "./src/Common/UrlUtility.ts",
"./src/Common/dataAccess/sendNotificationForError.ts",
"./src/Config.ts", "./src/Config.ts",
"./src/Contracts/ActionContracts.ts", "./src/Contracts/ActionContracts.ts",
"./src/Contracts/DataModels.ts", "./src/Contracts/DataModels.ts",