Skip to content

Commit

Permalink
PMM-13166: Ability to monitor DBs from a different node (#766)
Browse files Browse the repository at this point in the history
* Nodes for MySQLConnection

* Added Nodes Agents component

* Added pmm_agent_id parameter instead of agent/node

* Added NodesAgents to all the services

* Fixes after reviews

* Testing NodesAgents in progress

* Added NodesAgents test

* Fix from PR

* Fixes after PR

* Prettier fix

* Fixed ts issues

* Added the types to mappedNodes, nodesOptions, changed the agent name object

* Updated tests - partial

* Partially tests

* Fixed tests

* Added node_type to node mocks and fixed eslint for NodesAgents

* Fixed other tests related to Add Service

* More tests fixed

* Fixed prettier

* Added spy on console.error

* Added test for console error

* Added console error check to every test

* Fixes after PR

* Replaced the formAPI with taken values from the form, and added new mock with one non-pmm-server agent

* SelectedAgent can be undefined

* Clear mock before each test

* Added wait for to last test

* If address is localhost then send node_id instead of add_node, and send metrics_mode=2 if pmm_server

* Fixes after PR

* Fixed prettier

---------

Co-authored-by: DoraCretu594118 <[email protected]>
  • Loading branch information
doracretu3pillar and DoraCretu594118 authored Oct 3, 2024
1 parent f551f2b commit 7acb1ea
Show file tree
Hide file tree
Showing 31 changed files with 587 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ describe('AddRemoteInstanceService:: ', () => {
replication_set: 'test',
cluster: 'test',
custom_labels: 'test:test',
pmm_agent_id: {
value: 'pmm-server',
},
node: {
value: 'node1',
label: 'node1',
},
};

const payload = {
Expand All @@ -84,16 +91,12 @@ describe('AddRemoteInstanceService:: ', () => {
custom_labels: {
test: 'test',
},
add_node: {
node_name: 'localhost',
node_type: 'NODE_TYPE_REMOTE_NODE',
},
pmm_agent_id: 'pmm-server',
port: '80',
qan_postgresql_pgstatements_agent: true,
metrics_mode: 1,
node_id: 'node1',
};

expect(toPayload(data)).toStrictEqual(payload);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CancelToken } from 'axios';

import { PMM_SERVER_NODE_AGENT_ID } from 'app/percona/add-instance/components/AddRemoteInstance/FormParts/NodesAgents/NodesAgents.constants';
import { Databases } from 'app/percona/shared/core';
import { apiManagement } from 'app/percona/shared/helpers/api';

Expand Down Expand Up @@ -142,7 +143,9 @@ export const toPayload = (values: any, discoverName?: string, type?: InstanceAva
data.service_name = data.address;
}

if (!values.isAzure && data.add_node === undefined) {
if (data.address === '127.0.0.1' || data.address === 'localhost') {
data.node_id = data.node.value;
} else if (!values.isAzure && data.add_node === undefined) {
data.add_node = {
node_name: data.service_name,
node_type: 'NODE_TYPE_REMOTE_NODE',
Expand Down Expand Up @@ -179,8 +182,15 @@ export const toPayload = (values: any, discoverName?: string, type?: InstanceAva
}
}

data.metrics_mode = 1;
data.pmm_agent_id = values.pmm_agent_id.value;

if (data.pmm_agent_id === PMM_SERVER_NODE_AGENT_ID) {
data.metrics_mode = 1;
} else {
data.metrics_mode = 2;
}
delete data.tracking;
delete data.node;

return data;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';

import { Databases } from 'app/percona/shared/core';
import { configureStore } from 'app/store/configureStore';

import { InstanceTypesExtra } from '../../panel.types';

Expand All @@ -20,7 +22,11 @@ jest.mock('app/percona/shared/helpers/logger', () => {
describe('Add remote instance:: ', () => {
it('should render correct for mysql and postgres and highlight empty mandatory fields on submit', async () => {
const type = Databases.mysql;
render(<AddRemoteInstance onSubmit={jest.fn()} instance={{ type, credentials: {} }} selectInstance={jest.fn()} />);
render(
<Provider store={configureStore()}>
<AddRemoteInstance onSubmit={jest.fn()} instance={{ type, credentials: {} }} selectInstance={jest.fn()} />
</Provider>
);

expect(screen.getByTestId('address-text-input').classList.contains('invalid')).toBe(false);
expect(screen.getByTestId('username-text-input').classList.contains('invalid')).toBe(false);
Expand All @@ -35,7 +41,11 @@ describe('Add remote instance:: ', () => {

it('should render for external service and highlight empty mandatory fields on submit', async () => {
const type = InstanceTypesExtra.external;
render(<AddRemoteInstance onSubmit={jest.fn()} instance={{ type, credentials: {} }} selectInstance={jest.fn()} />);
render(
<Provider store={configureStore()}>
<AddRemoteInstance onSubmit={jest.fn()} instance={{ type, credentials: {} }} selectInstance={jest.fn()} />
</Provider>
);

expect(screen.getByTestId('address-text-input').classList.contains('invalid')).toBe(false);
expect(screen.getByTestId('metrics_path-text-input').classList.contains('invalid')).toBe(false);
Expand All @@ -55,7 +65,11 @@ describe('Add remote instance:: ', () => {
it('should render correct for HAProxy and highlight empty mandatory fields on submit', async () => {
const type = Databases.haproxy;

render(<AddRemoteInstance onSubmit={jest.fn()} instance={{ type, credentials: {} }} selectInstance={jest.fn()} />);
render(
<Provider store={configureStore()}>
<AddRemoteInstance onSubmit={jest.fn()} instance={{ type, credentials: {} }} selectInstance={jest.fn()} />
</Provider>
);

expect(screen.getByTestId('address-text-input').classList.contains('invalid')).toBe(false);
expect(screen.getByTestId('username-text-input').classList.contains('invalid')).toBe(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('Get instance data:: ', () => {
port: '5432',
metricsParameters: 'manually',
schema: 'https',
pmm_agent_id: '',
},
};

Expand Down Expand Up @@ -77,6 +78,7 @@ describe('Get instance data:: ', () => {
port: '27017',
metricsParameters: 'manually',
schema: 'https',
pmm_agent_id: '',
},
};

Expand All @@ -100,6 +102,7 @@ describe('Get instance data:: ', () => {
port: '3306',
metricsParameters: 'manually',
schema: 'https',
pmm_agent_id: '',
},
};

Expand All @@ -123,6 +126,7 @@ describe('Get instance data:: ', () => {
port: '6032',
metricsParameters: 'manually',
schema: 'https',
pmm_agent_id: '',
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export const getInstanceData = (instanceType: InstanceAvailableType, credentials
remoteInstanceCredentials: {
metricsParameters: MetricsParameters.manually,
schema: Schema.HTTPS,
pmm_agent_id: '',
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { render, fireEvent, screen } from '@testing-library/react';
import React from 'react';
import { Form } from 'react-final-form';
import { Provider } from 'react-redux';

import { configureStore } from 'app/store/configureStore';

import { ExternalServiceConnectionDetails } from './ExternalServiceConnectionDetails';

describe('Add remote instance:: ', () => {
it('should render correct for mysql and postgres and highlight empty mandatory fields on submit', async () => {
render(
<Form
onSubmit={jest.fn()}
mutators={{
setValue: ([field, value], state, { changeValue }) => {
changeValue(state, field, () => value);
},
}}
render={({ form }) => <ExternalServiceConnectionDetails form={form} />}
/>
<Provider store={configureStore()}>
<Form
onSubmit={jest.fn()}
mutators={{
setValue: ([field, value], state, { changeValue }) => {
changeValue(state, field, () => value);
},
}}
render={({ form }) => <ExternalServiceConnectionDetails form={form} />}
/>
</Provider>
);

const metricsParametrsRadioState = screen.getByTestId('metricsParameters-radio-state');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC, useCallback, useEffect, useMemo } from 'react';

import { useStyles2 } from '@grafana/ui';
import { NodesAgents } from 'app/percona/add-instance/components/AddRemoteInstance/FormParts/NodesAgents/NodesAgents';
import { PasswordInputField } from 'app/percona/shared/components/Form/PasswordInput';
import { RadioButtonGroupField } from 'app/percona/shared/components/Form/RadioButtonGroup';
import { TextInputField } from 'app/percona/shared/components/Form/TextInput';
Expand Down Expand Up @@ -96,6 +97,7 @@ export const ExternalServiceConnectionDetails: FC<FormPartProps> = ({ form }) =>
/>
<div />
</div>
<NodesAgents form={form} />
<div className={styles.group}>
<TextInputField
name="address"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export const Messages = {
username: 'Username',
password: 'Password',
},
nodesAgents: {
nodes: 'Nodes',
agents: 'Agents',
},
mainDetails: {
address: 'Hostname',
serviceName: 'Service name',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export const getStyles = ({ breakpoints, spacing, colors }: GrafanaTheme2) => ({
width: 100%;
margin-right: 5px;
`,
selectFieldWrapper: css`
width: 100%;
`,
selectField: css`
height: 38px;
`,
group: css`
display: flex;
flex-direction: row;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { render, screen } from '@testing-library/react';
import { FormApi, FormState } from 'final-form';
import React from 'react';
import { Form } from 'react-final-form';
import { Provider } from 'react-redux';

import { Databases } from 'app/percona/shared/core';
import { configureStore } from 'app/store/configureStore';

import { AdditionalOptionsFormPart, getAdditionalOptions } from './AdditionalOptions/AdditionalOptions';
import { ExternalServiceConnectionDetails } from './ExternalServiceConnectionDetails/ExternalServiceConnectionDetails';
Expand All @@ -20,14 +22,16 @@ const form: Partial<FormApi> = {
describe('MainDetailsFormPart ::', () => {
it('should disable fields with sat isRDS flag', async () => {
const { container } = render(
<Form
onSubmit={jest.fn()}
render={({ form }) => <MainDetailsFormPart form={form} remoteInstanceCredentials={{ isRDS: true }} />}
/>
<Provider store={configureStore()}>
<Form
onSubmit={jest.fn()}
render={({ form }) => <MainDetailsFormPart form={form} remoteInstanceCredentials={{ isRDS: true }} />}
/>
</Provider>
);

const fields = container.querySelectorAll('input');
expect(fields.length).toBe(5);
expect(fields.length).toBe(8);

expect(screen.getByTestId('address-text-input')).toBeDisabled();
expect(screen.getByTestId('serviceName-text-input')).not.toBeDisabled();
Expand All @@ -38,14 +42,16 @@ describe('MainDetailsFormPart ::', () => {

it('should disable fields with not sat isRDS flag', async () => {
const { container } = render(
<Form
onSubmit={jest.fn()}
render={({ form }) => <MainDetailsFormPart form={form} remoteInstanceCredentials={{ isRDS: false }} />}
/>
<Provider store={configureStore()}>
<Form
onSubmit={jest.fn()}
render={({ form }) => <MainDetailsFormPart form={form} remoteInstanceCredentials={{ isRDS: false }} />}
/>
</Provider>
);

const fields = container.querySelectorAll('input');
expect(fields.length).toBe(5);
expect(fields.length).toBe(8);

expect(screen.getByTestId('address-text-input')).not.toBeDisabled();
expect(screen.getByTestId('serviceName-text-input')).not.toBeDisabled();
Expand All @@ -58,10 +64,12 @@ describe('MainDetailsFormPart ::', () => {
describe('ExternalServiceConnectionDetails ::', () => {
it('should render', async () => {
const { container } = render(
<Form
onSubmit={jest.fn()}
render={() => <ExternalServiceConnectionDetails form={form as unknown as FormApi} />}
/>
<Provider store={configureStore()}>
<Form
onSubmit={jest.fn()}
render={() => <ExternalServiceConnectionDetails form={form as unknown as FormApi} />}
/>
</Provider>
);

const fields = container.querySelectorAll('input');
Expand Down Expand Up @@ -89,17 +97,19 @@ describe('AdditionalOptionsFormPart ::', () => {
};

render(
<Form
onSubmit={jest.fn()}
render={() => (
<AdditionalOptionsFormPart
instanceType={type}
remoteInstanceCredentials={remoteInstanceCredentials}
loading={false}
form={form as unknown as FormApi}
/>
)}
/>
<Provider store={configureStore()}>
<Form
onSubmit={jest.fn()}
render={() => (
<AdditionalOptionsFormPart
instanceType={type}
remoteInstanceCredentials={remoteInstanceCredentials}
loading={false}
form={form as unknown as FormApi}
/>
)}
/>
</Provider>
);

expect(screen.getByTestId('skip_connection_check-checkbox-input')).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { Form } from 'react-final-form';
import { Provider } from 'react-redux';

import { configureStore } from 'app/store/configureStore';

import { HAProxyConnectionDetails } from './HAProxyConnectionDetails';

describe('HAProxy connection details:: ', () => {
it('should trim username and password values right', () => {
render(<Form onSubmit={jest.fn()} render={() => <HAProxyConnectionDetails remoteInstanceCredentials={{}} />} />);
render(
<Provider store={configureStore()}>
<Form onSubmit={jest.fn()} render={() => <HAProxyConnectionDetails remoteInstanceCredentials={{}} />} />
</Provider>
);

const userNameTextInput = screen.getByTestId('username-text-input');
fireEvent.change(userNameTextInput, { target: { value: ' test ' } });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC, useCallback, useMemo } from 'react';

import { useStyles2 } from '@grafana/ui';
import { NodesAgents } from 'app/percona/add-instance/components/AddRemoteInstance/FormParts/NodesAgents/NodesAgents';
import { PasswordInputField } from 'app/percona/shared/components/Form/PasswordInput';
import { TextInputField } from 'app/percona/shared/components/Form/TextInput';
import Validators from 'app/percona/shared/helpers/validators';
Expand All @@ -10,7 +11,7 @@ import { Messages } from '../FormParts.messages';
import { getStyles } from '../FormParts.styles';
import { MainDetailsFormPartProps } from '../FormParts.types';

export const HAProxyConnectionDetails: FC<MainDetailsFormPartProps> = ({ remoteInstanceCredentials }) => {
export const HAProxyConnectionDetails: FC<MainDetailsFormPartProps> = ({ form, remoteInstanceCredentials }) => {
const styles = useStyles2(getStyles);

const portValidators = useMemo(() => [validators.required, Validators.validatePort], []);
Expand All @@ -29,6 +30,7 @@ export const HAProxyConnectionDetails: FC<MainDetailsFormPartProps> = ({ remoteI
/>
<div />
</div>
<NodesAgents form={form} />
<div className={styles.group}>
<TextInputField
name="address"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC, useMemo } from 'react';

import { useStyles2 } from '@grafana/ui';
import { NodesAgents } from 'app/percona/add-instance/components/AddRemoteInstance/FormParts/NodesAgents/NodesAgents';
import { PasswordInputField } from 'app/percona/shared/components/Form/PasswordInput';
import { TextInputField } from 'app/percona/shared/components/Form/TextInput';
import Validators from 'app/percona/shared/helpers/validators';
Expand Down Expand Up @@ -30,6 +31,7 @@ export const MainDetailsFormPart: FC<MainDetailsFormPartProps> = ({ form, remote
/>
<div />
</div>
<NodesAgents form={form} />
<div className={styles.group}>
<TextInputField
name="address"
Expand Down
Loading

0 comments on commit 7acb1ea

Please sign in to comment.