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 @@ -5,19 +5,201 @@
*/
package org.elasticsearch.xpack.core.indexlifecycle;

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.io.stream.Writeable;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.xpack.core.XPackFeatureSet;
import org.elasticsearch.xpack.core.XPackField;

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

public class IndexLifecycleFeatureSetUsage extends XPackFeatureSet.Usage {

private List<PolicyStats> policyStats;

public IndexLifecycleFeatureSetUsage(StreamInput input) throws IOException {
super(input);
if (input.readBoolean()) {
policyStats = input.readList(PolicyStats::new);
}
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
boolean hasPolicyStats = policyStats != null;
out.writeBoolean(hasPolicyStats);
if (hasPolicyStats) {
out.writeList(policyStats);
}
}

public IndexLifecycleFeatureSetUsage(boolean available, boolean enabled) {
this(available, enabled, null);
}

public IndexLifecycleFeatureSetUsage(boolean available, boolean enabled, List<PolicyStats> policyStats) {
super(XPackField.INDEX_LIFECYCLE, available, enabled);
this.policyStats = policyStats;
}

@Override
protected void innerXContent(XContentBuilder builder, Params params) throws IOException {
if (policyStats != null) {
builder.field("policy_count", policyStats.size());
builder.field("policy_stats", policyStats);
}
}

public List<PolicyStats> getPolicyStats() {
return policyStats;
}

@Override
public int hashCode() {
return Objects.hash(available, enabled, policyStats);
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
IndexLifecycleFeatureSetUsage other = (IndexLifecycleFeatureSetUsage) obj;
return Objects.equals(available, other.available) &&
Objects.equals(enabled, other.enabled) &&
Objects.equals(policyStats, other.policyStats);
}

public static final class PolicyStats implements ToXContentObject, Writeable {

public static final ParseField INDICES_MANAGED_FIELD = new ParseField("indices_managed");

private final Map<String, PhaseStats> phaseStats;
private final int indicesManaged;

public PolicyStats(Map<String, PhaseStats> phaseStats, int numberIndicesManaged) {
this.phaseStats = phaseStats;
this.indicesManaged = numberIndicesManaged;
}

public PolicyStats(StreamInput in) throws IOException {
this.phaseStats = in.readMap(StreamInput::readString, PhaseStats::new);
this.indicesManaged = in.readVInt();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeMap(phaseStats, StreamOutput::writeString, (o, p) -> p.writeTo(o));
out.writeVInt(indicesManaged);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(LifecyclePolicy.PHASES_FIELD.getPreferredName(), phaseStats);
builder.field(INDICES_MANAGED_FIELD.getPreferredName(), indicesManaged);
builder.endObject();
return builder;
}

public Map<String, PhaseStats> getPhaseStats() {
return phaseStats;
}

public int getIndicesManaged() {
return indicesManaged;
}

@Override
public int hashCode() {
return Objects.hash(phaseStats, indicesManaged);
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PolicyStats other = (PolicyStats) obj;
return Objects.equals(phaseStats, other.phaseStats) &&
Objects.equals(indicesManaged, other.indicesManaged);
}

@Override
public String toString() {
return Strings.toString(this);
}
}

public static final class PhaseStats implements ToXContentObject, Writeable {
private final String[] actionNames;
private final TimeValue minimumAge;

public PhaseStats(TimeValue after, String[] actionNames) {
this.actionNames = actionNames;
this.minimumAge = after;
}

public PhaseStats(StreamInput in) throws IOException {
actionNames = in.readStringArray();
minimumAge = in.readTimeValue();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeStringArray(actionNames);
out.writeTimeValue(minimumAge);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Phase.MINIMUM_AGE.getPreferredName(), minimumAge.getMillis());
builder.field(Phase.ACTIONS_FIELD.getPreferredName(), actionNames);
Copy link
Contributor

Choose a reason for hiding this comment

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

at first I thought this format would make it difficult to know how many policies didn't use a certain field, but after a few test queries, it looks like this is sufficient

builder.endObject();
return builder;
}

public String[] getActionNames() {
return actionNames;
}

public TimeValue getAfter() {
return minimumAge;
}

@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(actionNames), minimumAge);
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PhaseStats other = (PhaseStats) obj;
return Objects.equals(minimumAge, other.minimumAge) &&
Objects.deepEquals(actionNames, other.actionNames);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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.indexlifecycle;

import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.test.AbstractWireSerializingTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PolicyStats;

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

public class IndexLifecycleFeatureSetUsageTests extends AbstractWireSerializingTestCase<IndexLifecycleFeatureSetUsage> {

@Override
protected IndexLifecycleFeatureSetUsage createTestInstance() {
boolean enabled = randomBoolean();
boolean available = randomBoolean();
List<PolicyStats> policyStats = null;
if (enabled) {
int size = randomIntBetween(0, 10);
policyStats = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
policyStats.add(PolicyStatsTests.createRandomInstance());
}
}
return new IndexLifecycleFeatureSetUsage(available, enabled, policyStats);
}

@Override
protected IndexLifecycleFeatureSetUsage mutateInstance(IndexLifecycleFeatureSetUsage instance) throws IOException {
boolean available = instance.available();
boolean enabled = instance.enabled();
List<PolicyStats> policyStats = instance.getPolicyStats();
switch (between(0, 2)) {
case 0:
available = available == false;
break;
case 1:
enabled = enabled == false;
break;
case 2:
if (policyStats == null) {
policyStats = new ArrayList<>();
policyStats.add(PolicyStatsTests.createRandomInstance());
} else if (randomBoolean()) {
policyStats = null;
} else {
policyStats = new ArrayList<>(policyStats);
policyStats.add(PolicyStatsTests.createRandomInstance());
}
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new IndexLifecycleFeatureSetUsage(available, enabled, policyStats);
}

@Override
protected Reader<IndexLifecycleFeatureSetUsage> instanceReader() {
return IndexLifecycleFeatureSetUsage::new;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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.indexlifecycle;

import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.AbstractWireSerializingTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PhaseStats;

import java.io.IOException;
import java.util.Arrays;

public class PhaseStatsTests extends AbstractWireSerializingTestCase<PhaseStats> {

@Override
protected PhaseStats createTestInstance() {
return createRandomInstance();
}

public static PhaseStats createRandomInstance() {
TimeValue after = TimeValue.parseTimeValue(randomTimeValue(), "phase_stats_tests");
String[] actionNames = randomArray(0, 20, size -> new String[size], () -> randomAlphaOfLengthBetween(1, 20));
return new PhaseStats(after, actionNames);
}

@Override
protected PhaseStats mutateInstance(PhaseStats instance) throws IOException {
TimeValue after = instance.getAfter();
String[] actionNames = instance.getActionNames();
switch (between(0, 1)) {
case 0:
after = randomValueOtherThan(after, () -> TimeValue.parseTimeValue(randomPositiveTimeValue(), "rollover_action_test"));
break;
case 1:
actionNames = randomValueOtherThanMany(a -> Arrays.equals(a, instance.getActionNames()),
() -> randomArray(0, 20, size -> new String[size], () -> randomAlphaOfLengthBetween(1, 20)));
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new PhaseStats(after, actionNames);
}

@Override
protected Reader<PhaseStats> instanceReader() {
return PhaseStats::new;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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.indexlifecycle;

import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.test.AbstractWireSerializingTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PhaseStats;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PolicyStats;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class PolicyStatsTests extends AbstractWireSerializingTestCase<PolicyStats> {

@Override
protected PolicyStats createTestInstance() {
return createRandomInstance();
}

public static PolicyStats createRandomInstance() {
int size = randomIntBetween(0, 10);
Map<String, PhaseStats> phaseStats = new HashMap<>(size);
for (int i = 0; i < size; i++) {
phaseStats.put(randomAlphaOfLengthBetween(1, 20), PhaseStatsTests.createRandomInstance());
}
return new PolicyStats(phaseStats, randomIntBetween(0, 100));
}

@Override
protected PolicyStats mutateInstance(PolicyStats instance) throws IOException {
Map<String, PhaseStats> phaseStats = instance.getPhaseStats();
int indicesManaged = instance.getIndicesManaged();
switch (between(0, 1)) {
case 0:
phaseStats = new HashMap<>(instance.getPhaseStats());
phaseStats.put(randomAlphaOfLengthBetween(1, 20), PhaseStatsTests.createRandomInstance());
break;
case 1:
indicesManaged = randomIntBetween(1, 50);
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new PolicyStats(phaseStats, indicesManaged);
}

@Override
protected Reader<PolicyStats> instanceReader() {
return PolicyStats::new;
}

}
Loading