forked from aws/aws-toolkit-vscode
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request aws#6153 from Bit-Quill/muaydin/docdb-polling-bug-fix
feat(toolkit): Add DocumentDB support
- Loading branch information
Showing
55 changed files
with
8,116 additions
and
1 deletion.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/*! | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { Commands } from '../shared' | ||
import { ExtContext } from '../shared/extensions' | ||
import { DBResourceNode } from './explorer/dbResourceNode' | ||
import { DocumentDBNode } from './explorer/docdbNode' | ||
import { DBClusterNode } from './explorer/dbClusterNode' | ||
import { DBInstanceNode } from './explorer/dbInstanceNode' | ||
import { addRegion } from './commands/addRegion' | ||
import { createCluster } from './commands/createCluster' | ||
import { deleteCluster } from './commands/deleteCluster' | ||
import { renameCluster } from './commands/renameCluster' | ||
import { startCluster } from './commands/startCluster' | ||
import { stopCluster } from './commands/stopCluster' | ||
import { createInstance } from './commands/createInstance' | ||
import { deleteInstance } from './commands/deleteInstance' | ||
import { modifyInstance } from './commands/modifyInstance' | ||
import { rebootInstance } from './commands/rebootInstance' | ||
import { renameInstance } from './commands/renameInstance' | ||
import { addTag, listTags, removeTag } from './commands/tagCommands' | ||
import { Uri } from 'vscode' | ||
import { openUrl } from '../shared/utilities/vsCodeUtils' | ||
import { getLogger } from '../shared/logger' | ||
|
||
/** | ||
* A utility function to automatically invoke trackChanges after a command. | ||
*/ | ||
|
||
function withTrackChanges<T extends DBResourceNode>( | ||
command: (node: T) => Promise<void>, | ||
commandName: string = 'UnnamedCommand' | ||
): (node: T) => Promise<void> { | ||
return async (node: T) => { | ||
const arn = node.arn || 'UnknownARN' | ||
const startTime = new Date().toISOString() | ||
|
||
getLogger().info( | ||
`[${startTime}] Executing command "${commandName}" for resource with ARN: ${arn}. Tracking changes will be invoked post-execution.` | ||
) | ||
|
||
await command(node) | ||
|
||
const endTime = new Date().toISOString() | ||
getLogger().info( | ||
`[${endTime}] Successfully executed command "${commandName}" for resource with ARN: ${arn}. Invoking trackChanges now.` | ||
) | ||
|
||
await node.trackChangesWithWaitProcessingStatus() | ||
} | ||
} | ||
|
||
/** | ||
* Activates DocumentDB components. | ||
*/ | ||
export async function activate(ctx: ExtContext): Promise<void> { | ||
ctx.extensionContext.subscriptions.push( | ||
Commands.register('aws.docdb.createCluster', async (node?: DocumentDBNode) => { | ||
await createCluster(node) | ||
}), | ||
|
||
Commands.register('aws.docdb.deleteCluster', withTrackChanges<DBClusterNode>(deleteCluster, 'deleteCluster')), | ||
|
||
Commands.register('aws.docdb.renameCluster', withTrackChanges<DBClusterNode>(renameCluster, 'renameCluster')), | ||
|
||
Commands.register('aws.docdb.startCluster', withTrackChanges<DBClusterNode>(startCluster, 'startCluster')), | ||
|
||
Commands.register('aws.docdb.stopCluster', withTrackChanges<DBClusterNode>(stopCluster, 'stopCluster')), | ||
|
||
Commands.register('aws.docdb.addRegion', withTrackChanges<DBClusterNode>(addRegion, 'addRegion')), | ||
|
||
Commands.register( | ||
'aws.docdb.createInstance', | ||
withTrackChanges<DBClusterNode>(createInstance, 'createInstance') | ||
), | ||
|
||
Commands.register( | ||
'aws.docdb.deleteInstance', | ||
withTrackChanges<DBInstanceNode>(deleteInstance, 'deleteInstance') | ||
), | ||
|
||
Commands.register( | ||
'aws.docdb.modifyInstance', | ||
withTrackChanges<DBInstanceNode>(modifyInstance, 'modifyInstance') | ||
), | ||
|
||
Commands.register( | ||
'aws.docdb.rebootInstance', | ||
withTrackChanges<DBInstanceNode>(rebootInstance, 'rebootInstance') | ||
), | ||
|
||
Commands.register( | ||
'aws.docdb.renameInstance', | ||
withTrackChanges<DBInstanceNode>(renameInstance, 'renameInstance') | ||
), | ||
|
||
Commands.register('aws.docdb.listTags', async (node: DBResourceNode) => { | ||
await listTags(node) | ||
}), | ||
|
||
Commands.register('aws.docdb.addTag', async (node: DBResourceNode) => { | ||
await addTag(node) | ||
}), | ||
|
||
Commands.register('aws.docdb.removeTag', async (node: DBResourceNode) => { | ||
await removeTag(node) | ||
}), | ||
|
||
Commands.register('aws.docdb.viewConsole', async (node?: DBResourceNode) => { | ||
await node?.openInBrowser() | ||
}), | ||
|
||
Commands.register('aws.docdb.viewDocs', async () => { | ||
await openUrl( | ||
Uri.parse('https://docs.aws.amazon.com/documentdb/latest/developerguide/get-started-guide.html') | ||
) | ||
}), | ||
|
||
Commands.register('aws.docdb.copyEndpoint', async (node?: DBResourceNode) => { | ||
await node?.copyEndpoint() | ||
}) | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
/*! | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import * as vscode from 'vscode' | ||
import { getLogger } from '../../shared/logger' | ||
import { telemetry } from '../../shared/telemetry' | ||
import { localize } from '../../shared/utilities/vsCodeUtils' | ||
import { DBClusterNode } from '../explorer/dbClusterNode' | ||
import { DBGlobalClusterNode } from '../explorer/dbGlobalClusterNode' | ||
import { DefaultDocumentDBClient } from '../../shared/clients/docdbClient' | ||
import { ToolkitError } from '../../shared' | ||
import { showViewLogsMessage } from '../../shared/utilities/messages' | ||
import { isValidResponse } from '../../shared/wizards/wizard' | ||
import { CancellationError } from '../../shared/utilities/timeoutUtils' | ||
import { CreateGlobalClusterWizard } from '../wizards/createGlobalClusterWizard' | ||
import { CreateDBClusterMessage } from '@aws-sdk/client-docdb' | ||
import { createInstancesForCluster } from './createCluster' | ||
import { isSupportedGlobalInstanceClass } from '../utils' | ||
|
||
export async function addRegion(node: DBClusterNode | DBGlobalClusterNode): Promise<void> { | ||
if (!node) { | ||
throw new ToolkitError('No node specified for AddRegion') | ||
} | ||
|
||
return telemetry.docdb_addRegion.run(async () => { | ||
let globalClusterName = undefined | ||
|
||
if (node.cluster.StorageEncrypted) { | ||
void vscode.window.showErrorMessage('Encrypted clusters are not supported') | ||
return | ||
} | ||
|
||
if (node instanceof DBClusterNode) { | ||
if (node.clusterRole !== 'regional') { | ||
void vscode.window.showErrorMessage('Only regional clusters are supported') | ||
return | ||
} | ||
|
||
if (node.cluster.DBClusterMembers?.length === 0) { | ||
void vscode.window.showErrorMessage( | ||
localize( | ||
'AWS.docdb.addRegion.noInstances', | ||
'Cluster must have at least one instance to add a region' | ||
) | ||
) | ||
throw new ToolkitError('Cluster must have at least one instance to add a region', { cancelled: true }) | ||
} | ||
|
||
const unsupportedInstanceFound = node.instances.find( | ||
(instance) => !isSupportedGlobalInstanceClass(instance.DBInstanceClass!) | ||
) | ||
|
||
if (unsupportedInstanceFound) { | ||
void vscode.window.showErrorMessage( | ||
localize( | ||
'AWS.docdb.addRegion.unsupportedInstanceClass', | ||
'Instance class {0} not supported for global cluster. Upgrade the instances then try again.', | ||
unsupportedInstanceFound.DBInstanceClass | ||
) | ||
) | ||
throw new ToolkitError('Instance class not supported for global cluster', { | ||
cancelled: true, | ||
code: 'docdbInstanceClassNotSupported', | ||
}) | ||
} | ||
} else { | ||
globalClusterName = node.cluster.GlobalClusterIdentifier | ||
|
||
if (node.cluster.GlobalClusterMembers!.length > 4) { | ||
void vscode.window.showErrorMessage( | ||
localize('AWS.docdb.addRegion.maxRegions', 'Global clusters can have a maximum of 5 regions') | ||
) | ||
throw new ToolkitError('Global clusters can have a maximum of 5 regions', { | ||
cancelled: true, | ||
code: 'docdbMaxRegionsInUse', | ||
}) | ||
} | ||
} | ||
|
||
if (!node.isAvailable) { | ||
void vscode.window.showErrorMessage(localize('AWS.docdb.clusterStopped', 'Cluster must be running')) | ||
throw new ToolkitError('Cluster not available', { cancelled: true, code: 'docdbClusterStopped' }) | ||
} | ||
|
||
const wizard = new CreateGlobalClusterWizard(node.regionCode, node.cluster.EngineVersion, node.client, { | ||
initState: { GlobalClusterName: globalClusterName }, | ||
}) | ||
const response = await wizard.run() | ||
|
||
if (!isValidResponse(response)) { | ||
throw new CancellationError('user') | ||
} | ||
|
||
const regionCode = response.RegionCode | ||
let input: CreateDBClusterMessage | ||
let clusterName = response.GlobalClusterName | ||
|
||
try { | ||
if (node instanceof DBClusterNode) { | ||
// Create new global cluster from regional cluster | ||
const primaryCluster = node.cluster | ||
|
||
getLogger().info(`docdb: Creating global cluster: ${clusterName}`) | ||
const globalCluster = await node.client.createGlobalCluster({ | ||
GlobalClusterIdentifier: response.GlobalClusterName, | ||
SourceDBClusterIdentifier: primaryCluster.DBClusterArn, | ||
}) | ||
|
||
input = { | ||
GlobalClusterIdentifier: globalCluster?.GlobalClusterIdentifier, | ||
DBClusterIdentifier: response.Cluster.DBClusterIdentifier, | ||
DeletionProtection: primaryCluster.DeletionProtection, | ||
Engine: primaryCluster.Engine, | ||
EngineVersion: primaryCluster.EngineVersion, | ||
StorageType: primaryCluster.StorageType, | ||
StorageEncrypted: globalCluster?.StorageEncrypted, | ||
} | ||
} else { | ||
// Add secondary cluster to global cluster | ||
const globalCluster = node.cluster | ||
|
||
input = { | ||
GlobalClusterIdentifier: globalClusterName, | ||
DBClusterIdentifier: response.Cluster.DBClusterIdentifier, | ||
DeletionProtection: globalCluster.DeletionProtection, | ||
Engine: globalCluster.Engine, | ||
EngineVersion: globalCluster.EngineVersion, | ||
StorageEncrypted: globalCluster.StorageEncrypted, | ||
} | ||
} | ||
|
||
clusterName = response.Cluster.DBClusterIdentifier | ||
getLogger().info(`docdb: Creating secondary cluster: ${clusterName} in region ${regionCode}`) | ||
|
||
const client = DefaultDocumentDBClient.create(regionCode) | ||
const newCluster = await client.createCluster(input) | ||
|
||
if (response.Cluster.DBInstanceCount) { | ||
await createInstancesForCluster( | ||
client, | ||
clusterName, | ||
response.Cluster.DBInstanceClass, | ||
response.Cluster.DBInstanceCount | ||
) | ||
} | ||
|
||
getLogger().info('docdb: Created cluster: %O', newCluster) | ||
void vscode.window.showInformationMessage(localize('AWS.docdb.addRegion.success', 'Region added')) | ||
|
||
if (node instanceof DBClusterNode) { | ||
node?.parent.refresh() | ||
} else { | ||
node?.refresh() | ||
} | ||
} catch (e) { | ||
getLogger().error(`docdb: Failed to create cluster ${clusterName}: %s`, e) | ||
void showViewLogsMessage( | ||
localize('AWS.docdb.createCluster.error', 'Failed to create cluster: {0}', clusterName) | ||
) | ||
throw ToolkitError.chain(e, `Failed to create cluster ${clusterName}`) | ||
} | ||
}) | ||
} |
Oops, something went wrong.