mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
# Backport This will backport the following commits from `main` to `8.17`: - [[data views] data views + rollup index referenced by alias (#212592)](https://github.com/elastic/kibana/pull/212592) <!--- Backport version: 9.6.6 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Matthew Kime","email":"matt@mattki.me"},"sourceCommit":{"committedDate":"2025-03-11T01:16:04Z","message":"[data views] data views + rollup index referenced by alias (#212592)\n\n## Summary\n\nUpgrading to 9.x involves reindexing indices created in 7.x, which does\ninclude rollup indices. Reindexing means relying on aliases to preserve\nexisting index names. As it turns out, our existing code did not work\nwith rollups that referenced aliases, rather than indices. This is\nbecause the index name is used as an object key even if it was retrieved\nvia alias.\n\n\nNote - I need to verify this on 9.0 from scratch. I used upgraded data\nand need to verify the steps to make this work when testing.\n\nTo test\n1. Add sample data\n2. Create a rollup job that references the sample data. \n3. Create a data view that references the rollup index. It may take a\nfew minutes for the rollup index to be populated.\n4. Create an alias from the dev console, like such - \n\n```\nPOST _aliases\n{\n \"actions\": [\n {\n \"add\": {\n \"index\": \"rollup\",\n \"alias\": \"my-alias\"\n }\n }\n ]\n}\n``` \n5. Create a rollup data view based in the alias you just created.\n\nPart of https://github.com/elastic/kibana/issues/211850\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"5b6dbf2b2711c94cb32a39e6487f95abd128433c","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Feature:Data Views","Team:Kibana Management","Feature:Rollups","backport:prev-minor","v9.1.0"],"title":"[data views] data views + rollup index referenced by alias","number":212592,"url":"https://github.com/elastic/kibana/pull/212592","mergeCommit":{"message":"[data views] data views + rollup index referenced by alias (#212592)\n\n## Summary\n\nUpgrading to 9.x involves reindexing indices created in 7.x, which does\ninclude rollup indices. Reindexing means relying on aliases to preserve\nexisting index names. As it turns out, our existing code did not work\nwith rollups that referenced aliases, rather than indices. This is\nbecause the index name is used as an object key even if it was retrieved\nvia alias.\n\n\nNote - I need to verify this on 9.0 from scratch. I used upgraded data\nand need to verify the steps to make this work when testing.\n\nTo test\n1. Add sample data\n2. Create a rollup job that references the sample data. \n3. Create a data view that references the rollup index. It may take a\nfew minutes for the rollup index to be populated.\n4. Create an alias from the dev console, like such - \n\n```\nPOST _aliases\n{\n \"actions\": [\n {\n \"add\": {\n \"index\": \"rollup\",\n \"alias\": \"my-alias\"\n }\n }\n ]\n}\n``` \n5. Create a rollup data view based in the alias you just created.\n\nPart of https://github.com/elastic/kibana/issues/211850\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"5b6dbf2b2711c94cb32a39e6487f95abd128433c"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/212592","number":212592,"mergeCommit":{"message":"[data views] data views + rollup index referenced by alias (#212592)\n\n## Summary\n\nUpgrading to 9.x involves reindexing indices created in 7.x, which does\ninclude rollup indices. Reindexing means relying on aliases to preserve\nexisting index names. As it turns out, our existing code did not work\nwith rollups that referenced aliases, rather than indices. This is\nbecause the index name is used as an object key even if it was retrieved\nvia alias.\n\n\nNote - I need to verify this on 9.0 from scratch. I used upgraded data\nand need to verify the steps to make this work when testing.\n\nTo test\n1. Add sample data\n2. Create a rollup job that references the sample data. \n3. Create a data view that references the rollup index. It may take a\nfew minutes for the rollup index to be populated.\n4. Create an alias from the dev console, like such - \n\n```\nPOST _aliases\n{\n \"actions\": [\n {\n \"add\": {\n \"index\": \"rollup\",\n \"alias\": \"my-alias\"\n }\n }\n ]\n}\n``` \n5. Create a rollup data view based in the alias you just created.\n\nPart of https://github.com/elastic/kibana/issues/211850\n\n---------\n\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"5b6dbf2b2711c94cb32a39e6487f95abd128433c"}},{"url":"https://github.com/elastic/kibana/pull/213852","number":213852,"branch":"9.0","state":"OPEN"}]}] BACKPORT-->
This commit is contained in:
parent
320c031d91
commit
ef80a354cd
9 changed files with 109 additions and 14 deletions
|
@ -142,7 +142,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
|
|||
params: {
|
||||
rollup_index: rollupIndex,
|
||||
},
|
||||
aggs: rollupIndicesCapabilities[rollupIndex].aggs,
|
||||
aggs: rollupCaps?.aggs,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
|
|||
const isLoadingSources = useObservable(dataViewEditorService.isLoadingSources$, true);
|
||||
const existingDataViewNames = useObservable(dataViewEditorService.dataViewNames$);
|
||||
const rollupIndex = useObservable(dataViewEditorService.rollupIndex$);
|
||||
const rollupCaps = useObservable(dataViewEditorService.rollupCaps$);
|
||||
const rollupIndicesCapabilities = useObservable(dataViewEditorService.rollupIndicesCaps$, {});
|
||||
|
||||
useDebounce(
|
||||
|
@ -194,7 +195,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
|
|||
dataViewEditorService.setType(type);
|
||||
}, [dataViewEditorService, type]);
|
||||
|
||||
const getRollupIndices = (rollupCaps: RollupIndicesCapsResponse) => Object.keys(rollupCaps);
|
||||
const getRollupIndices = (rollupCapsRes: RollupIndicesCapsResponse) => Object.keys(rollupCapsRes);
|
||||
|
||||
const onTypeChange = useCallback(
|
||||
(newType: INDEX_PATTERN_TYPE) => {
|
||||
|
|
|
@ -80,8 +80,15 @@ const createMatchesIndicesValidator = ({
|
|||
}
|
||||
|
||||
// A rollup index pattern needs to match one and only one rollup index.
|
||||
const rollupIndexMatches = matchedIndices.exactMatchedIndices.filter((matchedIndex) =>
|
||||
rollupIndices.includes(matchedIndex.name)
|
||||
const rollupIndexMatches = matchedIndices.exactMatchedIndices.filter(
|
||||
(matchedIndex) =>
|
||||
rollupIndices.includes(matchedIndex.name) ||
|
||||
// matched item is alias
|
||||
(matchedIndex.item.indices?.length === 1 &&
|
||||
rollupIndices.includes(matchedIndex.item.indices[0])) ||
|
||||
// matched item is an index referenced by an alias
|
||||
(matchedIndex.item.aliases?.length === 1 &&
|
||||
rollupIndices.includes(matchedIndex.item.aliases[0]))
|
||||
);
|
||||
|
||||
if (!rollupIndexMatches.length) {
|
||||
|
|
|
@ -27,7 +27,12 @@ import {
|
|||
DataViewField,
|
||||
} from '@kbn/data-views-plugin/public';
|
||||
|
||||
import { RollupIndicesCapsResponse, MatchedIndicesSet, TimestampOption } from './types';
|
||||
import {
|
||||
RollupIndicesCapsResponse,
|
||||
RollupIndiciesCapability,
|
||||
MatchedIndicesSet,
|
||||
TimestampOption,
|
||||
} from './types';
|
||||
import { getMatchedIndices, ensureMinimumTime, extractTimeFields, removeSpaces } from './lib';
|
||||
import { GetFieldsOptions } from './shared_imports';
|
||||
|
||||
|
@ -70,6 +75,7 @@ interface DataViewEditorState {
|
|||
loadingTimestampFields: boolean;
|
||||
timestampFieldOptions: TimestampOption[];
|
||||
rollupIndexName?: string | null;
|
||||
rollupCaps?: RollupIndiciesCapability;
|
||||
}
|
||||
|
||||
const defaultDataViewEditorState: DataViewEditorState = {
|
||||
|
@ -119,6 +125,7 @@ export class DataViewEditorService {
|
|||
this.loadingTimestampFields$ = stateSelector((state) => state.loadingTimestampFields);
|
||||
this.timestampFieldOptions$ = stateSelector((state) => state.timestampFieldOptions);
|
||||
this.rollupIndex$ = stateSelector((state) => state.rollupIndexName);
|
||||
this.rollupCaps$ = stateSelector((state) => state.rollupCaps);
|
||||
|
||||
// when list of matched indices is updated always update timestamp fields
|
||||
this.loadTimestampFieldsSub = this.matchedIndices$.subscribe(() => this.loadTimestampFields());
|
||||
|
@ -162,6 +169,8 @@ export class DataViewEditorService {
|
|||
|
||||
// current matched rollup index
|
||||
rollupIndex$: Observable<string | undefined | null>;
|
||||
// current matched rollup capabilities
|
||||
rollupCaps$: Observable<RollupIndiciesCapability | undefined>;
|
||||
// alernates between value and undefined so validation can treat new value as thought its a promise
|
||||
private rollupIndexForProvider$ = new Subject<string | undefined | null>();
|
||||
|
||||
|
@ -244,11 +253,27 @@ export class DataViewEditorService {
|
|||
// verify we're looking at the current result
|
||||
if (currentLoadingMatchedIndicesIdx === this.currentLoadingMatchedIndices) {
|
||||
if (type === INDEX_PATTERN_TYPE.ROLLUP) {
|
||||
const rollupIndices = exactMatched.filter((index) => isRollupIndex(index.name));
|
||||
const rollupIndices = exactMatched.filter(
|
||||
(index) =>
|
||||
isRollupIndex(index.name) ||
|
||||
// if its an alias
|
||||
(index.item.indices?.length === 1 && isRollupIndex(index.item.indices[0])) ||
|
||||
// if its an index referenced by an alias
|
||||
(index.item.aliases?.length === 1 && isRollupIndex(index.item.aliases[0]))
|
||||
);
|
||||
|
||||
newRollupIndexName = rollupIndices.length === 1 ? rollupIndices[0].name : null;
|
||||
this.updateState({ rollupIndexName: newRollupIndexName });
|
||||
const newRollupCaps = await this.rollupCapsResponse.then((response) => {
|
||||
return (
|
||||
response[newRollupIndexName || ''] ||
|
||||
// if its an alias
|
||||
response[rollupIndices[0]?.item.indices?.[0] || '']
|
||||
);
|
||||
});
|
||||
|
||||
this.updateState({ rollupIndexName: newRollupIndexName, rollupCaps: newRollupCaps });
|
||||
} else {
|
||||
this.updateState({ rollupIndexName: null });
|
||||
this.updateState({ rollupIndexName: null, rollupCaps: undefined });
|
||||
}
|
||||
|
||||
this.updateState({ matchedIndices });
|
||||
|
|
|
@ -21,7 +21,7 @@ export const successfulResolveResponse = {
|
|||
aliases: [
|
||||
{
|
||||
name: 'f-alias',
|
||||
indices: ['freeze-index', 'my-index'],
|
||||
indices: ['my-index'],
|
||||
},
|
||||
],
|
||||
data_streams: [
|
||||
|
@ -69,6 +69,16 @@ describe('getIndices', () => {
|
|||
expect(result[2].name).toBe('remoteCluster1:bar-01');
|
||||
});
|
||||
|
||||
it('should work with rollup indices based on aliases', async () => {
|
||||
const isRollupIdx = (indexName: string) => indexName === 'my-index';
|
||||
const result = await getIndices({
|
||||
http,
|
||||
pattern: 'kibana',
|
||||
isRollupIndex: isRollupIdx,
|
||||
});
|
||||
expect(result[0].tags[1].key).toBe('rollup');
|
||||
});
|
||||
|
||||
it('should ignore ccs query-all', async () => {
|
||||
expect((await getIndices({ http, pattern: '*:', isRollupIndex })).length).toBe(0);
|
||||
});
|
||||
|
|
|
@ -119,6 +119,9 @@ export const responseToItemArray = (
|
|||
const isFrozen = (index.attributes || []).includes(ResolveIndexResponseItemIndexAttrs.FROZEN);
|
||||
|
||||
tags.push(...getTags(index.name));
|
||||
index.aliases?.forEach((alias) => {
|
||||
tags.push(...getTags(alias));
|
||||
});
|
||||
if (isFrozen) {
|
||||
tags.push({ name: frozenLabel, key: 'frozen', color: 'danger' });
|
||||
}
|
||||
|
@ -130,11 +133,15 @@ export const responseToItemArray = (
|
|||
});
|
||||
});
|
||||
(response.aliases || []).forEach((alias) => {
|
||||
source.push({
|
||||
const item = {
|
||||
name: alias.name,
|
||||
tags: [{ key: 'alias', name: aliasLabel, color: 'default' }],
|
||||
item: alias,
|
||||
});
|
||||
};
|
||||
// we only need to check the first index to see if its a rollup since there can only be one alias match
|
||||
item.tags.push(...getTags(alias.indices[0]));
|
||||
item.tags.push(...getTags(alias.name));
|
||||
source.push(item);
|
||||
});
|
||||
(response.data_streams || []).forEach((dataStream) => {
|
||||
source.push({
|
||||
|
|
|
@ -71,6 +71,19 @@ describe('Index Pattern Fetcher - server', () => {
|
|||
expect(esClient.rollup.getRollupIndexCaps).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("works with index aliases - when rollup response doesn't have index as key", async () => {
|
||||
esClient.rollup.getRollupIndexCaps.mockResponse(
|
||||
rollupResponse as unknown as estypes.RollupGetRollupIndexCapsResponse
|
||||
);
|
||||
indexPatterns = new IndexPatternsFetcher(esClient, optionalParams);
|
||||
await indexPatterns.getFieldsForWildcard({
|
||||
pattern: patternList,
|
||||
type: DataViewType.ROLLUP,
|
||||
rollupIndex: 'foo',
|
||||
});
|
||||
expect(esClient.rollup.getRollupIndexCaps).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("doesn't call rollup api when given rollup data view and rollups are disabled", async () => {
|
||||
esClient.rollup.getRollupIndexCaps.mockResponse(
|
||||
rollupResponse as unknown as estypes.RollupGetRollupIndexCapsResponse
|
||||
|
|
|
@ -116,11 +116,15 @@ export class IndexPatternsFetcher {
|
|||
|
||||
if (this.rollupsEnabled && type === DataViewType.ROLLUP && rollupIndex) {
|
||||
const rollupFields: FieldDescriptor[] = [];
|
||||
const capabilityCheck = getCapabilitiesForRollupIndices(
|
||||
const capabilities = getCapabilitiesForRollupIndices(
|
||||
await this.elasticsearchClient.rollup.getRollupIndexCaps({
|
||||
index: rollupIndex,
|
||||
})
|
||||
)[rollupIndex];
|
||||
);
|
||||
|
||||
const capabilityCheck =
|
||||
// use the rollup index name BUT if its an alias, we'll take the first one
|
||||
capabilities[rollupIndex] || capabilities[Object.keys(capabilities)[0]];
|
||||
|
||||
if (capabilityCheck.error) {
|
||||
throw new Error(capabilityCheck.error);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { IScopedClusterClient } from '@kbn/core/server';
|
||||
import { Index } from '@kbn/index-management-plugin/server';
|
||||
import { isArray } from 'lodash';
|
||||
|
||||
export const rollupDataEnricher = async (indicesList: Index[], client: IScopedClusterClient) => {
|
||||
if (!indicesList || !indicesList.length) {
|
||||
|
@ -19,7 +20,10 @@ export const rollupDataEnricher = async (indicesList: Index[], client: IScopedCl
|
|||
});
|
||||
|
||||
return indicesList.map((index) => {
|
||||
const isRollupIndex = !!rollupJobData[index.name];
|
||||
let isRollupIndex = !!rollupJobData[index.name];
|
||||
if (!isRollupIndex && isArray(index.aliases)) {
|
||||
isRollupIndex = index.aliases.some((alias) => !!rollupJobData[alias]);
|
||||
}
|
||||
return {
|
||||
...index,
|
||||
isRollupIndex,
|
||||
|
|
|
@ -113,6 +113,30 @@ export default function ({ getService, getPageObjects }) {
|
|||
expect(fields).to.eql(['@timestamp', '_id', '_ignored', '_index', '_score', '_source']);
|
||||
});
|
||||
|
||||
it('create hybrid index pattern - with alias to rollup index', async () => {
|
||||
const rollupAlias = 'rollup-alias';
|
||||
await es.indices.putAlias({
|
||||
index: rollupTargetIndexName,
|
||||
name: rollupAlias,
|
||||
});
|
||||
await PageObjects.common.navigateToApp('settings');
|
||||
await PageObjects.settings.createIndexPattern(rollupAlias, '@timestamp', false);
|
||||
|
||||
await PageObjects.settings.clickKibanaIndexPatterns();
|
||||
const indexPatternNames = await PageObjects.settings.getAllIndexPatternNames();
|
||||
//The assertion is going to check that the string has the right name and that the text Rollup
|
||||
//is included (since there is a Rollup tag).
|
||||
const filteredIndexPatternNames = indexPatternNames.filter(
|
||||
(i) => i.includes(rollupIndexPatternName) && i.includes('Rollup')
|
||||
);
|
||||
expect(filteredIndexPatternNames.length).to.be(1);
|
||||
|
||||
// ensure all fields are available
|
||||
await PageObjects.settings.clickIndexPatternByName(rollupAlias);
|
||||
const fields = await PageObjects.settings.getFieldNames();
|
||||
expect(fields).to.eql(['@timestamp', '_id', '_ignored', '_index', '_score', '_source']);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
// Delete the rollup job.
|
||||
await es.rollup.deleteJob({ id: rollupJobName });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue