Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,15 @@ export function ConnectionStatus({ isConnected, mode }) {
return (
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow={false}>
<span className="eui-displayBlock">{icon}</span>
<span data-test-subj="remoteClusterConnectionStatusIcon" className="eui-displayBlock">
{icon}
</span>
</EuiFlexItem>

<EuiFlexItem grow={false} className="remoteClustersConnectionStatus__message">
<EuiText size="s">{message}</EuiText>
<EuiText data-test-subj="remoteClusterConnectionStatusMessage" size="s">
{message}
</EuiText>
</EuiFlexItem>

{!isConnected && mode === SNIFF_MODE && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
EuiInMemoryTable,
EuiLink,
EuiToolTip,
EuiText,
} from '@elastic/eui';
import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public';
import { UIM_SHOW_DETAILS_CLICK } from '../../../constants';
Expand Down Expand Up @@ -205,24 +206,47 @@ export class RemoteClusterTable extends Component {
defaultMessage: 'Mode',
}),
sortable: true,
render: (mode) =>
render: (mode) => {
let modeMessage;
mode === PROXY_MODE
? mode
: i18n.translate('xpack.remoteClusters.remoteClusterList.table.sniffModeDescription', {
defaultMessage: 'default',
}),
? (modeMessage = mode)
: (modeMessage = i18n.translate(
'xpack.remoteClusters.remoteClusterList.table.sniffModeDescription',
{
defaultMessage: 'default',
}
));
const modeMessageComponent = (
<EuiFlexItem grow={false} className="remoteClustersConnectionMode__message">
<EuiText
id="xpack.remoteClusters.remoteClusterList.table.sniffModeDescription"
data-test-subj="remoteClusterConnectionModeMessage"
size="s"
>
{modeMessage}
</EuiText>
</EuiFlexItem>
);
return modeMessageComponent;
},
},
{
field: 'mode',
name: i18n.translate('xpack.remoteClusters.remoteClusterList.table.addressesColumnTitle', {
defaultMessage: 'Addresses',
}),
dataTestSubj: 'remoteClustersAddress',
truncateText: true,
render: (mode, { seeds, proxyAddress }) => {
if (mode === PROXY_MODE) {
return proxyAddress;
}
return seeds.join(', ');
const clusterAddressString = mode === PROXY_MODE ? proxyAddress : seeds.join(', ');
const connectionMode = (
<EuiFlexItem grow={false} className="remoteClustersConnectionAddress__message">
<EuiText data-test-subj="remoteClusterConnectionAddressMessage" size="s">
{clusterAddressString}
</EuiText>
</EuiFlexItem>
);
return connectionMode;
},
},
{
Expand All @@ -236,10 +260,16 @@ export class RemoteClusterTable extends Component {
sortable: true,
width: '160px',
render: (mode, { connectedNodesCount, connectedSocketsCount }) => {
if (mode === PROXY_MODE) {
return connectedSocketsCount;
}
return connectedNodesCount;
const remoteNodesCount =
mode === PROXY_MODE ? connectedSocketsCount : connectedNodesCount;
const connectionMode = (
<EuiFlexItem grow={false} className="remoteClustersNodeCount__message">
<EuiText data-test-subj="remoteClusterNodeCountMessage" size="s">
{remoteNodesCount}
</EuiText>
</EuiFlexItem>
);
return connectionMode;
},
},
{
Expand Down
6 changes: 5 additions & 1 deletion x-pack/test/accessibility/apps/cross_cluster_replication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.common.navigateToApp('crossClusterReplication');
await PageObjects.crossClusterReplication.clickCreateFollowerIndexButton();
await a11y.testAppSnapshot();
await PageObjects.crossClusterReplication.createFollowerIndex(testLeader, testFollower);
await PageObjects.crossClusterReplication.createFollowerIndex(
testLeader,
testFollower,
false
);
});
it('follower index flyout', async () => {
// https://github.com/elastic/kibana/issues/135503
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';

export default ({ getPageObjects, getService }: FtrProviderContext) => {
const pageObjects = getPageObjects([
'common',
'remoteClusters',
'indexManagement',
'crossClusterReplication',
]);
const security = getService('security');
const retry = getService('retry');
const testSubjects = getService('testSubjects');
const remoteEs = getService('remoteEs' as 'es');
const localEs = getService('es');

describe('CCS Remote Clusters > Index Management', function () {
const leaderName = 'my-index';
const followerName = 'my-follower';
before(async () => {
await security.testUser.setRoles(['superuser']);
// This test is temporarily using superuser because of an issue with the permissions
// of the follower index creation wizard. There is an open issue to address the issue.
// We can change the permissions to use follower_index_user once the issue is fixed.
// https://github.com/elastic/kibana/issues/143720
// await security.testUser.setRoles(['follower_index_user']);
});

describe('Remote Clusters', function () {
before(async () => {
await pageObjects.common.navigateToApp('remoteClusters');
});

it('Verify "ftr-remote" remote cluster exists', async () => {
await retry.waitFor('table to be visible', async () => {
return await testSubjects.isDisplayed('remoteClusterListTable');
});
const remotes = await pageObjects.remoteClusters.getRemoteClustersList();
expect(remotes.length).to.eql(1);
expect(remotes[0].remoteName).to.eql('ftr-remote');
expect(remotes[0].remoteAddress).to.contain('localhost');
expect(remotes[0].remoteStatus).to.eql('Connected');
expect(remotes[0].remoteConnectionCount).to.eql('1');
expect(remotes[0].remoteMode).to.eql('default');
});
});

describe('Cross Cluster Replication', function () {
before(async () => {
await remoteEs.indices.create({
index: leaderName,
body: {
settings: { number_of_shards: 1, soft_deletes: { enabled: true } },
},
});
await pageObjects.common.navigateToApp('crossClusterReplication');
await retry.waitFor('indices table to be visible', async () => {
return await testSubjects.isDisplayed('createFollowerIndexButton');
});
});
it('Create Follower Index', async () => {
await pageObjects.crossClusterReplication.clickCreateFollowerIndexButton();
await pageObjects.crossClusterReplication.createFollowerIndex(
leaderName,
followerName,
true,
'1s'
);
});
});
describe('Index Management', function () {
before(async () => {
await remoteEs.index({
index: leaderName,
body: { a: 'b' },
});
await pageObjects.common.navigateToApp('indexManagement');
await retry.waitForWithTimeout('indice table to be visible', 15000, async () => {
return await testSubjects.isDisplayed('indicesList');
});
});
it('Verify that the follower index is duplicating from the remote.', async () => {
await pageObjects.indexManagement.clickIndiceAt(0);
await pageObjects.indexManagement.performIndexActionInDetailPanel('flush');
await testSubjects.click('euiFlyoutCloseButton');
await pageObjects.common.navigateToApp('indexManagement');
await retry.waitForWithTimeout('indice table to be visible', 15000, async () => {
return await testSubjects.isDisplayed('indicesList');
});

const indicesList = await pageObjects.indexManagement.getIndexList();
const followerIndex = indicesList[0];
expect(followerIndex.indexDocuments).to.eql('1');
});
});

after(async () => {
await localEs.indices.delete({
index: followerName,
});
await remoteEs.indices.delete({
index: leaderName,
});
await security.testUser.restoreDefaults();
});
});
};
27 changes: 27 additions & 0 deletions x-pack/test/functional/config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,33 @@ export default async function ({ readConfigFile }) {
cluster: ['manage', 'manage_ccr'],
},
},
// There is an issue open for follower_index_user permissions not working correctly
// in kibana.
// https://github.com/elastic/kibana/issues/143720
// follower_index_user: {
// elasticsearch: {
// cluster: ['monitor', 'manage', 'manage_ccr', 'transport_client', 'read_ccr', 'all'],
// indices: [
// {
// names: ['*'],
// privileges: [
// 'write',
// 'monitor',
// 'manage_follow_index',
// 'manage_leader_index',
// 'read',
// 'view_index_metadata',
// ],
// },
// ],
// },
// kibana: [
// {
// base: ['all'],
// spaces: ['*'],
// },
// ],
// },

manage_ilm: {
elasticsearch: {
Expand Down
4 changes: 3 additions & 1 deletion x-pack/test/functional/config.ccs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
testFiles: [
require.resolve('./apps/canvas'),
require.resolve('./apps/lens/group1'),
require.resolve('./apps/remote_clusters/ccs/remote_clusters_index_management_flow'),
require.resolve('./apps/rollup_job'),
],

Expand All @@ -29,10 +30,11 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
...functionalConfig.get('security'),
remoteEsRoles: {
ccs_remote_search: {
cluster: ['manage', 'manage_ccr'],
indices: [
{
names: ['*'],
privileges: ['read', 'view_index_metadata', 'read_cross_cluster'],
privileges: ['read', 'view_index_metadata', 'read_cross_cluster', 'monitor'],
},
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,23 @@ export function CrossClusterReplicationPageProvider({ getService }: FtrProviderC
return await testSubjects.isDisplayed('nameInput');
});
},
async createFollowerIndex(leader: string, follower: string) {
async createFollowerIndex(
leader: string,
follower: string,
advancedSettings: boolean = false,
readPollTimeout?: string
) {
await testSubjects.setValue('leaderIndexInput', leader);
await testSubjects.setValue('followerIndexInput', follower);
if (advancedSettings) {
await this.clickAdvancedSettingsToggle();
await retry.waitFor('advanced settings to be shown', async () => {
return await testSubjects.isDisplayed('readPollTimeoutInput');
});
if (readPollTimeout) {
await testSubjects.setValue('readPollTimeoutInput', readPollTimeout);
}
}
await testSubjects.click('submitButton');
await retry.waitForWithTimeout('follower index to be in table', 45000, async () => {
return await testSubjects.isDisplayed('maxReadReqSize');
Expand All @@ -55,5 +69,8 @@ export function CrossClusterReplicationPageProvider({ getService }: FtrProviderC
return await testSubjects.isDisplayed('settingsValues');
});
},
async clickAdvancedSettingsToggle() {
await testSubjects.click('advancedSettingsToggle');
},
};
}
52 changes: 36 additions & 16 deletions x-pack/test/functional/page_objects/index_management_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,46 @@ export function IndexManagementPageProvider({ getService }: FtrProviderContext)
});
},

async performIndexActionInDetailPanel(action: string) {
await this.clickContextMenuInDetailPanel();
if (action === 'flush') {
await testSubjects.click('flushIndexMenuButton');
}
},

async clickContextMenuInDetailPanel() {
await testSubjects.click('indexActionsContextMenuButton');
},

async getIndexList() {
const table = await find.byCssSelector('table');
const $ = await table.parseDomContent();
const indexList = await $.findTestSubjects('indexTableRow')
.toArray()
.map((row) => {
const rows = await table.findAllByTestSubject('indexTableRow');
return await Promise.all(
rows.map(async (row) => {
return {
indexName: $(row).findTestSubject('indexTableIndexNameLink').text(),
indexHealth: $(row).findTestSubject('indexTableCell-health').text(),
indexStatus: $(row).findTestSubject('indexTableCell-status').text(),
indexPrimary: $(row).findTestSubject('indexTableCell-primary').text(),
indexReplicas: $(row).findTestSubject('indexTableCell-replica').text(),
indexDocuments: $(row)
.findTestSubject('indexTableCell-documents')
.text()
.replace('documents', ''),
indexSize: $(row).findTestSubject('indexTableCell-size').text(),
indexLink: await row.findByTestSubject('indexTableIndexNameLink'),
indexName: await (
await row.findByTestSubject('indexTableIndexNameLink')
).getVisibleText(),
indexHealth: await (
await row.findByTestSubject('indexTableCell-health')
).getVisibleText(),
indexStatus: await (
await row.findByTestSubject('indexTableCell-status')
).getVisibleText(),
indexPrimary: await (
await row.findByTestSubject('indexTableCell-primary')
).getVisibleText(),
indexReplicas: await (
await row.findByTestSubject('indexTableCell-replica')
).getVisibleText(),
indexDocuments: await (
await (await row.findByTestSubject('indexTableCell-documents')).getVisibleText()
).replace('documents', ''),
indexSize: await (await row.findByTestSubject('indexTableCell-size')).getVisibleText(),
};
});
return indexList;
})
);
},

async changeTabs(
Expand Down
Loading