diff --git a/public/app/percona/add-instance/components/AddRemoteInstance/AddRemoteInstance.types.ts b/public/app/percona/add-instance/components/AddRemoteInstance/AddRemoteInstance.types.ts index a8de85474a45d..47847aaab972e 100644 --- a/public/app/percona/add-instance/components/AddRemoteInstance/AddRemoteInstance.types.ts +++ b/public/app/percona/add-instance/components/AddRemoteInstance/AddRemoteInstance.types.ts @@ -103,6 +103,7 @@ export interface PostgreSQLPayload extends RemoteCommonPayload, TLSCommon { agent_password: string; max_query_length: number; auto_discovery_limit: number; + max_exporter_connections: number; } export interface MySQLPayload extends RemoteCommonPayload, TLSCommon { @@ -196,6 +197,7 @@ export interface RDSPayload extends CommonRDSAzurePayload { metrics_mode: string; qan_postgresql_pgstatements: boolean; agent_password: string; + max_postgresql_exporter_connections: number; } export interface MSAzurePayload extends CommonRDSAzurePayload { diff --git a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.constants.ts b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.constants.ts index 9db946b11a8eb..29114345ffb82 100644 --- a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.constants.ts +++ b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.constants.ts @@ -1,5 +1,9 @@ import { Messages } from './AdditionalOptions.messages'; -import { AutoDiscoveryOptionsInterface, TablestatOptionsInterface } from './AdditionalOptions.types'; +import { + AutoDiscoveryOptionsInterface, + TablestatOptionsInterface, + MaxConnectionLimitOptionsInterface, +} from './AdditionalOptions.types'; export const tablestatOptions = [ { @@ -30,3 +34,14 @@ export const autoDiscoveryOptions = [ label: Messages.form.autoDiscoveryOptions.custom, }, ]; + +export const maxConnectionLimitOptions = [ + { + value: MaxConnectionLimitOptionsInterface.enabled, + label: Messages.form.maxConnectionLimitOptions.enabled, + }, + { + value: MaxConnectionLimitOptionsInterface.disabled, + label: Messages.form.maxConnectionLimitOptions.disabled, + }, +]; diff --git a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.messages.ts b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.messages.ts index 76fd288d8892a..f81a325e52179 100644 --- a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.messages.ts +++ b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.messages.ts @@ -10,5 +10,9 @@ export const Messages = { disabled: 'Disabled', custom: 'Custom', }, + maxConnectionLimitOptions: { + enabled: 'Enabled', + disabled: 'Disabled', + }, }, }; diff --git a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.tsx b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.tsx index 82ecdc8a1cf63..f4e7be9d82425 100644 --- a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.tsx +++ b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.tsx @@ -7,6 +7,7 @@ import { CheckboxField } from 'app/percona/shared/components/Elements/Checkbox'; import { NumberInputField } from 'app/percona/shared/components/Form/NumberInput'; import { RadioButtonGroupField } from 'app/percona/shared/components/Form/RadioButtonGroup'; import { Databases } from 'app/percona/shared/core'; +import Validators from 'app/percona/shared/helpers/validators'; import { validators as platformCoreValidators } from 'app/percona/shared/helpers/validatorsForm'; import { rdsTrackingOptions, trackingOptions } from '../FormParts.constants'; @@ -14,8 +15,12 @@ import { Messages } from '../FormParts.messages'; import { getStyles } from '../FormParts.styles'; import { AdditionalOptionsFormPartProps, PostgreSQLAdditionalOptionsProps } from '../FormParts.types'; -import { autoDiscoveryOptions, tablestatOptions } from './AdditionalOptions.constants'; -import { AutoDiscoveryOptionsInterface, TablestatOptionsInterface } from './AdditionalOptions.types'; +import { autoDiscoveryOptions, tablestatOptions, maxConnectionLimitOptions } from './AdditionalOptions.constants'; +import { + AutoDiscoveryOptionsInterface, + MaxConnectionLimitOptionsInterface, + TablestatOptionsInterface, +} from './AdditionalOptions.types'; import { MongodbTLSCertificate } from './MongodbTLSCertificate'; import { MysqlTLSCertificate } from './MysqlTLSCertificate'; import { PostgreTLSCertificate } from './PostgreTLSCertificate'; @@ -43,19 +48,36 @@ export const AdditionalOptionsFormPart: FC = ({ export const PostgreSQLAdditionalOptions: FC = ({ form, isRDS, isAzure }) => { const selectedOption = form.getState()?.values?.autoDiscoveryOptions; + const maxConnSelectedOption = form.getState()?.values?.maxConnectionLimitOptions; const [selectedValue, setSelectedValue] = useState(selectedOption || AutoDiscoveryOptionsInterface.enabled); + const [maxConnSelectedValue, setMaxConnSelectedValue] = useState( + maxConnSelectedOption || MaxConnectionLimitOptionsInterface.disabled + ); const styles = useStyles2(getStyles); - const validators = [platformCoreValidators.containsNumber, ...platformCoreValidators.int32]; + const validators = [platformCoreValidators.containsNumber, platformCoreValidators.int32]; + const maxConnValidators = [Validators.min(0), platformCoreValidators.int32]; const getAutoDiscoveryLimitValue = (type: AutoDiscoveryOptionsInterface) => type === AutoDiscoveryOptionsInterface.disabled ? -1 : 10; + const getMaxConnectionLimitValue = (type: MaxConnectionLimitOptionsInterface) => + type === MaxConnectionLimitOptionsInterface.disabled ? null : 5; + useEffect(() => { setSelectedValue(selectedOption); form.change('autoDiscoveryLimit', getAutoDiscoveryLimitValue(selectedOption)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedOption]); + useEffect(() => { + setMaxConnSelectedValue(maxConnSelectedOption); + form.change( + isRDS ? 'maxPostgresqlExporterConnections' : 'maxExporterConnections', + getMaxConnectionLimitValue(maxConnSelectedOption) + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [maxConnSelectedOption]); + return ( <>

{Messages.form.labels.trackingOptions}

@@ -87,6 +109,34 @@ export const PostgreSQLAdditionalOptions: FC = tooltipText={Messages.form.tooltips.postgresqlDetails.autoDiscoveryLimit} /> + {!isAzure && ( +
+

{Messages.form.labels.postgresqlDetails.maxConnection}

+
+ + +
+
+ )} ); }; diff --git a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.types.ts b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.types.ts index ad4d29f414076..c7857f353da2f 100644 --- a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.types.ts +++ b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/AdditionalOptions/AdditionalOptions.types.ts @@ -9,3 +9,8 @@ export enum AutoDiscoveryOptionsInterface { disabled = 'disabled', custom = 'custom', } + +export enum MaxConnectionLimitOptionsInterface { + enabled = 'enabled', + disabled = 'disabled', +} diff --git a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.messages.ts b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.messages.ts index 9fcee1d47cdc2..98f7fd6c7b1e3 100644 --- a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.messages.ts +++ b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.messages.ts @@ -32,6 +32,9 @@ export const Messages = { autoDiscovery: 'Auto-discovery', autoDiscoveryLimit: 'Auto-discovery limit', autoDiscoveryLimitOptions: 'State', + maxConnection: 'Maximum connection limit', + maxConnectionLimit: 'Maximum connection limit per PostgreSQL instance', + maxConnectionLimitOptions: 'State', }, mysqlDetails: { maxQueryLength: 'Max query length', @@ -91,6 +94,7 @@ export const Messages = { database: 'Database (default: postgres)', maxQueryLength: 'Max query length', autoDiscoveryLimit: 'Auto-discovery limit', + maxConnectionLimit: 'Maximum connection limit per PostgreSQL instance', }, mysqlDetails: { maxQueryLength: 'Max query length', @@ -131,6 +135,8 @@ export const Messages = { database: 'Database name', maxQueryLength: 'Full Example (Fingerprint) storage is not allowed by default to have the best performance', autoDiscoveryLimit: 'Turn off auto-discovery when the total count of databases exceeds the limit.', + maxConnectionLimit: + 'The maximum connections the Exporter can open to each PostgreSQL instance for monitoring. Higher values might be needed for larger or busier instances, but avoid setting it too high as it can impact performance. Adjust based on your instance size and monitoring needs.', }, mysqlDetails: { maxQueryLength: 'Full Example (Fingerprint) storage is not allowed by default to have the best performance', diff --git a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.test.tsx b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.test.tsx index 7af1b758c480e..dbd3684fcc7fe 100644 --- a/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.test.tsx +++ b/public/app/percona/add-instance/components/AddRemoteInstance/FormParts/FormParts.test.tsx @@ -181,7 +181,7 @@ describe('getAdditionalOptions ::', () => { const fields = container.querySelectorAll('input'); const trakingFields = screen.getAllByTestId('tracking-radio-button'); expect(trakingFields.length).toBe(trackingOptions.length); - expect(fields.length).toBe(12); + expect(fields.length).toBe(16); }); it('should render correct for RDS PostgreSQL', async () => { const type = Databases.postgresql; @@ -198,6 +198,6 @@ describe('getAdditionalOptions ::', () => { const fields = container.querySelectorAll('input'); const trakingFields = screen.getAllByTestId('tracking-radio-button'); expect(trakingFields.length).toBe(rdsTrackingOptions.length); - expect(fields.length).toBe(13); + expect(fields.length).toBe(17); }); }); diff --git a/public/app/percona/shared/helpers/validatorsForm/int32.ts b/public/app/percona/shared/helpers/validatorsForm/int32.ts index b499466da4dbe..3d8872b25a2ab 100644 --- a/public/app/percona/shared/helpers/validatorsForm/int32.ts +++ b/public/app/percona/shared/helpers/validatorsForm/int32.ts @@ -1,5 +1,10 @@ import { INT_32 } from '../../core'; -import { lessThan, greaterThan } from '.'; +export const int32 = (value: string) => { + const num = parseFloat(value); + if (Number.isFinite(num) && Number.isInteger(num) && num > INT_32.min - 1 && num < INT_32.max + 1) { + return undefined; + } -export const int32 = [greaterThan(INT_32.min - 1), lessThan(INT_32.max + 1)]; + return `Must be an Integer number`; +};