Skip to content

Commit

Permalink
Merge branch 'master' into input-diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
gally47 authored Jan 6, 2025
2 parents 27c8be0 + b8e039e commit 6428e55
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 154 deletions.
4 changes: 4 additions & 0 deletions changelog/unreleased/issue-21248.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type = "f"
message = "Add error handling for event definition bulk action on general perspective."

pulls = ["21248"]
4 changes: 4 additions & 0 deletions changelog/unreleased/pr-21208.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type = "f"
message = "batching request for index block status if the combined length of the indices exceed the max possible URL length "

pulls = ["21208"]
4 changes: 4 additions & 0 deletions changelog/unreleased/pr-21238.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type = "a"
message = "Enabling bulk actions for event definitions."

pulls = ["21238"]
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ public class IndicesAdapterES7 implements IndicesAdapter {
private final ClusterStateApi clusterStateApi;
private final IndexTemplateAdapter indexTemplateAdapter;

// this is the maximum amount of bytes that the index list is supposed to fill in a request,
// it assumes that these don't need url encoding. If we exceed the maximum, we request settings for all indices
// and filter after wards
private final int MAX_INDICES_URL_LENGTH = 3000;

@Inject
public IndicesAdapterES7(ElasticsearchClient client,
StatsApi statsApi,
Expand Down Expand Up @@ -435,14 +440,17 @@ public IndicesBlockStatus getIndicesBlocksStatus(final List<String> indices) {
if (indices == null || indices.isEmpty()) {
throw new IllegalArgumentException("Expecting list of indices with at least one index present.");
}
final GetSettingsRequest getSettingsRequest = new GetSettingsRequest()
.indices(indices.toArray(new String[]{}))

final GetSettingsRequest request = new GetSettingsRequest()
.indicesOptions(IndicesOptions.fromOptions(false, true, true, true))
.names(new String[]{});
.names("index.blocks.read", "index.blocks.write", "index.blocks.metadata", "index.blocks.read_only", "index.blocks.read_only_allow_delete");

final var maxLengthExceeded = String.join(",", indices).length() > MAX_INDICES_URL_LENGTH;
final GetSettingsRequest getSettingsRequest = maxLengthExceeded ? request : request.indices(indices.toArray(new String[]{}));

return client.execute((c, requestOptions) -> {
final GetSettingsResponse settingsResponse = c.indices().getSettings(getSettingsRequest, requestOptions);
return BlockSettingsParser.parseBlockSettings(settingsResponse);
return BlockSettingsParser.parseBlockSettings(settingsResponse, maxLengthExceeded ? Optional.of(indices) : Optional.empty());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import org.graylog.shaded.elasticsearch7.org.elasticsearch.common.settings.Settings;
import org.graylog2.indexer.indices.blocks.IndicesBlockStatus;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -29,23 +32,31 @@ public class BlockSettingsParser {
static final String BLOCK_SETTINGS_PREFIX = "index.blocks.";

public static IndicesBlockStatus parseBlockSettings(final GetSettingsResponse settingsResponse) {
IndicesBlockStatus result = new IndicesBlockStatus();
return parseBlockSettings(settingsResponse, Optional.empty());
}

public static IndicesBlockStatus parseBlockSettings(final GetSettingsResponse settingsResponse, final Optional<List<String>> indices) {
final IndicesBlockStatus result = new IndicesBlockStatus();
final ImmutableOpenMap<String, Settings> indexToSettingsMap = settingsResponse.getIndexToSettings();
final String[] indicesInResponse = indexToSettingsMap.keys().toArray(String.class);
for (String index : indicesInResponse) {
final Settings blockSettings = indexToSettingsMap.get(index).getByPrefix(BLOCK_SETTINGS_PREFIX);

if (!blockSettings.isEmpty()) {
final Set<String> blockSettingsNames = blockSettings.names();
final Set<String> blockSettingsSetToTrue = blockSettingsNames.stream()
.filter(s -> blockSettings.getAsBoolean(s, false))
.map(s -> BLOCK_SETTINGS_PREFIX + s)
.collect(Collectors.toSet());
if (!blockSettingsSetToTrue.isEmpty()) {
result.addIndexBlocks(index, blockSettingsSetToTrue);

indices.orElse(Arrays.stream(indicesInResponse).toList()).forEach(index -> {
final var settings = indexToSettingsMap.get(index);
if(settings != null) {
final Settings blockSettings = settings.getByPrefix(BLOCK_SETTINGS_PREFIX);

if (!blockSettings.isEmpty()) {
final Set<String> blockSettingsNames = blockSettings.names();
final Set<String> blockSettingsSetToTrue = blockSettingsNames.stream()
.filter(s -> blockSettings.getAsBoolean(s, false))
.map(s -> BLOCK_SETTINGS_PREFIX + s)
.collect(Collectors.toSet());
if (!blockSettingsSetToTrue.isEmpty()) {
result.addIndexBlocks(index, blockSettingsSetToTrue);
}
}
}
}
});

return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -97,6 +98,7 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.graylog.storage.opensearch2.OpenSearchClient.withTimeout;

Expand All @@ -109,6 +111,11 @@ public class IndicesAdapterOS2 implements IndicesAdapter {
private final ClusterStateApi clusterStateApi;
private final IndexTemplateAdapter indexTemplateAdapter;

// this is the maximum amount of bytes that the index list is supposed to fill in a request,
// it assumes that these don't need url encoding. If we exceed the maximum, we request settings for all indices
// and filter after wards
private final int MAX_INDICES_URL_LENGTH = 3000;

@Inject
public IndicesAdapterOS2(OpenSearchClient client,
StatsApi statsApi,
Expand Down Expand Up @@ -431,19 +438,23 @@ public List<ShardsInfo> getShardsInfo(String indexName) {
return catApi.getShardsInfo(indexName);
}


@Override
public IndicesBlockStatus getIndicesBlocksStatus(final List<String> indices) {
if (indices == null || indices.isEmpty()) {
throw new IllegalArgumentException("Expecting list of indices with at least one index present.");
}
final GetSettingsRequest getSettingsRequest = new GetSettingsRequest()
.indices(indices.toArray(new String[]{}))

final GetSettingsRequest request = new GetSettingsRequest()
.indicesOptions(IndicesOptions.fromOptions(false, true, true, true))
.names(new String[]{});
.names("index.blocks.read", "index.blocks.write", "index.blocks.metadata", "index.blocks.read_only", "index.blocks.read_only_allow_delete");

final var maxLengthExceeded = String.join(",", indices).length() > MAX_INDICES_URL_LENGTH;
final GetSettingsRequest getSettingsRequest = maxLengthExceeded ? request : request.indices(indices.toArray(new String[]{}));

return client.execute((c, requestOptions) -> {
final GetSettingsResponse settingsResponse = c.indices().getSettings(getSettingsRequest, requestOptions);
return BlockSettingsParser.parseBlockSettings(settingsResponse);
return BlockSettingsParser.parseBlockSettings(settingsResponse, maxLengthExceeded ? Optional.of(indices) : Optional.empty());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.graylog.shaded.opensearch2.org.opensearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.graylog.shaded.opensearch2.org.opensearch.common.settings.Settings;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -28,23 +30,30 @@ public class BlockSettingsParser {
static final String BLOCK_SETTINGS_PREFIX = "index.blocks.";

public static IndicesBlockStatus parseBlockSettings(final GetSettingsResponse settingsResponse) {
IndicesBlockStatus result = new IndicesBlockStatus();
return parseBlockSettings(settingsResponse, Optional.empty());
}

public static IndicesBlockStatus parseBlockSettings(final GetSettingsResponse settingsResponse, final Optional<List<String>> indices) {
final IndicesBlockStatus result = new IndicesBlockStatus();
final var indexToSettingsMap = settingsResponse.getIndexToSettings();
final String[] indicesInResponse = indexToSettingsMap.keySet().toArray(new String[0]);
for (String index : indicesInResponse) {
final Settings blockSettings = indexToSettingsMap.get(index).getByPrefix(BLOCK_SETTINGS_PREFIX);

if (!blockSettings.isEmpty()) {
final Set<String> blockSettingsNames = blockSettings.names();
final Set<String> blockSettingsSetToTrue = blockSettingsNames.stream()
.filter(s -> blockSettings.getAsBoolean(s, false))
.map(s -> BLOCK_SETTINGS_PREFIX + s)
.collect(Collectors.toSet());
if (!blockSettingsSetToTrue.isEmpty()) {
result.addIndexBlocks(index, blockSettingsSetToTrue);

indices.orElse(indexToSettingsMap.keySet().stream().toList()).forEach(index -> {
final var settings = indexToSettingsMap.get(index);
if(settings != null) {
final Settings blockSettings = settings.getByPrefix(BLOCK_SETTINGS_PREFIX);

if (!blockSettings.isEmpty()) {
final Set<String> blockSettingsNames = blockSettings.names();
final Set<String> blockSettingsSetToTrue = blockSettingsNames.stream()
.filter(s -> blockSettings.getAsBoolean(s, false))
.map(s -> BLOCK_SETTINGS_PREFIX + s)
.collect(Collectors.toSet());
if (!blockSettingsSetToTrue.isEmpty()) {
result.addIndexBlocks(index, blockSettingsSetToTrue);
}
}
}
}
});

return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static org.junit.Assert.assertEquals;
Expand All @@ -35,7 +36,7 @@ public class BlockSettingsParserTest {
@Test
public void noBlockedIndicesIdentifiedIfEmptyResponseParsed() {
GetSettingsResponse emptyResponse = new GetSettingsResponse(Map.of(), Map.of());
final IndicesBlockStatus indicesBlockStatus = BlockSettingsParser.parseBlockSettings(emptyResponse);
final IndicesBlockStatus indicesBlockStatus = BlockSettingsParser.parseBlockSettings(emptyResponse, Optional.empty());
assertNotNull(indicesBlockStatus);
assertEquals(0, indicesBlockStatus.countBlockedIndices());
}
Expand All @@ -44,7 +45,7 @@ public void noBlockedIndicesIdentifiedIfEmptyResponseParsed() {
public void noBlockedIndicesIdentifiedIfEmptySettingsPresent() {
var settingsBuilder = Map.of("index_0", Settings.builder().build());
GetSettingsResponse emptySettingsResponse = new GetSettingsResponse(settingsBuilder, Map.of());
final IndicesBlockStatus indicesBlockStatus = BlockSettingsParser.parseBlockSettings(emptySettingsResponse);
final IndicesBlockStatus indicesBlockStatus = BlockSettingsParser.parseBlockSettings(emptySettingsResponse, Optional.empty());
assertNotNull(indicesBlockStatus);
assertEquals(0, indicesBlockStatus.countBlockedIndices());
}
Expand All @@ -64,7 +65,7 @@ public void parserProperlyResponseWithMultipleIndicesWithDifferentBlockSettings(
.put("index.blocks.read_only_allow_delete", true)
.build());
GetSettingsResponse settingsResponse = new GetSettingsResponse(settingsBuilder, Map.of());
final IndicesBlockStatus indicesBlockStatus = BlockSettingsParser.parseBlockSettings(settingsResponse);
final IndicesBlockStatus indicesBlockStatus = BlockSettingsParser.parseBlockSettings(settingsResponse, Optional.empty());
assertNotNull(indicesBlockStatus);
assertEquals(3, indicesBlockStatus.countBlockedIndices());
final Set<String> blockedIndices = indicesBlockStatus.getBlockedIndices();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"dependencies": {
"@babel/eslint-parser": "7.16.5",
"@tanstack/eslint-plugin-query": "4.36.1",
"@typescript-eslint/eslint-plugin": "8.18.1",
"@typescript-eslint/parser": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.19.0",
"@typescript-eslint/parser": "8.19.0",
"eslint": "8.57.0",
"eslint-config-airbnb": "19.0.4",
"eslint-import-resolver-webpack": "0.13.10",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ const BulkActions = () => {
if (failures?.length) {
const notUpdatedDefinitionIds = failures.map(({ entity_id }) => entity_id);
setSelectedEntities(notUpdatedDefinitionIds);
UserNotification.error(`${notUpdatedDefinitionIds.length} out of ${selectedItemsAmount} selected ${getDescriptor(selectedItemsAmount)} could not be ${actionType}d.`);
} else {
setSelectedEntities([]);
UserNotification.success(`${selectedItemsAmount} ${getDescriptor(selectedItemsAmount)} ${StringUtils.pluralize(selectedItemsAmount, 'was', 'were')} ${actionType}d successfully.`, 'Success');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import * as React from 'react';
import { useCallback } from 'react';

import {
QueryHelper,
Expand All @@ -24,9 +23,9 @@ import {
} from 'components/common';
import { Link } from 'components/common/router';
import Routes from 'routing/Routes';
import type { ColumnRenderers } from 'components/common/EntityDataTable';
import FilterValueRenderers from 'components/streams/StreamsOverview/FilterValueRenderers';
import { keyFn, fetchEventDefinitions } from 'components/event-definitions/hooks/useEventDefinitions';
import BulkActions from 'components/event-definitions/event-definitions/BulkActions';

import EventDefinitionActions from './EventDefinitionActions';
import SchedulingCell from './SchedulingCell';
Expand All @@ -35,7 +34,7 @@ import StatusCell from './StatusCell';
import type { EventDefinition } from '../event-definitions-types';
import { DEFAULT_LAYOUT, ADDITIONAL_ATTRIBUTES, COLUMNS_ORDER } from '../constants';

const customColumnRenderers = (): ColumnRenderers<EventDefinition> => ({
const customColumnRenderers = {
attributes: {
title: {
renderCell: (title: string, eventDefinition) => (
Expand All @@ -62,28 +61,29 @@ const customColumnRenderers = (): ColumnRenderers<EventDefinition> => ({
staticWidth: 100,
},
},
});

const EventDefinitionsContainer = () => {
const columnRenderers = customColumnRenderers();
};

const renderEventDefinitionActions = useCallback((listItem: EventDefinition) => (
<EventDefinitionActions eventDefinition={listItem} />
), []);
const bulkSelection = {
actions: <BulkActions />,

return (
<PaginatedEntityTable<EventDefinition> humanName="event definitions"
columnsOrder={COLUMNS_ORDER}
additionalAttributes={ADDITIONAL_ATTRIBUTES}
queryHelpComponent={<QueryHelper entityName="event definition" />}
tableLayout={DEFAULT_LAYOUT}
fetchEntities={fetchEventDefinitions}
entityActions={renderEventDefinitionActions}
keyFn={keyFn}
entityAttributesAreCamelCase={false}
filterValueRenderers={FilterValueRenderers}
columnRenderers={columnRenderers} />
);
};
const renderEventDefinitionActions = (listItem: EventDefinition) => (
<EventDefinitionActions eventDefinition={listItem} />
);

const EventDefinitionsContainer = () => (
<PaginatedEntityTable<EventDefinition> humanName="event definitions"
columnsOrder={COLUMNS_ORDER}
additionalAttributes={ADDITIONAL_ATTRIBUTES}
queryHelpComponent={<QueryHelper entityName="event definition" />}
tableLayout={DEFAULT_LAYOUT}
fetchEntities={fetchEventDefinitions}
entityActions={renderEventDefinitionActions}
keyFn={keyFn}
entityAttributesAreCamelCase={false}
filterValueRenderers={FilterValueRenderers}
columnRenderers={customColumnRenderers}
bulkSelection={bulkSelection} />
);

export default EventDefinitionsContainer;
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ export const UseCreateViewForEvent = (

const groupBy = eventDefinition?.config?.group_by ?? [];

const searchFilters = eventDefinition.config?.filters;
const searchFilters = eventDefinition?.config?.filters;

return useMemo(
() => ViewGenerator({ streams, streamCategories, timeRange, queryString, aggregations, groupBy, queryParameters, searchFilters }),
Expand Down
Loading

0 comments on commit 6428e55

Please sign in to comment.