diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleFeatureSetUsage.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleFeatureSetUsage.java index 052db7337edff..a738ad3e34cfa 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleFeatureSetUsage.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleFeatureSetUsage.java @@ -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; + 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) { 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 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 phaseStats; + private final int indicesManaged; + + public PolicyStats(Map 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 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); + 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); + } } } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleFeatureSetUsageTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleFeatureSetUsageTests.java new file mode 100644 index 0000000000000..1035eb7a7462c --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleFeatureSetUsageTests.java @@ -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 { + + @Override + protected IndexLifecycleFeatureSetUsage createTestInstance() { + boolean enabled = randomBoolean(); + boolean available = randomBoolean(); + List 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 = 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 instanceReader() { + return IndexLifecycleFeatureSetUsage::new; + } + +} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/PhaseStatsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/PhaseStatsTests.java new file mode 100644 index 0000000000000..ae4325abe5d87 --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/PhaseStatsTests.java @@ -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 { + + @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 instanceReader() { + return PhaseStats::new; + } + +} diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/PolicyStatsTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/PolicyStatsTests.java new file mode 100644 index 0000000000000..0a9ac853c89fe --- /dev/null +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/PolicyStatsTests.java @@ -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 { + + @Override + protected PolicyStats createTestInstance() { + return createRandomInstance(); + } + + public static PolicyStats createRandomInstance() { + int size = randomIntBetween(0, 10); + Map 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 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 instanceReader() { + return PolicyStats::new; + } + +} diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java index e3214f61ed80d..2469621316889 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSet.java @@ -6,7 +6,10 @@ package org.elasticsearch.xpack.indexlifecycle; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.XPackLicenseState; @@ -14,16 +17,25 @@ import org.elasticsearch.xpack.core.XPackField; import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PhaseStats; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PolicyStats; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; +import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class IndexLifecycleFeatureSet implements XPackFeatureSet { private final boolean enabled; private final XPackLicenseState licenseState; + private ClusterService clusterService; @Inject - public IndexLifecycleFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState) { + public IndexLifecycleFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, ClusterService clusterService) { + this.clusterService = clusterService; this.enabled = XPackSettings.INDEX_LIFECYCLE_ENABLED.get(settings); this.licenseState = licenseState; } @@ -55,7 +67,31 @@ public Map nativeCodeInfo() { @Override public void usage(ActionListener listener) { - listener.onResponse(new IndexLifecycleFeatureSetUsage(available(), enabled())); + MetaData metaData = clusterService.state().metaData(); + IndexLifecycleMetadata lifecycleMetadata = metaData.custom(IndexLifecycleMetadata.TYPE); + if (enabled() && lifecycleMetadata != null) { + Map policyUsage = new HashMap<>(); + metaData.indices().forEach(entry -> { + String policyName = LifecycleSettings.LIFECYCLE_NAME_SETTING.get(entry.value.getSettings()); + Integer indicesManaged = policyUsage.get(policyName); + if (indicesManaged == null) { + indicesManaged = 1; + } else { + indicesManaged = indicesManaged + 1; + } + policyUsage.put(policyName, indicesManaged); + }); + List policyStats = lifecycleMetadata.getPolicies().values().stream().map(policy -> { + Map phaseStats = policy.getPhases().values().stream().map(phase -> { + String[] actionNames = phase.getActions().keySet().toArray(new String[phase.getActions().size()]); + return new Tuple(phase.getName(), new PhaseStats(phase.getMinimumAge(), actionNames)); + }).collect(Collectors.toMap(Tuple::v1, Tuple::v2)); + return new PolicyStats(phaseStats, policyUsage.getOrDefault(policy.getName(), 0)); + }).collect(Collectors.toList()); + listener.onResponse(new IndexLifecycleFeatureSetUsage(available(), enabled(), policyStats)); + } else { + listener.onResponse(new IndexLifecycleFeatureSetUsage(available(), enabled())); + } } } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetTests.java new file mode 100644 index 0000000000000..d83a41b4e60bc --- /dev/null +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetTests.java @@ -0,0 +1,146 @@ +/* + * 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.indexlifecycle; + +import org.elasticsearch.Version; +import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.cluster.ClusterName; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage.PolicyStats; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; +import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; +import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata; +import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; +import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; +import org.elasticsearch.xpack.core.indexlifecycle.Phase; +import org.junit.Before; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class IndexLifecycleFeatureSetTests extends ESTestCase { + + private XPackLicenseState licenseState; + private ClusterService clusterService; + + @Before + public void init() throws Exception { + licenseState = mock(XPackLicenseState.class); + clusterService = mock(ClusterService.class); + } + + public void testAvailable() { + IndexLifecycleFeatureSet featureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, licenseState, clusterService); + + when(licenseState.isIndexLifecycleAllowed()).thenReturn(false); + assertThat(featureSet.available(), equalTo(false)); + + when(licenseState.isIndexLifecycleAllowed()).thenReturn(true); + assertThat(featureSet.available(), equalTo(true)); + + featureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, null, clusterService); + assertThat(featureSet.available(), equalTo(false)); + } + + public void testEnabled() { + Settings.Builder settings = Settings.builder().put("xpack.ilm.enabled", false); + IndexLifecycleFeatureSet featureSet = new IndexLifecycleFeatureSet(settings.build(), licenseState, clusterService); + assertThat(featureSet.enabled(), equalTo(false)); + + settings = Settings.builder().put("xpack.ilm.enabled", true); + featureSet = new IndexLifecycleFeatureSet(settings.build(), licenseState, clusterService); + assertThat(featureSet.enabled(), equalTo(true)); + } + + public void testName() { + IndexLifecycleFeatureSet featureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, licenseState, clusterService); + assertThat(featureSet.name(), equalTo("ilm")); + } + + public void testNativeCodeInfo() { + IndexLifecycleFeatureSet featureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, licenseState, clusterService); + assertNull(featureSet.nativeCodeInfo()); + } + + public void testUsageStats() throws Exception { + Map indexPolicies = new HashMap<>(); + List policies = new ArrayList<>(); + String policy1Name = randomAlphaOfLength(10); + String policy2Name = randomAlphaOfLength(10); + String policy3Name = randomAlphaOfLength(10); + indexPolicies.put("index_1", policy1Name); + indexPolicies.put("index_2", policy1Name); + indexPolicies.put("index_3", policy1Name); + indexPolicies.put("index_4", policy1Name); + indexPolicies.put("index_5", policy3Name); + LifecyclePolicy policy1 = new LifecyclePolicy(policy1Name, Collections.emptyMap()); + policies.add(policy1); + PolicyStats policy1Stats = new PolicyStats(Collections.emptyMap(), 4); + + Map phases1 = new HashMap<>(); + LifecyclePolicy policy2 = new LifecyclePolicy(policy2Name, phases1); + policies.add(policy2); + PolicyStats policy2Stats = new PolicyStats(Collections.emptyMap(), 0); + + LifecyclePolicy policy3 = new LifecyclePolicy(policy3Name, Collections.emptyMap()); + policies.add(policy3); + PolicyStats policy3Stats = new PolicyStats(Collections.emptyMap(), 1); + + ClusterState clusterState = buildClusterState(policies, indexPolicies); + Mockito.when(clusterService.state()).thenReturn(clusterState); + + PlainActionFuture future = new PlainActionFuture<>(); + IndexLifecycleFeatureSet ilmFeatureSet = new IndexLifecycleFeatureSet(Settings.EMPTY, licenseState, clusterService); + ilmFeatureSet.usage(future); + IndexLifecycleFeatureSetUsage ilmUsage = (IndexLifecycleFeatureSetUsage) future.get(); + assertThat(ilmUsage.enabled(), equalTo(ilmFeatureSet.enabled())); + assertThat(ilmUsage.available(), equalTo(ilmFeatureSet.available())); + + List policyStatsList = ilmUsage.getPolicyStats(); + assertThat(policyStatsList.size(), equalTo(policies.size())); + assertTrue(policyStatsList.contains(policy1Stats)); + assertTrue(policyStatsList.contains(policy2Stats)); + assertTrue(policyStatsList.contains(policy3Stats)); + + } + + private ClusterState buildClusterState(List lifecyclePolicies, Map indexPolicies) { + Map lifecyclePolicyMetadatasMap = lifecyclePolicies.stream() + .map(p -> new LifecyclePolicyMetadata(p, Collections.emptyMap(), 1, 0L)) + .collect(Collectors.toMap(LifecyclePolicyMetadata::getName, Function.identity())); + IndexLifecycleMetadata indexLifecycleMetadata = new IndexLifecycleMetadata(lifecyclePolicyMetadatasMap, OperationMode.RUNNING); + + MetaData.Builder metadata = MetaData.builder().putCustom(IndexLifecycleMetadata.TYPE, indexLifecycleMetadata); + indexPolicies.forEach((indexName, policyName) -> { + Settings indexSettings = Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, policyName) + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0) + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); + IndexMetaData.Builder indexMetadata = IndexMetaData.builder(indexName).settings(indexSettings); + metadata.put(indexMetadata); + }); + + return ClusterState.builder(new ClusterName("my_cluster")).metaData(metadata).build(); + } +} diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetUsageTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetUsageTests.java new file mode 100644 index 0000000000000..7bd974d31c176 --- /dev/null +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleFeatureSetUsageTests.java @@ -0,0 +1,59 @@ +/* + * 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.indexlifecycle; + +import org.elasticsearch.common.io.stream.Writeable.Reader; +import org.elasticsearch.test.AbstractWireSerializingTestCase; +import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleFeatureSetUsage; +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 { + + @Override + protected IndexLifecycleFeatureSetUsage createTestInstance() { + boolean available = randomBoolean(); + boolean enabled = randomBoolean(); + List policyStats = new ArrayList<>(); + int size = randomIntBetween(0, 10); + for (int i = 0; i < size; i++) { + policyStats.add(PolicyStatsTests.randomPolicyStats()); + } + return new IndexLifecycleFeatureSetUsage(available, enabled, policyStats); + } + + @Override + protected IndexLifecycleFeatureSetUsage mutateInstance(IndexLifecycleFeatureSetUsage instance) throws IOException { + boolean available = instance.available(); + boolean enabled = instance.enabled(); + List policyStats = instance.getPolicyStats(); + switch (between(0, 2)) { + case 0: + available = available == false; + break; + case 1: + enabled = enabled == false; + break; + case 2: + policyStats = new ArrayList<>(policyStats); + policyStats.add(PolicyStatsTests.randomPolicyStats()); + break; + default: + throw new AssertionError("Illegal randomisation branch"); + } + return new IndexLifecycleFeatureSetUsage(available, enabled, policyStats); + } + + @Override + protected Reader instanceReader() { + return IndexLifecycleFeatureSetUsage::new; + } + +} diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PhaseStatsTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PhaseStatsTests.java new file mode 100644 index 0000000000000..fe7fd1fca05d3 --- /dev/null +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PhaseStatsTests.java @@ -0,0 +1,54 @@ +/* + * 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.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 { + + @Override + protected PhaseStats createTestInstance() { + return randomPhaseStats(); + } + + static PhaseStats randomPhaseStats() { + TimeValue minimumAge = TimeValue.parseTimeValue(randomTimeValue(0, 1000000000, "s", "m", "h", "d"), "test_after"); + String[] actionNames = generateRandomStringArray(10, 20, false); + return new PhaseStats(minimumAge, actionNames); + } + + @Override + protected PhaseStats mutateInstance(PhaseStats instance) throws IOException { + TimeValue minimumAge = instance.getAfter(); + String[] actionNames = instance.getActionNames(); + switch (between(0, 1)) { + case 0: + minimumAge = randomValueOtherThan(minimumAge, + () -> TimeValue.parseTimeValue(randomTimeValue(0, 1000000000, "s", "m", "h", "d"), "test_after")); + break; + case 1: + actionNames = Arrays.copyOf(actionNames, actionNames.length + 1); + actionNames[actionNames.length - 1] = randomAlphaOfLengthBetween(10, 20); + break; + default: + throw new AssertionError("Illegal randomisation branch"); + } + return new PhaseStats(minimumAge, actionNames); + } + + @Override + protected Reader instanceReader() { + return PhaseStats::new; + } + +} diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStatsTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStatsTests.java new file mode 100644 index 0000000000000..f2a77ee9e246c --- /dev/null +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/indexlifecycle/PolicyStatsTests.java @@ -0,0 +1,58 @@ +/* + * 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.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 { + + @Override + protected PolicyStats createTestInstance() { + return randomPolicyStats(); + } + + static PolicyStats randomPolicyStats() { + Map phaseStats = new HashMap<>(); + int size = randomIntBetween(0, 10); + for (int i = 0; i < size; i++) { + phaseStats.put(randomAlphaOfLength(10), PhaseStatsTests.randomPhaseStats()); + } + int numberIndicesManaged = randomIntBetween(0, 1000); + return new PolicyStats(phaseStats, numberIndicesManaged); + } + + @Override + protected PolicyStats mutateInstance(PolicyStats instance) throws IOException { + Map phaseStats = instance.getPhaseStats(); + int numberIndicesManaged = instance.getIndicesManaged(); + switch (between(0, 1)) { + case 0: + phaseStats = new HashMap<>(phaseStats); + phaseStats.put(randomAlphaOfLength(10), PhaseStatsTests.randomPhaseStats()); + break; + case 1: + numberIndicesManaged += randomIntBetween(1, 10); + break; + default: + throw new AssertionError("Illegal randomisation branch"); + } + return new PolicyStats(phaseStats, numberIndicesManaged); + } + + @Override + protected Reader instanceReader() { + return PolicyStats::new; + } + +}