mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-22 10:21:37 +00:00
Portal changes for DedicatedGateway (#742)
* src/SelfServe/Example/SelfServeExample.rp.ts. Portal changes for DedicatedGateway 1. Change Sqlx endpoints to SqlDedicatedGateway endpoint 2. Remove D32s from the SKU list 3. Add telemetry 4. Remove SKU details field per discussion 5. Support dynamic instance scaling. * format files to ensure format check and lint tests pass * Lint fixes * Lint fixes * Added metrics blade link * updated conditions for warning banner * fixed lint error * Incorporate metrics link and CR feedback * Lint fixes * CR feedback and fix links * CR feedback and fix links * Link fix Co-authored-by: Srinath Narayanan <srnara@microsoft.com>
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { RefreshResult } from "../SelfServeTypes";
|
||||
import { configContext } from "../../ConfigContext";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { armRequestWithoutPolling } from "../../Utils/arm/request";
|
||||
import { configContext } from "../../ConfigContext";
|
||||
import { selfServeTraceFailure, selfServeTraceStart, selfServeTraceSuccess } from "../SelfServeTelemetryProcessor";
|
||||
import { RefreshResult } from "../SelfServeTypes";
|
||||
import SqlX from "./SqlX";
|
||||
import { SqlxServiceResource, UpdateDedicatedGatewayRequestParameters } from "./SqlxTypes";
|
||||
|
||||
const apiVersion = "2020-06-01-preview";
|
||||
const apiVersion = "2021-04-01-preview";
|
||||
|
||||
export enum ResourceStatus {
|
||||
Running = "Running",
|
||||
@@ -21,7 +23,7 @@ export interface DedicatedGatewayResponse {
|
||||
}
|
||||
|
||||
export const getPath = (subscriptionId: string, resourceGroup: string, name: string): string => {
|
||||
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${name}/services/sqlx`;
|
||||
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${name}/services/SqlDedicatedGateway`;
|
||||
};
|
||||
|
||||
export const updateDedicatedGatewayResource = async (sku: string, instances: number): Promise<string> => {
|
||||
@@ -30,39 +32,66 @@ export const updateDedicatedGatewayResource = async (sku: string, instances: num
|
||||
properties: {
|
||||
instanceSize: sku,
|
||||
instanceCount: instances,
|
||||
serviceType: "Sqlx",
|
||||
serviceType: "SqlDedicatedGateway",
|
||||
},
|
||||
};
|
||||
const armRequestResult = await armRequestWithoutPolling({
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path,
|
||||
method: "PUT",
|
||||
apiVersion,
|
||||
body,
|
||||
});
|
||||
return armRequestResult.operationStatusUrl;
|
||||
const telemetryData = { ...body, httpMethod: "PUT", selfServeClassName: SqlX.name };
|
||||
const updateTimeStamp = selfServeTraceStart(telemetryData);
|
||||
let armRequestResult;
|
||||
try {
|
||||
armRequestResult = await armRequestWithoutPolling({
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path,
|
||||
method: "PUT",
|
||||
apiVersion,
|
||||
body,
|
||||
});
|
||||
selfServeTraceSuccess(telemetryData, updateTimeStamp);
|
||||
} catch (e) {
|
||||
const failureTelemetry = { ...body, e, selfServeClassName: SqlX.name };
|
||||
selfServeTraceFailure(failureTelemetry, updateTimeStamp);
|
||||
}
|
||||
return armRequestResult?.operationStatusUrl;
|
||||
};
|
||||
|
||||
export const deleteDedicatedGatewayResource = async (): Promise<string> => {
|
||||
const path = getPath(userContext.subscriptionId, userContext.resourceGroup, userContext.databaseAccount.name);
|
||||
const armRequestResult = await armRequestWithoutPolling({
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path,
|
||||
method: "DELETE",
|
||||
apiVersion,
|
||||
});
|
||||
return armRequestResult.operationStatusUrl;
|
||||
const telemetryData = { httpMethod: "DELETE", selfServeClassName: SqlX.name };
|
||||
const deleteTimeStamp = selfServeTraceStart(telemetryData);
|
||||
let armRequestResult;
|
||||
try {
|
||||
armRequestResult = await armRequestWithoutPolling({
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path,
|
||||
method: "DELETE",
|
||||
apiVersion,
|
||||
});
|
||||
selfServeTraceSuccess(telemetryData, deleteTimeStamp);
|
||||
} catch (e) {
|
||||
const failureTelemetry = { e, selfServeClassName: SqlX.name };
|
||||
selfServeTraceFailure(failureTelemetry, deleteTimeStamp);
|
||||
}
|
||||
return armRequestResult?.operationStatusUrl;
|
||||
};
|
||||
|
||||
export const getDedicatedGatewayResource = async (): Promise<SqlxServiceResource> => {
|
||||
const path = getPath(userContext.subscriptionId, userContext.resourceGroup, userContext.databaseAccount.name);
|
||||
const armRequestResult = await armRequestWithoutPolling<SqlxServiceResource>({
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path,
|
||||
method: "GET",
|
||||
apiVersion,
|
||||
});
|
||||
return armRequestResult.result;
|
||||
const telemetryData = { httpMethod: "GET", selfServeClassName: SqlX.name };
|
||||
const getResourceTimeStamp = selfServeTraceStart(telemetryData);
|
||||
let armRequestResult;
|
||||
try {
|
||||
armRequestResult = await armRequestWithoutPolling<SqlxServiceResource>({
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path,
|
||||
method: "GET",
|
||||
apiVersion,
|
||||
});
|
||||
selfServeTraceSuccess(telemetryData, getResourceTimeStamp);
|
||||
} catch (e) {
|
||||
const failureTelemetry = { e, selfServeClassName: SqlX.name };
|
||||
selfServeTraceFailure(failureTelemetry, getResourceTimeStamp);
|
||||
}
|
||||
return armRequestResult?.result;
|
||||
};
|
||||
|
||||
export const getCurrentProvisioningState = async (): Promise<DedicatedGatewayResponse> => {
|
||||
|
||||
@@ -23,7 +23,7 @@ const costPerHourValue: Description = {
|
||||
textTKey: "CostText",
|
||||
type: DescriptionType.Text,
|
||||
link: {
|
||||
href: "https://azure.microsoft.com/en-us/pricing/details/cosmos-db/",
|
||||
href: "https://aka.ms/cosmos-db-dedicated-gateway-pricing",
|
||||
textTKey: "DedicatedGatewayPricing",
|
||||
},
|
||||
};
|
||||
@@ -37,43 +37,56 @@ const connectionStringValue: Description = {
|
||||
},
|
||||
};
|
||||
|
||||
const metricsStringValue: Description = {
|
||||
textTKey: "MetricsText",
|
||||
type: DescriptionType.Text,
|
||||
link: {
|
||||
href: generateBladeLink(BladeType.Metrics),
|
||||
textTKey: "MetricsBlade",
|
||||
},
|
||||
};
|
||||
|
||||
const resizingDecisionValue: Description = {
|
||||
textTKey: "ResizingDecisionText",
|
||||
type: DescriptionType.Text,
|
||||
link: {
|
||||
href: "https://aka.ms/cosmos-db-dedicated-gateway-size",
|
||||
textTKey: "ResizingDecisionLink",
|
||||
},
|
||||
};
|
||||
|
||||
const CosmosD4s = "Cosmos.D4s";
|
||||
const CosmosD8s = "Cosmos.D8s";
|
||||
const CosmosD16s = "Cosmos.D16s";
|
||||
const CosmosD32s = "Cosmos.D32s";
|
||||
|
||||
const getSKUDetails = (sku: string): string => {
|
||||
if (sku === CosmosD4s) {
|
||||
return "CosmosD4Details";
|
||||
} else if (sku === CosmosD8s) {
|
||||
return "CosmosD8Details";
|
||||
} else if (sku === CosmosD16s) {
|
||||
return "CosmosD16Details";
|
||||
} else if (sku === CosmosD32s) {
|
||||
return "CosmosD32Details";
|
||||
}
|
||||
return "Not Supported Yet";
|
||||
};
|
||||
|
||||
const onSKUChange = (newValue: InputType, currentValues: Map<string, SmartUiInput>): Map<string, SmartUiInput> => {
|
||||
currentValues.set("sku", { value: newValue });
|
||||
currentValues.set("skuDetails", {
|
||||
value: { textTKey: getSKUDetails(`${newValue.toString()}`), type: DescriptionType.Text } as Description,
|
||||
});
|
||||
currentValues.set("costPerHour", { value: costPerHourValue });
|
||||
return currentValues;
|
||||
};
|
||||
|
||||
const onNumberOfInstancesChange = (
|
||||
newValue: InputType,
|
||||
currentValues: Map<string, SmartUiInput>
|
||||
currentValues: Map<string, SmartUiInput>,
|
||||
baselineValues: Map<string, SmartUiInput>
|
||||
): Map<string, SmartUiInput> => {
|
||||
currentValues.set("instances", { value: newValue });
|
||||
currentValues.set("warningBanner", {
|
||||
value: { textTKey: "WarningBannerOnUpdate" } as Description,
|
||||
hidden: false,
|
||||
});
|
||||
|
||||
const dedicatedGatewayOriginallyEnabled = baselineValues.get("enableDedicatedGateway")?.value as boolean;
|
||||
const baselineInstances = baselineValues.get("instances")?.value as number;
|
||||
if (!dedicatedGatewayOriginallyEnabled || baselineInstances !== newValue) {
|
||||
currentValues.set("warningBanner", {
|
||||
value: {
|
||||
textTKey: "WarningBannerOnUpdate",
|
||||
link: {
|
||||
href: "https://aka.ms/cosmos-db-dedicated-gateway-overview",
|
||||
textTKey: "DedicatedGatewayPricing",
|
||||
},
|
||||
} as Description,
|
||||
hidden: false,
|
||||
});
|
||||
} else {
|
||||
currentValues.set("warningBanner", undefined);
|
||||
}
|
||||
return currentValues;
|
||||
};
|
||||
|
||||
@@ -87,10 +100,11 @@ const onEnableDedicatedGatewayChange = (
|
||||
if (dedicatedGatewayOriginallyEnabled === newValue) {
|
||||
currentValues.set("sku", baselineValues.get("sku"));
|
||||
currentValues.set("instances", baselineValues.get("instances"));
|
||||
currentValues.set("skuDetails", baselineValues.get("skuDetails"));
|
||||
currentValues.set("costPerHour", baselineValues.get("costPerHour"));
|
||||
currentValues.set("warningBanner", baselineValues.get("warningBanner"));
|
||||
currentValues.set("connectionString", baselineValues.get("connectionString"));
|
||||
currentValues.set("metricsString", baselineValues.get("metricsString"));
|
||||
currentValues.set("resizingDecisionString", baselineValues.get("resizingDecisionString"));
|
||||
return currentValues;
|
||||
}
|
||||
|
||||
@@ -100,7 +114,7 @@ const onEnableDedicatedGatewayChange = (
|
||||
value: {
|
||||
textTKey: "WarningBannerOnUpdate",
|
||||
link: {
|
||||
href: "https://docs.microsoft.com/en-us/azure/cosmos-db/introduction",
|
||||
href: "https://aka.ms/cosmos-db-dedicated-gateway-pricing",
|
||||
textTKey: "DedicatedGatewayPricing",
|
||||
},
|
||||
} as Description,
|
||||
@@ -111,7 +125,7 @@ const onEnableDedicatedGatewayChange = (
|
||||
value: {
|
||||
textTKey: "WarningBannerOnDelete",
|
||||
link: {
|
||||
href: "https://docs.microsoft.com/en-us/azure/cosmos-db/introduction",
|
||||
href: "https://aka.ms/cosmos-db-dedicated-gateway-overview",
|
||||
textTKey: "DeprovisioningDetailsText",
|
||||
},
|
||||
} as Description,
|
||||
@@ -132,18 +146,22 @@ const onEnableDedicatedGatewayChange = (
|
||||
disabled: dedicatedGatewayOriginallyEnabled,
|
||||
});
|
||||
|
||||
currentValues.set("skuDetails", {
|
||||
value: { textTKey: getSKUDetails(`${currentValues.get("sku").value}`), type: DescriptionType.Text } as Description,
|
||||
hidden: hideAttributes,
|
||||
disabled: dedicatedGatewayOriginallyEnabled,
|
||||
});
|
||||
|
||||
currentValues.set("costPerHour", { value: costPerHourValue, hidden: hideAttributes });
|
||||
currentValues.set("connectionString", {
|
||||
value: connectionStringValue,
|
||||
hidden: !newValue || !dedicatedGatewayOriginallyEnabled,
|
||||
});
|
||||
|
||||
currentValues.set("metricsString", {
|
||||
value: metricsStringValue,
|
||||
hidden: !newValue || !dedicatedGatewayOriginallyEnabled,
|
||||
});
|
||||
|
||||
currentValues.set("resizingDecisionString", {
|
||||
value: resizingDecisionValue,
|
||||
hidden: !newValue || !dedicatedGatewayOriginallyEnabled,
|
||||
});
|
||||
|
||||
return currentValues;
|
||||
};
|
||||
|
||||
@@ -151,7 +169,6 @@ const skuDropDownItems: ChoiceItem[] = [
|
||||
{ labelTKey: "CosmosD4s", key: CosmosD4s },
|
||||
{ labelTKey: "CosmosD8s", key: CosmosD8s },
|
||||
{ labelTKey: "CosmosD16s", key: CosmosD16s },
|
||||
{ labelTKey: "CosmosD32s", key: CosmosD32s },
|
||||
];
|
||||
|
||||
const getSkus = async (): Promise<ChoiceItem[]> => {
|
||||
@@ -184,7 +201,6 @@ export default class SqlX extends SelfServeBaseClass {
|
||||
|
||||
currentValues.set("warningBanner", undefined);
|
||||
|
||||
//TODO : Add try catch for each RP call and return relevant notifications
|
||||
if (dedicatedGatewayOriginallyEnabled) {
|
||||
if (!dedicatedGatewayCurrentlyEnabled) {
|
||||
const operationStatusUrl = await deleteDedicatedGatewayResource();
|
||||
@@ -206,9 +222,11 @@ export default class SqlX extends SelfServeBaseClass {
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// Check for scaling up/down/in/out
|
||||
const sku = currentValues.get("sku")?.value as string;
|
||||
const instances = currentValues.get("instances").value as number;
|
||||
const operationStatusUrl = await updateDedicatedGatewayResource(sku, instances);
|
||||
return {
|
||||
operationStatusUrl: undefined,
|
||||
operationStatusUrl: operationStatusUrl,
|
||||
portalNotification: {
|
||||
initialize: {
|
||||
titleTKey: "UpdateInitializeTitle",
|
||||
@@ -255,24 +273,37 @@ export default class SqlX extends SelfServeBaseClass {
|
||||
defaults.set("enableDedicatedGateway", { value: false });
|
||||
defaults.set("sku", { value: CosmosD4s, hidden: true });
|
||||
defaults.set("instances", { value: await getInstancesMin(), hidden: true });
|
||||
defaults.set("skuDetails", undefined);
|
||||
defaults.set("costPerHour", undefined);
|
||||
defaults.set("connectionString", undefined);
|
||||
defaults.set("metricsString", {
|
||||
value: undefined,
|
||||
hidden: true,
|
||||
});
|
||||
defaults.set("resizingDecisionString", {
|
||||
value: undefined,
|
||||
hidden: true,
|
||||
});
|
||||
|
||||
const response = await getCurrentProvisioningState();
|
||||
if (response.status && response.status !== "Deleting") {
|
||||
defaults.set("enableDedicatedGateway", { value: true });
|
||||
defaults.set("sku", { value: response.sku, disabled: true });
|
||||
defaults.set("instances", { value: response.instances, disabled: true });
|
||||
defaults.set("instances", { value: response.instances, disabled: false });
|
||||
defaults.set("costPerHour", { value: costPerHourValue });
|
||||
defaults.set("skuDetails", {
|
||||
value: { textTKey: getSKUDetails(`${defaults.get("sku").value}`), type: DescriptionType.Text } as Description,
|
||||
hidden: false,
|
||||
});
|
||||
defaults.set("connectionString", {
|
||||
value: connectionStringValue,
|
||||
hidden: false,
|
||||
});
|
||||
|
||||
defaults.set("metricsString", {
|
||||
value: metricsStringValue,
|
||||
hidden: false,
|
||||
});
|
||||
|
||||
defaults.set("resizingDecisionString", {
|
||||
value: resizingDecisionValue,
|
||||
hidden: false,
|
||||
});
|
||||
}
|
||||
|
||||
defaults.set("warningBanner", undefined);
|
||||
@@ -289,7 +320,7 @@ export default class SqlX extends SelfServeBaseClass {
|
||||
textTKey: "DedicatedGatewayDescription",
|
||||
type: DescriptionType.Text,
|
||||
link: {
|
||||
href: "https://docs.microsoft.com/en-us/azure/cosmos-db/introduction",
|
||||
href: "https://aka.ms/cosmos-db-dedicated-gateway-overview",
|
||||
textTKey: "LearnAboutDedicatedGateway",
|
||||
},
|
||||
},
|
||||
@@ -312,12 +343,6 @@ export default class SqlX extends SelfServeBaseClass {
|
||||
})
|
||||
sku: ChoiceItem;
|
||||
|
||||
@Values({
|
||||
labelTKey: "SKUDetails",
|
||||
isDynamicDescription: true,
|
||||
})
|
||||
skuDetails: string;
|
||||
|
||||
@OnChange(onNumberOfInstancesChange)
|
||||
@Values({
|
||||
labelTKey: "NumberOfInstances",
|
||||
@@ -328,6 +353,16 @@ export default class SqlX extends SelfServeBaseClass {
|
||||
})
|
||||
instances: number;
|
||||
|
||||
@Values({
|
||||
description: metricsStringValue,
|
||||
})
|
||||
metricsString: string;
|
||||
|
||||
@Values({
|
||||
description: resizingDecisionValue,
|
||||
})
|
||||
resizingDecisionString: string;
|
||||
|
||||
@Values({
|
||||
labelTKey: "Cost",
|
||||
isDynamicDescription: true,
|
||||
|
||||
Reference in New Issue
Block a user