mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-02-24 13:07:14 +00:00
Portal changes for DedicatedGateway
Changes to support creation and deletion of DedicatedGateway resource. Tested locally with various scenarios.
This commit is contained in:
parent
6aaddd9c60
commit
faa98de9e9
@ -28,6 +28,23 @@
|
|||||||
"SubmissionMessage": "Submitted successfully"
|
"SubmissionMessage": "Submitted successfully"
|
||||||
},
|
},
|
||||||
"SqlX": {
|
"SqlX": {
|
||||||
|
"DedicatedGatewayDescription": "Provisioning dedicated gateways for SqlX accounts.",
|
||||||
|
"DedicatedGateway": "Dedicated Gateway",
|
||||||
|
"Enable": "Enable",
|
||||||
|
"Disable": "Disable",
|
||||||
|
"LearnAboutDedicatedGateway": "Learn more about dedicated gateway.",
|
||||||
|
"SKUs": "SKUs",
|
||||||
|
"NumberOfInstances": "Number of instances",
|
||||||
|
"CosmosD4s": "Cosmos.D4s",
|
||||||
|
"CosmosD8s": "Cosmos.D8s",
|
||||||
|
"CosmosD16s": "Cosmos.D16s",
|
||||||
|
"CosmosD32s": "Cosmos.D32s",
|
||||||
|
"CreateMessage": "DedicatedGateway resource is being created.",
|
||||||
|
"UpdateMessage": "DedicatedGateway resource is being updated.",
|
||||||
|
"DeleteMessage": "DedicatedGateway resource is being deleted.",
|
||||||
|
"CannotSave": "Cannot save the changes to the DedicatedGateway resource at the moment",
|
||||||
|
"DedicatedGatewayEndpoint": "DedicatedGatewayEndpoint",
|
||||||
|
"NoValue": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -126,5 +126,5 @@ export interface SelfServeNotification {
|
|||||||
|
|
||||||
export interface RefreshResult {
|
export interface RefreshResult {
|
||||||
isUpdateInProgress: boolean;
|
isUpdateInProgress: boolean;
|
||||||
notificationMessage: string;
|
notificationMessage?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,33 +1,89 @@
|
|||||||
import { RefreshResult } from "../SelfServeTypes";
|
import { RefreshResult } from "../SelfServeTypes";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { configContext } from "../../ConfigContext";
|
||||||
|
import {
|
||||||
|
SqlxServiceResource,
|
||||||
|
UpdateDedicatedGatewayRequestParameters
|
||||||
|
} from "./SqlxTypes"
|
||||||
|
|
||||||
|
const apiVersion = "2020-06-01-preview";
|
||||||
|
|
||||||
export interface DedicatedGatewayResponse {
|
export interface DedicatedGatewayResponse {
|
||||||
sku: string;
|
sku: string;
|
||||||
instances: number;
|
instances: number;
|
||||||
|
status: string;
|
||||||
|
endpoint: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRegionSpecificMinInstances = async (): Promise<number> => {
|
export enum SKU {
|
||||||
// TODO: write RP call to get min number of instances needed for this region
|
CosmosD4s = "Cosmos.D4s",
|
||||||
throw new Error("getRegionSpecificMinInstances not implemented");
|
CosmosD8s = "Cosmos.D8s",
|
||||||
};
|
CosmosD16s = "Cosmos.D16s",
|
||||||
|
CosmosD32s = "Cosmos.D32s"
|
||||||
|
}
|
||||||
|
|
||||||
export const getRegionSpecificMaxInstances = async (): Promise<number> => {
|
export const updateDedicatedGatewayResource = async (sku: string, instances: number): Promise<void> => {
|
||||||
// TODO: write RP call to get max number of instances needed for this region
|
|
||||||
throw new Error("getRegionSpecificMaxInstances not implemented");
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updateDedicatedGatewayProvisioning = async (sku: string, instances: number): Promise<void> => {
|
|
||||||
// TODO: write RP call to update dedicated gateway provisioning
|
// TODO: write RP call to update dedicated gateway provisioning
|
||||||
throw new Error(
|
const path = `/subscriptions/${userContext.subscriptionId}/resourceGroups/${userContext.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/services/sqlx`;
|
||||||
`updateDedicatedGatewayProvisioning not implemented. Parameters- sku: ${sku}, instances:${instances}`
|
const body: UpdateDedicatedGatewayRequestParameters = {
|
||||||
);
|
properties: {
|
||||||
|
instanceSize: sku,
|
||||||
|
instanceCount: instances,
|
||||||
|
serviceType: "Sqlx"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const initializeDedicatedGatewayProvisioning = async (): Promise<DedicatedGatewayResponse> => {
|
export const deleteDedicatedGatewayResource = async (): Promise<void> => {
|
||||||
// TODO: write RP call to initialize UI for dedicated gateway provisioning
|
const path = `/subscriptions/${userContext.subscriptionId}/resourceGroups/${userContext.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/services/sqlx`;
|
||||||
throw new Error("initializeDedicatedGatewayProvisioning not implemented");
|
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getDedicatedGatewayResource = async() : Promise<SqlxServiceResource> => {
|
||||||
|
const path = `/subscriptions/${userContext.subscriptionId}/resourceGroups/${userContext.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${userContext.databaseAccount.name}/services/sqlx`;
|
||||||
|
return armRequest<SqlxServiceResource>({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCurrentProvisioningState = async (): Promise<DedicatedGatewayResponse> => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const response = await getDedicatedGatewayResource();
|
||||||
|
return { sku: response.properties.instanceSize, instances: response.properties.instanceCount, status: response.properties.status, endpoint: response.properties.sqlxEndPoint}
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
return {sku: null, instances: null, status: null, endpoint: null};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const refreshDedicatedGatewayProvisioning = async (): Promise<RefreshResult> => {
|
export const refreshDedicatedGatewayProvisioning = async (): Promise<RefreshResult> => {
|
||||||
// TODO: write RP call to check if dedicated gateway update has gone through
|
// TODO: write RP call to check if dedicated gateway update has gone through
|
||||||
throw new Error("refreshDedicatedGatewayProvisioning not implemented");
|
try
|
||||||
|
{
|
||||||
|
const response = await getDedicatedGatewayResource();
|
||||||
|
if (response.properties.status == "Running")
|
||||||
|
{
|
||||||
|
return {isUpdateInProgress: false}
|
||||||
|
}
|
||||||
|
else if (response.properties.status == "Creating")
|
||||||
|
{
|
||||||
|
return {isUpdateInProgress: true, notificationMessage: "CreateMessage"};
|
||||||
|
}
|
||||||
|
else if (response.properties.status == "Deleting")
|
||||||
|
{
|
||||||
|
console.log(response.properties.status);
|
||||||
|
return {isUpdateInProgress: true, notificationMessage: "DeleteMessage"};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.log(response.properties.status);
|
||||||
|
return {isUpdateInProgress: true, notificationMessage: "UpdateMessage"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return {isUpdateInProgress: false}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { IsDisplayable, OnChange, Values } from "../Decorators";
|
import { IsDisplayable, OnChange, Values } from "../Decorators";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
import {
|
import {
|
||||||
ChoiceItem,
|
ChoiceItem,
|
||||||
InputType,
|
InputType,
|
||||||
@ -6,36 +7,55 @@ import {
|
|||||||
RefreshResult,
|
RefreshResult,
|
||||||
SelfServeBaseClass,
|
SelfServeBaseClass,
|
||||||
SelfServeNotification,
|
SelfServeNotification,
|
||||||
|
SelfServeNotificationType,
|
||||||
SmartUiInput,
|
SmartUiInput,
|
||||||
} from "../SelfServeTypes";
|
} from "../SelfServeTypes";
|
||||||
import { refreshDedicatedGatewayProvisioning } from "./SqlX.rp";
|
import {
|
||||||
|
refreshDedicatedGatewayProvisioning,
|
||||||
|
getDedicatedGatewayResource,
|
||||||
|
updateDedicatedGatewayResource,
|
||||||
|
deleteDedicatedGatewayResource,
|
||||||
|
SKU,
|
||||||
|
getCurrentProvisioningState
|
||||||
|
} from "./SqlX.rp";
|
||||||
|
import { Console } from "console";
|
||||||
|
|
||||||
|
let disableAttributesOnDedicatedGatewayChange = false;
|
||||||
|
|
||||||
const onEnableDedicatedGatewayChange = (
|
const onEnableDedicatedGatewayChange = (
|
||||||
currentState: Map<string, SmartUiInput>,
|
currentState: Map<string, SmartUiInput>,
|
||||||
newValue: InputType
|
newValue: InputType
|
||||||
): Map<string, SmartUiInput> => {
|
): Map<string, SmartUiInput> => {
|
||||||
|
console.log("Disable Attributes is " + disableAttributesOnDedicatedGatewayChange);
|
||||||
const sku = currentState.get("sku");
|
const sku = currentState.get("sku");
|
||||||
const instances = currentState.get("instances");
|
const instances = currentState.get("instances");
|
||||||
const isSkuHidden = newValue === undefined || !(newValue as boolean);
|
const hideAttributes = newValue === undefined || !(newValue as boolean);
|
||||||
currentState.set("enableDedicatedGateway", { value: newValue });
|
currentState.set("enableDedicatedGateway", { value: newValue });
|
||||||
currentState.set("sku", { value: sku.value, hidden: isSkuHidden });
|
currentState.set("sku", { value: sku.value, hidden: hideAttributes, disabled: disableAttributesOnDedicatedGatewayChange});
|
||||||
currentState.set("instances", { value: instances.value, hidden: isSkuHidden });
|
currentState.set("instances", { value: instances.value, hidden: hideAttributes, disabled: disableAttributesOnDedicatedGatewayChange});
|
||||||
return currentState;
|
return currentState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const skuDropDownItems: ChoiceItem[] = [
|
||||||
|
{ label: "CosmosD4s", key: SKU.CosmosD4s },
|
||||||
|
{ label: "CosmosD8s", key: SKU.CosmosD8s },
|
||||||
|
{ label: "CosmosD16s", key: SKU.CosmosD16s },
|
||||||
|
{ label: "CosmosD32s", key: SKU.CosmosD32s },
|
||||||
|
];
|
||||||
|
|
||||||
const getSkus = async (): Promise<ChoiceItem[]> => {
|
const getSkus = async (): Promise<ChoiceItem[]> => {
|
||||||
// TODO: get SKUs from getRegionSpecificSkus() RP call and return array of {label:..., key:...}.
|
// TODO: get SKUs from getRegionSpecificSkus() RP call and return array of {label:..., key:...}.
|
||||||
throw new Error("getSkus not implemented.");
|
return skuDropDownItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getInstancesMin = async (): Promise<number> => {
|
const getInstancesMin = async (): Promise<number> => {
|
||||||
// TODO: get SKUs from getRegionSpecificSkus() RP call and return array of {label:..., key:...}.
|
// TODO: get SKUs from getRegionSpecificSkus() RP call and return array of {label:..., key:...}.
|
||||||
throw new Error("getInstancesMin not implemented.");
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getInstancesMax = async (): Promise<number> => {
|
const getInstancesMax = async (): Promise<number> => {
|
||||||
// TODO: get SKUs from getRegionSpecificSkus() RP call and return array of {label:..., key:...}.
|
// TODO: get SKUs from getRegionSpecificSkus() RP call and return array of {label:..., key:...}.
|
||||||
throw new Error("getInstancesMax not implemented.");
|
return 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
const validate = (currentValues: Map<string, SmartUiInput>): void => {
|
const validate = (currentValues: Map<string, SmartUiInput>): void => {
|
||||||
@ -50,22 +70,94 @@ export default class SqlX extends SelfServeBaseClass {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public onSave = async (currentValues: Map<string, SmartUiInput>): Promise<SelfServeNotification> => {
|
public onSave = async (currentValues: Map<string, SmartUiInput>): Promise<SelfServeNotification> => {
|
||||||
validate(currentValues);
|
const response = await getCurrentProvisioningState();
|
||||||
// TODO: add pre processing logic before calling the updateDedicatedGatewayProvisioning() RP call.
|
|
||||||
throw new Error(`onSave not implemented. No. of properties to save: ${currentValues.size}`);
|
// null implies the resource has not been provisioned.
|
||||||
|
if (response.status != null && response.status != "Running")
|
||||||
|
{
|
||||||
|
switch(response.status)
|
||||||
|
{
|
||||||
|
case "Creating":
|
||||||
|
return {message: "CreateMessage", type: SelfServeNotificationType.error};
|
||||||
|
case "Updating":
|
||||||
|
return {message: "UpdateMessage", type: SelfServeNotificationType.error};
|
||||||
|
case "Deleting":
|
||||||
|
return {message: "DeleteMessage", type: SelfServeNotificationType.error};
|
||||||
|
default:
|
||||||
|
console.log("UnexpectedStatus: " + response.status);
|
||||||
|
return {message: "CannotSave", type: SelfServeNotificationType.error}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const enableDedicatedGateway = currentValues.get("enableDedicatedGateway")?.value as boolean;
|
||||||
|
|
||||||
|
if (response.status != null)
|
||||||
|
{
|
||||||
|
if (!enableDedicatedGateway)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await deleteDedicatedGatewayResource();
|
||||||
|
return { message: "DedicatedGateway resource will be deleted.", type: SelfServeNotificationType.info };
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
console.log(e);
|
||||||
|
return { message: "Deleting Dedicated Gateway resource failed. DedicatedGateway will not be deleted.", type: SelfServeNotificationType.error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check for scaling up/down/in/out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (enableDedicatedGateway) {
|
||||||
|
const sku = currentValues.get("sku")?.value as string;
|
||||||
|
const instances = currentValues.get("instances").value as number;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await updateDedicatedGatewayResource(sku, instances);
|
||||||
|
return { message: "Dedicated Gateway resource will be provisioned.", type: SelfServeNotificationType.info };
|
||||||
|
}
|
||||||
|
catch(e)
|
||||||
|
{
|
||||||
|
console.log(e);
|
||||||
|
return { message: "Updating Dedicated Gateway resource failed. Dedicated Gateway will not be updated.", type: SelfServeNotificationType.error };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { message: "No updates were applied at this time", type: SelfServeNotificationType.warning };
|
||||||
};
|
};
|
||||||
|
|
||||||
public initialize = async (): Promise<Map<string, SmartUiInput>> => {
|
public initialize = async (): Promise<Map<string, SmartUiInput>> => {
|
||||||
// TODO: get initialization data from initializeDedicatedGatewayProvisioning() RP call.
|
// TODO: RP call to check if dedicated gateway has already been provisioned.
|
||||||
throw new Error("onSave not implemented");
|
// Based on the RP call enableDedicatedGateway will be true if it has not yet been enabled and false if it has.
|
||||||
|
const defaults = new Map<string, SmartUiInput>();
|
||||||
|
const enableDedicatedGateway = false;
|
||||||
|
defaults.set("enableDedicatedGateway", { value: enableDedicatedGateway, hidden: false, disabled: false});
|
||||||
|
defaults.set("sku", { value: SKU.CosmosD4s, hidden: !enableDedicatedGateway, disabled: false});
|
||||||
|
defaults.set("instances", { value: await getInstancesMin(), hidden: !enableDedicatedGateway, disabled: false});
|
||||||
|
const response = await getCurrentProvisioningState()
|
||||||
|
if (response.status != null)
|
||||||
|
{
|
||||||
|
disableAttributesOnDedicatedGatewayChange = true;
|
||||||
|
defaults.set("enableDedicatedGateway", { value: true, hidden: false, disabled: false});
|
||||||
|
defaults.set("sku", { value: response.sku, hidden: false, disabled: true});
|
||||||
|
defaults.set("instances", { value: response.instances, hidden: false, disabled: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults;
|
||||||
};
|
};
|
||||||
|
|
||||||
@Values({
|
@Values({
|
||||||
description: {
|
description: {
|
||||||
textTKey: "Provisioning dedicated gateways for SqlX accounts.",
|
textTKey: "DedicatedGatewayDescription",
|
||||||
link: {
|
link: {
|
||||||
href: "https://docs.microsoft.com/en-us/azure/cosmos-db/introduction",
|
href: "https://docs.microsoft.com/en-us/azure/cosmos-db/introduction",
|
||||||
textTKey: "Learn more about dedicated gateway.",
|
textTKey: "LearnAboutDedicatedGateway",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -87,7 +179,7 @@ export default class SqlX extends SelfServeBaseClass {
|
|||||||
sku: ChoiceItem;
|
sku: ChoiceItem;
|
||||||
|
|
||||||
@Values({
|
@Values({
|
||||||
labelTKey: "Number of instances",
|
labelTKey: "NumberOfInstances",
|
||||||
min: getInstancesMin,
|
min: getInstancesMin,
|
||||||
max: getInstancesMax,
|
max: getInstancesMax,
|
||||||
step: 1,
|
step: 1,
|
||||||
|
31
src/SelfServe/SqlX/SqlxTypes.ts
Normal file
31
src/SelfServe/SqlX/SqlxTypes.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export type SqlxServiceResource = {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
type: string,
|
||||||
|
properties: SqlxServiceProps
|
||||||
|
locations: SqlxServiceLocations
|
||||||
|
}
|
||||||
|
export type SqlxServiceProps = {
|
||||||
|
serviceType: string,
|
||||||
|
creationTime: string,
|
||||||
|
status: string,
|
||||||
|
instanceSize: string,
|
||||||
|
instanceCount: number,
|
||||||
|
sqlxEndPoint: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SqlxServiceLocations = {
|
||||||
|
location: string,
|
||||||
|
status: string,
|
||||||
|
sqlxEndpoint: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateDedicatedGatewayRequestParameters = {
|
||||||
|
properties: UpdateDedicatedGatewayRequestProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateDedicatedGatewayRequestProperties = {
|
||||||
|
instanceSize: string,
|
||||||
|
instanceCount: number,
|
||||||
|
serviceType: string
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user