diff --git a/packages/api-v4/src/databases/types.ts b/packages/api-v4/src/databases/types.ts index 971a59a6869..9974bd22d08 100644 --- a/packages/api-v4/src/databases/types.ts +++ b/packages/api-v4/src/databases/types.ts @@ -120,8 +120,6 @@ type MemberType = 'failover' | 'primary'; export interface DatabaseInstance { allow_list: string[]; cluster_size: ClusterSize; - /** @Deprecated replaced by `endpoints` property */ - connection_pool_port: null | number; connection_strings: ConnectionStrings[]; created: string; /** @Deprecated used by rdbms-legacy only, rdbms-default always encrypts */ diff --git a/packages/manager/.changeset/pr-13439-upcoming-features-1772132438864.md b/packages/manager/.changeset/pr-13439-upcoming-features-1772132438864.md new file mode 100644 index 00000000000..8e1c634a320 --- /dev/null +++ b/packages/manager/.changeset/pr-13439-upcoming-features-1772132438864.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Use new hostname endpoints in Service URIs and display public/private URIs for public VPCs ([#13439](https://github.com/linode/manager/pull/13439)) diff --git a/packages/manager/src/factories/databases.ts b/packages/manager/src/factories/databases.ts index 7e57944aede..6defd0cc837 100644 --- a/packages/manager/src/factories/databases.ts +++ b/packages/manager/src/factories/databases.ts @@ -161,8 +161,6 @@ export const databaseInstanceFactory = ? ([1, 3][i % 2] as ClusterSize) : ([1, 2, 3][i % 3] as ClusterSize) ), - connection_pool_port: - null /** @Deprecated replaced by `endpoints` property */, connection_strings: [], created: '2021-12-09T17:15:12', encrypted: false, @@ -203,9 +201,7 @@ export const databaseInstanceFactory = members: { '2.2.2.2': 'primary', }, - platform: Factory.each((i) => - adb10(i) ? 'rdbms-legacy' : 'rdbms-default' - ), + platform: 'rdbms-default', region: Factory.each((i) => possibleRegions[i % possibleRegions.length]), status: Factory.each((i) => possibleStatuses[i % possibleStatuses.length]), type: Factory.each((i) => possibleTypes[i % possibleTypes.length]), @@ -230,8 +226,6 @@ export const databaseInstanceFactory = export const databaseFactory = Factory.Sync.makeFactory({ allow_list: [...IPv4List], cluster_size: Factory.each(() => pickRandom([1, 3])), - connection_pool_port: - null /** @Deprecated replaced by `endpoints` property */, connection_strings: [ { driver: 'python', @@ -277,7 +271,7 @@ export const databaseFactory = Factory.Sync.makeFactory({ '2.2.2.2': 'primary', }, oldest_restore_time: '2024-09-15T17:15:12', - platform: Factory.each((i) => (adb10(i) ? 'rdbms-legacy' : 'rdbms-default')), + platform: 'rdbms-default', private_network: null, port: 3306, region: 'us-east', diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.test.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.test.tsx index d0f617f20e9..d592612de4d 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.test.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.test.tsx @@ -14,6 +14,23 @@ import { DatabaseConnectionPools } from './DatabaseConnectionPools'; const mockDatabase = databaseFactory.build({ platform: 'rdbms-default', private_network: null, + hosts: { + primary: 'db-mysql-primary-0.b.linodeb.net', + endpoints: [ + { + role: 'primary', + address: 'db-mysql-primary-0.b.linodeb.net', + port: 15847, + public_access: true, + }, + { + role: 'primary-connection-pool', + address: 'public-db-mysql-primary-0.b.linodeb.net', + port: 15848, + public_access: true, + }, + ], + }, engine: 'postgresql', id: 1, }); @@ -30,6 +47,7 @@ const mockConnectionPool = databaseConnectionPoolFactory.build({ const queryMocks = vi.hoisted(() => { return { useDatabaseConnectionPoolsQuery: vi.fn(), + useFlags: vi.fn().mockReturnValue({}), }; }); @@ -41,6 +59,14 @@ vi.mock('@linode/queries', async () => { }; }); +vi.mock('src/hooks/useFlags', () => { + const actual = vi.importActual('src/hooks/useFlags'); + return { + ...actual, + useFlags: queryMocks.useFlags, + }; +}); + describe('DatabaseConnectionPools Component', () => { beforeEach(() => { vi.resetAllMocks(); @@ -109,11 +135,14 @@ describe('DatabaseConnectionPools Component', () => { expect(errorStateText).toBeInTheDocument(); }); - it('should render service URI component if there are connection pools', () => { + it('should render service URI component if there are connection pools and hostnameEndpoints flag is true', () => { queryMocks.useDatabaseConnectionPoolsQuery.mockReturnValue({ data: makeResourcePage([mockConnectionPool]), isLoading: false, }); + queryMocks.useFlags.mockReturnValue({ + hostnameEndpoints: true, + }); renderWithTheme(); const serviceURIText = screen.getByText('Service URI'); diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.tsx index e1fb2238719..78893f1bb79 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseNetworking/DatabaseConnectionPools.tsx @@ -7,6 +7,7 @@ import { Stack, Typography, } from '@linode/ui'; +import Grid from '@mui/material/Grid'; import { useTheme } from '@mui/material/styles'; import { Pagination } from 'akamai-cds-react-components/Pagination'; import { @@ -28,6 +29,12 @@ import { CONNECTION_POOL_LABEL_CELL_STYLES, MANAGE_CONNECTION_POOLS_LEARN_MORE_LINK, } from 'src/features/Databases/constants'; +import { + StyledGridContainer, + StyledLabelTypography, + StyledValueGrid, +} from 'src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.style'; +import { useFlags } from 'src/hooks/useFlags'; import { usePaginationV2 } from 'src/hooks/usePaginationV2'; import { makeSettingsItemStyles } from '../../shared.styles'; @@ -47,6 +54,7 @@ interface Props { export const DatabaseConnectionPools = ({ database }: Props) => { const { classes } = makeSettingsItemStyles(); const theme = useTheme(); + const flags = useFlags(); const isDatabaseInactive = database.status !== 'active'; const [deletePoolLabelSelection, setDeletePoolLabelSelection] = @@ -80,6 +88,9 @@ export const DatabaseConnectionPools = ({ database }: Props) => { ); } + const hasVPC = Boolean(database?.private_network?.vpc_id); + const hasPublicVPC = hasVPC && database.private_network?.public_access; + return ( <>
@@ -110,9 +121,42 @@ export const DatabaseConnectionPools = ({ database }: Props) => { Add Pool
- {connectionPools && connectionPools.data.length > 0 && ( - - )} + {flags?.hostnameEndpoints && + connectionPools && + connectionPools.data.length > 0 && ( + + + + {hasPublicVPC ? 'Public Service URI' : 'Service URI'} + + + + + + {hasPublicVPC && ( + <> + + + Private Service URI + + + + + + + )} + + )}
{ connectionPools && connectionPools.data.length > 0; + const hasVPC = Boolean(database?.private_network?.vpc_id); + const hasPublicVPC = hasVPC && database.private_network?.public_access; + return ( @@ -47,7 +55,7 @@ export const DatabaseSummary = () => { > - {showPgBouncerConnectionDetails && ( + {flags.hostnameEndpoints && showPgBouncerConnectionDetails && ( { PgBouncer Connection Details - + + + + {hasPublicVPC ? 'Public Service URI' : 'Service URI'} + + + + + + {hasPublicVPC && ( + <> + + + Private Service URI + + + + + + + )} + )} diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryConnectionDetails.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryConnectionDetails.tsx index 378605b6578..4e99bfa1a9b 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryConnectionDetails.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryConnectionDetails.tsx @@ -117,17 +117,32 @@ export const DatabaseSummaryConnectionDetails = (props: Props) => { ); + const hasPublicVPC = hasVPC && database.private_network?.public_access; + const showServiceURIs = flags.hostnameEndpoints && flags.databasePgBouncer; + return ( <> Connection Details - {flags.databasePgBouncer && ( - + {showServiceURIs && ( + )} + {showServiceURIs && hasPublicVPC && ( + + + + )} {username} diff --git a/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.test.tsx b/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.test.tsx index b9379d57746..050d13a2f01 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.test.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.test.tsx @@ -8,19 +8,142 @@ import { renderWithTheme } from 'src/utilities/testHelpers'; import { ServiceURI } from './ServiceURI'; -const mockDatabase = databaseFactory.build({ - connection_pool_port: 100, - engine: 'postgresql', - id: 1, - platform: 'rdbms-default', - private_network: null, -}); - const mockCredentials = { password: 'password123', username: 'lnroot', }; +const DEFAULT_PRIMARY = 'db-postgres-default-primary.net'; +const DEFAULT_STANDBY = 'db-postgres-default-standby.net'; + +const PRIVATE_PRIMARY = `private-${DEFAULT_PRIMARY}`; +const PRIVATE_STANDBY = `private-${DEFAULT_STANDBY}`; + +const PRIMARY_PUBLIC_CONNECTION_POOL = + 'public-db-postgres-primary-connection-pool-0.b.linodeb.net'; +const PRIMARY_PRIVATE_CONNECTION_POOL = + 'private-db-postgres-primary-connection-pool-0.b.linodeb.net'; + +const databaseWithNoVPC = databaseFactory.build({ + engine: 'postgresql', + hosts: { + primary: DEFAULT_PRIMARY, + standby: DEFAULT_STANDBY, + endpoints: [ + { + role: 'primary', + address: DEFAULT_PRIMARY, + port: 3306, + public_access: true, + }, + { + role: 'primary-connection-pool', + address: PRIMARY_PUBLIC_CONNECTION_POOL, + port: 15848, + public_access: true, + }, + { + role: 'standby-connection-pool', + address: + 'public-replica-db-postgres-standby-connection-pool-0.b.linodeb.net', + port: 15848, + public_access: true, + }, + ], + }, + platform: 'rdbms-default', + private_network: null, // No VPC configured +}); + +const databaseWithPrivateVPC = databaseFactory.build({ + engine: 'postgresql', + hosts: { + primary: PRIVATE_PRIMARY, + standby: PRIVATE_STANDBY, + endpoints: [ + { + role: 'primary', + address: PRIVATE_PRIMARY, + port: 3306, + public_access: false, + }, + { + role: 'primary-connection-pool', + address: PRIMARY_PRIVATE_CONNECTION_POOL, + port: 15848, + public_access: false, + }, + { + role: 'standby-connection-pool', + address: + 'private-replica-db-postgres-standby-connection-pool-0.b.linodeb.net', + port: 15848, + public_access: false, + }, + ], + }, + platform: 'rdbms-default', + private_network: { + public_access: false, + subnet_id: 1, + vpc_id: 123, + }, +}); + +const databaseWithPublicVPC = databaseFactory.build({ + engine: 'postgresql', + hosts: { + primary: PRIVATE_PRIMARY, + standby: PRIVATE_STANDBY, + endpoints: [ + { + role: 'primary', + address: PRIVATE_PRIMARY, + port: 3306, + public_access: false, + }, + { + role: 'primary-connection-pool', + address: PRIMARY_PRIVATE_CONNECTION_POOL, + port: 15848, + public_access: false, + }, + { + role: 'standby-connection-pool', + address: + 'private-replica-db-postgres-standby-connection-pool-0.b.linodeb.net', + port: 15848, + public_access: false, + }, + { + role: 'primary', + address: DEFAULT_PRIMARY, + port: 3306, + public_access: true, + }, + { + role: 'primary-connection-pool', + address: PRIMARY_PUBLIC_CONNECTION_POOL, + port: 15848, + public_access: true, + }, + { + role: 'standby-connection-pool', + address: + 'public-replica-db-postgres-standby-connection-pool-0.b.linodeb.net', + port: 15848, + public_access: true, + }, + ], + }, + platform: 'rdbms-default', + private_network: { + public_access: true, + subnet_id: 1, + vpc_id: 123, + }, +}); + // Hoist query mocks const queryMocks = vi.hoisted(() => { return { @@ -41,8 +164,9 @@ describe('ServiceURI', () => { queryMocks.useDatabaseCredentialsQuery.mockReturnValue({ data: mockCredentials, }); + const { container } = renderWithTheme( - + ); const revealPasswordBtn = screen.getByRole('button', { @@ -52,7 +176,7 @@ describe('ServiceURI', () => { expect(revealPasswordBtn).toBeInTheDocument(); expect(serviceURIText).toBe( - `postgres://{click to reveal password}@db-mysql-primary-0.b.linodeb.net:100/{connection pool label}?sslmode=require` + `postgres://{click to reveal password}@${PRIMARY_PUBLIC_CONNECTION_POOL}:15848/{connection pool label}?sslmode=require` ); // eslint-disable-next-line testing-library/no-container @@ -65,7 +189,8 @@ describe('ServiceURI', () => { data: mockCredentials, refetch: vi.fn(), }); - renderWithTheme(); + + renderWithTheme(); const revealPasswordBtn = screen.getByRole('button', { name: '{click to reveal password}', @@ -75,7 +200,7 @@ describe('ServiceURI', () => { const serviceURIText = screen.getByTestId('service-uri').textContent; expect(revealPasswordBtn).not.toBeInTheDocument(); expect(serviceURIText).toBe( - `postgres://lnroot:password123@db-mysql-primary-0.b.linodeb.net:100/{connection pool label}?sslmode=require` + `postgres://lnroot:password123@${PRIMARY_PUBLIC_CONNECTION_POOL}:15848/{connection pool label}?sslmode=require` ); }); @@ -84,7 +209,7 @@ describe('ServiceURI', () => { error: new Error('Failed to fetch credentials'), }); - renderWithTheme(); + renderWithTheme(); const errorRetryBtn = screen.getByRole('button', { name: '{error. click to retry}', @@ -96,8 +221,9 @@ describe('ServiceURI', () => { queryMocks.useDatabaseCredentialsQuery.mockReturnValue({ data: mockCredentials, }); - const { container } = renderWithTheme( - + + renderWithTheme( + ); const revealPasswordBtn = screen.getByRole('button', { @@ -107,12 +233,8 @@ describe('ServiceURI', () => { expect(revealPasswordBtn).toBeInTheDocument(); expect(serviceURIText).toBe( - `postgres://{click to reveal password}@db-mysql-primary-0.b.linodeb.net:3306/defaultdb?sslmode=require` + `postgres://{click to reveal password}@${DEFAULT_PRIMARY}:3306/defaultdb?sslmode=require` ); - - // eslint-disable-next-line testing-library/no-container - const copyButton = container.querySelector('[data-qa-copy-btn]'); - expect(copyButton).toBeInTheDocument(); }); it('should reveal general service URI password after clicking reveal button', async () => { @@ -120,7 +242,9 @@ describe('ServiceURI', () => { data: mockCredentials, refetch: vi.fn(), }); - renderWithTheme(); + renderWithTheme( + + ); const revealPasswordBtn = screen.getByRole('button', { name: '{click to reveal password}', @@ -130,7 +254,107 @@ describe('ServiceURI', () => { const serviceURIText = screen.getByTestId('service-uri').textContent; expect(revealPasswordBtn).not.toBeInTheDocument(); expect(serviceURIText).toBe( - `postgres://password123@db-mysql-primary-0.b.linodeb.net:3306/defaultdb?sslmode=require` + `postgres://password123@${DEFAULT_PRIMARY}:3306/defaultdb?sslmode=require` + ); + }); + + it('should render private service URI component if there is a private-only VPC', async () => { + queryMocks.useDatabaseCredentialsQuery.mockReturnValue({ + data: mockCredentials, + }); + + renderWithTheme(); + + const revealPasswordBtn = screen.getByRole('button', { + name: '{click to reveal password}', + }); + const serviceURIText = screen.getByTestId('service-uri').textContent; + + expect(revealPasswordBtn).toBeInTheDocument(); + expect(serviceURIText).toBe( + `postgres://{click to reveal password}@${PRIMARY_PRIVATE_CONNECTION_POOL}:15848/{connection pool label}?sslmode=require` + ); + }); + + it('should render private general service URI component if there is a private-only VPC', async () => { + queryMocks.useDatabaseCredentialsQuery.mockReturnValue({ + data: mockCredentials, + }); + + renderWithTheme( + + ); + + const revealPasswordBtn = screen.getByRole('button', { + name: '{click to reveal password}', + }); + const serviceURIText = screen.getByTestId('service-uri').textContent; + + expect(revealPasswordBtn).toBeInTheDocument(); + expect(serviceURIText).toBe( + `postgres://{click to reveal password}@${PRIVATE_PRIMARY}:3306/defaultdb?sslmode=require` + ); + }); + + it('should render public service URI component if there is a VPC with public access', async () => { + queryMocks.useDatabaseCredentialsQuery.mockReturnValue({ + data: mockCredentials, + }); + + renderWithTheme(); + + const revealPasswordBtn = screen.getByRole('button', { + name: '{click to reveal password}', + }); + const serviceURIText = screen.getByTestId('service-uri').textContent; + + expect(revealPasswordBtn).toBeInTheDocument(); + expect(serviceURIText).toBe( + `postgres://{click to reveal password}@${PRIMARY_PUBLIC_CONNECTION_POOL}:15848/{connection pool label}?sslmode=require` + ); + }); + + it('should render private service URI component if there is a VPC with public access and showPrivateVPC is true', async () => { + queryMocks.useDatabaseCredentialsQuery.mockReturnValue({ + data: mockCredentials, + }); + + renderWithTheme( + + ); + + const revealPasswordBtn = screen.getByRole('button', { + name: '{click to reveal password}', + }); + const serviceURIText = screen.getByTestId('service-uri').textContent; + + expect(revealPasswordBtn).toBeInTheDocument(); + expect(serviceURIText).toBe( + `postgres://{click to reveal password}@${PRIMARY_PRIVATE_CONNECTION_POOL}:15848/{connection pool label}?sslmode=require` + ); + }); + + it('should render general private service URI if there is a VPC with public access, isGeneralServiceURI is true, and showPrivateVPC is true', () => { + queryMocks.useDatabaseCredentialsQuery.mockReturnValue({ + data: mockCredentials, + }); + + renderWithTheme( + + ); + + const revealPasswordBtn = screen.getByRole('button', { + name: '{click to reveal password}', + }); + const serviceURIText = screen.getByTestId('service-uri').textContent; + + expect(revealPasswordBtn).toBeInTheDocument(); + expect(serviceURIText).toBe( + `postgres://{click to reveal password}@${PRIVATE_PRIMARY}:3306/defaultdb?sslmode=require` ); }); }); diff --git a/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.tsx b/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.tsx index 0cfe994211d..d417979e572 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/ServiceURI.tsx @@ -1,5 +1,5 @@ import { useDatabaseCredentialsQuery } from '@linode/queries'; -import { Button } from '@linode/ui'; +import { Button, TooltipIcon } from '@linode/ui'; import { Grid, styled } from '@mui/material'; import copy from 'copy-to-clipboard'; import { enqueueSnackbar } from 'notistack'; @@ -7,21 +7,22 @@ import React, { useState } from 'react'; import { Code } from 'src/components/Code/Code'; import { CopyTooltip } from 'src/components/CopyTooltip/CopyTooltip'; -import { - StyledGridContainer, - StyledLabelTypography, - StyledValueGrid, -} from 'src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.style'; +import { StyledValueGrid } from 'src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.style'; import type { Database, DatabaseCredentials } from '@linode/api-v4'; interface ServiceURIProps { database: Database; isGeneralServiceURI?: boolean; + showPrivateVPC?: boolean; } export const ServiceURI = (props: ServiceURIProps) => { - const { database, isGeneralServiceURI = false } = props; + const { + database, + isGeneralServiceURI = false, + showPrivateVPC = false, + } = props; const [hidePassword, setHidePassword] = useState(true); const [isCopying, setIsCopying] = useState(false); @@ -36,6 +37,26 @@ export const ServiceURI = (props: ServiceURIProps) => { refetch: getDatabaseCredentials, } = useDatabaseCredentialsQuery(database.engine, database.id, !hidePassword); + const hasVPC = Boolean(database?.private_network?.vpc_id); + const hasPublicVPC = hasVPC && database.private_network?.public_access; + // If there is a VPC, use VPC public access unless we want to explicitly show private access, otherwise default to public + const publicAccess = + hasPublicVPC && showPrivateVPC + ? false + : hasVPC + ? database.private_network?.public_access + : true; + + const primaryHost = database.hosts?.endpoints.find( + (endpoint) => + endpoint.role === 'primary' && endpoint.public_access === publicAccess + ); + const primaryConnectionPoolHost = database.hosts?.endpoints.find( + (endpoint) => + endpoint.role === 'primary-connection-pool' && + endpoint.public_access === publicAccess + ); + const handleCopy = async () => { if (!credentials) { try { @@ -43,7 +64,7 @@ export const ServiceURI = (props: ServiceURIProps) => { const { data } = await getDatabaseCredentials(); if (data) { // copy with revealed credentials - copy(getServiceURIText(isGeneralServiceURI, data)); + copy(getServiceURIText(data, isGeneralServiceURI)); } else { enqueueSnackbar( 'There was an error retrieving cluster credentials. Please try again.', @@ -62,13 +83,13 @@ export const ServiceURI = (props: ServiceURIProps) => { }; const getServiceURIText = ( - isGeneralServiceURI: boolean, - credentials: DatabaseCredentials | undefined + credentials: DatabaseCredentials | undefined, + isGeneralServiceURI?: boolean ) => { if (isGeneralServiceURI) { - return `${engine}://${credentials?.password}@${database.hosts?.primary}:${database.port}/defaultdb?sslmode=require`; + return `${engine}://${credentials?.password}@${primaryHost?.address}:${primaryHost?.port}/defaultdb?sslmode=require`; } - return `postgres://${credentials?.username}:${credentials?.password}@${database.hosts?.primary}:${database.connection_pool_port}/{connection pool label}?sslmode=require`; + return `postgres://${credentials?.username}:${credentials?.password}@${primaryConnectionPoolHost?.address}:${primaryConnectionPoolHost?.port}/{connection pool label}?sslmode=require`; }; const getCredentials = (isGeneralServiceURI: boolean) => { @@ -110,7 +131,7 @@ export const ServiceURI = (props: ServiceURIProps) => { ); - const ServiceURIJSX = (isGeneralServiceURI: boolean) => ( + return ( { sx={{ overflowX: 'auto', overflowY: 'hidden', - p: isGeneralServiceURI ? '0' : null, + p: '0', }} whiteSpace="pre" > @@ -128,16 +149,17 @@ export const ServiceURI = (props: ServiceURIProps) => { : hidePassword || (!credentialsError && !credentials) ? RevealPasswordButton : getCredentials(isGeneralServiceURI)} - {!isGeneralServiceURI ? ( + {isGeneralServiceURI ? ( <> - @{database.hosts?.primary}:{database.connection_pool_port}/ - {'{connection pool label}'} - ?sslmode=require + @{primaryHost?.address}: + {`${primaryHost?.port}/defaultdb?sslmode=require`} ) : ( <> - @{database.hosts?.primary}: - {`${database.port}/defaultdb?sslmode=require`} + @{primaryConnectionPoolHost?.address}: + {primaryConnectionPoolHost?.port}/ + {'{connection pool label}'} + ?sslmode=require )} @@ -149,33 +171,29 @@ export const ServiceURI = (props: ServiceURIProps) => { + + )} + {hasPublicVPC && showPrivateVPC && ( + + )} ); - - if (isGeneralServiceURI) { - return ServiceURIJSX(isGeneralServiceURI); - } - - return ( - - - Service URI - - {ServiceURIJSX(isGeneralServiceURI)} - - ); }; -const StyledCode = styled(Code, { +export const StyledCode = styled(Code, { label: 'StyledCode', })(() => ({ margin: 0, diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 2ab6f042881..253f679434f 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -214,10 +214,6 @@ const makeMockDatabase = (params: PathParams): Database => { db.ssl_connection = true; } - if (db.engine === 'postgresql') { - db.connection_pool_port = 100; /** @Deprecated replaced by `endpoints` property */ - } - const database = databaseFactory.build(db); // Mock a database cluster with a public VPC Configuration @@ -241,27 +237,33 @@ const makeMockDatabase = (params: PathParams): Database => { { role: 'primary', address: 'public-db-mysql-primary-0.b.linodeb.net', - port: 15847, + port: 3306, public_access: true, }, { role: 'primary', address: 'private-db-mysql-primary-0.b.linodeb.net', - port: 15847, + port: 3306, public_access: false, }, { role: 'standby', address: 'public-replica-db-mysql-standby-0.b.linodeb.net', - port: 15847, + port: 3306, public_access: true, }, { role: 'standby', address: 'private-replica-db-mysql-standby-0.b.linodeb.net', - port: 15847, + port: 3306, public_access: false, }, + { + role: 'primary-connection-pool', + address: 'public-db-mysql-primary-0.b.linodeb.net', + port: 15848, + public_access: true, + }, { role: 'primary-connection-pool', address: 'private-db-mysql-primary-0.b.linodeb.net', @@ -280,7 +282,13 @@ const makeMockDatabase = (params: PathParams): Database => { // { // role: 'primary', // address: 'db-mysql-primary-0.b.linodeb.net', - // port: 15847, + // port: 3306, + // public_access: true, + // }, + // { + // role: 'primary-connection-pool', + // address: 'public-db-mysql-primary-0.b.linodeb.net', + // port: 15848, // public_access: true, // }, // ],