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 b466218db5eb..18d2efc11137 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 9db946b11a8e..29114345ffb8 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 76fd288d8892..f81a325e5217 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 82ecdc8a1cf6..f4e7be9d8242 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 ad4d29f41407..c7857f353da2 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 9fcee1d47cdc..98f7fd6c7b1e 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 1965a451f08b..64ab6b28cf81 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 b499466da4db..3d8872b25a2a 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`; +};