Skip to content

Commit aa61a1e

Browse files
authored
Stores security headers with the LifecyclePolicy and uses them for AsyncSteps (#30657)
* Stores security headers with the LifecyclePolicy and uses them for AsyncSteps x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ClientHelp er.java x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifec ycle/IndexLifecycleMetadata.java x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifec ycle/LifecyclePolicyMetadata.java x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifec ycle/LifecyclePolicyMetadataTests.java x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/IndexLifecycleRunner.java x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/LifecyclePolicyClient.java x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/PolicyStepsRegistry.java x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/action/TransportDeleteLifcycleAction.java x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/action/TransportGetLifecycleAction.java x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/action/TransportPutLifecycleAction.java x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/ExecuteStepsUpdateTaskTests.java x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/IndexLifecycleMetadataTests.java x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/IndexLifecycleRunnerTests.java x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/IndexLifecycleServiceTests.java x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/LifecyclePolicyClientTests.java x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/PolicyStepsRegistryTests.java * Small renaming and Javadocs x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/LifecyclePolicyClient.java -> x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/LifecyclePolicySecurityClient.java x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/PolicyStepsRegistry.java x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/LifecyclePolicyClientTests.java * Fixes checkstyle x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/inde xlifecycle/LifecyclePolicySecurityClient.java * Fixes checkstyle x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/LifecyclePolicyClientTests.java * Fixes Tests x-pack/plugin/index-lifecycle/src/test/java/org/elasticsearch/xpack/inde xlifecycle/ExecuteStepsUpdateTaskTests.java
1 parent 46a3aba commit aa61a1e

File tree

16 files changed

+499
-64
lines changed

16 files changed

+499
-64
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ClientHelper.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public final class ClientHelper {
4040
public static final String SECURITY_ORIGIN = "security";
4141
public static final String WATCHER_ORIGIN = "watcher";
4242
public static final String ML_ORIGIN = "ml";
43+
public static final String INDEX_LIFECYCLE_ORIGIN = "index_lifecycle";
4344
public static final String MONITORING_ORIGIN = "monitoring";
4445
public static final String DEPRECATION_ORIGIN = "deprecation";
4546
public static final String PERSISTENT_TASK_ORIGIN = "persistent_tasks";

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleMetadata.java

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import java.util.Map;
2727
import java.util.Objects;
2828
import java.util.TreeMap;
29+
import java.util.function.Function;
30+
import java.util.stream.Collectors;
2931

3032

3133
public class IndexLifecycleMetadata implements MetaData.Custom {
@@ -35,40 +37,45 @@ public class IndexLifecycleMetadata implements MetaData.Custom {
3537
@SuppressWarnings("unchecked")
3638
public static final ConstructingObjectParser<IndexLifecycleMetadata, Void> PARSER = new ConstructingObjectParser<>(
3739
TYPE, a -> new IndexLifecycleMetadata(
38-
ObjectParserUtils.convertListToMapValues(LifecyclePolicy::getName, (List<LifecyclePolicy>) a[0])));
40+
ObjectParserUtils.convertListToMapValues(LifecyclePolicyMetadata::getName, (List<LifecyclePolicyMetadata>) a[0])));
3941
static {
40-
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> LifecyclePolicy.parse(p, n),
42+
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> LifecyclePolicyMetadata.parse(p, n),
4143
v -> {
4244
throw new IllegalArgumentException("ordered " + POLICIES_FIELD.getPreferredName() + " are not supported");
4345
}, POLICIES_FIELD);
4446
}
4547

46-
private final Map<String, LifecyclePolicy> policies;
48+
private final Map<String, LifecyclePolicyMetadata> policyMetadatas;
4749

48-
public IndexLifecycleMetadata(Map<String, LifecyclePolicy> policies) {
49-
this.policies = Collections.unmodifiableMap(policies);
50+
public IndexLifecycleMetadata(Map<String, LifecyclePolicyMetadata> policies) {
51+
this.policyMetadatas = Collections.unmodifiableMap(policies);
5052
}
5153

5254
public IndexLifecycleMetadata(StreamInput in) throws IOException {
5355
int size = in.readVInt();
54-
TreeMap<String, LifecyclePolicy> policies = new TreeMap<>();
56+
TreeMap<String, LifecyclePolicyMetadata> policies = new TreeMap<>();
5557
for (int i = 0; i < size; i++) {
56-
policies.put(in.readString(), new LifecyclePolicy(in));
58+
policies.put(in.readString(), new LifecyclePolicyMetadata(in));
5759
}
58-
this.policies = policies;
60+
this.policyMetadatas = policies;
5961
}
6062

6163
@Override
6264
public void writeTo(StreamOutput out) throws IOException {
63-
out.writeVInt(policies.size());
64-
for (Map.Entry<String, LifecyclePolicy> entry : policies.entrySet()) {
65+
out.writeVInt(policyMetadatas.size());
66+
for (Map.Entry<String, LifecyclePolicyMetadata> entry : policyMetadatas.entrySet()) {
6567
out.writeString(entry.getKey());
6668
entry.getValue().writeTo(out);
6769
}
6870
}
6971

72+
public Map<String, LifecyclePolicyMetadata> getPolicyMetadatas() {
73+
return policyMetadatas;
74+
}
75+
7076
public Map<String, LifecyclePolicy> getPolicies() {
71-
return policies;
77+
return policyMetadatas.values().stream().map(LifecyclePolicyMetadata::getPolicy)
78+
.collect(Collectors.toMap(LifecyclePolicy::getName, Function.identity()));
7279
}
7380

7481
@Override
@@ -78,7 +85,7 @@ public Diff<Custom> diff(Custom previousState) {
7885

7986
@Override
8087
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
81-
builder.field(POLICIES_FIELD.getPreferredName(), policies);
88+
builder.field(POLICIES_FIELD.getPreferredName(), policyMetadatas);
8289
return builder;
8390
}
8491

@@ -99,7 +106,7 @@ public EnumSet<MetaData.XContentContext> context() {
99106

100107
@Override
101108
public int hashCode() {
102-
return Objects.hash(policies);
109+
return Objects.hash(policyMetadatas);
103110
}
104111

105112
@Override
@@ -111,7 +118,7 @@ public boolean equals(Object obj) {
111118
return false;
112119
}
113120
IndexLifecycleMetadata other = (IndexLifecycleMetadata) obj;
114-
return Objects.equals(policies, other.policies);
121+
return Objects.equals(policyMetadatas, other.policyMetadatas);
115122
}
116123

117124
@Override
@@ -121,20 +128,21 @@ public String toString() {
121128

122129
public static class IndexLifecycleMetadataDiff implements NamedDiff<MetaData.Custom> {
123130

124-
final Diff<Map<String, LifecyclePolicy>> policies;
131+
final Diff<Map<String, LifecyclePolicyMetadata>> policies;
125132

126133
IndexLifecycleMetadataDiff(IndexLifecycleMetadata before, IndexLifecycleMetadata after) {
127-
this.policies = DiffableUtils.diff(before.policies, after.policies, DiffableUtils.getStringKeySerializer());
134+
this.policies = DiffableUtils.diff(before.policyMetadatas, after.policyMetadatas, DiffableUtils.getStringKeySerializer());
128135
}
129136

130137
public IndexLifecycleMetadataDiff(StreamInput in) throws IOException {
131-
this.policies = DiffableUtils.readJdkMapDiff(in, DiffableUtils.getStringKeySerializer(), LifecyclePolicy::new,
138+
this.policies = DiffableUtils.readJdkMapDiff(in, DiffableUtils.getStringKeySerializer(), LifecyclePolicyMetadata::new,
132139
IndexLifecycleMetadataDiff::readLifecyclePolicyDiffFrom);
133140
}
134141

135142
@Override
136143
public MetaData.Custom apply(MetaData.Custom part) {
137-
TreeMap<String, LifecyclePolicy> newPolicies = new TreeMap<>(policies.apply(((IndexLifecycleMetadata) part).policies));
144+
TreeMap<String, LifecyclePolicyMetadata> newPolicies = new TreeMap<>(
145+
policies.apply(((IndexLifecycleMetadata) part).policyMetadatas));
138146
return new IndexLifecycleMetadata(newPolicies);
139147
}
140148

@@ -148,8 +156,8 @@ public String getWriteableName() {
148156
return TYPE;
149157
}
150158

151-
static Diff<LifecyclePolicy> readLifecyclePolicyDiffFrom(StreamInput in) throws IOException {
152-
return AbstractDiffable.readDiffFrom(LifecyclePolicy::new, in);
159+
static Diff<LifecyclePolicyMetadata> readLifecyclePolicyDiffFrom(StreamInput in) throws IOException {
160+
return AbstractDiffable.readDiffFrom(LifecyclePolicyMetadata::new, in);
153161
}
154162
}
155163
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.core.indexlifecycle;
8+
9+
import org.elasticsearch.cluster.AbstractDiffable;
10+
import org.elasticsearch.cluster.Diffable;
11+
import org.elasticsearch.common.ParseField;
12+
import org.elasticsearch.common.io.stream.StreamInput;
13+
import org.elasticsearch.common.io.stream.StreamOutput;
14+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
15+
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
16+
import org.elasticsearch.common.xcontent.ToXContentObject;
17+
import org.elasticsearch.common.xcontent.XContentBuilder;
18+
import org.elasticsearch.common.xcontent.XContentParser;
19+
20+
import java.io.IOException;
21+
import java.util.Map;
22+
import java.util.Objects;
23+
24+
public class LifecyclePolicyMetadata extends AbstractDiffable<LifecyclePolicyMetadata>
25+
implements ToXContentObject, Diffable<LifecyclePolicyMetadata> {
26+
27+
public static final ParseField POLICY = new ParseField("policy");
28+
public static final ParseField HEADERS = new ParseField("headers");
29+
@SuppressWarnings("unchecked")
30+
public static final ConstructingObjectParser<LifecyclePolicyMetadata, String> PARSER = new ConstructingObjectParser<>("policy_metadata",
31+
a -> new LifecyclePolicyMetadata((LifecyclePolicy) a[0], (Map<String, String>) a[1]));
32+
static {
33+
PARSER.declareObject(ConstructingObjectParser.constructorArg(), (p, c) -> LifecyclePolicy.parse(p, c), POLICY);
34+
PARSER.declareField(ConstructingObjectParser.constructorArg(), p -> p.mapStrings(), HEADERS, ValueType.OBJECT);
35+
}
36+
37+
public static LifecyclePolicyMetadata parse(XContentParser parser, String name) {
38+
return PARSER.apply(parser, name);
39+
}
40+
41+
private final LifecyclePolicy policy;
42+
private final Map<String, String> headers;
43+
44+
public LifecyclePolicyMetadata(LifecyclePolicy policy, Map<String, String> headers) {
45+
this.policy = policy;
46+
this.headers = headers;
47+
}
48+
49+
@SuppressWarnings("unchecked")
50+
public LifecyclePolicyMetadata(StreamInput in) throws IOException {
51+
this.policy = new LifecyclePolicy(in);
52+
this.headers = (Map<String, String>) in.readGenericValue();
53+
}
54+
55+
public Map<String, String> getHeaders() {
56+
return headers;
57+
}
58+
59+
public LifecyclePolicy getPolicy() {
60+
return policy;
61+
}
62+
63+
public String getName() {
64+
return policy.getName();
65+
}
66+
67+
@Override
68+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
69+
builder.startObject();
70+
builder.field(POLICY.getPreferredName(), policy);
71+
builder.field(HEADERS.getPreferredName(), headers);
72+
builder.endObject();
73+
return builder;
74+
}
75+
76+
@Override
77+
public void writeTo(StreamOutput out) throws IOException {
78+
policy.writeTo(out);
79+
out.writeGenericValue(headers);
80+
}
81+
82+
@Override
83+
public int hashCode() {
84+
return Objects.hash(policy, headers);
85+
}
86+
87+
@Override
88+
public boolean equals(Object obj) {
89+
if (obj == null) {
90+
return false;
91+
}
92+
if (getClass() != obj.getClass()) {
93+
return false;
94+
}
95+
LifecyclePolicyMetadata other = (LifecyclePolicyMetadata) obj;
96+
return Objects.equals(policy, other.policy) &&
97+
Objects.equals(headers, other.headers);
98+
}
99+
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.core.indexlifecycle;
8+
9+
import org.elasticsearch.cluster.ClusterModule;
10+
import org.elasticsearch.common.ParseField;
11+
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
12+
import org.elasticsearch.common.io.stream.Writeable.Reader;
13+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
14+
import org.elasticsearch.common.xcontent.XContentParser;
15+
import org.elasticsearch.test.AbstractSerializingTestCase;
16+
import org.junit.Before;
17+
18+
import java.io.IOException;
19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.HashMap;
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
public class LifecyclePolicyMetadataTests extends AbstractSerializingTestCase<LifecyclePolicyMetadata> {
26+
27+
private String lifecycleName;
28+
29+
@Before
30+
public void setup() {
31+
lifecycleName = randomAlphaOfLength(20); // NORELEASE we need to randomise the lifecycle name rather
32+
// than use the same name for all instances
33+
}
34+
35+
@Override
36+
protected NamedWriteableRegistry getNamedWriteableRegistry() {
37+
return new NamedWriteableRegistry(
38+
Arrays.asList(new NamedWriteableRegistry.Entry(LifecycleAction.class, MockAction.NAME, MockAction::new),
39+
new NamedWriteableRegistry.Entry(LifecycleType.class, TestLifecycleType.TYPE, (in) -> TestLifecycleType.INSTANCE)));
40+
}
41+
42+
@Override
43+
protected NamedXContentRegistry xContentRegistry() {
44+
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());
45+
entries.add(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(MockAction.NAME), MockAction::parse));
46+
entries.add(new NamedXContentRegistry.Entry(LifecycleType.class, new ParseField(TestLifecycleType.TYPE),
47+
(p) -> TestLifecycleType.INSTANCE));
48+
return new NamedXContentRegistry(entries);
49+
}
50+
51+
@Override
52+
protected LifecyclePolicyMetadata doParseInstance(XContentParser parser) throws IOException {
53+
return LifecyclePolicyMetadata.parse(parser, lifecycleName);
54+
}
55+
56+
@Override
57+
protected LifecyclePolicyMetadata createTestInstance() {
58+
Map<String, String> headers = new HashMap<>();
59+
int numberHeaders = between(0, 10);
60+
for (int i = 0; i < numberHeaders; i++) {
61+
headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10));
62+
}
63+
return new LifecyclePolicyMetadata(LifecyclePolicyTests.randomLifecyclePolicy(lifecycleName), headers);
64+
}
65+
66+
@Override
67+
protected Reader<LifecyclePolicyMetadata> instanceReader() {
68+
return LifecyclePolicyMetadata::new;
69+
}
70+
71+
@Override
72+
protected LifecyclePolicyMetadata mutateInstance(LifecyclePolicyMetadata instance) throws IOException {
73+
LifecyclePolicy policy = instance.getPolicy();
74+
Map<String, String> headers = instance.getHeaders();
75+
switch (between(0, 1)) {
76+
case 0:
77+
policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, policy.getName() + randomAlphaOfLengthBetween(1, 5),
78+
policy.getPhases());
79+
break;
80+
case 1:
81+
headers = new HashMap<>(headers);
82+
headers.put(randomAlphaOfLength(11), randomAlphaOfLength(11));
83+
break;
84+
default:
85+
throw new AssertionError("Illegal randomisation branch");
86+
}
87+
return new LifecyclePolicyMetadata(policy, headers);
88+
}
89+
90+
}

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleRunner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ private void moveToStep(Index index, String policy, StepKey currentStepKey, Step
238238
}
239239

240240
private void moveToErrorStep(Index index, String policy, StepKey currentStepKey, Exception e) {
241-
logger.debug("policy [" + policy + "] for index [" + index.getName() + "] failed on step [" + currentStepKey
241+
logger.error("policy [" + policy + "] for index [" + index.getName() + "] failed on step [" + currentStepKey
242242
+ "]. Moving to ERROR step.", e);
243243
clusterService.submitStateUpdateTask("ILM", new MoveToErrorStepUpdateTask(index, policy, currentStepKey, e, nowSupplier));
244244
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.indexlifecycle;
8+
9+
import org.elasticsearch.action.Action;
10+
import org.elasticsearch.action.ActionListener;
11+
import org.elasticsearch.action.ActionRequest;
12+
import org.elasticsearch.action.ActionRequestBuilder;
13+
import org.elasticsearch.action.ActionResponse;
14+
import org.elasticsearch.client.Client;
15+
import org.elasticsearch.client.support.AbstractClient;
16+
import org.elasticsearch.xpack.core.ClientHelper;
17+
import org.elasticsearch.xpack.core.indexlifecycle.Step;
18+
19+
import java.util.Map;
20+
21+
/**
22+
* This class wraps a client and calls the client using the headers provided in
23+
* constructor. The intent is to abstract away the fact that there are headers
24+
* so {@link Step}s etc. can call this client as if it was a normal client.
25+
*
26+
* Note: This client will not close the wrapped {@link Client} instance since
27+
* the intent is that the wrapped client is shared between multiple instances of
28+
* this class.
29+
*/
30+
public class LifecyclePolicySecurityClient extends AbstractClient {
31+
32+
private Client client;
33+
private Map<String, String> headers;
34+
private String origin;
35+
36+
public LifecyclePolicySecurityClient(Client client, String origin, Map<String, String> headers) {
37+
super(client.settings(), client.threadPool());
38+
this.client = client;
39+
this.origin = origin;
40+
this.headers = headers;
41+
}
42+
43+
@Override
44+
public void close() {
45+
// Doesn't close the wrapped client since this client object is shared
46+
// among multiple instances
47+
}
48+
49+
@Override
50+
protected <Request extends ActionRequest, Response extends ActionResponse,
51+
RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void doExecute(
52+
Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) {
53+
ClientHelper.executeWithHeadersAsync(headers, origin, client, action, request, listener);
54+
}
55+
56+
}

0 commit comments

Comments
 (0)