From aa681f0318d015f1529feb194d6673b0ed306a70 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Thu, 11 May 2023 23:27:57 -0700 Subject: [PATCH 01/10] Add aws rds fields to databases responses --- .../src/services/databases/databases.test.ts | 27 +++++++++++++++++++ .../src/services/databases/makeDatabase.ts | 13 ++++++++- .../teleport/src/services/databases/types.ts | 5 ++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/web/packages/teleport/src/services/databases/databases.test.ts b/web/packages/teleport/src/services/databases/databases.test.ts index 333dd54ddca63..eb08c2ce36f79 100644 --- a/web/packages/teleport/src/services/databases/databases.test.ts +++ b/web/packages/teleport/src/services/databases/databases.test.ts @@ -40,6 +40,19 @@ test('correct formatting of database fetch response', async () => { { name: 'cluster', value: 'root' }, { name: 'env', value: 'aws' }, ], + aws: { + rds: { + resourceId: 'resource-id', + }, + }, + }, + { + name: 'self-hosted', + type: 'Self-hosted PostgreSQL', + protocol: 'postgres', + names: [], + users: [], + labels: [], }, ], startKey: mockResponse.startKey, @@ -150,6 +163,7 @@ test('null array fields in database services fetch response', async () => { const mockResponse = { items: [ + // aws rds { name: 'aurora', desc: 'PostgreSQL 11.6: AWS Aurora', @@ -160,6 +174,19 @@ const mockResponse = { { name: 'cluster', value: 'root' }, { name: 'env', value: 'aws' }, ], + aws: { + rds: { + resource_id: 'resource-id', + }, + }, + }, + // non-aws self-hosted + { + name: 'self-hosted', + type: 'self-hosted', + protocol: 'postgres', + uri: 'localhost:5432', + labels: [], }, ], startKey: 'mockKey', diff --git a/web/packages/teleport/src/services/databases/makeDatabase.ts b/web/packages/teleport/src/services/databases/makeDatabase.ts index 135d2c5970aa2..4597afc3eb434 100644 --- a/web/packages/teleport/src/services/databases/makeDatabase.ts +++ b/web/packages/teleport/src/services/databases/makeDatabase.ts @@ -19,10 +19,20 @@ import { formatDatabaseInfo } from 'shared/services/databases'; import { Database, DatabaseService } from './types'; export function makeDatabase(json: any): Database { - const { name, desc, protocol, type } = json; + const { name, desc, protocol, type, aws } = json; const labels = json.labels || []; + // Only setting RDS fields for now. + let rds; + if (aws && aws.rds) { + rds = { + rds: { + resourceId: aws.rds.resource_id, + }, + }; + } + return { name, description: desc, @@ -32,6 +42,7 @@ export function makeDatabase(json: any): Database { names: json.database_names || [], users: json.database_users || [], hostname: json.hostname, + aws: rds, }; } diff --git a/web/packages/teleport/src/services/databases/types.ts b/web/packages/teleport/src/services/databases/types.ts index c7e6e8490c299..469927a1559c4 100644 --- a/web/packages/teleport/src/services/databases/types.ts +++ b/web/packages/teleport/src/services/databases/types.ts @@ -20,6 +20,10 @@ import { AgentLabel } from 'teleport/services/agents'; import { RdsEngine } from '../integrations'; +export type Aws = { + rds?: { resourceId: string }; +}; + export interface Database { name: string; description: string; @@ -29,6 +33,7 @@ export interface Database { names?: string[]; users?: string[]; hostname: string; + aws?: Aws; } export type DatabasesResponse = { From bf8a0b2ed9982fc3d26cba413f9f31ed37afedc4 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Thu, 11 May 2023 23:28:52 -0700 Subject: [PATCH 02/10] Type ApiError response field --- .../src/services/api/{parseError.js => parseError.ts} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename web/packages/teleport/src/services/api/{parseError.js => parseError.ts} (86%) diff --git a/web/packages/teleport/src/services/api/parseError.js b/web/packages/teleport/src/services/api/parseError.ts similarity index 86% rename from web/packages/teleport/src/services/api/parseError.js rename to web/packages/teleport/src/services/api/parseError.ts index 697caa30d682b..a6c5273d0cfb9 100644 --- a/web/packages/teleport/src/services/api/parseError.js +++ b/web/packages/teleport/src/services/api/parseError.ts @@ -12,7 +12,9 @@ export default function parseError(json) { } export class ApiError extends Error { - constructor(message, response) { + response: Response; + + constructor(message, response: Response) { message = message || 'Unknown error'; super(message); this.response = response; From cca80a38e3ad38aee6c880460941b56a17b7d0bf Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Thu, 11 May 2023 23:29:38 -0700 Subject: [PATCH 03/10] Add utility func for returning err msg from Error --- web/packages/shared/utils/errorType.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/web/packages/shared/utils/errorType.ts b/web/packages/shared/utils/errorType.ts index 5a07e0208ee91..2d334e2e64c8f 100644 --- a/web/packages/shared/utils/errorType.ts +++ b/web/packages/shared/utils/errorType.ts @@ -19,3 +19,14 @@ import { privateKeyEnablingPolicies } from 'shared/services'; export function isPrivateKeyRequiredError(err: Error) { return privateKeyEnablingPolicies.some(p => err.message.includes(p)); } + +// getErrMessage first checks if the error is of type Error +// before attempting to access the error message field. +// Used with try catch blocks, where the error caught +// may not necessary be of type Error. +export function getErrMessage(err) { + let message = 'something went wrong'; + if (err instanceof Error) message = err.message; + + return message; +} From a04976a2aff7ed04645a0a854d9c452ade6b8710 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Thu, 11 May 2023 23:44:21 -0700 Subject: [PATCH 04/10] Implement checking for existing db servers when fetching rds dbs --- .../EnrollRdsDatabase.story.tsx | 7 +- .../EnrollRdsDatabase/EnrollRdsDatabase.tsx | 99 ++++++++++++++----- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx index 92cc7a7d4599e..d309298a1ed76 100644 --- a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx +++ b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.story.tsx @@ -16,10 +16,9 @@ import React from 'react'; -import { AwsRdsDatabase } from 'teleport/services/integrations'; - import { AwsRegionSelector } from './AwsRegionSelector'; import { DatabaseList } from './RdsDatabaseList'; +import { CheckedAwsRdsDatabase } from './EnrollRdsDatabase'; export default { title: 'Teleport/Discover/Database/EnrollRds', @@ -85,7 +84,7 @@ export const RdsDatabaseListLoading = () => ( /> ); -const fixtures: AwsRdsDatabase[] = [ +const fixtures: CheckedAwsRdsDatabase[] = [ { name: 'postgres-name', engine: 'postgres', @@ -103,6 +102,7 @@ const fixtures: AwsRdsDatabase[] = [ status: 'available', accountId: '', resourceId: '', + dbServerExists: true, }, { name: 'alpaca', @@ -137,6 +137,7 @@ const fixtures: AwsRdsDatabase[] = [ status: 'Unknown' as any, accountId: '', resourceId: '', + dbServerExists: true, }, { name: 'llama', diff --git a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx index b7ed9612bc2dd..70c5f2d5cf013 100644 --- a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx +++ b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx @@ -20,16 +20,17 @@ import { FetchStatus } from 'design/DataTable/types'; import { Danger } from 'design/Alert'; import useAttempt from 'shared/hooks/useAttemptNext'; +import { getErrMessage } from 'shared/utils/errorType'; import { DbMeta, useDiscover } from 'teleport/Discover/useDiscover'; import { AwsRdsDatabase, - ListAwsRdsDatabaseResponse, RdsEngineIdentifier, Regions, integrationService, } from 'teleport/services/integrations'; import { DatabaseEngine } from 'teleport/Discover/SelectResource'; +import { Database } from 'teleport/services/databases'; import { ActionButtons, Header } from '../../Shared'; @@ -40,7 +41,7 @@ import { AwsRegionSelector } from './AwsRegionSelector'; import { DatabaseList } from './RdsDatabaseList'; type TableData = { - items: ListAwsRdsDatabaseResponse['databases']; + items: CheckedAwsRdsDatabase[]; fetchStatus: FetchStatus; startKey?: string; currRegion?: Regions; @@ -52,6 +53,14 @@ const emptyTableData: TableData = { startKey: '', }; +// CheckedAwsRdsDatabase is a type to describe that a +// AwsRdsDatabase has been checked (by its resource id) +// with the backend whether or not a database server already +// exists for it. +export type CheckedAwsRdsDatabase = AwsRdsDatabase & { + dbServerExists?: boolean; +}; + export function EnrollRdsDatabase() { const { createdDb, @@ -60,6 +69,7 @@ export function EnrollRdsDatabase() { attempt: registerAttempt, clearAttempt: clearRegisterAttempt, nextStep, + fetchDatabaseServers, } = useCreateDatabase(); const { agentMeta, resourceSpec, emitErrorEvent } = useDiscover(); @@ -71,7 +81,7 @@ export function EnrollRdsDatabase() { startKey: '', fetchStatus: 'disabled', }); - const [selectedDb, setSelectedDb] = useState(); + const [selectedDb, setSelectedDb] = useState(); function fetchDatabasesWithNewRegion(region: Regions) { // Clear table when fetching with new region. @@ -87,36 +97,73 @@ export function EnrollRdsDatabase() { fetchDatabases({ ...tableData, startKey: '', items: [] }); } - function fetchDatabases(data: TableData) { + async function fetchDatabases(data: TableData) { const integrationName = (agentMeta as DbMeta).integrationName; setTableData({ ...data, fetchStatus: 'loading' }); setFetchDbAttempt({ status: 'processing' }); - integrationService - .fetchAwsRdsDatabases( - integrationName, - getRdsEngineIdentifier(resourceSpec.dbMeta?.engine), - { - region: data.currRegion, - nextToken: data.startKey, + try { + const { databases: fetchedRdsDbs, nextToken } = + await integrationService.fetchAwsRdsDatabases( + integrationName, + getRdsEngineIdentifier(resourceSpec.dbMeta?.engine), + { + region: data.currRegion, + nextToken: data.startKey, + } + ); + + // Check if fetched rds databases have a database + // server for it, to prevent user from enrolling + // the same db and getting an error from it. + + // Build the predicate string that will query for + // all the fetched rds dbs by its resource ids. + const resourceIds: string[] = fetchedRdsDbs.map( + d => `resource.spec.aws.rds.resource_id == "${d.resourceId}"` + ); + const query = resourceIds.join(' || '); + const { agents: fetchedDbServers } = await fetchDatabaseServers( + query, + // Adding +5 for the corner case possiblity where user + // registered the same rds dbs but under a different name. + // This was possible before the check for existing db servers + // existed. + fetchedRdsDbs.length + 5 // limit + ); + + const dbServerLookupByResourceId: Record = {}; + fetchedDbServers.forEach( + d => (dbServerLookupByResourceId[d.aws.rds.resourceId] = d) + ); + + // Check for db server matches. + const checkedRdsDbs: CheckedAwsRdsDatabase[] = fetchedRdsDbs.map(rds => { + const dbServer = dbServerLookupByResourceId[rds.resourceId]; + if (dbServer) { + return { + ...rds, + dbServerExists: true, + }; } - ) - .then(resp => { - setFetchDbAttempt({ status: 'success' }); - setTableData({ - currRegion: data.currRegion, - startKey: resp.nextToken, - fetchStatus: resp.nextToken ? '' : 'disabled', - // concat each page fetch. - items: [...data.items, ...resp.databases], - }); - }) - .catch((err: Error) => { - setFetchDbAttempt({ status: 'failed', statusText: err.message }); - setTableData(data); // fallback to previous data - emitErrorEvent(`failed to fetch aws rds list: ${err.message}`); + return rds; }); + + setFetchDbAttempt({ status: 'success' }); + setTableData({ + currRegion: data.currRegion, + startKey: nextToken, + fetchStatus: nextToken ? '' : 'disabled', + // concat each page fetch. + items: [...data.items, ...checkedRdsDbs], + }); + } catch (err) { + const errMsg = getErrMessage(err); + setFetchDbAttempt({ status: 'failed', statusText: errMsg }); + setTableData(data); // fallback to previous data + emitErrorEvent(`database fetch error: ${errMsg}`); + } } function clear() { From 35a3b022e1fcc73bd1a89c5cb29b574f9faf6c8f Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Fri, 12 May 2023 01:52:04 -0700 Subject: [PATCH 05/10] Disable selecting table row when db servers exists --- .../EnrollRdsDatabase/RdsDatabaseList.tsx | 82 +++++++++++++------ 1 file changed, 57 insertions(+), 25 deletions(-) diff --git a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/RdsDatabaseList.tsx b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/RdsDatabaseList.tsx index 40a8666f3ef02..bc5d698e3f0b4 100644 --- a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/RdsDatabaseList.tsx +++ b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/RdsDatabaseList.tsx @@ -17,21 +17,19 @@ import React from 'react'; import styled from 'styled-components'; import { Flex, Box, Label as Pill } from 'design'; -import Table, { Cell } from 'design/DataTable'; +import Table, { Cell as TableCell } from 'design/DataTable'; import { FetchStatus } from 'design/DataTable/types'; -import { - AwsRdsDatabase, - ListAwsRdsDatabaseResponse, -} from 'teleport/services/integrations'; import { Label } from 'teleport/types'; +import { CheckedAwsRdsDatabase } from './EnrollRdsDatabase'; + type Props = { - items: ListAwsRdsDatabaseResponse['databases']; + items: CheckedAwsRdsDatabase[]; fetchStatus: FetchStatus; fetchNextPage(): void; - onSelectDatabase(item: AwsRdsDatabase): void; - selectedDatabase?: AwsRdsDatabase; + onSelectDatabase(item: CheckedAwsRdsDatabase): void; + selectedDatabase?: CheckedAwsRdsDatabase; }; export const DatabaseList = ({ @@ -55,9 +53,10 @@ export const DatabaseList = ({ return ( ); }, @@ -65,17 +64,25 @@ export const DatabaseList = ({ { key: 'name', headerText: 'Name', - render: ({ name }) => {name}, + render: ({ name, dbServerExists }) => ( + {name} + ), }, { key: 'engine', headerText: 'Engine', - render: ({ engine }) => {engine}, + render: ({ engine, dbServerExists }) => ( + {engine} + ), }, { key: 'labels', headerText: 'Labels', - render: ({ labels }) => , + render: ({ labels, dbServerExists }) => ( + + + + ), }, { key: 'status', @@ -92,11 +99,11 @@ export const DatabaseList = ({ ); }; -const StatusCell = ({ item }: { item: AwsRdsDatabase }) => { +const StatusCell = ({ item }: { item: CheckedAwsRdsDatabase }) => { const status = getStatus(item); return ( - + {item.status} @@ -109,25 +116,32 @@ function RadioCell({ item, isChecked, onChange, + disabled, }: { - item: AwsRdsDatabase; + item: CheckedAwsRdsDatabase; isChecked: boolean; - onChange(selectedItem: AwsRdsDatabase): void; + onChange(selectedItem: CheckedAwsRdsDatabase): void; + disabled: boolean; }) { return ( - + props.theme.space[2]}px 0 0; accent-color: ${props => props.theme.colors.brand.accent}; cursor: pointer; + + &:disabled { + cursor: not-allowed; + } `} type="radio" name={item.name} checked={isChecked} onChange={() => onChange(item)} value={item.name} + disabled={disabled} /> @@ -140,7 +154,7 @@ enum Status { Error, } -function getStatus(item: AwsRdsDatabase) { +function getStatus(item: CheckedAwsRdsDatabase) { switch (item.status) { case 'available': return Status.Success; @@ -172,7 +186,7 @@ const StatusLight = styled(Box)` }}; `; -const LabelCell = ({ labels }: { labels: Label[] }) => { +const Labels = ({ labels }: { labels: Label[] }) => { const $labels = labels.map((label, index) => { const labelText = `${label.name}: ${label.value}`; @@ -183,11 +197,7 @@ const LabelCell = ({ labels }: { labels: Label[] }) => { ); }); - return ( - - {$labels} - - ); + return {$labels}; }; // labelMatcher allows user to client search by labels in the format @@ -197,7 +207,7 @@ const LabelCell = ({ labels }: { labels: Label[] }) => { function labelMatcher( targetValue: any, searchValue: string, - propName: keyof AwsRdsDatabase & string + propName: keyof CheckedAwsRdsDatabase & string ) { if (propName === 'labels') { return targetValue.some((label: Label) => { @@ -211,3 +221,25 @@ function labelMatcher( }); } } + +const Cell: React.FC<{ disabled: boolean; width?: string }> = ({ + disabled, + width, + children, +}) => { + return ( + + {children} + + ); +}; From de442d449e706b25d20fd3badeb718928cfba265 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Fri, 12 May 2023 02:04:24 -0700 Subject: [PATCH 06/10] Provide a more accurate actionable steps in case of dup err --- .../CreateDatabase/CreateDatabase.story.tsx | 1 + .../CreateDatabase/CreateDatabaseDialog.tsx | 4 +- .../CreateDatabase/useCreateDatabase.ts | 73 ++++++++++++++++++- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx index 636d20e50aa6f..f917d194cea72 100644 --- a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx +++ b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabase.story.tsx @@ -68,6 +68,7 @@ const props: State = { attempt: { status: '' }, clearAttempt: () => null, registerDatabase: () => null, + fetchDatabaseServers: () => null, canCreateDatabase: true, pollTimeout: Date.now() + 30000, dbEngine: DatabaseEngine.Postgres, diff --git a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx index 547adb2a5c858..8df99e4c72b02 100644 --- a/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx +++ b/web/packages/teleport/src/Discover/Database/CreateDatabase/CreateDatabaseDialog.tsx @@ -52,7 +52,7 @@ export function CreateDatabaseDialog({ <> - Register Failed: {attempt.statusText} + {attempt.statusText} @@ -104,7 +104,7 @@ export function CreateDatabaseDialog({ return ( Date: Fri, 12 May 2023 02:04:37 -0700 Subject: [PATCH 07/10] Fix blank id on resuming discover flow --- web/packages/teleport/src/Discover/useDiscover.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/packages/teleport/src/Discover/useDiscover.tsx b/web/packages/teleport/src/Discover/useDiscover.tsx index ec7db069ef4e6..754b01c10d7d8 100644 --- a/web/packages/teleport/src/Discover/useDiscover.tsx +++ b/web/packages/teleport/src/Discover/useDiscover.tsx @@ -63,6 +63,7 @@ type EventState = { }; type CustomEventInput = { + id?: string; eventName?: DiscoverEvent; eventResourceName?: DiscoverEventResource; autoDiscoverResourcesCount?: number; @@ -116,7 +117,7 @@ export function DiscoverProvider( userEventService.captureDiscoverEvent({ event: custom?.eventName || currEventName, eventData: { - id, + id: id || custom.id, resource: custom?.eventResourceName || resourceSpec?.event, autoDiscoverResourcesCount: custom?.autoDiscoverResourcesCount, selectedResourcesCount: custom?.selectedResourcesCount, @@ -213,6 +214,7 @@ export function DiscoverProvider( { eventName: discover.eventState.currEventName, eventResourceName: discover.resourceSpec.event, + id: discover.eventState.id, } ); } From 83b362c155b5aa48d696c779a5857ff31f2d38c9 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Mon, 15 May 2023 19:15:07 -0700 Subject: [PATCH 08/10] Address code review --- web/packages/shared/utils/errorType.ts | 2 +- .../CreateDatabase/useCreateDatabase.ts | 39 +++++++------------ 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/web/packages/shared/utils/errorType.ts b/web/packages/shared/utils/errorType.ts index 2d334e2e64c8f..79e7aab24bc74 100644 --- a/web/packages/shared/utils/errorType.ts +++ b/web/packages/shared/utils/errorType.ts @@ -24,7 +24,7 @@ export function isPrivateKeyRequiredError(err: Error) { // before attempting to access the error message field. // Used with try catch blocks, where the error caught // may not necessary be of type Error. -export function getErrMessage(err) { +export function getErrMessage(err: unknown) { let message = 'something went wrong'; if (err instanceof Error) message = err.message; diff --git a/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.ts b/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.ts index 6014a0dfbb063..dd31f215e3732 100644 --- a/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.ts +++ b/web/packages/teleport/src/Discover/Database/CreateDatabase/useCreateDatabase.ts @@ -22,6 +22,7 @@ import useTeleport from 'teleport/useTeleport'; import { useDiscover } from 'teleport/Discover/useDiscover'; import { usePoll } from 'teleport/Discover/Shared/usePoll'; import { compareByString } from 'teleport/lib/util'; +import { ApiError } from 'teleport/services/api/parseError'; import { matchLabels } from '../util'; @@ -32,7 +33,6 @@ import type { } from 'teleport/services/databases'; import type { AgentLabel } from 'teleport/services/agents'; import type { DbMeta } from 'teleport/Discover/useDiscover'; -import { ApiError } from 'teleport/services/api/parseError'; export const WAITING_TIMEOUT = 30000; // 30 seconds @@ -158,14 +158,9 @@ export function useCreateDatabase() { } catch (err) { // Check if the error is a result of an existing database. if (err instanceof ApiError) { - if ( - err.response.status === 409 || - err.message.toLowerCase().includes('already exists') - ) { - return attemptDbServerQueryAndBuildErrMsg( - db.name, - Boolean(db.awsRds && db.awsRds.accountId) - ); + if (err.response.status === 409) { + const isAwsRds = Boolean(db.awsRds && db.awsRds.accountId); + return attemptDbServerQueryAndBuildErrMsg(db.name, isAwsRds); } } handleRequestError(err, 'failed to create database: '); @@ -224,32 +219,24 @@ export function useCreateDatabase() { isAwsRds = false ) { const preErrMsg = 'failed to register database: '; + const nonAwsMsg = `use a different name and try again`; + const awsMsg = `change (or define) the value of the \ + tag "teleport.dev/database_name" on the RDS instance and try again`; + try { await ctx.databaseService.fetchDatabase(clusterId, dbName); let message = `a database with the name "${dbName}" is already \ - a part of this cluster, `; - if (isAwsRds) { - message += `set "teleport.dev/database_name" tag on this RDS instance to `; - } - message += `use a different name and try again`; + a part of this cluster, ${isAwsRds ? awsMsg : nonAwsMsg}`; handleRequestError(new Error(message), preErrMsg); } catch (e) { // No database server were found for the database name. if (e instanceof ApiError) { - if ( - e.response.status === 404 || - e.message.toLowerCase().includes('not found') - ) { + if (e.response.status === 404) { let message = `a database with the name "${dbName}" already exists \ but there are no database servers for it, you can remove this \ - database using the command, “tctl rm db/${dbName}”`; - - if (isAwsRds) { - message += `, or set a "teleport.dev/database_name" tag on this RDS \ - instance to use a different name and try again`; - } else { - message += `, or use a different name and try again`; - } + database using the command, “tctl rm db/${dbName}”, or ${ + isAwsRds ? awsMsg : nonAwsMsg + }`; handleRequestError(new Error(message), preErrMsg); } return; From 8433b7ce3d32be942f394306916d63432ce54770 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Tue, 16 May 2023 11:46:19 -0700 Subject: [PATCH 09/10] Fix lint: missing license --- .../teleport/src/services/api/parseError.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/web/packages/teleport/src/services/api/parseError.ts b/web/packages/teleport/src/services/api/parseError.ts index a6c5273d0cfb9..fd922ef3b156e 100644 --- a/web/packages/teleport/src/services/api/parseError.ts +++ b/web/packages/teleport/src/services/api/parseError.ts @@ -1,3 +1,19 @@ +/** + * Copyright 2023 Gravitational, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + export default function parseError(json) { let msg = ''; From 824c5743931b4bc3e337480faf52b0701dd97e7d Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Tue, 16 May 2023 12:01:55 -0700 Subject: [PATCH 10/10] Remove increasing limit +5, corner case handling seems unnecessary --- .../Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx index 70c5f2d5cf013..d9a1aceae14fe 100644 --- a/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx +++ b/web/packages/teleport/src/Discover/Database/EnrollRdsDatabase/EnrollRdsDatabase.tsx @@ -126,11 +126,7 @@ export function EnrollRdsDatabase() { const query = resourceIds.join(' || '); const { agents: fetchedDbServers } = await fetchDatabaseServers( query, - // Adding +5 for the corner case possiblity where user - // registered the same rds dbs but under a different name. - // This was possible before the check for existing db servers - // existed. - fetchedRdsDbs.length + 5 // limit + fetchedRdsDbs.length // limit ); const dbServerLookupByResourceId: Record = {};