Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
176af36
Add Rollup ILM Action
talevy Nov 24, 2020
ca3e695
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Dec 8, 2020
3631adc
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Dec 8, 2020
184c7ca
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Dec 9, 2020
434f49c
respond to review
talevy Dec 9, 2020
fe1f124
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Dec 14, 2020
638cbe7
fix for latest master
talevy Dec 14, 2020
91371d9
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Dec 21, 2020
e46d4ec
remove delete option and add to hot before snapshotting
talevy Dec 21, 2020
3e38fd6
enable rollup_v2 flag for ilm tests
talevy Jan 4, 2021
277549b
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 4, 2021
6f7f6f3
put Rollup behind feature flag in ilm hot phase actions
talevy Jan 4, 2021
ff38007
fix rollup ilm action test
talevy Jan 4, 2021
a5b1bb9
really fix it
talevy Jan 5, 2021
c430366
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 12, 2021
d954f55
update rollup ilm to more steps and retryable
talevy Jan 12, 2021
4679677
fix test bugs
talevy Jan 15, 2021
4091a96
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 15, 2021
ffcc4a2
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 19, 2021
d9523a8
simplify and fix tests
talevy Jan 19, 2021
d53427e
fix checkstyle
talevy Jan 19, 2021
05de2e1
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 20, 2021
0f8ebcc
re-introduce policy updating by way of a new step
talevy Jan 20, 2021
1905843
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 21, 2021
b622f39
fix merge exceptions
talevy Jan 21, 2021
968e7aa
fix test setup
talevy Jan 25, 2021
1d03113
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 25, 2021
96a1622
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 26, 2021
c9e31d5
docs and cleanup
talevy Jan 26, 2021
1d1fc31
add docs to ILM Actions page
talevy Jan 26, 2021
49b5802
place ILM Rollup Docs behind unreleased branch conditional
talevy Jan 26, 2021
e340f07
Update docs/reference/ilm/actions/ilm-rollup.asciidoc
talevy Jan 27, 2021
7efb1a3
Update docs/reference/ilm/actions/ilm-rollup.asciidoc
talevy Jan 27, 2021
10487aa
Update docs/reference/ilm/actions/ilm-rollup.asciidoc
talevy Jan 27, 2021
382915d
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 27, 2021
e01d063
Merge remote-tracking branch 'elastic/master' into rollup-ilm
talevy Jan 28, 2021
ec30764
prioritize rollup before shrink/forcemerge in hot phase
talevy Jan 29, 2021
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
56 changes: 56 additions & 0 deletions docs/reference/ilm/actions/ilm-rollup.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
[role="xpack"]
[[ilm-rollup]]
=== Rollup

Phases allowed: hot, cold.

Aggregates an index's time series data and stores the results in a new read-only
index. For example, you can roll up hourly data into daily or weekly summaries.

For more information about rollup, see the <<rollup-api, rollup action documentation>>

The name of the rolled up index will be the original index name of the managed index prefixed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@talevy How does this work in the context of data streams? Does it work in the context of data streams? What are the index names there?

Copy link
Copy Markdown
Contributor

@jrodewig jrodewig Jan 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ILM works on the index level, not directly on data streams. You can roll up a backing index for a data stream but not a data stream itself.

If the index is a backing index for a data stream, the rollup index is a backing index for the same stream. The name of the new rollup index is based on the name of the backing index. For example, the name of a rollup index for .ds-my-data-stream-2021.01.29-000001 would be rollup-.ds-my-data-stream-2021.01.29-000001.

I hope that helps. I'll open up a follow-up PR to better clarify this in the docs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ruflin and @jrodewig,

this is exactly how it works today, but due to some failure-scenarios we discussed recently, we're going to change this behavior.

In the context of datastreams, we will likely randomize the name of the rollup index to prevent collision and conflict with any past or rogue rollup actions. The belief is that the underlying name of the index should not be of concern to users since they will be added into the datastream and managed in ILM. Do you see any problems with this on your end @ruflin?

For this reason, it might make sense to hold off just a little bit on your docs change PR @jrodewig, but much appreciated!

I've opened #68225 to track it. Will likely change next week

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update, @talevy!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The belief is that the underlying name of the index should not be of concern to users since they will be added into the datastream and managed in ILM

If this is the case, it is great. I was under the assumption all indices belong to a data stream must use the .ds-* prefix and be hidden. So I expect index names like .ds-rollup-* or something similar. This would also ensure there are no conflicts and makes it clear that these rollups belong to the data streams.

The rollup- prefix is what put me on the wrong track here and made me assume it does not belong to the data stream.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is actually common for indices managed by ILM to be renamed with a new prefix. For example, shrunken indices start with the shrunk- prefix.

independent of the name, the indices will be hidden and added to the backing datastream

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@talevy Interesting. Why are these not prefixed by a . and not inside .ds-*-shrunk-* or similar to indicate they belong together? I think I'm derailing but could you share a link where I can read up on this? The part I'm concerned is that this not seem to fully fit into our naming scheme: https://www.elastic.co/blog/an-introduction-to-the-elastic-data-stream-naming-scheme

with `rollup-`.

[[ilm-rollup-options]]
==== Rollup options
`config`::
(Required, integer)
The rollup configuration, a more detailed description of the
rollup configuration specification can be found <<rollup-api-request-body,here>>.

`rollup_policy`::
(Optional, string)
The name of an <<index-lifecycle-management, {ilm}>> ({ilm-init}) policy to associate
with the newly created rollup index.

[[ilm-rollup-ex]]
==== Example

[source,console]
--------------------------------------------------
PUT _ilm/policy/my_policy
{
"policy": {
"phases": {
"cold": {
"actions": {
"rollup" : {
"config": {
"groups": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "1y"
}
},
"metrics": [
{ "field": "temperature", "metrics": [ "avg" ] }
]
}
}
}
}
}
}
}
--------------------------------------------------
26 changes: 19 additions & 7 deletions docs/reference/ilm/ilm-actions.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<<ilm-allocate,Allocate>>::
Move shards to nodes with different performance characteristics
and reduce the number of replicas.
and reduce the number of replicas.

<<ilm-delete,Delete>>::
Permanently remove the index.
Expand All @@ -22,10 +22,10 @@ Move the index shards to the <<data-tiers, data tier>> that corresponds
to the current {ilm-init} phase.

<<ilm-readonly,Read only>>::
Block write operations to the index.
Block write operations to the index.

<<ilm-rollover,Rollover>>::
Remove the index as the write index for the rollover alias and
Remove the index as the write index for the rollover alias and
start indexing to a new index.

<<ilm-searchable-snapshot, Searchable snapshot>>::
Expand All @@ -35,17 +35,25 @@ and mount it as a searchable snapshot.

<<ilm-set-priority,Set priority>>::
Lower the priority of an index as it moves through the lifecycle
to ensure that hot indices are recovered first.
to ensure that hot indices are recovered first.

<<ilm-shrink,Shrink>>::
Reduce the number of primary shards by shrinking the index into a new index.

<<ilm-unfollow,Unfollow>>::
Convert a follower index to a regular index.
Performed automatically before a rollover, shrink, or searchable snapshot action.
Performed automatically before a rollover, shrink, or searchable snapshot action.

<<ilm-wait-for-snapshot,Wait for snapshot>>::
Ensure that a snapshot exists before deleting the index.
Ensure that a snapshot exists before deleting the index.

ifdef::permanently-unreleased-branch[]

<<ilm-rollup,Rollup>>::
Aggregates an index's time series data and stores the results in a new read-only
index. For example, you can roll up hourly data into daily or weekly summaries.

endif::[]

include::actions/ilm-allocate.asciidoc[]
include::actions/ilm-delete.asciidoc[]
Expand All @@ -59,3 +67,7 @@ include::actions/ilm-set-priority.asciidoc[]
include::actions/ilm-shrink.asciidoc[]
include::actions/ilm-unfollow.asciidoc[]
include::actions/ilm-wait-for-snapshot.asciidoc[]

ifdef::permanently-unreleased-branch[]
include::actions/ilm-rollup.asciidoc[]
endif::[]
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import org.elasticsearch.xpack.core.ilm.MigrateAction;
import org.elasticsearch.xpack.core.ilm.ReadOnlyAction;
import org.elasticsearch.xpack.core.ilm.RolloverAction;
import org.elasticsearch.xpack.core.ilm.RollupILMAction;
import org.elasticsearch.xpack.core.ilm.SearchableSnapshotAction;
import org.elasticsearch.xpack.core.ilm.SetPriorityAction;
import org.elasticsearch.xpack.core.ilm.ShrinkAction;
Expand Down Expand Up @@ -422,7 +423,7 @@ public List<ActionType<? extends ActionResponse>> getClientActions() {

@Override
public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
return Arrays.asList(
List<NamedWriteableRegistry.Entry> namedWriteables = new ArrayList<>(Arrays.asList(
// graph
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.GRAPH, GraphFeatureSetUsage::new),
// logstash
Expand Down Expand Up @@ -526,7 +527,13 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
// Data Tiers
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.DATA_TIERS, DataTiersFeatureSetUsage::new),
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.RUNTIME_FIELDS, RuntimeFieldsFeatureSetUsage::new)
);
));

if (RollupV2.isEnabled()) {
namedWriteables.add(new NamedWriteableRegistry.Entry(LifecycleAction.class, RollupILMAction.NAME, RollupILMAction::new));
}

return namedWriteables;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ilm;

import org.elasticsearch.client.Client;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.ilm.Step.StepKey;
import org.elasticsearch.xpack.core.rollup.RollupActionConfig;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
* A {@link LifecycleAction} which calls {@link org.elasticsearch.xpack.core.rollup.action.RollupAction} on an index
*/
public class RollupILMAction implements LifecycleAction {
public static final String NAME = "rollup";

private static final ParseField CONFIG_FIELD = new ParseField("config");
private static final ParseField POLICY_FIELD = new ParseField("rollup_policy");

@SuppressWarnings("unchecked")
private static final ConstructingObjectParser<RollupILMAction, Void> PARSER = new ConstructingObjectParser<>(NAME,
a -> new RollupILMAction((RollupActionConfig) a[0], (String) a[1]));

private final RollupActionConfig config;
private final String rollupPolicy;

static {
PARSER.declareField(ConstructingObjectParser.constructorArg(),
(p, c) -> RollupActionConfig.fromXContent(p), CONFIG_FIELD, ObjectParser.ValueType.OBJECT);
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), POLICY_FIELD);
}

public static RollupILMAction parse(XContentParser parser) {
return PARSER.apply(parser, null);
}

public RollupILMAction(RollupActionConfig config, @Nullable String rollupPolicy) {
this.config = config;
this.rollupPolicy = rollupPolicy;
}

public RollupILMAction(StreamInput in) throws IOException {
this(new RollupActionConfig(in), in.readOptionalString());
}

@Override
public String getWriteableName() {
return NAME;
}

RollupActionConfig config() {
return config;
}

String rollupPolicy() {
return rollupPolicy;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(CONFIG_FIELD.getPreferredName(), config);
if (rollupPolicy != null) {
builder.field(POLICY_FIELD.getPreferredName(), rollupPolicy);
}
builder.endObject();
return builder;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
config.writeTo(out);
out.writeOptionalString(rollupPolicy);
}

@Override
public boolean isSafeAction() {
return false;
}

@Override
public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) {
StepKey checkNotWriteIndex = new StepKey(phase, NAME, CheckNotDataStreamWriteIndexStep.NAME);
StepKey readOnlyKey = new StepKey(phase, NAME, ReadOnlyStep.NAME);
StepKey rollupKey = new StepKey(phase, NAME, NAME);
CheckNotDataStreamWriteIndexStep checkNotWriteIndexStep = new CheckNotDataStreamWriteIndexStep(checkNotWriteIndex,
readOnlyKey);
ReadOnlyStep readOnlyStep = new ReadOnlyStep(readOnlyKey, rollupKey, client);
if (rollupPolicy == null) {
Step rollupStep = new RollupStep(rollupKey, nextStepKey, client, config);
return List.of(checkNotWriteIndexStep, readOnlyStep, rollupStep);
} else {
StepKey updateRollupIndexPolicyStepKey = new StepKey(phase, NAME, UpdateRollupIndexPolicyStep.NAME);
Step rollupStep = new RollupStep(rollupKey, updateRollupIndexPolicyStepKey, client, config);
Step updateRollupIndexPolicyStep = new UpdateRollupIndexPolicyStep(updateRollupIndexPolicyStepKey, nextStepKey,
client, rollupPolicy);
return List.of(checkNotWriteIndexStep, readOnlyStep, rollupStep, updateRollupIndexPolicyStep);
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

RollupILMAction that = (RollupILMAction) o;

return Objects.equals(this.config, that.config)
&& Objects.equals(this.rollupPolicy, that.rollupPolicy);
}

@Override
public int hashCode() {
return Objects.hash(config, rollupPolicy);
}

@Override
public String toString() {
return Strings.toString(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ilm;

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateObserver;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.xpack.core.rollup.RollupActionConfig;
import org.elasticsearch.xpack.core.rollup.action.RollupAction;

import java.util.Objects;

/**
* Rolls up index using a {@link RollupActionConfig}
*/
public class RollupStep extends AsyncActionStep {
public static final String NAME = "rollup";
public static final String ROLLUP_INDEX_NAME_PREFIX = "rollup-";

private final RollupActionConfig config;

public RollupStep(StepKey key, StepKey nextStepKey, Client client, RollupActionConfig config) {
super(key, nextStepKey, client);
this.config = config;
}

public static String getRollupIndexName(String index) {
return ROLLUP_INDEX_NAME_PREFIX + index;
}

@Override
public boolean isRetryable() {
return true;
}

@Override
public void performAction(IndexMetadata indexMetadata, ClusterState currentState, ClusterStateObserver observer, Listener listener) {
String originalIndex = indexMetadata.getIndex().getName();
RollupAction.Request request = new RollupAction.Request(originalIndex, getRollupIndexName(originalIndex), config);
// currently RollupAction always acknowledges action was complete when no exceptions are thrown.
getClient().execute(RollupAction.INSTANCE, request,
ActionListener.wrap(response -> listener.onResponse(true), listener::onFailure));
}

public RollupActionConfig getConfig() {
return config;
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), config);
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
RollupStep other = (RollupStep) obj;
return super.equals(obj)
&& Objects.equals(config, other.config);
}
}
Loading